Skip to content

Commit

Permalink
Add first version of the package (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
traversaro authored Aug 31, 2023
1 parent 0f28d1c commit 947d31d
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 1 deletion.
51 changes: 51 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: CI Workflow

on:
push:
pull_request:
schedule:
# * is a special character in YAML so you have to quote this string
# Execute a "nightly" build at 2 AM UTC
- cron: '0 2 * * *'

jobs:
build-with-conda-dependencies:
name: '[conda:${{ matrix.os }}]'
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
build_type: [Release]
os: [ubuntu-22.04, macos-latest, windows-2019]

steps:
- uses: actions/checkout@v3

- name: Print used environment (no conda) [Conda]
shell: bash
run: |
env
- uses: mamba-org/setup-micromamba@v1
with:
environment-file: ci_env.yml

- name: Install the package
shell: bash -l {0}
run: python -m pip install --no-deps .

- name: Import the package
shell: bash -l {0}
run: python -c "import resolve_robotics_uri_py"

# This test requires the conda-forge::icub-models,
# robotology::ergocub-software and
# robostack-staging::ros-humble-moveit-resources-panda-description
# conda packages, that are installed in ci_env.yml environment
- name: Check command line helper
shell: bash -l {0}
run: |
resolve-robotics-uri-py package://iCub/robots/iCubGazeboV2_7/model.urdf
resolve-robotics-uri-py package://ergoCub/robots/ergoCubSN000/model.urdf
resolve-robotics-uri-py package://moveit_resources_panda_description/urdf/panda.urdf
! resolve-robotics-uri-py package://this/file/does/not/exist
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,53 @@
# resolve-robotics-uri-py
Resolve a package:// or model:// URI to an absolute filename in Python.

Pure Python package (that only depends on Python stdlib) to resolve a package:// (ROS-style) or model:// (Gazebo-style) URI to an absolute filename.

## Installation

Use the package manager [pip](https://pip.pypa.io/en/stable/) to install resolve-robotics-uri-py.

```bash
python -m pip install git+https://github.com/ami-iit/resolve-robotics-uri-py
```

## Usage in Python

Add `import resolve_robotics_uri_py` to your Python file, then take inspiration from the following examples.

If you want to get the location of the `iCubGazeboV2_7` iCub model installed from [`icub-models`](https://github.com/robotology/icub-models):

~~~python
absolute_path = resolve_robotics_uri_py.resolve_robotics_uri("package://iCub/robots/iCubGazeboV2_7/model.urdf")
~~~

If you want to get the location of the `ergoCubSN00` model installed from [`ergocub-software`](https://github.com/icub-tech-iit/ergocub-software):

~~~python
absolute_path = resolve_robotics_uri_py.resolve_robotics_uri("package://ergoCub/robots/ergoCubSN000/model.urdf")
~~~

If you want to get the location of the `panda` model installed by [`moveit_resources_panda_description`](https://index.ros.org/p/moveit_resources_panda_description/):

~~~python
absolute_path = resolve_robotics_uri_py.resolve_robotics_uri("package://moveit_resources_panda_description/urdf/panda.urdf")
~~~


## Command Line usage

`resolve_robotics_uri_py` also install a command line tool called `resolve-robotics-uri-py` for use in scripts, that can be used as:

~~~
resolve-robotics-uri-py package://iCub/robots/iCubGazeboV2_7/model.urdf
~~~

## Contributing

Pull requests are welcome. For major changes, please open an issue first
to discuss what you would like to change.

Please make sure to update tests as appropriate.

## License

[BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html)
12 changes: 12 additions & 0 deletions ci_env.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: testenv
channels:
- conda-forge
- robotology
- robostack-staging
dependencies:
- python
- pip
# packages that ship URDFs used to test
- icub-models
- ergocub-software
- ros-humble-moveit-resources-panda-description
17 changes: 17 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[build-system]
build-backend = "setuptools.build_meta"
requires = [
"wheel",
"setuptools>=45",
"setuptools_scm[toml]>=6.2",
]

[tool.setuptools_scm]
local_scheme = "dirty-tag"

[tool.black]
line-length = 88

[tool.isort]
profile = "black"
multi_line_output = 3
62 changes: 62 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[metadata]
name = resolve-robotics-uri-py
description = Pure python package to solve ROS-style package:// and Gazebo-style model:// URIs in absolute paths.
long_description = file: README.md
long_description_content_type = text/markdown
author = Silvio Traversaro
author_email = [email protected]
license = BSD
license_files = LICENSE
platforms = any
url = https://github.com/ami-iit/resolve-robotics-uri-py

project_urls =
Changelog = https://github.com/ami-iit/resolve-robotics-uri-py/releases
Source = https://github.com/ami-iit/resolve-robotics-uri-py
Tracker = https://github.com/ami-iit/resolve-robotics-uri-py/issues

keywords =

classifiers =
Development Status :: 4 - Beta
Intended Audience :: Developers
License :: OSI Approved :: BSD License
Operating System :: POSIX :: Linux
Operating System :: MacOS
Operating System :: Microsoft
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3 :: Only
Programming Language :: Python :: Implementation :: CPython
Topic :: Software Development

[options]
zip_safe = False
packages = find:
package_dir =
=src
python_requires = >=3.8
install_requires =


[options.packages.find]
where = src

[options.entry_points]
console_scripts =
resolve-robotics-uri-py = resolve_robotics_uri_py.resolve_robotics_uri_py:main

[options.extras_require]
style =
black
isort
testing =
all =
%(style)s
%(testing)s

[tool:pytest]
addopts = -rsxX -v --strict-markers
testpaths = tests
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import setuptools

setuptools.setup()
Empty file.
81 changes: 81 additions & 0 deletions src/resolve_robotics_uri_py/resolve_robotics_uri_py.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import argparse
import os
import pathlib
import sys
from typing import List
import warnings

# Function inspired from https://github.com/ami-iit/robot-log-visualizer/pull/51
def get_search_paths_from_envs(env_list):
return [
pathlib.Path(f) if (env != "AMENT_PREFIX_PATH") else pathlib.Path(f) / "share"
for env in env_list if os.getenv(env) is not None
for f in os.getenv(env).split(os.pathsep)
]

def pathlist_list_to_string(path_list):
return ' '.join(str(path) for path in path_list)

def resolve_robotics_uri(uri: str) -> pathlib.Path:
# List of environment variables to consider, see:
# * https://github.com/robotology/idyntree/issues/291
# * https://github.com/gazebosim/sdformat/issues/1234
# AMENT_PREFIX_PATH is the only "special" as we need to add
# "share" after each value, see https://github.com/stack-of-tasks/pinocchio/issues/1520
# This list specify the origin of each env variable:
# * GAZEBO_MODEL_PATH: Used in Gazebo Classic
# * ROS_PACKAGE_PATH: Used in ROS1
# * AMENT_PREFIX_PATH: Used in ROS2
# * SDF_PATH: Used in sdformat
# * IGN_GAZEBO_RESOURCE_PATH: Used in Ignition Gazebo <= 7
# * GZ_SIM_RESOURCE_PATH: Used in Gazebo Sim >= 7
env_list = ["GAZEBO_MODEL_PATH", "ROS_PACKAGE_PATH", "AMENT_PREFIX_PATH", "SDF_PATH", "IGN_GAZEBO_RESOURCE_PATH", "GZ_SIM_RESOURCE_PATH"]

# Preliminary step: if there is no scheme, we just consider this a path and we return it as it is
if "://" not in uri:
return pathlib.Path(uri)

# Get scheme from URI
from urllib.parse import urlparse
parsed_uri = urlparse(uri)

# We only support at the moment:
# file:// scheme: to pass a file path directly
# package:// : ROS-style package URI
# model:// : SDF-style model URI
if parsed_uri.scheme not in ["file", "package", "model"]:
raise FileNotFoundError(f"Passed URI \"{uri}\" use non-supported scheme {parsed_uri.scheme}")

model_filenames = []

if parsed_uri.scheme == "file":
model_filenames.append(uri.replace("file:/", ""))

if parsed_uri.scheme == "package" or parsed_uri.scheme == "model":
uri_path = uri.replace(f"{parsed_uri.scheme}://","")
for folder in get_search_paths_from_envs(env_list):
candidate_file_name = folder / pathlib.Path(uri_path)
if (candidate_file_name.is_file()):
if candidate_file_name not in model_filenames:
model_filenames.append(candidate_file_name)

if model_filenames:
if (len(model_filenames) > 1):
warnings.warn(f"resolve-robotics-uri-py: Multiple files ({pathlist_list_to_string(model_filenames)}) found for uri \"{uri}\", returning the first one.")
return pathlib.Path(model_filenames[0])

# If no file was found raise error
raise FileNotFoundError(f"resolve-robotics-uri-py: No file corresponding to uri \"{uri}\" found")

def main():
parser = argparse.ArgumentParser(description="Utility resolve a robotics URI (file://, model://, package://) to an absolute filename.")
parser.add_argument("uri", metavar="uri", type=str, help="URI to resolve")

args = parser.parse_args()
result = resolve_robotics_uri(args.uri)

print(result)
sys.exit(0)

if __name__ == "__main__":
main()

0 comments on commit 947d31d

Please sign in to comment.