From 12d37389c65da1ca61f6ee00da63577cbe80376b Mon Sep 17 00:00:00 2001 From: "R. Kent James" Date: Thu, 21 Mar 2024 10:34:46 -0700 Subject: [PATCH 1/3] Add build tests --- .github/workflows/test.yml | 11 +- .gitignore | 12 + README.md | 23 +- test/packages/full_package/Changelog.rst | 1 + test/packages/full_package/LICENSE | 201 +++++++++++++++++ test/packages/full_package/README.md | 1 + test/packages/full_package/contributing.md | 3 + .../full_package/doc/instructions.rst | 9 + .../full_package/doc/morestuff/hereismore.md | 11 + .../doc/morestuff/more_of_more/subsub.md | 3 + test/packages/full_package/doc/unknown.xyz | 1 + .../full_package/full_package/__init__.py | 15 ++ .../full_package/full_package/dummy.py | 31 +++ .../full_package/srv/NodeCommand.srv | 5 + .../include/full_package/iamcpp.hpp | 58 +++++ .../full_package/msg/NumPwrResult.msg | 10 + test/packages/full_package/package.xml | 23 ++ test/packages/full_package/src/iamcpp.cpp | 0 .../minimal_publisher_py/CHANGELOG.rst | 114 ++++++++++ test/packages/minimal_publisher_py/README.md | 6 + .../minimal_publisher_py/__init__.py | 0 .../publisher_local_function.py | 50 +++++ .../publisher_member_function.py | 52 +++++ .../publisher_old_school.py | 51 +++++ .../packages/minimal_publisher_py/package.xml | 24 ++ .../resource/minimal_publisher_py | 0 test/packages/minimal_publisher_py/setup.cfg | 4 + test/packages/minimal_publisher_py/setup.py | 39 ++++ test/packages/minimum_package/package.xml | 9 + test/test_builder.py | 209 ++++++++++++++++++ 30 files changed, 970 insertions(+), 6 deletions(-) create mode 100644 test/packages/full_package/Changelog.rst create mode 100644 test/packages/full_package/LICENSE create mode 100644 test/packages/full_package/README.md create mode 100644 test/packages/full_package/contributing.md create mode 100644 test/packages/full_package/doc/instructions.rst create mode 100644 test/packages/full_package/doc/morestuff/hereismore.md create mode 100644 test/packages/full_package/doc/morestuff/more_of_more/subsub.md create mode 100644 test/packages/full_package/doc/unknown.xyz create mode 100644 test/packages/full_package/full_package/__init__.py create mode 100644 test/packages/full_package/full_package/dummy.py create mode 100644 test/packages/full_package/full_package/srv/NodeCommand.srv create mode 100644 test/packages/full_package/include/full_package/iamcpp.hpp create mode 100644 test/packages/full_package/msg/NumPwrResult.msg create mode 100644 test/packages/full_package/package.xml create mode 100644 test/packages/full_package/src/iamcpp.cpp create mode 100644 test/packages/minimal_publisher_py/CHANGELOG.rst create mode 100644 test/packages/minimal_publisher_py/README.md create mode 100644 test/packages/minimal_publisher_py/minimal_publisher_py/__init__.py create mode 100644 test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py create mode 100644 test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py create mode 100644 test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py create mode 100644 test/packages/minimal_publisher_py/package.xml create mode 100644 test/packages/minimal_publisher_py/resource/minimal_publisher_py create mode 100644 test/packages/minimal_publisher_py/setup.cfg create mode 100644 test/packages/minimal_publisher_py/setup.py create mode 100644 test/packages/minimum_package/package.xml create mode 100644 test/test_builder.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3b8de5e..2bd861f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,8 +2,6 @@ name: CI on: push: - branches: - - main pull_request: branches: - main @@ -11,10 +9,10 @@ on: jobs: unit_tests: name: Unit Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: - python-version: ['3.8', '3.9'] + python-version: ['3.8', '3.9', '3.10'] steps: - name: Checkout @@ -38,5 +36,8 @@ jobs: python -m pip install --upgrade --upgrade-strategy eager .[test] python -m pip freeze + - name: Install apt dependencies + run: sudo apt update && sudo apt install -y doxygen graphviz + - name: Run tests - run: py.test --verbose test + run: python -m pytest -s test diff --git a/.gitignore b/.gitignore index 1c1874d..d4018a2 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,15 @@ docs/_build/ # PyBuilder target/ .pytest_cache + +# Editors +.vscode/ + +# tests +generated/ +test/packages/full_package/index.rst +test/packages/full_package/conf.py +test/packages/minimum_package/index.rst +test/packages/minimum_package/conf.py +test/packages/minimal_publisher_py/index.rst +test/packages/minimal_publisher_py/conf.py diff --git a/README.md b/README.md index 0955808..c1a64d4 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,28 @@ TODO ## Testing -TODO +To install rosdoc2 prerequisites for testing, run +``` +pip install --user --upgrade .[test] +``` + +You probably want to test rosdoc2 using code in a local directory rather than +re-running install every time you do a change. To do this, run (from the directory +containing this README): +``` +python3 -m pytest +``` +If you want to see more output, try the ```-rP``` and/or ```--log-level=DEBUG``` option. +To limit to a particular test, for example the test of "full_package", use ```-k full_package``` + +Combining these as an example, to get detailed output from the full_package test even for +passed tests, run: +``` +python3 -m pytest -rP --log-level=DEBUG -k full_package +``` + + + ## Contributing diff --git a/test/packages/full_package/Changelog.rst b/test/packages/full_package/Changelog.rst new file mode 100644 index 0000000..dca2c15 --- /dev/null +++ b/test/packages/full_package/Changelog.rst @@ -0,0 +1 @@ +This should have a changelog. diff --git a/test/packages/full_package/LICENSE b/test/packages/full_package/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/test/packages/full_package/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/test/packages/full_package/README.md b/test/packages/full_package/README.md new file mode 100644 index 0000000..761cadc --- /dev/null +++ b/test/packages/full_package/README.md @@ -0,0 +1 @@ +This is the package readme. Note it has no markdown headings. Normally these should be included, but in case they are not we insert a README heading. diff --git a/test/packages/full_package/contributing.md b/test/packages/full_package/contributing.md new file mode 100644 index 0000000..55bf811 --- /dev/null +++ b/test/packages/full_package/contributing.md @@ -0,0 +1,3 @@ +# How to Contribute + +This file would contain contribution instructions. Here it is testing a lower case filename, which should be allowed. diff --git a/test/packages/full_package/doc/instructions.rst b/test/packages/full_package/doc/instructions.rst new file mode 100644 index 0000000..f64b46c --- /dev/null +++ b/test/packages/full_package/doc/instructions.rst @@ -0,0 +1,9 @@ +Instructions +============ + +Do it this way. + +Subheading +---------- + +Here is more detail of how to do it. diff --git a/test/packages/full_package/doc/morestuff/hereismore.md b/test/packages/full_package/doc/morestuff/hereismore.md new file mode 100644 index 0000000..3b9557d --- /dev/null +++ b/test/packages/full_package/doc/morestuff/hereismore.md @@ -0,0 +1,11 @@ +# This is more documentation + +blah, blah. + +## Level 2 header + +more blah. + +### Level 3 header + +even more blah. diff --git a/test/packages/full_package/doc/morestuff/more_of_more/subsub.md b/test/packages/full_package/doc/morestuff/more_of_more/subsub.md new file mode 100644 index 0000000..468f10e --- /dev/null +++ b/test/packages/full_package/doc/morestuff/more_of_more/subsub.md @@ -0,0 +1,3 @@ +# This is deep + +A deeper file's content diff --git a/test/packages/full_package/doc/unknown.xyz b/test/packages/full_package/doc/unknown.xyz new file mode 100644 index 0000000..875ab4f --- /dev/null +++ b/test/packages/full_package/doc/unknown.xyz @@ -0,0 +1 @@ +This file demonstrates what happens with a file of unknown type. Namely, it is ignored. diff --git a/test/packages/full_package/full_package/__init__.py b/test/packages/full_package/full_package/__init__.py new file mode 100644 index 0000000..f5a59d4 --- /dev/null +++ b/test/packages/full_package/full_package/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This is the documentation for the whole ROS package as a python module.""" diff --git a/test/packages/full_package/full_package/dummy.py b/test/packages/full_package/full_package/dummy.py new file mode 100644 index 0000000..2d0ed40 --- /dev/null +++ b/test/packages/full_package/full_package/dummy.py @@ -0,0 +1,31 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This file is used to test documentation generation.""" + + +class Example(): + """This is the overview of the Example class.""" + + def __init__(self): + """Construct example.""" + pass + + def do_something(p) -> str: + """Do something. + + :param list[str] p: This is a parameter description + :return: just the input arm itself + """ + return p diff --git a/test/packages/full_package/full_package/srv/NodeCommand.srv b/test/packages/full_package/full_package/srv/NodeCommand.srv new file mode 100644 index 0000000..d861003 --- /dev/null +++ b/test/packages/full_package/full_package/srv/NodeCommand.srv @@ -0,0 +1,5 @@ +# Commands to start or stop launch files or behaviors +string name # thing to start +string command # start, stop, status +--- +string response diff --git a/test/packages/full_package/include/full_package/iamcpp.hpp b/test/packages/full_package/include/full_package/iamcpp.hpp new file mode 100644 index 0000000..e25cbed --- /dev/null +++ b/test/packages/full_package/include/full_package/iamcpp.hpp @@ -0,0 +1,58 @@ +// +// Copyright 2022 R. Kent James +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FULL_PACKAGE__IAMCPP_HPP_ +#define FULL_PACKAGE__IAMCPP_HPP_ + +/// @file +/// @brief This is the header file for the DoSomeCpp class implementing a node do_some_cpp + +#include +#include "rclcpp/rclcpp.hpp" + +/// namespace for the ROS2 package containing the do_some_cpp node +namespace full_package +{ + +/** + + A demonstration of a simple ROS2 node that does nothing. + + Bold Statement Describe that boldness + + Just plain old documentation. + + */ + +class DoSomeCpp: public rclcpp::node +{ +public: + DoSomeCpp(); + virtual ~DoSomeCpp() {} + + /// Generate the root and power of a number + static std::tuple apply_powers( + const double_t number, ///< base value we want to take to a power or root + const double exponent ///< the exponent for the power or root + ); + + /// here I document some variable + + size_t count +}; + +} // namespace full_package + +#endif // FULL_PACKAGE__IAMCPP_HPP_ diff --git a/test/packages/full_package/msg/NumPwrResult.msg b/test/packages/full_package/msg/NumPwrResult.msg new file mode 100644 index 0000000..2b05524 --- /dev/null +++ b/test/packages/full_package/msg/NumPwrResult.msg @@ -0,0 +1,10 @@ +# Demo of a custom message definition in a ros package. +# +# This message is supposed to be a simulation for a node that is like a message +# filter. This is the response. The node has received an incoming message, and +# publishes this message in response. + +# Result of raising the incoming number to a power +float64 to_power +# Result of taking the powereth_root of the number, eg to the power (1./exponent) +float64 to_root diff --git a/test/packages/full_package/package.xml b/test/packages/full_package/package.xml new file mode 100644 index 0000000..08a82f4 --- /dev/null +++ b/test/packages/full_package/package.xml @@ -0,0 +1,23 @@ + + + + full_package + 0.1.3 + Full ROS2 test package + Some One + https://example.com/repo + https://example.com/website + https://example.com/issues + Apache License 2.0 + + ament_cmake + ament_cmake_python + + rclcpp + rclpy + + + ament_cmake + + + diff --git a/test/packages/full_package/src/iamcpp.cpp b/test/packages/full_package/src/iamcpp.cpp new file mode 100644 index 0000000..e69de29 diff --git a/test/packages/minimal_publisher_py/CHANGELOG.rst b/test/packages/minimal_publisher_py/CHANGELOG.rst new file mode 100644 index 0000000..1bbc974 --- /dev/null +++ b/test/packages/minimal_publisher_py/CHANGELOG.rst @@ -0,0 +1,114 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for packageminimal_publisher_py +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +0.16.0 (2022-04-29) +------------------- + +0.15.0 (2022-03-01) +------------------- + +0.14.0 (2022-01-14) +------------------- +* Update maintainers to Aditya Pande and Shane Loretz (`#332 `_) +* Updated maintainers (`#329 `_) +* Contributors: Aditya Pande, Audrow Nash + +0.13.0 (2021-10-18) +------------------- + +0.12.0 (2021-08-05) +------------------- + +0.11.2 (2021-04-26) +------------------- +* Use underscores instead of dashes in setup.cfg (`#310 `_) +* Contributors: Ivan Santiago Paunovic + +0.11.1 (2021-04-12) +------------------- + +0.11.0 (2021-04-06) +------------------- + +0.10.3 (2021-03-18) +------------------- + +0.10.2 (2021-01-25) +------------------- + +0.10.1 (2020-12-10) +------------------- +* Update maintainers (`#292 `_) +* Contributors: Shane Loretz + +0.10.0 (2020-09-21) +------------------- + +0.9.2 (2020-06-01) +------------------ + +0.9.1 (2020-05-26) +------------------ + +0.9.0 (2020-04-30) +------------------ +* more verbose test_flake8 error messages (same as `ros2/launch_ros#135 `_) +* Contributors: Dirk Thomas + +0.8.2 (2019-11-19) +------------------ + +0.8.1 (2019-10-24) +------------------ + +0.7.3 (2019-05-29) +------------------ + +0.7.2 (2019-05-20) +------------------ +* Fix deprecation warnings (`#241 `_) +* Contributors: Jacob Perron + +0.7.1 (2019-05-08) +------------------ + +0.7.0 (2019-04-14) +------------------ + +0.6.2 (2019-02-08) +------------------ +* Modified examples to install entry point scripts into a package. (`#226 `_) +* Contributors: Shane Loretz + +0.6.0 (2018-11-20) +------------------ +* Updated maintainer info. (`#218 `_) +* Contributors: Shane Loretz + +0.5.1 (2018-06-27) +------------------ + +0.5.0 (2018-06-26) +------------------ +* add pytest markers to linter tests +* set zip_safe to avoid warning during installation (`#205 `_) +* Contributors: Dirk Thomas, Mikael Arguedas + +0.4.0 (2017-12-08) +------------------ +* Use logging (`#190 `_) +* Fix import statement and usage for rclpy.node.Node (`#189 `_) +* remove test_suite, add pytest as test_requires +* 0.0.3 +* Examples for Executors and callback groups (`#182 `_) +* remove dependency on ament_python and perform customizations in setup.py `#178 `_ +* 0.0.2 +* rename executables with shorter names (`#177 `_) +* install data_files `#176 `_ +* install executables in package specific path `#173 `_ +* use explicit kwargs `#169 `_ +* fix function name (`#168 `_) +* comply with flake8 import order (`#167 `_) +* Rclpy minimal pub sub (`#139 `_) +* Contributors: Dirk Thomas, Mikael Arguedas, Shane Loretz diff --git a/test/packages/minimal_publisher_py/README.md b/test/packages/minimal_publisher_py/README.md new file mode 100644 index 0000000..fc9d22a --- /dev/null +++ b/test/packages/minimal_publisher_py/README.md @@ -0,0 +1,6 @@ +# Minimal "publisher" cookbook recipes + +This package contains a few different strategies for creating short nodes that blast out messages. +The `publisher_old_school` recipe creates a talker node very similar to how it would be done in ROS 1 using rospy. +The `publisher_local_function` recipe shows how to leverage the timers provided by ROS 2 to trigger message publication. +The `publisher_member_function` recipe creates a class MinimalPublisher that sends messages periodically. diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/__init__.py b/test/packages/minimal_publisher_py/minimal_publisher_py/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py new file mode 100644 index 0000000..8c3267b --- /dev/null +++ b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py @@ -0,0 +1,50 @@ +# Copyright 2016 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import rclpy +from std_msgs.msg import String + + +def main(args=None): + rclpy.init(args=args) + + node = rclpy.create_node('minimal_publisher') + publisher = node.create_publisher(String, 'topic', 10) + + msg = String() + i = 0 + + def timer_callback(): + nonlocal i + msg.data = 'Hello World: %d' % i + i += 1 + node.get_logger().info('Publishing: "%s"' % msg.data) + publisher.publish(msg) + + timer_period = 0.5 # seconds + timer = node.create_timer(timer_period, timer_callback) + + rclpy.spin(node) + + # Destroy the timer attached to the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + node.destroy_timer(timer) + node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py new file mode 100644 index 0000000..74f1405 --- /dev/null +++ b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py @@ -0,0 +1,52 @@ +# Copyright 2016 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import rclpy +from rclpy.node import Node +from std_msgs.msg import String + + +class MinimalPublisher(Node): + + def __init__(self): + super().__init__('minimal_publisher') + self.publisher_ = self.create_publisher(String, 'topic', 10) + timer_period = 0.5 # seconds + self.timer = self.create_timer(timer_period, self.timer_callback) + self.i = 0 + + def timer_callback(self): + msg = String() + msg.data = 'Hello World: %d' % self.i + self.publisher_.publish(msg) + self.get_logger().info('Publishing: "%s"' % msg.data) + self.i += 1 + + +def main(args=None): + rclpy.init(args=args) + + minimal_publisher = MinimalPublisher() + + rclpy.spin(minimal_publisher) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + minimal_publisher.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py new file mode 100644 index 0000000..6610f74 --- /dev/null +++ b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py @@ -0,0 +1,51 @@ +# Copyright 2016 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from time import sleep + +import rclpy +from std_msgs.msg import String + +# We do not recommend this style as ROS 2 provides timers for this purpose, +# and it is recommended that all nodes call a variation of spin. +# This example is only included for completeness because it is similar to examples in ROS 1. +# For periodic publication please see the other examples using timers. + + +def main(args=None): + rclpy.init(args=args) + + node = rclpy.create_node('minimal_publisher') + + publisher = node.create_publisher(String, 'topic', 10) + + msg = String() + + i = 0 + while rclpy.ok(): + msg.data = 'Hello World: %d' % i + i += 1 + node.get_logger().info('Publishing: "%s"' % msg.data) + publisher.publish(msg) + sleep(0.5) # seconds + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/test/packages/minimal_publisher_py/package.xml b/test/packages/minimal_publisher_py/package.xml new file mode 100644 index 0000000..7ef33af --- /dev/null +++ b/test/packages/minimal_publisher_py/package.xml @@ -0,0 +1,24 @@ + + + + minimal_publisher_py + 0.16.0 + Examples of minimal publishers using rclpy. + First Maintainer + Second Maintainer + Apache License 2.0 + + rclpy + std_msgs + + + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/test/packages/minimal_publisher_py/resource/minimal_publisher_py b/test/packages/minimal_publisher_py/resource/minimal_publisher_py new file mode 100644 index 0000000..e69de29 diff --git a/test/packages/minimal_publisher_py/setup.cfg b/test/packages/minimal_publisher_py/setup.cfg new file mode 100644 index 0000000..774d7e2 --- /dev/null +++ b/test/packages/minimal_publisher_py/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/examples_rclpy_minimal_publisher +[install] +install_scripts=$base/lib/examples_rclpy_minimal_publisher diff --git a/test/packages/minimal_publisher_py/setup.py b/test/packages/minimal_publisher_py/setup.py new file mode 100644 index 0000000..46257a5 --- /dev/null +++ b/test/packages/minimal_publisher_py/setup.py @@ -0,0 +1,39 @@ +from setuptools import setup + +package_name = 'examples_rclpy_minimal_publisher' + +setup( + name=package_name, + version='0.16.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + author='Mikael Arguedas', + author_email='mikael@osrfoundation.org', + maintainer='First Maintainer, Second Maintainer', + maintainer_email='maint1@example.com, maint2@example.com', + keywords=['ROS'], + classifiers=[ + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python', + 'Topic :: Software Development', + ], + description='Examples of minimal publishers using rclpy.', + license='Apache License, Version 2.0', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'publisher_old_school =minimal_publisher_py.publisher_old_school:main', + 'publisher_local_function =' + 'minimal_publisher_py.publisher_local_function:main', + 'publisher_member_function =' + 'minimal_publisher_py.publisher_member_function:main', + ], + }, +) diff --git a/test/packages/minimum_package/package.xml b/test/packages/minimum_package/package.xml new file mode 100644 index 0000000..4bb1f0f --- /dev/null +++ b/test/packages/minimum_package/package.xml @@ -0,0 +1,9 @@ + + + + minimum_package + 0.1.2 + Minimal ROS2 test package + Some One + Apache License 2.0 + diff --git a/test/test_builder.py b/test/test_builder.py new file mode 100644 index 0000000..6fb2329 --- /dev/null +++ b/test/test_builder.py @@ -0,0 +1,209 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""testing of builder.py using pytest.""" + +import argparse +from html.parser import HTMLParser +import logging +import pathlib +from urllib.parse import urlparse + +from rosdoc2.verbs.build.impl import main_impl, prepare_arguments + +logger = logging.getLogger('test-builder') +DATAPATH = pathlib.Path('test/packages') + + +class htmlParser(HTMLParser): + """Minimal html parsing collecing links and content.""" + + def __init__(self): + super().__init__() + # data we have seen + self.content = set() + # href in tags we have seen + self.links = set() + + def handle_starttag(self, tag, attrs): + if tag == 'a': + for (name, link) in attrs: + if name == 'href': + self.links.add(link) + + def handle_data(self, data): + data_black = data.strip(' \n') + if data_black: + self.content.add(data_black.lower()) + + +def do_build_package(package_path, work_path) -> None: + build_dir = work_path / 'build' + output_dir = work_path / 'output' + cr_dir = work_path / 'cross_references' + + # Create a top level parser + parser = prepare_arguments(argparse.ArgumentParser()) + options = parser.parse_args([ + '-p', str(package_path), + '-c', str(cr_dir), + '-o', str(output_dir), + '-d', str(build_dir), + ]) + logger.info(f'*** Building package(s) at {package_path} with options {options}') + + # run rosdoc2 on the package + main_impl(options) + + +def do_test_package( + name, + work_path, + includes=[], + excludes=[], + file_includes=[], + file_excludes=[], + links_exist=[], +) -> None: + """Test that package documentation exists and includes/excludes certain text. + + :param pathlib.Path work_path: path where generated files were placed + :param list[str] includes: lower case text found in index.html data + :param list[str] excludes: lower case text not found in index.html data + :param list[str] file_includes: path to files + (relative to root index.html directory) of files that should exist + :param list[str] file_excludes: path to files + (relative to root index.html directory) of files that should not exist + :param list[str] links_exist: Confirm that 1) a link exists containing this text, and + 2) the link is a valid file + """ + logger.info(f'*** Testing package {name} work_path {work_path}') + output_dir = work_path / 'output' + + # tests on the main index.html + index_path = output_dir / name / 'index.html' + + # smoke test + assert index_path.is_file(), \ + 'html index file exists' + + # read and parse the index file + # + # The package title html has a permalink icon at the end which is + # a unicode character. For some reason, on Windows this character generates + # a unicode error in Windows, though it seems to work fine + # in the browser. So ignore unicode errors. + with index_path.open(mode='r', errors='replace') as f: + index_content = f.read() + assert len(index_content) > 0, \ + 'index.html is not empty' + + parser = htmlParser() + parser.feed(index_content) + logger.debug('HTML text content: ' + str(parser.content)) + logger.debug('HTML tag links: ' + str(parser.links)) + # test inclusions + for item in includes: + assert item.lower() in parser.content, \ + f'html should have content <{item}>' + + # test exclusions + for item in excludes: + assert item.lower() not in parser.content, \ + f'html should not have content <{item}>' + + # file inclusions + for item in file_includes: + path = output_dir / name / item + assert path.is_file(), \ + f'file <{item}> should exist' + + # file exclusions + for item in file_excludes: + path = output_dir / name / item + assert not path.is_file(), \ + f'file <{item}> should not exist' + + # look for links + for item in links_exist: + found_item = None + for link in parser.links: + if item in link: + found_item = link + assert found_item, \ + f'a link should exist containing the string <{item}>' + link_object = urlparse(found_item) + link_path = output_dir / name / link_object.path + assert link_path.is_file(), \ + f'file represented by <{found_item}> should exist at <{link_path}>' + + +def test_minimum_package(tmp_path): + """Tests of a package containing as little as possible.""" + PKG_NAME = 'minimum_package' + do_build_package(DATAPATH / PKG_NAME, tmp_path) + + includes = [ + PKG_NAME, + ] + excludes = [ + 'classes and structs', # only found in C++ projects + ] + file_includes = [ + 'search.html', + ] + file_excludes = [ + 'generated/index.html', # empty packages have no generated content + ] + links_exist = [ + 'genindex.html', + ] + do_test_package(PKG_NAME, tmp_path, + includes=includes, + excludes=excludes, + file_includes=file_includes, + file_excludes=file_excludes, + links_exist=links_exist) + + +def test_full_package(tmp_path): + """Test a package with C++, python, and docs.""" + PKG_NAME = 'full_package' + do_build_package(DATAPATH / PKG_NAME, tmp_path) + + includes = [ + PKG_NAME, + ] + file_includes = [ + 'generated/index.html' + ] + do_test_package(PKG_NAME, tmp_path, + includes=includes, + file_includes=file_includes) + + +def test_minimal_publisher_py(tmp_path): + """Test a pure python package.""" + PKG_NAME = 'minimal_publisher_py' + do_build_package(DATAPATH / PKG_NAME, tmp_path) + + includes = [ + PKG_NAME, + ] + links_exist = [ + 'minimal_publisher_py.html', + ] + do_test_package(PKG_NAME, tmp_path, + includes=includes, + links_exist=links_exist) From 580897ea62455f61f44a5868ffa366226476c676 Mon Sep 17 00:00:00 2001 From: "R. Kent James" Date: Thu, 21 Mar 2024 11:38:32 -0700 Subject: [PATCH 2/3] Use a common session directory in test --- .gitignore | 9 ++------- test/test_builder.py | 27 ++++++++++++++++++--------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index d4018a2..3fe5347 100644 --- a/.gitignore +++ b/.gitignore @@ -62,10 +62,5 @@ target/ .vscode/ # tests -generated/ -test/packages/full_package/index.rst -test/packages/full_package/conf.py -test/packages/minimum_package/index.rst -test/packages/minimum_package/conf.py -test/packages/minimal_publisher_py/index.rst -test/packages/minimal_publisher_py/conf.py +test/packages/**/index.rst +test/packages/**/conf.py diff --git a/test/test_builder.py b/test/test_builder.py index 6fb2329..be07b7c 100644 --- a/test/test_builder.py +++ b/test/test_builder.py @@ -20,12 +20,21 @@ import pathlib from urllib.parse import urlparse +import pytest from rosdoc2.verbs.build.impl import main_impl, prepare_arguments logger = logging.getLogger('test-builder') DATAPATH = pathlib.Path('test/packages') +@pytest.fixture(scope='session') +def session_dir(tmp_path_factory): + tmp_path_factory.mktemp('build', False) + tmp_path_factory.mktemp('cross_references', False) + tmp_path_factory.mktemp('output', False) + return tmp_path_factory.getbasetemp() + + class htmlParser(HTMLParser): """Minimal html parsing collecing links and content.""" @@ -149,10 +158,10 @@ def do_test_package( f'file represented by <{found_item}> should exist at <{link_path}>' -def test_minimum_package(tmp_path): +def test_minimum_package(session_dir): """Tests of a package containing as little as possible.""" PKG_NAME = 'minimum_package' - do_build_package(DATAPATH / PKG_NAME, tmp_path) + do_build_package(DATAPATH / PKG_NAME, session_dir) includes = [ PKG_NAME, @@ -169,7 +178,7 @@ def test_minimum_package(tmp_path): links_exist = [ 'genindex.html', ] - do_test_package(PKG_NAME, tmp_path, + do_test_package(PKG_NAME, session_dir, includes=includes, excludes=excludes, file_includes=file_includes, @@ -177,10 +186,10 @@ def test_minimum_package(tmp_path): links_exist=links_exist) -def test_full_package(tmp_path): +def test_full_package(session_dir): """Test a package with C++, python, and docs.""" PKG_NAME = 'full_package' - do_build_package(DATAPATH / PKG_NAME, tmp_path) + do_build_package(DATAPATH / PKG_NAME, session_dir) includes = [ PKG_NAME, @@ -188,15 +197,15 @@ def test_full_package(tmp_path): file_includes = [ 'generated/index.html' ] - do_test_package(PKG_NAME, tmp_path, + do_test_package(PKG_NAME, session_dir, includes=includes, file_includes=file_includes) -def test_minimal_publisher_py(tmp_path): +def test_minimal_publisher_py(session_dir): """Test a pure python package.""" PKG_NAME = 'minimal_publisher_py' - do_build_package(DATAPATH / PKG_NAME, tmp_path) + do_build_package(DATAPATH / PKG_NAME, session_dir) includes = [ PKG_NAME, @@ -204,6 +213,6 @@ def test_minimal_publisher_py(tmp_path): links_exist = [ 'minimal_publisher_py.html', ] - do_test_package(PKG_NAME, tmp_path, + do_test_package(PKG_NAME, session_dir, includes=includes, links_exist=links_exist) From ff4c6c82c5845011c4cb0308b37c7d97b4b831a5 Mon Sep 17 00:00:00 2001 From: "R. Kent James" Date: Fri, 22 Mar 2024 10:15:49 -0700 Subject: [PATCH 3/3] Resolve review comments --- .github/workflows/test.yml | 6 +- .gitignore | 7 -- .../minimal_publisher_py/CHANGELOG.rst | 114 ------------------ test/packages/minimal_publisher_py/README.md | 6 - .../publisher_local_function.py | 50 -------- .../publisher_member_function.py | 52 -------- .../publisher_old_school.py | 51 -------- .../packages/minimal_publisher_py/package.xml | 24 ---- test/packages/minimal_publisher_py/setup.cfg | 4 - test/packages/minimal_publisher_py/setup.py | 39 ------ .../only_python}/__init__.py | 0 .../only_python/only_python/python_node.py | 6 + test/packages/only_python/package.xml | 18 +++ .../resource/only_python} | 0 test/packages/only_python/setup.cfg | 4 + test/packages/only_python/setup.py | 26 ++++ test/test_builder.py | 8 +- 17 files changed, 60 insertions(+), 355 deletions(-) delete mode 100644 test/packages/minimal_publisher_py/CHANGELOG.rst delete mode 100644 test/packages/minimal_publisher_py/README.md delete mode 100644 test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py delete mode 100644 test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py delete mode 100644 test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py delete mode 100644 test/packages/minimal_publisher_py/package.xml delete mode 100644 test/packages/minimal_publisher_py/setup.cfg delete mode 100644 test/packages/minimal_publisher_py/setup.py rename test/packages/{minimal_publisher_py/minimal_publisher_py => only_python/only_python}/__init__.py (100%) create mode 100644 test/packages/only_python/only_python/python_node.py create mode 100644 test/packages/only_python/package.xml rename test/packages/{minimal_publisher_py/resource/minimal_publisher_py => only_python/resource/only_python} (100%) create mode 100644 test/packages/only_python/setup.cfg create mode 100644 test/packages/only_python/setup.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2bd861f..f701fa0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,10 +9,10 @@ on: jobs: unit_tests: name: Unit Tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-20.04 strategy: matrix: - python-version: ['3.8', '3.9', '3.10'] + python-version: ['3.8', '3.9'] steps: - name: Checkout @@ -40,4 +40,4 @@ jobs: run: sudo apt update && sudo apt install -y doxygen graphviz - name: Run tests - run: python -m pytest -s test + run: py.test --verbose test diff --git a/.gitignore b/.gitignore index 3fe5347..1c1874d 100644 --- a/.gitignore +++ b/.gitignore @@ -57,10 +57,3 @@ docs/_build/ # PyBuilder target/ .pytest_cache - -# Editors -.vscode/ - -# tests -test/packages/**/index.rst -test/packages/**/conf.py diff --git a/test/packages/minimal_publisher_py/CHANGELOG.rst b/test/packages/minimal_publisher_py/CHANGELOG.rst deleted file mode 100644 index 1bbc974..0000000 --- a/test/packages/minimal_publisher_py/CHANGELOG.rst +++ /dev/null @@ -1,114 +0,0 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Changelog for packageminimal_publisher_py -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -0.16.0 (2022-04-29) -------------------- - -0.15.0 (2022-03-01) -------------------- - -0.14.0 (2022-01-14) -------------------- -* Update maintainers to Aditya Pande and Shane Loretz (`#332 `_) -* Updated maintainers (`#329 `_) -* Contributors: Aditya Pande, Audrow Nash - -0.13.0 (2021-10-18) -------------------- - -0.12.0 (2021-08-05) -------------------- - -0.11.2 (2021-04-26) -------------------- -* Use underscores instead of dashes in setup.cfg (`#310 `_) -* Contributors: Ivan Santiago Paunovic - -0.11.1 (2021-04-12) -------------------- - -0.11.0 (2021-04-06) -------------------- - -0.10.3 (2021-03-18) -------------------- - -0.10.2 (2021-01-25) -------------------- - -0.10.1 (2020-12-10) -------------------- -* Update maintainers (`#292 `_) -* Contributors: Shane Loretz - -0.10.0 (2020-09-21) -------------------- - -0.9.2 (2020-06-01) ------------------- - -0.9.1 (2020-05-26) ------------------- - -0.9.0 (2020-04-30) ------------------- -* more verbose test_flake8 error messages (same as `ros2/launch_ros#135 `_) -* Contributors: Dirk Thomas - -0.8.2 (2019-11-19) ------------------- - -0.8.1 (2019-10-24) ------------------- - -0.7.3 (2019-05-29) ------------------- - -0.7.2 (2019-05-20) ------------------- -* Fix deprecation warnings (`#241 `_) -* Contributors: Jacob Perron - -0.7.1 (2019-05-08) ------------------- - -0.7.0 (2019-04-14) ------------------- - -0.6.2 (2019-02-08) ------------------- -* Modified examples to install entry point scripts into a package. (`#226 `_) -* Contributors: Shane Loretz - -0.6.0 (2018-11-20) ------------------- -* Updated maintainer info. (`#218 `_) -* Contributors: Shane Loretz - -0.5.1 (2018-06-27) ------------------- - -0.5.0 (2018-06-26) ------------------- -* add pytest markers to linter tests -* set zip_safe to avoid warning during installation (`#205 `_) -* Contributors: Dirk Thomas, Mikael Arguedas - -0.4.0 (2017-12-08) ------------------- -* Use logging (`#190 `_) -* Fix import statement and usage for rclpy.node.Node (`#189 `_) -* remove test_suite, add pytest as test_requires -* 0.0.3 -* Examples for Executors and callback groups (`#182 `_) -* remove dependency on ament_python and perform customizations in setup.py `#178 `_ -* 0.0.2 -* rename executables with shorter names (`#177 `_) -* install data_files `#176 `_ -* install executables in package specific path `#173 `_ -* use explicit kwargs `#169 `_ -* fix function name (`#168 `_) -* comply with flake8 import order (`#167 `_) -* Rclpy minimal pub sub (`#139 `_) -* Contributors: Dirk Thomas, Mikael Arguedas, Shane Loretz diff --git a/test/packages/minimal_publisher_py/README.md b/test/packages/minimal_publisher_py/README.md deleted file mode 100644 index fc9d22a..0000000 --- a/test/packages/minimal_publisher_py/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Minimal "publisher" cookbook recipes - -This package contains a few different strategies for creating short nodes that blast out messages. -The `publisher_old_school` recipe creates a talker node very similar to how it would be done in ROS 1 using rospy. -The `publisher_local_function` recipe shows how to leverage the timers provided by ROS 2 to trigger message publication. -The `publisher_member_function` recipe creates a class MinimalPublisher that sends messages periodically. diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py deleted file mode 100644 index 8c3267b..0000000 --- a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_local_function.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2016 Open Source Robotics Foundation, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import rclpy -from std_msgs.msg import String - - -def main(args=None): - rclpy.init(args=args) - - node = rclpy.create_node('minimal_publisher') - publisher = node.create_publisher(String, 'topic', 10) - - msg = String() - i = 0 - - def timer_callback(): - nonlocal i - msg.data = 'Hello World: %d' % i - i += 1 - node.get_logger().info('Publishing: "%s"' % msg.data) - publisher.publish(msg) - - timer_period = 0.5 # seconds - timer = node.create_timer(timer_period, timer_callback) - - rclpy.spin(node) - - # Destroy the timer attached to the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - node.destroy_timer(timer) - node.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py deleted file mode 100644 index 74f1405..0000000 --- a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_member_function.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2016 Open Source Robotics Foundation, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import rclpy -from rclpy.node import Node -from std_msgs.msg import String - - -class MinimalPublisher(Node): - - def __init__(self): - super().__init__('minimal_publisher') - self.publisher_ = self.create_publisher(String, 'topic', 10) - timer_period = 0.5 # seconds - self.timer = self.create_timer(timer_period, self.timer_callback) - self.i = 0 - - def timer_callback(self): - msg = String() - msg.data = 'Hello World: %d' % self.i - self.publisher_.publish(msg) - self.get_logger().info('Publishing: "%s"' % msg.data) - self.i += 1 - - -def main(args=None): - rclpy.init(args=args) - - minimal_publisher = MinimalPublisher() - - rclpy.spin(minimal_publisher) - - # Destroy the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - minimal_publisher.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py b/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py deleted file mode 100644 index 6610f74..0000000 --- a/test/packages/minimal_publisher_py/minimal_publisher_py/publisher_old_school.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 Open Source Robotics Foundation, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from time import sleep - -import rclpy -from std_msgs.msg import String - -# We do not recommend this style as ROS 2 provides timers for this purpose, -# and it is recommended that all nodes call a variation of spin. -# This example is only included for completeness because it is similar to examples in ROS 1. -# For periodic publication please see the other examples using timers. - - -def main(args=None): - rclpy.init(args=args) - - node = rclpy.create_node('minimal_publisher') - - publisher = node.create_publisher(String, 'topic', 10) - - msg = String() - - i = 0 - while rclpy.ok(): - msg.data = 'Hello World: %d' % i - i += 1 - node.get_logger().info('Publishing: "%s"' % msg.data) - publisher.publish(msg) - sleep(0.5) # seconds - - # Destroy the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - node.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() diff --git a/test/packages/minimal_publisher_py/package.xml b/test/packages/minimal_publisher_py/package.xml deleted file mode 100644 index 7ef33af..0000000 --- a/test/packages/minimal_publisher_py/package.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - minimal_publisher_py - 0.16.0 - Examples of minimal publishers using rclpy. - First Maintainer - Second Maintainer - Apache License 2.0 - - rclpy - std_msgs - - - ament_copyright - ament_flake8 - ament_pep257 - python3-pytest - - - ament_python - - diff --git a/test/packages/minimal_publisher_py/setup.cfg b/test/packages/minimal_publisher_py/setup.cfg deleted file mode 100644 index 774d7e2..0000000 --- a/test/packages/minimal_publisher_py/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[develop] -script_dir=$base/lib/examples_rclpy_minimal_publisher -[install] -install_scripts=$base/lib/examples_rclpy_minimal_publisher diff --git a/test/packages/minimal_publisher_py/setup.py b/test/packages/minimal_publisher_py/setup.py deleted file mode 100644 index 46257a5..0000000 --- a/test/packages/minimal_publisher_py/setup.py +++ /dev/null @@ -1,39 +0,0 @@ -from setuptools import setup - -package_name = 'examples_rclpy_minimal_publisher' - -setup( - name=package_name, - version='0.16.0', - packages=[package_name], - data_files=[ - ('share/ament_index/resource_index/packages', - ['resource/' + package_name]), - ('share/' + package_name, ['package.xml']), - ], - install_requires=['setuptools'], - zip_safe=True, - author='Mikael Arguedas', - author_email='mikael@osrfoundation.org', - maintainer='First Maintainer, Second Maintainer', - maintainer_email='maint1@example.com, maint2@example.com', - keywords=['ROS'], - classifiers=[ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python', - 'Topic :: Software Development', - ], - description='Examples of minimal publishers using rclpy.', - license='Apache License, Version 2.0', - tests_require=['pytest'], - entry_points={ - 'console_scripts': [ - 'publisher_old_school =minimal_publisher_py.publisher_old_school:main', - 'publisher_local_function =' - 'minimal_publisher_py.publisher_local_function:main', - 'publisher_member_function =' - 'minimal_publisher_py.publisher_member_function:main', - ], - }, -) diff --git a/test/packages/minimal_publisher_py/minimal_publisher_py/__init__.py b/test/packages/only_python/only_python/__init__.py similarity index 100% rename from test/packages/minimal_publisher_py/minimal_publisher_py/__init__.py rename to test/packages/only_python/only_python/__init__.py diff --git a/test/packages/only_python/only_python/python_node.py b/test/packages/only_python/only_python/python_node.py new file mode 100644 index 0000000..6092246 --- /dev/null +++ b/test/packages/only_python/only_python/python_node.py @@ -0,0 +1,6 @@ +def main(): + print('Hi from only_python.') + + +if __name__ == '__main__': + main() diff --git a/test/packages/only_python/package.xml b/test/packages/only_python/package.xml new file mode 100644 index 0000000..8d5c003 --- /dev/null +++ b/test/packages/only_python/package.xml @@ -0,0 +1,18 @@ + + + + only_python + 0.0.0 + Basic Python node using ros2 create command + Python Pro + Apache-2.0 + + ament_copyright + ament_flake8 + ament_pep257 + python3-pytest + + + ament_python + + diff --git a/test/packages/minimal_publisher_py/resource/minimal_publisher_py b/test/packages/only_python/resource/only_python similarity index 100% rename from test/packages/minimal_publisher_py/resource/minimal_publisher_py rename to test/packages/only_python/resource/only_python diff --git a/test/packages/only_python/setup.cfg b/test/packages/only_python/setup.cfg new file mode 100644 index 0000000..2b64109 --- /dev/null +++ b/test/packages/only_python/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/only_python +[install] +install_scripts=$base/lib/only_python diff --git a/test/packages/only_python/setup.py b/test/packages/only_python/setup.py new file mode 100644 index 0000000..2d0763a --- /dev/null +++ b/test/packages/only_python/setup.py @@ -0,0 +1,26 @@ +from setuptools import find_packages, setup + +package_name = 'only_python' + +setup( + name=package_name, + version='0.0.0', + packages=find_packages(exclude=['test']), + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='kent', + maintainer_email='kent@caspia.com', + description='TODO: Package description', + license='TODO: License declaration', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'python_node = only_python.python_node:main' + ], + }, +) diff --git a/test/test_builder.py b/test/test_builder.py index be07b7c..ed6755a 100644 --- a/test/test_builder.py +++ b/test/test_builder.py @@ -202,17 +202,15 @@ def test_full_package(session_dir): file_includes=file_includes) -def test_minimal_publisher_py(session_dir): +def test_only_python(session_dir): """Test a pure python package.""" - PKG_NAME = 'minimal_publisher_py' + PKG_NAME = 'only_python' do_build_package(DATAPATH / PKG_NAME, session_dir) includes = [ PKG_NAME, ] - links_exist = [ - 'minimal_publisher_py.html', - ] + links_exist = ['only_python.python_node.html'] do_test_package(PKG_NAME, session_dir, includes=includes, links_exist=links_exist)