Skip to content

Commit

Permalink
Merge pull request #17 from open-dynamic-robot-initiative/fkloss/py
Browse files Browse the repository at this point in the history
Convert to Python package
  • Loading branch information
luator authored Jul 30, 2024
2 parents 4bb4064 + dc34eb2 commit a3e97d2
Show file tree
Hide file tree
Showing 66 changed files with 155 additions and 80 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Install package via pip and run tests
name: Tests (pip install)

on:
push:
branches:
- master
pull_request:

jobs:
pytest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Update pip
run: |
python -m pip install --upgrade pip
- name: Install package
run: |
python -m pip install ".[test]"
- name: Run tests
run: |
python -m pytest
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.pyc
urdf/*
.DS_Store
build/
*.egg-info
.DS_Store
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

## [Unreleased]

### Changed
- Converted to pure Python package. You can still use the package in a colcon workspace
as before, but it is now also possible to install it with pip.
- **BREAKING:** Model files are not installed to `share/` anymore. Instead they are
installed as package data inside the Python package. This allows to get the
path to the installed files in the same way with both a colcon-based and a pip-based
installation.

### Added
- Python package with function `get_urdf_base_path()`
- Moved Pinocchio-based `Kinematics` class from trifinger_simulation to this package.
Expand Down
62 changes: 0 additions & 62 deletions CMakeLists.txt

This file was deleted.

9 changes: 9 additions & 0 deletions doc/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,12 @@ Installation
The ``robot_properties_fingers`` package is part of the TriFinger software
bundle. See :ref:`trifinger_docs:install_software` in the TriFinger
documentation.


Alternatively, it can also be installed with standard Python tools, e.g.:

.. code-block:: bash
git clone https://github.com/open-dynamic-robot-initiative/robot_properties_fingers.git
cd robot_properties_fingers
pip install .
13 changes: 6 additions & 7 deletions package.xml
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
<?xml version="1.0"?>
<package format="2">
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>robot_properties_fingers</name>
<version>1.1.0</version>
<version>1.2.0</version>
<description>Xacro files and meshes of the (Tri-)Finger robots.</description>
<maintainer email="[email protected]">Felix Widmaier</maintainer>
<license>BSD 3-clause</license>

<buildtool_depend>ament_cmake</buildtool_depend>
<license>BSD-3-Clause</license>

<!-- We need the xacro package to build the urdf model -->
<build_depend>xacro</build_depend>

<exec_depend>pinocchio</exec_depend>

<test_depend>ament_cmake_pytest</test_depend>
<test_depend>python3-pytest</test_depend>

<export>
<build_type>ament_cmake</build_type>
<build_type>ament_python</build_type>
</export>
</package>
19 changes: 18 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
[build-system]
requires = ["setuptools", "xacro"]
build-backend = "setuptools.build_meta"


[tool.pylint.messages_control]
disable = "C0330, C0326"

Expand All @@ -7,9 +12,10 @@ exclude = "doc/"
[[tool.mypy.overrides]]
# list all modules for which no type hints are available
module = [
"ament_index_python.*",
"xacro",
"pinocchio",
"pytest",
"setuptools.*",
]
ignore_missing_imports = true

Expand Down Expand Up @@ -54,3 +60,14 @@ convention = "google"
"__init__.py" = ["F401"] # unused imports
"tests/*" = ["D", "ANN", "PLR2004"]
"scripts/*" = ["D"]


[tool.pytest.ini_options]
# Explicitly specifying the test directory here is needed for `colcon test`, otherwise
# it insists on importing robot_properties_fingers from the source directory for some
# reason (which fails as URDF files only exist in the install space).
# See https://robotics.stackexchange.com/q/112352/16508
testpaths = "tests"
addopts = [
"--import-mode=importlib",
]
Empty file.
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[develop]
script_dir=$base/lib/robot_properties_fingers
[install]
install_scripts=$base/lib/robot_properties_fingers
72 changes: 72 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""Setup script for the robot_properties_fingers package."""

import pathlib
from os import path

from setuptools import find_packages, setup
from setuptools.command.build_py import build_py

import xacro

package_name = "robot_properties_fingers"


class CustomBuildCommand(build_py):
"""Custom build command to process xacro files."""

def run(self) -> None:
"""Run the build command."""
# Call the original build_py command
build_py.run(self)

# Define the paths
xacro_dir = pathlib.Path("xacro_files")
urdf_dir = pathlib.Path(self.build_lib) / package_name / "urdf"

# Process each xacro file
for xacro_file in xacro_dir.glob("**/*.xacro"):
relative_urdf_path = xacro_file.relative_to(xacro_dir).with_suffix("")
urdf_file = urdf_dir / relative_urdf_path

# ensure output directory exists
urdf_file.parent.mkdir(parents=True, exist_ok=True)

# Use xacro API to process the file
doc = xacro.process_file(str(xacro_file))
urdf_content = doc.toprettyxml(indent=" ")
urdf_file.write_text(urdf_content)


setup(
name=package_name,
version="1.2.0",
packages=find_packages(where="src"),
package_dir={"": "src"},
package_data={"robot_properties_fingers": ["meshes/*.stl", "meshes/**/*.stl"]},
data_files=[
(
"share/ament_index/resource_index/packages",
[path.join("resource", package_name)],
),
(
path.join("share", package_name),
["package.xml"],
),
],
install_requires=[
"setuptools",
"xacro",
"pin", # pinocchio
],
extras_require={"test": ["pytest"]},
zip_safe=True,
maintainer="Felix Kloss",
maintainer_email="[email protected]",
description="Xacro files and meshes of the (Tri-)Finger robots.",
license="BSD-3-Clause",
tests_require=["pytest"],
entry_points={
"console_scripts": [],
},
cmdclass={"build_py": CustomBuildCommand},
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import pathlib

from ament_index_python.packages import get_package_share_directory

from .pinocchio_utils import Kinematics


Expand All @@ -17,22 +15,22 @@ def get_urdf_base_path(robot_type: str) -> pathlib.Path:
urdf_path = get_urdf_base_path("pro") / "trifingerpro.urdf"
Args:
robot_type: Type of the robot. One of {"pro", "edu", "one"}.
robot_type: Type of the robot. One of {"pro", "edu", "one", "_root_"}.
"_root_" is a special type that returns the root directory containing all
the URDF files.
Returns:
Path to the directory containing the URDF files of the specified robot type.
"""
ROBOT_TYPES = ("pro", "edu", "one")
ROBOT_TYPES = ("pro", "edu", "one", "_root_")
if robot_type not in ROBOT_TYPES:
raise ValueError(
f"Invalid robot type {robot_type}. Valid types are {ROBOT_TYPES}."
)

base_dir = (
pathlib.Path(get_package_share_directory("robot_properties_fingers")) / "urdf"
)
base_dir = pathlib.Path(__file__).parent / "urdf"

if robot_type == "one":
if robot_type in ("_root_", "one"):
return base_dir
return base_dir / robot_type

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
Diff not rendered.
File renamed without changes.
3 changes: 3 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
def test_get_urdf_base_path() -> None:
# verify paths by checking for existence of one of the expected URDF files

root = get_urdf_base_path("_root_")
assert (root / "pro").is_dir()

one = get_urdf_base_path("one")
assert (one / "finger.urdf").is_file()

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit a3e97d2

Please sign in to comment.