diff --git a/.gitignore b/.gitignore index dc106bf..c3cebe4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,10 @@ *.pyc build +dist .tox .hypothesis *.egg-info +.cache +.idea +__pycache__ + diff --git a/.gitmodules b/.gitmodules index a9868ce..0922419 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ -[submodule "rosdeps/genmsg"] - path = rosdeps/genmsg - url = https://github.com/ros/genmsg.git -[submodule "rosdeps/genpy"] - path = rosdeps/genpy - url = https://github.com/ros/genpy.git -[submodule "rosdeps/std_msgs"] - path = rosdeps/std_msgs +[submodule "tests/rosdeps/std_msgs"] + path = tests/rosdeps/std_msgs url = https://github.com/ros/std_msgs.git +[submodule "tests/rosdeps/ros_comm_msgs"] + path = tests/rosdeps/ros_comm_msgs + url = https://github.com/ros/ros_comm_msgs.git diff --git a/.travis.yml b/.travis.yml index 90c9640..dc344e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,34 @@ -sudo: required -dist: trusty language: python branches: except: - gh-pages +env: + - ROS_DISTRO=indigo + - ROS_DISTRO=kinetic + # Not LTS + - ROS_DISTRO=lunar + # to get latest dependencies (not released in a ROS distro yet) + - ROS_DISTRO=latest + python: + # always test python2 (default supported python version for ROS1) - 2.7 - #- 3.4 + # always test latest python3 (to guarantee recent python support) + - 3.6 #- pypy #- pypy3 +# Add specific python3 versions +matrix: + include: + # explicitely matching python version to the version on the ubuntu distro supported by the ROS LTS distro + - python: 3.4 + env: ROS_DISTRO=indigo + - python: 3.5 + env: ROS_DISTRO=kinetic + before_install: install: diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..b570fbf --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +# default +include README.rst +include setup.py diff --git a/README.md b/README.md deleted file mode 100644 index bd2783c..0000000 --- a/README.md +++ /dev/null @@ -1,13 +0,0 @@ -[![Code Issues](https://www.quantifiedcode.com/api/v1/project/646d87c377144f1fa5c9a328a883c619/badge.svg)](https://www.quantifiedcode.com/app/project/646d87c377144f1fa5c9a328a883c619) -[![Build Status](https://travis-ci.org/asmodehn/pyros-msgs.svg?branch=master)](https://travis-ci.org/asmodehn/pyros-msgs) - -# Pyros-msgs - -ROS Package enabling ROS communication for other Pyros multiprocess systems. - -## Features - -### ROS -- optional field as a ROS array -- optional field as a specific message type (Work In Progress) - diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..f5e357a --- /dev/null +++ b/README.rst @@ -0,0 +1,21 @@ +|Code Issues| |Build Status| + +Pyros-msgs +========== + +ROS Package enabling ROS communication for other Pyros multiprocess +systems. + +Features +-------- + +ROS +~~~ + +- optional field as a ROS array +- optional field as a specific message type (Work In Progress) + +.. |Code Issues| image:: https://www.quantifiedcode.com/api/v1/project/646d87c377144f1fa5c9a328a883c619/badge.svg + :target: https://www.quantifiedcode.com/app/project/646d87c377144f1fa5c9a328a883c619 +.. |Build Status| image:: https://travis-ci.org/asmodehn/pyros-msgs.svg?branch=master + :target: https://travis-ci.org/asmodehn/pyros-msgs \ No newline at end of file diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index 4ec6317..0000000 --- a/dev-requirements.txt +++ /dev/null @@ -1 +0,0 @@ -#pathlib2 \ No newline at end of file diff --git a/msg b/msg new file mode 120000 index 0000000..7ad3823 --- /dev/null +++ b/msg @@ -0,0 +1 @@ +pyros_msgs/msg \ No newline at end of file diff --git a/pyros_msgs/__init__.py b/pyros_msgs/__init__.py index 62b0fcc..e69de29 100644 --- a/pyros_msgs/__init__.py +++ b/pyros_msgs/__init__.py @@ -1,15 +0,0 @@ -from __future__ import absolute_import, division, print_function -# This is a namespace package to merge the ROS generated messages and the python subpackage sources -# Note : this file must be loaded first in order for other subpackages to be found -# Note : this works for development packages only if pyros_setup has been activated -# because it will put egg directories on pythonpath FIRST. - -# Ref : https://packaging.python.org/namespace_packages/ - -# pkgutil does not seem, somehow, to be compatible with ROS devel space... -# import pkgutil -# __path__ = pkgutil.extend_path(__path__, __name__) - -# Be aware : https://github.com/jonparrott/namespace-pkg-tests/blob/master/table.md -import pkg_resources -pkg_resources.declare_namespace(__name__) diff --git a/pyros_msgs/importer/__init__.py b/pyros_msgs/importer/__init__.py deleted file mode 100644 index 90a7037..0000000 --- a/pyros_msgs/importer/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import absolute_import - - -# This is useful only if we need relative imports. Ref : http://stackoverflow.com/a/28154841/4006172 -# declaring __package__ if needed (this module is run individually) -if __package__ is None and not __name__.startswith('pyros_msgs.importer.'): - import os - import sys - # from pathlib2 import Path - # top = Path(__file__).resolve().parents[2] - # Or - from os.path import abspath, dirname - top = abspath(__file__) - for _ in range(4): - top = dirname(top) - - if sys.path[0] == os.path.dirname(__file__): - sys.path[0] = str( - top) # we replace first path in list (current module dir path) by the path of the package. - # this avoid unintentional relative import (even without point notation). - else: # not sure in which case this could happen, but just in case we don't want to break stuff - sys.path.append(str(top)) - - if __name__ == '__main__': - __name__ = '__init__' - - __package__ = 'pyros_msgs.importer' - # Note we do NOT want to import everything in pyros_msgs in this case - - -from .rosmsg_generator import ( - MsgDependencyNotFound, - generate_msgsrv_nspkg -) - -__all__ = [ - 'MsgDependencyNotFound', - 'generate_msgsrv_nspkg', -] diff --git a/pyros_msgs/importer/rosmsg_generator.py b/pyros_msgs/importer/rosmsg_generator.py deleted file mode 100644 index 4ed9361..0000000 --- a/pyros_msgs/importer/rosmsg_generator.py +++ /dev/null @@ -1,306 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import os -import sys -import tempfile -import traceback -import importlib - -import time - -import pkg_resources - -""" -Module that can be used standalone, or as part of the pyros_msgs.importer package - -It provides a set of functions to generate your ros messages, even when ROS is not installed on your system. -You might however need to have dependent messages definitions reachable by rospack somewhere. - -Note : Generated modules/packages can only be imported once. So it is important to provide an API that : -- makes it easy to generate the whole module/package at once, since this is our priority -- makes it easy to optionally import the whole generated module/package -- still allows to generate only one module / a part of the whole package, caveats apply / warning added. -""" - -try: - # Using genpy and genmsg directly if ROS has been setup (while using from ROS pkg) - import genmsg as genmsg - import genmsg.command_line as genmsg_command_line - import genpy.generator as genpy_generator - import genpy.generate_initpy as genpy_generate_initpy - -except ImportError: - - # Otherwise we refer to our submodules here (setup.py usecase, or running from tox without site-packages) - - import site - ros_site_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'ros-site') - print("Adding site directory {ros_site_dir} to access genpy and genmsg.".format(**locals())) - site.addsitedir(ros_site_dir) - - import genmsg as genmsg - import genmsg.command_line as genmsg_command_line - import genpy.generator as genpy_generator - import genpy.generate_initpy as genpy_generate_initpy - - # Note we do not want to use pyros_setup here. - # We do not want to do a full ROS setup, only import specific packages. - # If needed it should have been done before (loading a parent package). - # this handle the case where we want to be independent of any underlying ROS system. - - -class MsgDependencyNotFound(Exception): - pass - - -class PkgAlreadyExists(Exception): - pass - - -def genros_py(rosfiles, generator, package, outdir, includepath=None): - includepath = includepath or [] - - if not os.path.exists(outdir): - # This script can be run multiple times in parallel. We - # don't mind if the makedirs call fails because somebody - # else snuck in and created the directory before us. - try: - os.makedirs(outdir) - except OSError as e: - if not os.path.exists(outdir): - raise - # TODO : maybe we dont need this, and that translation should be handled before ? - search_path = genmsg.command_line.includepath_to_dict(includepath) - generator.generate_messages(package, rosfiles, outdir, search_path) - - -def genmsg_py(msg_files, package, outdir_pkg, includepath=None, initpy=True): - """ - Generates message modules for a package, in that package directory, in a subpackage called 'msg', following ROS conventions - :param msg_files: the .msg files to use as input for generating the python message classes - :param package: the package for which we want to generate these messages - :param outdir_pkg: the directory of the package, where to put these messages. It should finish with path - :param includepath: optionally the list of path to include, in order to retrieve message dependencies - :param initpy: whether create an __init__.py for this package - :return: the list of files generated - """ - includepath = includepath or [] - outdir = os.path.join(outdir_pkg, 'msg') - try: - genros_py(rosfiles=[f for f in msg_files if f.endswith('.msg')], - generator=genpy_generator.MsgGenerator(), - package=package, - outdir=outdir, - includepath=includepath, - ) - # because the OS interface might not be synchronous.... - while not os.path.exists(outdir): - time.sleep(.1) - - except genmsg.InvalidMsgSpec as e: - print("ERROR: ", e, file=sys.stderr) - raise - except genmsg.MsgGenerationException as e: - print("ERROR: ", e, file=sys.stderr) - raise - except Exception as e: - traceback.print_exc() - print("ERROR: ", e) - raise - - genset = set() - - # optionally we can generate __init__.py - if initpy: - init_path = os.path.join(outdir, '__init__.py') - if os.path.exists(init_path): - raise PkgAlreadyExists("Keeping {init_path}, generation skipped.") - else: - genpy_generate_initpy.write_modules(outdir) - genset.add(init_path) - else: # we list all files, only if init.py was not created (and user has to import one by one) - for f in msg_files: - f, _ = os.path.splitext(f) # removing extension - os.path.relpath(outdir) - genset.add(os.path.join(outdir, '_' + os.path.basename(f) + '.py')) - - return genset - - -def gensrv_py(srv_files, package, outdir_pkg, includepath=None, initpy=True): - """ - Generates service modules for a package, in that package directory, in a subpackage called 'srv', following ROS conventions - :param srv_files: the .srv files to use as input for generating the python service classes - :param package: the package for which we want to generate these services - :param outdir_pkg: the directory of the package, where to put these services. It should finish with path - :param includepath: optionally the list of path to include, in order to retrieve message dependencies - :param initpy: whether create an __init__.py for this package - :return: the list of files generated - """ - includepath = includepath or [] - outdir = os.path.join(outdir_pkg, 'srv') - try: - genros_py(rosfiles=[f for f in srv_files if f.endswith('.srv')], - generator=genpy_generator.SrvGenerator(), - package=package, - outdir=outdir, - includepath=includepath, - ) - # because the OS interface might not be synchronous.... - while not os.path.exists(outdir): - time.sleep(.1) - - except genmsg.InvalidMsgSpec as e: - print("ERROR: ", e, file=sys.stderr) - raise - except genmsg.MsgGenerationException as e: - print("ERROR: ", e, file=sys.stderr) - raise - except Exception as e: - traceback.print_exc() - print("ERROR: ", e) - raise - - genset = set() - - # optionally we can generate __init__.py - if initpy: - init_path = os.path.join(outdir, '__init__.py') - if os.path.exists(init_path): - raise PkgAlreadyExists("Keeping {init_path}, generation skipped.") - else: - genpy_generate_initpy.write_modules(outdir) - genset.add(init_path) - else: # we list all files, only if init.py was not created (and user has to import one by one) - for f in srv_files: - f, _ = os.path.splitext(f) # removing extension - os.path.relpath(outdir) - genset.add(os.path.join(outdir, '_' + os.path.basename(f) + '.py')) - - return genset - - -def genmsgsrv_py(msgsrv_files, package, outdir_pkg, includepath=None, ns_pkg=True): - """""" - includepath = includepath or [] - - # checking if we have files with unknown extension to except early - for f in msgsrv_files: - if not f.endswith(('.msg', '.srv')): - print("WARNING: {f} doesnt have the proper .msg or .srv extension. It has been Ignored.".format(**locals()), file=sys.stderr) - - genset = set() - generated_msg = genmsg_py(msg_files=[f for f in msgsrv_files if f.endswith('.msg')], - package=package, - outdir_pkg=outdir_pkg, - includepath=includepath, - initpy=True) # we always create an __init__.py when called from here. - generated_srv = gensrv_py(srv_files=[f for f in msgsrv_files if f.endswith('.srv')], - package=package, - outdir_pkg=outdir_pkg, - includepath=includepath, - initpy=True) # we always create an __init__.py when called from here. - - if ns_pkg: - # The namespace package creation is only here to allow mixing different path for the same package - # so that we do not have to generate messages and services in the package path (that might not be writeable) - # Note : the *first* package imported need to declare the namespace package for this to work. - # Ref : https://packaging.python.org/namespace_packages/ - nspkg_init_path = os.path.join(outdir_pkg, '__init__.py') - if os.path.exists(nspkg_init_path): - raise PkgAlreadyExists("Keeping {nspkg_init_path}, generation skipped.") - else: - with open(nspkg_init_path, "w") as nspkg_init: - nspkg_init.writelines([ - "from __future__ import absolute_import, division, print_function\n", - "# this is an autogenerated file for dynamic ROS message creation\n", - "import pkg_resources\n", - "pkg_resources.declare_namespace(__name__)\n", - "" - ]) - - # because the OS interface might not be synchronous.... - while not os.path.exists(nspkg_init_path): - time.sleep(.1) - - # Whether or not we create the namespace package, we have to return back both msg and srv subpackages, - # since they need to be imported explicitely - genset = genset.union(generated_msg) - genset = genset.union(generated_srv) - - return genset - - -def generate_msgsrv_nspkg(msgsrvfiles, package=None, dependencies=None, include_path=None, outdir_pkg=None, ns_pkg=True): - # TODO : since we return a full package, we should probably pass a dir, not the files one by one... - # by default we generate for this package (does it make sense ?) - # Careful it might still be None - package = package or 'gen_msgs' - - # by default we have no dependencies - dependencies = dependencies or [] - - if not outdir_pkg or not outdir_pkg.startswith(os.sep): - # if path is not absolute, we create a temporary directory to hold our generated package - gendir = tempfile.mkdtemp('pyros_gen_site') - outdir_pkg = os.path.join(gendir, outdir_pkg if outdir_pkg else package) - - include_path = include_path or [] - - # we might need to resolve some dependencies - unresolved_dependencies = [d for d in dependencies if d not in [p.split(':')[0] for p in include_path]] - - if unresolved_dependencies: - try: - # In that case we have no choice but to rely on ros packages (on the system) => ROS has to be setup. - import rospkg - - # get an instance of RosPack with the default search paths - rospack = rospkg.RosPack() - for d in unresolved_dependencies: - try: - # get the file path for a dependency - dpath = rospack.get_path(d) - # we populate include_path - include_path.append('{d}:{dpath}/msg'.format(**locals())) # AFAIK only msg can be dependent msg types - except rospkg.ResourceNotFound as rnf: - raise MsgDependencyNotFound(rnf.message) - except ImportError: - print("Attempt to import rospkg failed before attempting to resolve dependencies {0}".format(unresolved_dependencies)) - - gen_files = genmsgsrv_py(msgsrv_files=msgsrvfiles, package=package, outdir_pkg=outdir_pkg, includepath=include_path, ns_pkg=ns_pkg) - - # computing module names that will be importable after outdir_pkg has been added as sitedir - gen_msgs = None - gen_srvs = None - # Not ideal, but it will do until we implement a custom importer - for f in gen_files: - test_gen_msgs_parent = None - f = f[:-len('.py')] if f.endswith('.py') else f - f = f[:-len(os.sep + '__init__')] if f.endswith(os.sep + '__init__') else f - - if f.endswith('msg'): - gen_msgs = package + '.msg' - - if f.endswith('srv'): - gen_srvs = package + '.srv' - - # we need to get one level up to get the sitedir (containing the generated namespace package) - return os.path.dirname(outdir_pkg), gen_msgs, gen_srvs - # TODO : return something that can be imported later... with custom importer or following importlib API... - - -# This API is useful to import after a generation has been done with details. -# TODO : implement custom importer to do this as properly as possible -def import_msgsrv(sitedir, gen_msgs = None, gen_srvs = None): - import site - site.addsitedir(sitedir) # we add our output dir as a site (to be able to import from it as usual) - # because we modify sys.path, we also need to handle namespace packages - pkg_resources.fixup_namespace_packages(sitedir) - - msgs_mod = importlib.import_module(gen_msgs) - srvs_mod = importlib.import_module(gen_srvs) - - return msgs_mod, srvs_mod - # TODO : doublecheck and fix that API to return the same thing as importlib.import_module returns, for consistency,... - diff --git a/pyros_msgs/importer/rosmsg_importer.py b/pyros_msgs/importer/rosmsg_importer.py deleted file mode 100644 index 6a32022..0000000 --- a/pyros_msgs/importer/rosmsg_importer.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import absolute_import, division, print_function - -""" -A module to setup custom importer for .msg and .srv files -Upon import, it will first find the .msg file, then generate the python module for it, then load it. - -TODO... -""" - -# We need to be extra careful with python versions -# Ref : https://docs.python.org/dev/library/importlib.html#importlib.import_module - -# Ref : http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path -# Note : Coudlnt find a way to make imp.load_source deal with packages or relative imports (necessary for our generated message classes) -import os -import sys - -# This will take the ROS distro version if ros has been setup -import genpy.generator -import genpy.generate_initpy - - -class ROSLoader(object): - def __init__(self, generator, ext): - self.ext = ext - self.generator = generator - - # defining this to benefit from backward compat import mechanism in python 3.X - def get_filename(self, name): - os.sep.join(name.split(".")) + '.' + self.ext - - # defining this to benefit from backward compat import mechanism in python 3.X - def is_package(self, name): - return None # TODO : implement check - - def load_module(self, fullname): - - - return - - -class ROSFinder(object): - - def __init__(self): - self.loaders = { - '.srv': ROSLoader(genpy.generator.SrvGenerator(), 'srv'), - '.msg': ROSLoader(genpy.generator.MsgGenerator(), 'msg') - } - - def find_module(self, name, path=None): - """ - Return the loader for the specified module. - """ - # Ref : https://www.python.org/dev/peps/pep-0302/#specification-part-1-the-importer-protocol - - loader = None - - path = path or sys.path - for p in path: - for f in os.listdir(p): - filename, ext = os.path.splitext(f) - # our modules generated from messages are always a leaf in import tree so we only care about this case - if ext in self.loaders.keys() and filename == name.split('.')[-1]: - loader = self.loaders.get(ext) - break # we found it. break out. - - return loader - - -sys.meta_path += [ROSFinder()] diff --git a/pyros_msgs/importer/tests/__init__.py b/pyros_msgs/importer/tests/__init__.py deleted file mode 100644 index 71eff8b..0000000 --- a/pyros_msgs/importer/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# TODO ! diff --git a/pyros_msgs/importer/tests/msg/TestMsg.msg b/pyros_msgs/importer/tests/msg/TestMsg.msg deleted file mode 100644 index 6634a31..0000000 --- a/pyros_msgs/importer/tests/msg/TestMsg.msg +++ /dev/null @@ -1,3 +0,0 @@ -string test_string -bool test_bool -# TOOD : add more fields for more testing \ No newline at end of file diff --git a/pyros_msgs/importer/tests/test_rosmsg_generator_exec.py b/pyros_msgs/importer/tests/test_rosmsg_generator_exec.py deleted file mode 100644 index c616b95..0000000 --- a/pyros_msgs/importer/tests/test_rosmsg_generator_exec.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import absolute_import, division, print_function - -""" -Testing executing rosmsg_generator directly (like setup.py would) -""" - -import os -import runpy - -# Ref : http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path - -# Including generator module directly from code to be able to generate our message classes -import imp -rosmsg_generator = imp.load_source('rosmsg_generator', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'rosmsg_generator.py')) - - -def test_generate_msgsrv_nspkg_usable(): - # generating message class - sitedir, generated_msg, generated_srv = rosmsg_generator.generate_msgsrv_nspkg( - [os.path.join(os.path.dirname(__file__), 'msg', 'TestMsg.msg')], - package='test_gen_msgs', - ns_pkg=True, - ) - - # Verify that files exists and are importable - for m in [generated_msg, generated_srv]: - # modules are generated where the file is launched - gen_file = os.path.join(sitedir, *m.split(".")) - assert os.path.exists(gen_file + '.py') or os.path.exists(os.path.join(gen_file, '__init__.py')) - - msg_mod, srv_mod = rosmsg_generator.import_msgsrv(sitedir, generated_msg, generated_srv) - - assert msg_mod is not None - assert srv_mod is not None - diff --git a/pyros_msgs/importer/tests/test_rosmsg_generator_import.py b/pyros_msgs/importer/tests/test_rosmsg_generator_import.py deleted file mode 100644 index 93b6334..0000000 --- a/pyros_msgs/importer/tests/test_rosmsg_generator_import.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import absolute_import, division, print_function - -""" -Testing executing rosmsg_generator directly (like setup.py would) -""" - -import os -import runpy - -# Ref : http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path - -# Importing generator module -from pyros_msgs.importer import rosmsg_generator - - -def test_generate_msgsrv_nspkg_usable(): - # generating message class - sitedir, generated_msg, generated_srv = rosmsg_generator.generate_msgsrv_nspkg( - [os.path.join(os.path.dirname(__file__), 'msg', 'TestMsg.msg')], - package='test_gen_msgs', - ns_pkg=True, - ) - - - # Verify that files exists and are importable - for m in [generated_msg, generated_srv]: - # modules are generated where the file is launched - gen_file = os.path.join(sitedir, *m.split(".")) - assert os.path.exists(gen_file + '.py') or os.path.exists(os.path.join(gen_file, '__init__.py')) - - msg_mod, srv_mod = rosmsg_generator.import_msgsrv(sitedir, generated_msg, generated_srv) - - assert msg_mod is not None - assert srv_mod is not None - - diff --git a/msg/OptionalFields.msg b/pyros_msgs/msg/OptionalFields.msg similarity index 70% rename from msg/OptionalFields.msg rename to pyros_msgs/msg/OptionalFields.msg index f0a219a..3f5c1c8 100644 --- a/msg/OptionalFields.msg +++ b/pyros_msgs/msg/OptionalFields.msg @@ -1,5 +1,6 @@ # The list of fields names that should be considered optional string[] optional_field_names +# TODO: find a way to make that static, in the definition itself, and not dynamically... # A boolean value per field, indicating if that field has been initialized or not bool[] optional_field_initialized_ \ No newline at end of file diff --git a/pyros_msgs/opt_as_array/tests/msg_generate.py b/pyros_msgs/opt_as_array/tests/msg_generate.py deleted file mode 100644 index ac556aa..0000000 --- a/pyros_msgs/opt_as_array/tests/msg_generate.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import os -import sys - -""" -module handling test message generation and import. -We need to generate all and import only one time ( in case we have one instance of pytest running multiple tests ) -""" - -from pyros_msgs.importer.rosmsg_generator import generate_msgsrv_nspkg, import_msgsrv - -# These depends on file structure and should no be in functions - -# dependencies for our generated messages -std_msgs_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'rosdeps', 'std_msgs', 'msg') - -# our own test messages we need to generate -test_gen_msg_dir = os.path.join(os.path.dirname(__file__), 'msg') - - -# TODO : replace this by a clever custom importer -def generate_std_msgs(): - flist = os.listdir(std_msgs_dir) - generated = generate_msgsrv_nspkg( - [os.path.join(std_msgs_dir, f) for f in flist], - package='std_msgs', - dependencies=['std_msgs'], - include_path=['std_msgs:{0}'.format(std_msgs_dir)], - ns_pkg=True - ) - std_msgs, std_srvs = import_msgsrv(*generated) - - return std_msgs, std_srvs - - -def generate_test_msgs(): - try: - # This should succeed if the message has been generated previously. - import std_msgs.msg as std_msgs - except ImportError: # we should enter here if the message class hasnt been generated yet. - std_msgs, std_srvs = generate_std_msgs() - - flist = os.listdir(test_gen_msg_dir) - generated = generate_msgsrv_nspkg( - [os.path.join(test_gen_msg_dir, f) for f in flist], - package='test_array_gen_msgs', - dependencies=['std_msgs'], - include_path=['std_msgs:{0}'.format(std_msgs_dir)], - ns_pkg=True - ) - test_gen_msgs, test_gen_srvs = import_msgsrv(*generated) - - return test_gen_msgs, test_gen_srvs - - diff --git a/pyros_msgs/opt_as_nested/opt_as_nested.py b/pyros_msgs/opt_as_nested/opt_as_nested.py index 0937155..8aafe28 100644 --- a/pyros_msgs/opt_as_nested/opt_as_nested.py +++ b/pyros_msgs/opt_as_nested/opt_as_nested.py @@ -11,10 +11,6 @@ make_typechecker_field_hidden, ) -import os -import sys - - from .ros_mappings import typechecker_from_rosfield_opttype diff --git a/pyros_msgs/opt_as_nested/tests/__init__.py b/pyros_msgs/opt_as_nested/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pyros_msgs/opt_as_nested/tests/msg_generate.py b/pyros_msgs/opt_as_nested/tests/msg_generate.py deleted file mode 100644 index f156728..0000000 --- a/pyros_msgs/opt_as_nested/tests/msg_generate.py +++ /dev/null @@ -1,82 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import os -import sys - -""" -module handling test message generation and import. -We need to generate all and import only one time ( in case we have one instance of pytest running multiple tests ) -""" - -from pyros_msgs.importer.rosmsg_generator import generate_msgsrv_nspkg, import_msgsrv - -# These depends on file structure and should no be in functions - -# dependencies for our generated messages -pyros_msgs_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'msg') -std_msgs_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'rosdeps', 'std_msgs', 'msg') - - -# our own test messages we need to generate -test_gen_msg_dir = os.path.join(os.path.dirname(__file__), 'msg') - - - -# TODO : replace this by a clever custom importer -def generate_pyros_msgs(): - flist = os.listdir(pyros_msgs_dir) - #flist = flist + os.listdir(std_msgs_dir) - generated = generate_msgsrv_nspkg( - [os.path.join(pyros_msgs_dir, f) for f in flist], - package='pyros_msgs', - dependencies=['pyros_msgs'], - include_path=['pyros_msgs:{0}'.format(pyros_msgs_dir)], - ns_pkg=True - ) - pyros_msgs_msg, pyros_srvs_srv = import_msgsrv(*generated) - - return pyros_msgs_msg, pyros_srvs_srv - -def generate_std_msgs(): - flist = os.listdir(std_msgs_dir) - generated = generate_msgsrv_nspkg( - [os.path.join(std_msgs_dir, f) for f in flist], - package='std_msgs', - dependencies=['std_msgs'], - include_path=['std_msgs:{0}'.format(std_msgs_dir)], - ns_pkg=True - ) - std_msgs, std_srvs = import_msgsrv(*generated) - - return std_msgs, std_srvs - - -def generate_test_msgs(): - try: - # This should succeed if the message has been generated previously (or accessing ROS generated message) - import pyros_msgs.msg as pyros_msgs - except ImportError: # we should enter here if the message class hasn't been generated yet. - pyros_msgs_msg, pyros_msgs_srv = generate_pyros_msgs() - - try: - # This should succeed if the message class was already generated - import std_msgs.msg as std_msgs - except ImportError: # we should enter here if the message was not generated yet. - _, _ = generate_std_msgs() - - flist = os.listdir(test_gen_msg_dir) - #flist = flist + os.listdir(std_msgs_dir) - generated = generate_msgsrv_nspkg( - [os.path.join(test_gen_msg_dir, f) for f in flist], - package='test_nested_gen_msgs', - dependencies=['pyros_msgs', 'std_msgs'], - include_path=['pyros_msgs:{0}'.format(pyros_msgs_dir), 'std_msgs:{0}'.format(std_msgs_dir)], - ns_pkg=True - ) - test_gen_msgs, test_gen_srvs = import_msgsrv(*generated) - - return test_gen_msgs, test_gen_srvs - - - - diff --git a/pyros_msgs/typecheck/ros_mappings.py b/pyros_msgs/typecheck/ros_mappings.py index cceb128..e1e397a 100644 --- a/pyros_msgs/typecheck/ros_mappings.py +++ b/pyros_msgs/typecheck/ros_mappings.py @@ -9,20 +9,17 @@ import os +# TMP : waiting for proper pip installable version of genpy and genmsd try: # Using genpy directly if ROS has been setup (while using from ROS pkg) - import genpy - + import genpy, genmsg except ImportError: - # Otherwise we refer to our submodules here (setup.py usecase, or running from tox without site-packages) - import site site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'ros-site')) + import genpy, genmsg - import genpy - - # Note we do not want to use pyros_setup here. + # Note we do not want to use pyros_setup/rosimport here. # We do not want to do a full ROS setup, only import specific packages. # If needed it should have been done before (loading a parent package). # this handle the case where we want to be independent of any underlying ROS system. @@ -30,7 +27,7 @@ import six -from pyros_msgs.typecheck import ( +from .typechecker import ( six_long, Accepter, Sanitizer, Array, Any, MinMax, CodePoint, TypeChecker, diff --git a/pyros_msgs/typecheck/tests/msg_generate.py b/pyros_msgs/typecheck/tests/msg_generate.py deleted file mode 100644 index 9022f31..0000000 --- a/pyros_msgs/typecheck/tests/msg_generate.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import os -import sys - -""" -module handling test message generation and import. -We need to generate all and import only one time ( in case we have one instance of pytest running multiple tests ) -""" - -from pyros_msgs.importer.rosmsg_generator import generate_msgsrv_nspkg, import_msgsrv - -# These depends on file structure and should no be in functions - -# dependencies for our generated messages -std_msgs_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), 'rosdeps', 'std_msgs', 'msg') - -# our own test messages we need to generate -test_gen_msg_dir = os.path.join(os.path.dirname(__file__), 'msg') - - -# TODO : replace this by a clever custom importer -def generate_std_msgs(): - flist = os.listdir(std_msgs_dir) - generated = generate_msgsrv_nspkg( - [os.path.join(std_msgs_dir, f) for f in flist], - package='std_msgs', - dependencies=['std_msgs'], - include_path=['std_msgs:{0}'.format(std_msgs_dir)], - ns_pkg=True - ) - test_gen_msgs, test_gen_srvs = import_msgsrv(*generated) - - return test_gen_msgs, test_gen_srvs - - - diff --git a/pyros_msgs/typecheck/tests/test_ros_mappings.py b/pyros_msgs/typecheck/tests/test_ros_mappings.py deleted file mode 100644 index 2782aea..0000000 --- a/pyros_msgs/typecheck/tests/test_ros_mappings.py +++ /dev/null @@ -1,158 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import os -import sys -import numpy -import pytest -from StringIO import StringIO - - -# generating all and accessing the required message class. -from pyros_msgs.typecheck.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import std_msgs.msg as std_msgs -except ImportError: # we should enter here if the message was not generated yet. - std_msgs, std_srvs = msg_generate.generate_std_msgs() - -import genpy - -from pyros_msgs.typecheck.typechecker import ( - six_long, - maybe_list, - maybe_tuple, - Sanitizer, Accepter, Array, Any, MinMax, - TypeChecker, - TypeCheckerException, -) - -from pyros_msgs.typecheck.ros_mappings import typechecker_from_rosfield_type - - -from hypothesis import given, example, settings, Verbosity -import hypothesis.strategies as st - - -# The main point here is insuring that any sanitized type will safely serialize and deserialize -# And also that any type that doesnt safely serialize / deserialize will not pass the type checker - -rosmsg_slot_types = [ - ('bool', st.booleans()), - ('int', st.integers()), - ('float', st.floats()), - ('string', st.binary()), - ('time', st.builds(genpy.Time, secs=st.integers(min_value=0), nsecs=st.integers(min_value=0))), # ROS time - ('duration', st.builds(genpy.Duration, secs=st.integers(), nsecs=st.integers())), # ROS duration -] - -rosmsg_slot_arraytypes = [ - (s[0] + '[]', st.lists(elements=s[1])) - for s in rosmsg_slot_types -] - -# TODO : is there a way to generate messages on the fly to test all possible field combinations ? - -# For now We use a set of basic messages for testing -std_msgs_types_strat_ok = { - 'std_msgs/Bool': st.builds(std_msgs.Bool, data=st.booleans()), - 'std_msgs/Int8': st.builds(std_msgs.Int8, data=st.one_of(st.booleans(), st.integers(min_value=-128, max_value=127))), # in python booleans are integers - 'std_msgs/Int16': st.builds(std_msgs.Int16, data=st.one_of(st.booleans(), st.integers(min_value=-32768, max_value=32767))), - 'std_msgs/Int32': st.builds(std_msgs.Int32, data=st.one_of(st.booleans(), st.integers(min_value=-2147483648, max_value=2147483647))), - 'std_msgs/Int64': st.builds(std_msgs.Int64, data=st.one_of(st.booleans(), st.integers(min_value=-six_long(9223372036854775808), max_value=six_long(9223372036854775807)))), - 'std_msgs/UInt8': st.builds(std_msgs.UInt8, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=255))), - 'std_msgs/UInt16': st.builds(std_msgs.UInt16, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=65535))), - 'std_msgs/UInt32': st.builds(std_msgs.UInt32, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=4294967295))), - 'std_msgs/UInt64': st.builds(std_msgs.UInt64, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=six_long(18446744073709551615)))), - # TMP : seems we have some problems with float arithmetic between numpy and hypothesis... - #'std_msgs/Float32': st.builds(std_msgs.Float32, data=st.floats(min_value=-3.4028235e+38, max_value=3.4028235e+38)), - #'std_msgs/Float64': st.builds(std_msgs.Float64, data=st.floats(min_value=-1.7976931348623157e+308, max_value=1.7976931348623157e+308, )), - #'std_msgs/String': st.builds(std_msgs.String, data=st.one_of(st.binary(), st.text(alphabet=st.characters(max_codepoint=127)))), - 'std_msgs/String': st.builds(std_msgs.String, data=st.text(alphabet=st.characters(max_codepoint=127))), # binary can break hypothesis reporting - # CAREFUL : we need to avoid having nsecs making our secs overflow after canonization from __init__ - 'std_msgs/Time': st.builds(std_msgs.Time, data=st.builds(genpy.Time, secs=st.integers(min_value=0, max_value=4294967295 -3), nsecs=st.integers(min_value=0, max_value=4294967295))), - 'std_msgs/Duration': st.builds(std_msgs.Duration, data=st.builds(genpy.Duration, secs=st.integers(min_value=-2147483648 +1, max_value=2147483647 -1), nsecs=st.integers(min_value=-2147483648, max_value=2147483647))), - # TODO : add more. we should test all. -} - -std_msgs_types_strat_broken = { - # everything else... - 'std_msgs/Bool': st.builds(std_msgs.Bool, data=st.one_of(st.integers(), st.floats())), - 'std_msgs/Int8': st.builds(std_msgs.Int8, data=st.one_of(st.floats(), st.integers(min_value=127+1), st.integers(max_value=-128-1))), - 'std_msgs/Int16': st.builds(std_msgs.Int16, data=st.one_of(st.floats(), st.integers(min_value=32767+1), st.integers(max_value=-32768-1))), - 'std_msgs/Int32': st.builds(std_msgs.Int32, data=st.one_of(st.floats(), st.integers(min_value=2147483647+1), st.integers(max_value=-2147483648-1))), - 'std_msgs/Int64': st.builds(std_msgs.Int64, data=st.one_of(st.floats(), st.integers(min_value=six_long(9223372036854775807+1)), st.integers(max_value=six_long(-9223372036854775808-1)))), - 'std_msgs/UInt8': st.builds(std_msgs.UInt8, data=st.one_of(st.floats(), st.integers(min_value=255+1), st.integers(max_value=-1))), - 'std_msgs/UInt16': st.builds(std_msgs.UInt16, data=st.one_of(st.floats(), st.integers(min_value=65535+1), st.integers(max_value=-1))), - 'std_msgs/UInt32': st.builds(std_msgs.UInt32, data=st.one_of(st.floats(), st.integers(min_value=4294967295+1), st.integers(max_value=-1))), - 'std_msgs/UInt64': st.builds(std_msgs.UInt64, data=st.one_of(st.floats(), st.integers(min_value=six_long(18446744073709551615+1)), st.integers(max_value=-1))), - 'std_msgs/Float32': st.builds(std_msgs.Float32, data=st.one_of(st.booleans(), st.integers())), # st.floats(max_value=-3.4028235e+38), st.floats(min_value=3.4028235e+38))), - 'std_msgs/Float64': st.builds(std_msgs.Float64, data=st.one_of(st.booleans(), st.integers())), # st.floats(max_value=-1.7976931348623157e+308), st.floats(min_value=1.7976931348623157e+308))), - # TODO : add more. we should test all -} - -pyros_msgs_types_strat_ok = { - # TODO -} - -pyros_msgs_types_strat_broken = { - -} - -# We need a composite strategy to link slot type and slot value -@st.composite -@settings(verbosity=Verbosity.verbose, timeout=1) -def msg_type_and_value(draw, msgs_type_st): - msg_type = draw(st.sampled_from(msgs_type_st)) - msg_value = draw(msgs_type_st.get(msg_type)) - return msg_type, msg_value - - -@given(msg_type_and_value(std_msgs_types_strat_ok)) -@settings(verbosity=Verbosity.verbose, timeout=1) -def test_typechecker_serialize_deserialize_inverse(msg_type_and_ok_value): - """""" - tc = typechecker_from_rosfield_type(msg_type_and_ok_value[0]) - value = tc(msg_type_and_ok_value[1]) - - # sending - buff = StringIO() - value.serialize(buff) - serialized = buff.getvalue() - buff.close() - - # receiving - received = tc() - received.deserialize(serialized) - - if isinstance(value, std_msgs.Float64): # for floats, this is only true relative to some epsilon... - numpy.testing.assert_allclose(received.data, value.data) - if isinstance(value, std_msgs.Float32): # for floats, this is only true relative to some epsilon... - numpy.testing.assert_allclose(received.data, value.data, rtol=1e-5) - else: - assert received == value - - -@given(msg_type_and_value(std_msgs_types_strat_broken)) -@settings(verbosity=Verbosity.verbose, timeout=1) -def test_typechecker_typechecker_prevent_broken_values(msg_type_and_bad_value): - tc = typechecker_from_rosfield_type(msg_type_and_bad_value[0]) - - # assert we have a somehow broken value : - with pytest.raises(Exception) as excinfo: - value = tc(msg_type_and_bad_value[1]) - - # sending - buff = StringIO() - value.serialize(buff) - serialized = buff.getvalue() - buff.close() - - # receiving - received = tc() - received.deserialized(serialized) - - # assert the type checker doesnt accept it - with pytest.raises(TypeCheckerException) as excinfo: - _ = tc(msg_type_and_bad_value[1]) - assert 'is not accepted' in excinfo.value.message diff --git a/pyros_msgs/typecheck/typechecker.py b/pyros_msgs/typecheck/typechecker.py index d795793..550dae3 100644 --- a/pyros_msgs/typecheck/typechecker.py +++ b/pyros_msgs/typecheck/typechecker.py @@ -39,7 +39,7 @@ The keys denote the message fields names, and the values are the types, following the previous rules. """ - +import sys import six # to get long for py2 and int for py3 six_long = six.integer_types[-1] @@ -83,7 +83,26 @@ def __call__(self, *args, **kwargs): #TODO : is it the same with slots ? elif args: # basic type (or mapping type but we pass a full value) # we sanitize by running the type initializer with the value - return self.t(*(a for a in args if a is not None)) # careful we do not want to pass None to a basic type + if self.t == six.binary_type: + # we need to encode + initializer = args[0] + # Ref : https://www.python.org/dev/peps/pep-0358/ + if isinstance(initializer, six.text_type) and sys.version_info > (3, 0): + encoding = args[1] if len(args) > 1 else sys.getdefaultencoding() + return self.t(initializer, encoding) + elif initializer is not None: + return self.t(initializer) + else: + return self.t() + elif self.t == six.text_type: + # we need to decode + obj = args[0] + if isinstance(args[0], six.binary_type): + obj.decode(sys.getdefaultencoding()) + return self.t(obj) + else: + return self.t( + *(a for a in args if a is not None)) # careful we do not want to pass None to a basic type else: TypeCheckerException("Calling {self} with {args} and {kwargs}. not supported".format(**locals())) @@ -191,22 +210,25 @@ class TypeCheckerException(Exception): def __init__(self, message): if isinstance(message, six.text_type): - super(TypeCheckerException, self).__init__(message.encode('utf-8')) + super(TypeCheckerException, self).__init__(message.encode('utf-8', 'replace')) self.message = message elif isinstance(message, six.binary_type): super(TypeCheckerException, self).__init__(message) - self.message = message.decode('utf-8') + self.message = message.decode('utf-8', 'replace') else: # This shouldn't happen... raise TypeError("message in an exception has to be a string (optionally unicode)") def __str__(self): # when we need a binary string - return self.message.encode('ascii', 'ignore') + return self.message.encode('ascii', 'replace') def __unicode__(self): # when we need a text string return self.message + def __repr__(self): + return "TypeCheckerException(" + self.message + ")" + class TypeChecker(object): def __init__(self, sanitizer, accepter): diff --git a/requirements/indigo/debs_in_venv.txt b/requirements/indigo/debs_in_venv.txt new file mode 100644 index 0000000..b949165 --- /dev/null +++ b/requirements/indigo/debs_in_venv.txt @@ -0,0 +1,15 @@ +# trusty packages versions to validate behavior with these versions for a potential ROS package for pyros-msgs +pytest==2.5.1 +pytest-xdist==1.8 # for --boxed +hypothesis==3.0.1 # backported to indigo as https://github.com/asmodehn/hypothesis-rosrelease +numpy>=1.8.1 + +# TODO : lock this on indigo +# ros dependencies (necessary when running tests from install) +-e git+https://github.com/asmodehn/genmsg.git@setuptools#egg=ros_genmsg +-e git+https://github.com/asmodehn/genpy.git@setuptools#egg=ros_genpy + +# source access to latest filefinder and rosimport from git ... +-e git+https://github.com/asmodehn/filefinder2.git#egg=filefinder2 +-e git+https://github.com/asmodehn/rosimport.git#egg=rosimport + diff --git a/requirements/kinetic/debs_in_venv.txt b/requirements/kinetic/debs_in_venv.txt new file mode 100644 index 0000000..6f222e0 --- /dev/null +++ b/requirements/kinetic/debs_in_venv.txt @@ -0,0 +1,15 @@ +# xenial packages versions to validate behavior with these versions for a potential ROS package for pyros-msgs +pytest==2.8.7 +pytest-xdist==1.8 # for --boxed +hypothesis==3.0.1 +numpy==1.11.0 + +# TODO : lock this on kinetic +# ros dependencies (necessary when running tests from install) +-e git+https://github.com/asmodehn/genmsg.git@setuptools#egg=ros_genmsg +-e git+https://github.com/asmodehn/genpy.git@setuptools-kinetic#egg=ros_genpy + +# source access to latest filefinder and rosimport from git ... +-e git+https://github.com/asmodehn/filefinder2.git#egg=filefinder2 +-e git+https://github.com/asmodehn/rosimport.git#egg=rosimport + diff --git a/requirements/lunar/debs_in_venv.txt b/requirements/lunar/debs_in_venv.txt new file mode 100644 index 0000000..e5c0fee --- /dev/null +++ b/requirements/lunar/debs_in_venv.txt @@ -0,0 +1,14 @@ +# xenial packages versions to validate behavior with these versions for a potential ROS package for pyros-msgs +pytest==2.8.7 +pytest-xdist==1.8 # for --boxed +hypothesis==3.0.1 +numpy==1.11.0 + +# TODO : lock this on lunar +# ros dependencies (necessary when running tests from install) +-e git+https://github.com/asmodehn/genmsg.git@setuptools#egg=ros_genmsg +-e git+https://github.com/asmodehn/genpy.git@setuptools-kinetic#egg=ros_genpy + +# source access to latest filefinder and rosimport from git ... +-e git+https://github.com/asmodehn/filefinder2.git#egg=filefinder2 +-e git+https://github.com/asmodehn/rosimport.git#egg=rosimport diff --git a/requirements/python/indigo.txt b/requirements/python/indigo.txt new file mode 100644 index 0000000..3f95607 --- /dev/null +++ b/requirements/python/indigo.txt @@ -0,0 +1,11 @@ +# Requirements for running a pure python setup on top of indigo + +# TODO : lock this on indigo +# ros dependencies (necessary when running tests from install) +-e git+https://github.com/asmodehn/genmsg.git@setuptools#egg=ros_genmsg +-e git+https://github.com/asmodehn/genpy.git@setuptools#egg=ros_genpy + +# source access to latest filefinder and rosimport from git ... +-e git+https://github.com/asmodehn/filefinder2.git#egg=filefinder2 +-e git+https://github.com/asmodehn/rosimport.git#egg=rosimport + diff --git a/requirements/python/kinetic.txt b/requirements/python/kinetic.txt new file mode 100644 index 0000000..8d456af --- /dev/null +++ b/requirements/python/kinetic.txt @@ -0,0 +1,11 @@ +# Requirements for running a pure python setup on top of kinetic + +# TODO : lock this on kinetic +# ros dependencies (necessary when running tests from install) +-e git+https://github.com/asmodehn/genmsg.git@setuptools#egg=ros_genmsg +-e git+https://github.com/asmodehn/genpy.git@setuptools-kinetic#egg=ros_genpy + +# source access to latest filefinder and rosimport from git ... +-e git+https://github.com/asmodehn/filefinder2.git#egg=filefinder2 +-e git+https://github.com/asmodehn/rosimport.git#egg=rosimport + diff --git a/requirements/python/latest.txt b/requirements/python/latest.txt new file mode 100644 index 0000000..8fbfdf0 --- /dev/null +++ b/requirements/python/latest.txt @@ -0,0 +1,10 @@ +# Requirements for running a pure python setup on top of the next upcoming rosdistro + +# TODO : lock this on lunar +# ros dependencies (necessary when running tests from install) +-e git+https://github.com/asmodehn/genmsg.git@setuptools#egg=ros_genmsg +-e git+https://github.com/asmodehn/genpy.git@setuptools-kinetic#egg=ros_genpy + +# source access to latest filefinder and rosimport from git ... +-e git+https://github.com/asmodehn/filefinder2.git#egg=filefinder2 +-e git+https://github.com/asmodehn/rosimport.git#egg=rosimport diff --git a/requirements/python/lunar.txt b/requirements/python/lunar.txt new file mode 100644 index 0000000..4827006 --- /dev/null +++ b/requirements/python/lunar.txt @@ -0,0 +1,10 @@ +# Requirements for running a pure python setup on top of lunar + +# TODO : lock this on lunar +# ros dependencies (necessary when running tests from install) +-e git+https://github.com/asmodehn/genmsg.git@setuptools#egg=ros_genmsg +-e git+https://github.com/asmodehn/genpy.git@setuptools-kinetic#egg=ros_genpy + +# source access to latest filefinder and rosimport from git ... +-e git+https://github.com/asmodehn/filefinder2.git#egg=filefinder2 +-e git+https://github.com/asmodehn/rosimport.git#egg=rosimport diff --git a/requirements/python/tests.txt b/requirements/python/tests.txt new file mode 100644 index 0000000..3ecc996 --- /dev/null +++ b/requirements/python/tests.txt @@ -0,0 +1,5 @@ +# latest version to validate behavior on pure python env +pytest +pytest-xdist # for --boxed +hypothesis +numpy diff --git a/requirements/tools.txt b/requirements/tools.txt new file mode 100644 index 0000000..7a9dbd5 --- /dev/null +++ b/requirements/tools.txt @@ -0,0 +1,3 @@ +# for release, version doesnt matter, we always work in virtualenv +gitchangelog +twine \ No newline at end of file diff --git a/ros-site/README.md b/ros-site/README.md deleted file mode 100644 index 24202b8..0000000 --- a/ros-site/README.md +++ /dev/null @@ -1,6 +0,0 @@ -This folder is added with site.addsitedir() to provide a set of ROS python packages from source. -It happens when the import of one of these packages(usually found on ROS systems) fails. -This is the case from pure python, for our automated testing tox suite. - -If ROS is setup before executing pyros_msgs/importer/rosmsg_generator.py, -then the ROS versions of these packages will be used instead \ No newline at end of file diff --git a/ros-site/genmsg.pth b/ros-site/genmsg.pth deleted file mode 100644 index 297013a..0000000 --- a/ros-site/genmsg.pth +++ /dev/null @@ -1 +0,0 @@ -../rosdeps/genmsg/src \ No newline at end of file diff --git a/ros-site/genpy.pth b/ros-site/genpy.pth deleted file mode 100644 index 79a5b28..0000000 --- a/ros-site/genpy.pth +++ /dev/null @@ -1 +0,0 @@ -../rosdeps/genpy/src \ No newline at end of file diff --git a/rosdeps/genmsg b/rosdeps/genmsg deleted file mode 160000 index 490b375..0000000 --- a/rosdeps/genmsg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 490b3753213ed3e2251acd218c62224b2787ee0e diff --git a/rosdeps/genpy b/rosdeps/genpy deleted file mode 160000 index cb07134..0000000 --- a/rosdeps/genpy +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cb07134e084a4fb6099de5cefcbb6b9a7f666cf5 diff --git a/setup.py b/setup.py index 609660c..3f49ec1 100644 --- a/setup.py +++ b/setup.py @@ -12,11 +12,6 @@ version = runpy.run_path('pyros_msgs/typecheck/_version.py') __version__ = version.get('__version__') -# Including generator module directly from code to be able to generate our message classes -# Ref : http://stackoverflow.com/questions/67631/how-to-import-a-module-given-the-full-path -import imp -rosmsg_generator = imp.load_source('rosmsg_generator', 'pyros_msgs/importer/rosmsg_generator.py') - # Best Flow : # Clean previous build & dist @@ -30,40 +25,6 @@ # TODO : command to retrieve extra ROS stuff from a third party release repo ( for ROS devs ). useful in dev only so maybe "rosdevelop" ? or via catkin_pip ? # TODO : command to release to Pip and ROS (bloom) same version one after the other... - -# Clean way to add a custom "python setup.py " -# Ref setup.py command extension : https://blog.niteoweb.com/setuptools-run-custom-code-in-setup-py/ -class GenerateMsgCommand(setuptools.Command): - """Command to generate message class""" - description = "generate messages for pyros_msgs" - user_options = [] - - def initialize_options(self): - """init options""" - # TODO : pass distro path [indigo|jade|etc.] - pass - - def finalize_options(self): - """finalize options""" - pass - - def run(self): - """runner""" - - # generating message class - generated = rosmsg_generator.generate_msgsrv_nspkg( - [os.path.join(os.path.dirname(__file__), 'msg', 'OptionalFields.msg')], - package='pyros_msgs', - ns_pkg=False, # no need to generate ns_pkg here, we can use the one we already have - ) - - # Note we have a tricky problem here since the ros distro for our target needs to be installed on the machine packaging this... - # But pip packages are supposed to work on any platform, so we might need another way... - - print("Check that the messages classes have been generated properly...") - sys.exit() - - # Clean way to add a custom "python setup.py " # Ref setup.py command extension : https://blog.niteoweb.com/setuptools-run-custom-code-in-setup-py/ class PrepareReleaseCommand(setuptools.Command): @@ -235,29 +196,33 @@ def run(self): license='MIT', packages=[ 'pyros_msgs', - # 'pyros_msgs.msg', #TODO : generate this for pure python package, in a way that is compatible with catkin (so we can still use catkin_make with this) - 'pyros_msgs.typecheck', 'pyros_msgs.typecheck.tests', - 'pyros_msgs.opt_as_array', 'pyros_msgs.opt_as_array.tests', - 'pyros_msgs.opt_as_nested', 'pyros_msgs.opt_as_nested.tests', + 'pyros_msgs.msg', # catkin build should generate it. python build can assume client uses rosimport. + 'pyros_msgs.typecheck', + 'pyros_msgs.opt_as_array', + 'pyros_msgs.opt_as_nested', ], - namespace_packages=['pyros_msgs'], + package_data={ + '': ['*.msg', '*.srv'] + }, # this is better than using package data ( since behavior is a bit different from distutils... ) - include_package_data=True, # use MANIFEST.in during install. + #include_package_data=True, # use MANIFEST.in during install. # Reference for optional dependencies : http://stackoverflow.com/questions/4796936/does-pip-handle-extras-requires-from-setuptools-distribute-based-sources install_requires=[ - # this is needed as install dependency since we embed tests in the package. - # 'pyros_setup>=0.2.1', # needed to grab ros environment even if distro setup.sh not sourced - # 'pyros_utils', # this must be satisfied by the ROS package system... + 'six', 'pyyaml>=3.10', # genpy relies on this... + ], + tests_require=[ + 'filefinder2', + 'rosimport', # we rely on this for generating ROS message if necessary before importing 'pytest>=2.8.0', # as per hypothesis requirement (careful with 2.5.1 on trusty) + 'pytest-xdist', # for --boxed (careful with the version it will be moved out of xdist) 'hypothesis>=3.0.1', # to target xenial LTS version 'numpy>=1.8.2', # from trusty version ], cmdclass={ - 'generatemsg': GenerateMsgCommand, 'rosdevelop': RosDevelopCommand, 'rospublish': ROSPublishCommand, }, - zip_safe=False, # TODO testing... + zip_safe=False, # TODO testing... including using rosimport to generate code from message definition... ) diff --git a/tests/rosdeps/ros_comm_msgs b/tests/rosdeps/ros_comm_msgs new file mode 160000 index 0000000..bfb8533 --- /dev/null +++ b/tests/rosdeps/ros_comm_msgs @@ -0,0 +1 @@ +Subproject commit bfb8533fd6c6e959c71f0d2a9669baeff2dac1ad diff --git a/rosdeps/std_msgs b/tests/rosdeps/std_msgs similarity index 100% rename from rosdeps/std_msgs rename to tests/rosdeps/std_msgs diff --git a/pyros_msgs/opt_as_array/tests/__init__.py b/tests/test_pyros_msgs/__init__.py similarity index 100% rename from pyros_msgs/opt_as_array/tests/__init__.py rename to tests/test_pyros_msgs/__init__.py diff --git a/tests/test_pyros_msgs/opt_as_array/__init__.py b/tests/test_pyros_msgs/opt_as_array/__init__.py new file mode 100644 index 0000000..962feef --- /dev/null +++ b/tests/test_pyros_msgs/opt_as_array/__init__.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import, division, print_function + +import os +import sys +import site + +added_site_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'rosdeps') +print("Adding site directory {0} to access std_msgs".format(added_site_dir)) +site.addsitedir(added_site_dir) + +import rosimport +rosimport.activate() diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_bool_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_bool_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_bool_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_bool_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_duration_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_duration_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_duration_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_duration_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_float32_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_float32_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_float32_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_float32_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_float64_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_float64_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_float64_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_float64_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_header_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_header_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_header_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_header_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_int16_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_int16_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_int16_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_int16_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_int32_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_int32_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_int32_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_int32_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_int64_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_int64_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_int64_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_int64_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_int8_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_int8_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_int8_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_int8_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_std_empty_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_std_empty_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_std_empty_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_std_empty_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_string_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_string_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_string_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_string_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_time_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_time_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_time_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_time_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_uint16_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint16_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_uint16_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint16_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_uint32_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint32_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_uint32_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint32_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_uint64_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint64_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_uint64_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint64_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/msg/test_opt_uint8_as_array.msg b/tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint8_as_array.msg similarity index 100% rename from pyros_msgs/opt_as_array/tests/msg/test_opt_uint8_as_array.msg rename to tests/test_pyros_msgs/opt_as_array/msg/test_opt_uint8_as_array.msg diff --git a/pyros_msgs/opt_as_array/tests/test_opt_bool.py b/tests/test_pyros_msgs/opt_as_array/test_opt_bool.py similarity index 87% rename from pyros_msgs/opt_as_array/tests/test_opt_bool.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_bool.py index a877a66..bc2bf74 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_bool.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_bool.py @@ -1,12 +1,7 @@ from __future__ import absolute_import, division, print_function -import os -import sys - -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -test_gen_msgs, test_gen_srvs = msg_generate.generate_test_msgs() +from . import msg as test_gen_msgs # patching (need to know the field name) import pyros_msgs.opt_as_array @@ -14,8 +9,6 @@ import pytest - -import hypothesis import hypothesis.strategies @@ -56,7 +49,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_bool_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of" in str(cm.value) # Just in case we run this directly diff --git a/pyros_msgs/opt_as_array/tests/test_opt_duration.py b/tests/test_pyros_msgs/opt_as_array/test_opt_duration.py similarity index 78% rename from pyros_msgs/opt_as_array/tests/test_opt_duration.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_duration.py index 17405ca..ec233af 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_duration.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_duration.py @@ -1,23 +1,13 @@ from __future__ import absolute_import, division, print_function -import os -import sys - - import genpy -# TODO : find a better place for this ? - -from pyros_msgs.importer.rosmsg_generator import generate_msgsrv_nspkg, import_msgsrv - +from . import msg as test_gen_msgs -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_duration_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_duration_as_array, ['data']) import pytest import hypothesis @@ -38,7 +28,7 @@ ), max_size=1 )) def test_init_rosdata(data): - msg = gen_test_msgs.test_opt_duration_as_array(data=data) + msg = test_gen_msgs.test_opt_duration_as_array(data=data) assert msg.data == data @@ -57,7 +47,7 @@ def test_init_rosdata(data): ) ) def test_init_data(data): - msg = gen_test_msgs.test_opt_duration_as_array(data=data) + msg = test_gen_msgs.test_opt_duration_as_array(data=data) assert msg.data == [data] @@ -75,12 +65,12 @@ def test_init_data(data): ) ) def test_init_raw(data): - msg = gen_test_msgs.test_opt_duration_as_array(data) + msg = test_gen_msgs.test_opt_duration_as_array(data) assert msg.data == [data] def test_init_default(): - msg = gen_test_msgs.test_opt_duration_as_array() + msg = test_gen_msgs.test_opt_duration_as_array() assert msg.data == [] # TODO : test_wrong_init_except(data) check typecheck.tests.test_ros_mappings diff --git a/pyros_msgs/opt_as_array/tests/test_opt_int16.py b/tests/test_pyros_msgs/opt_as_array/test_opt_int16.py similarity index 73% rename from pyros_msgs/opt_as_array/tests/test_opt_int16.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_int16.py index 83fad1a..ae46014 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_int16.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_int16.py @@ -1,16 +1,10 @@ from __future__ import absolute_import, division, print_function -import os -import sys - - -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() +from . import msg as test_gen_msgs import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_int16_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_int16_as_array, ['data']) import pytest import hypothesis @@ -20,27 +14,27 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=-32768, max_value=32767), max_size=1)) def test_init_rosdata(data): """Testing that a proper data is stored as is""" - msg = gen_test_msgs.test_opt_int16_as_array(data=data) + msg = test_gen_msgs.test_opt_int16_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=-32768, max_value=32767)) def test_init_data(data): """Testing that an implicitely convertible data is stored as expected""" - msg = gen_test_msgs.test_opt_int16_as_array(data=data) + msg = test_gen_msgs.test_opt_int16_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=-32768, max_value=32767)) def test_init_raw(data): """Testing storing of data without specifying the field""" - msg = gen_test_msgs.test_opt_int16_as_array(data) + msg = test_gen_msgs.test_opt_int16_as_array(data) assert msg.data == [data] def test_init_default(): """Testing default value""" - msg = gen_test_msgs.test_opt_int16_as_array() + msg = test_gen_msgs.test_opt_int16_as_array() assert msg.data == [] @@ -53,9 +47,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_int16_as_array(data) + test_gen_msgs.test_opt_int16_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_array/tests/test_opt_int32.py b/tests/test_pyros_msgs/opt_as_array/test_opt_int32.py similarity index 74% rename from pyros_msgs/opt_as_array/tests/test_opt_int32.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_int32.py index 5c0a7f9..3b39c25 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_int32.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_int32.py @@ -1,16 +1,12 @@ from __future__ import absolute_import, division, print_function -import os -import sys +from . import msg as test_gen_msgs -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_int32_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_int32_as_array, ['data']) import pytest import hypothesis @@ -20,27 +16,27 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=-2147483648, max_value=2147483647),max_size=1)) def test_init_rosdata(data): """Testing that a proper data is stored as is""" - msg = gen_test_msgs.test_opt_int32_as_array(data=data) + msg = test_gen_msgs.test_opt_int32_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=-2147483648, max_value=2147483647)) def test_init_data(data): """Testing that an implicitely convertible data is stored as expected""" - msg = gen_test_msgs.test_opt_int32_as_array(data=data) + msg = test_gen_msgs.test_opt_int32_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=-2147483648, max_value=2147483647)) def test_init_raw(data): """Testing storing of data without specifying the field""" - msg = gen_test_msgs.test_opt_int32_as_array(data) + msg = test_gen_msgs.test_opt_int32_as_array(data) assert msg.data == [data] def test_init_default(): """Testing default value""" - msg = gen_test_msgs.test_opt_int32_as_array() + msg = test_gen_msgs.test_opt_int32_as_array() assert msg.data == [] @@ -53,9 +49,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_int32_as_array(data) + test_gen_msgs.test_opt_int32_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_array/tests/test_opt_int64.py b/tests/test_pyros_msgs/opt_as_array/test_opt_int64.py similarity index 73% rename from pyros_msgs/opt_as_array/tests/test_opt_int64.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_int64.py index 23f9c2c..5deef74 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_int64.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_int64.py @@ -1,16 +1,11 @@ from __future__ import absolute_import, division, print_function -import os -import sys +from . import msg as test_gen_msgs -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() - import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_int64_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_int64_as_array, ['data']) import pytest import hypothesis @@ -21,24 +16,24 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=six_long(-9223372036854775808), max_value=six_long(9223372036854775807)), max_size=1)) def test_init_rosdata(data): - msg = gen_test_msgs.test_opt_int64_as_array(data=data) + msg = test_gen_msgs.test_opt_int64_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=six_long(-9223372036854775808), max_value=six_long(9223372036854775807))) def test_init_data(data): - msg = gen_test_msgs.test_opt_int64_as_array(data=data) + msg = test_gen_msgs.test_opt_int64_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=six_long(-9223372036854775808), max_value=six_long(9223372036854775807))) def test_init_raw(data): - msg = gen_test_msgs.test_opt_int64_as_array(data) + msg = test_gen_msgs.test_opt_int64_as_array(data) assert msg.data == [data] def test_init_default(): - msg = gen_test_msgs.test_opt_int64_as_array() + msg = test_gen_msgs.test_opt_int64_as_array() assert msg.data == [] @@ -51,9 +46,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_int64_as_array(data) + test_gen_msgs.test_opt_int64_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_array/tests/test_opt_int8.py b/tests/test_pyros_msgs/opt_as_array/test_opt_int8.py similarity index 74% rename from pyros_msgs/opt_as_array/tests/test_opt_int8.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_int8.py index 2f89161..dcc9843 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_int8.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_int8.py @@ -1,13 +1,11 @@ from __future__ import absolute_import, division, print_function +from . import msg as test_gen_msgs -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_int8_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_int8_as_array, ['data']) import pytest import hypothesis @@ -17,27 +15,27 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=-128, max_value=127), max_size=1)) def test_init_rosdata(data): """Testing that a proper data is stored as is""" - msg = gen_test_msgs.test_opt_int8_as_array(data=data) + msg = test_gen_msgs.test_opt_int8_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=-128, max_value=127)) def test_init_data(data): """Testing that an implicitely convertible data is stored as expected""" - msg = gen_test_msgs.test_opt_int8_as_array(data=data) + msg = test_gen_msgs.test_opt_int8_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=-128, max_value=127)) def test_init_raw(data): """Testing storing of data without specifying the field""" - msg = gen_test_msgs.test_opt_int8_as_array(data) + msg = test_gen_msgs.test_opt_int8_as_array(data) assert msg.data == [data] def test_init_default(): """Testing default value""" - msg = gen_test_msgs.test_opt_int8_as_array() + msg = test_gen_msgs.test_opt_int8_as_array() assert msg.data == [] @@ -50,9 +48,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_int8_as_array(data) + test_gen_msgs.test_opt_int8_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_array/tests/test_opt_std_empty.py b/tests/test_pyros_msgs/opt_as_array/test_opt_std_empty.py similarity index 70% rename from pyros_msgs/opt_as_array/tests/test_opt_std_empty.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_std_empty.py index 052608b..a8e7adf 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_std_empty.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_std_empty.py @@ -1,22 +1,9 @@ from __future__ import absolute_import, division, print_function -import os -import sys - - import pytest - -# generating all and accessing the required message class. -from pyros_msgs.opt_as_array.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import std_msgs.msg as std_msgs -except ImportError: # we should enter here if the message was not generated yet. - std_msgs, _ = msg_generate.generate_std_msgs() - -test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() +from . import msg as test_gen_msgs +import std_msgs.msg as std_msgs import pyros_msgs.opt_as_array diff --git a/pyros_msgs/opt_as_array/tests/test_opt_string.py b/tests/test_pyros_msgs/opt_as_array/test_opt_string.py similarity index 68% rename from pyros_msgs/opt_as_array/tests/test_opt_string.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_string.py index 1732a35..cc096ba 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_string.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_string.py @@ -1,17 +1,12 @@ from __future__ import absolute_import, division, print_function -import os import sys +from . import msg as test_gen_msgs - -# generating all and accessing the required message class. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() - import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_string_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_string_as_array, ['data']) import pytest import hypothesis @@ -25,8 +20,11 @@ # hypothesis.strategies.binary() ), max_size=1)) def test_init_rosdata(data): - msg = gen_test_msgs.test_opt_string_as_array(data=data) - assert msg.data == data + msg = test_gen_msgs.test_opt_string_as_array(data=data) + if sys.version_info > (3, 0): # encoding/decoding is explicit + assert [d.decode(sys.getdefaultencoding()) for d in msg.data] == data + else: + assert msg.data == data @hypothesis.given(hypothesis.strategies.one_of( @@ -36,8 +34,11 @@ def test_init_rosdata(data): # hypothesis.strategies.binary() )) def test_init_data(data): - msg = gen_test_msgs.test_opt_string_as_array(data=data) - assert msg.data == [data] + msg = test_gen_msgs.test_opt_string_as_array(data=data) + if sys.version_info > (3, 0): # encoding/decoding is explicit + assert msg.data[0].decode(sys.getdefaultencoding()) == data + else: + assert msg.data[0] == data @hypothesis.given(hypothesis.strategies.one_of( @@ -47,12 +48,15 @@ def test_init_data(data): # hypothesis.strategies.binary() )) def test_init_raw(data): - msg = gen_test_msgs.test_opt_string_as_array(data) - assert msg.data == [data] + msg = test_gen_msgs.test_opt_string_as_array(data) + if sys.version_info > (3, 0): # encoding/decoding is explicit + assert msg.data[0].decode(sys.getdefaultencoding()) == data + else: + assert msg.data[0] == data def test_init_default(): - msg = gen_test_msgs.test_opt_string_as_array() + msg = test_gen_msgs.test_opt_string_as_array() assert msg.data == [] @@ -66,9 +70,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_string_as_array(data) + test_gen_msgs.test_opt_string_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly diff --git a/pyros_msgs/opt_as_array/tests/test_opt_time.py b/tests/test_pyros_msgs/opt_as_array/test_opt_time.py similarity index 74% rename from pyros_msgs/opt_as_array/tests/test_opt_time.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_time.py index 17eea7e..02190db 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_time.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_time.py @@ -1,19 +1,13 @@ from __future__ import absolute_import, division, print_function -import os -import sys - import genpy - -# generating all and accessing the required message class. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() +from . import msg as test_gen_msgs import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_time_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_time_as_array, ['data']) import pytest import hypothesis @@ -28,7 +22,7 @@ ), max_size=1 )) def test_init_rosdata(data): - msg = gen_test_msgs.test_opt_time_as_array(data=data) + msg = test_gen_msgs.test_opt_time_as_array(data=data) assert msg.data == data @@ -40,7 +34,7 @@ def test_init_rosdata(data): ) ) def test_init_data(data): - msg = gen_test_msgs.test_opt_time_as_array(data=data) + msg = test_gen_msgs.test_opt_time_as_array(data=data) assert msg.data == [data] @@ -52,12 +46,12 @@ def test_init_data(data): ) ) def test_init_raw(data): - msg = gen_test_msgs.test_opt_time_as_array(data) + msg = test_gen_msgs.test_opt_time_as_array(data) assert msg.data == [data] def test_init_default(): - msg = gen_test_msgs.test_opt_time_as_array() + msg = test_gen_msgs.test_opt_time_as_array() assert msg.data == [] diff --git a/pyros_msgs/opt_as_array/tests/test_opt_uint16.py b/tests/test_pyros_msgs/opt_as_array/test_opt_uint16.py similarity index 73% rename from pyros_msgs/opt_as_array/tests/test_opt_uint16.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_uint16.py index a362aa8..0e8000b 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_uint16.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_uint16.py @@ -1,13 +1,11 @@ from __future__ import absolute_import, division, print_function +from . import msg as test_gen_msgs -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_uint16_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_uint16_as_array, ['data']) import pytest import hypothesis @@ -17,27 +15,27 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=0, max_value=65535), max_size=1)) def test_init_rosdata(data): """Testing that a proper data is stored as is""" - msg = gen_test_msgs.test_opt_uint16_as_array(data=data) + msg = test_gen_msgs.test_opt_uint16_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=65535)) def test_init_data(data): """Testing that an implicitely convertible data is stored as expected""" - msg = gen_test_msgs.test_opt_uint16_as_array(data=data) + msg = test_gen_msgs.test_opt_uint16_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=65535)) def test_init_raw(data): """Testing storing of data without specifying the field""" - msg = gen_test_msgs.test_opt_uint16_as_array(data) + msg = test_gen_msgs.test_opt_uint16_as_array(data) assert msg.data == [data] def test_init_default(): """Testing default value""" - msg = gen_test_msgs.test_opt_uint16_as_array() + msg = test_gen_msgs.test_opt_uint16_as_array() assert msg.data == [] @@ -50,9 +48,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_uint16_as_array(data) + test_gen_msgs.test_opt_uint16_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_array/tests/test_opt_uint32.py b/tests/test_pyros_msgs/opt_as_array/test_opt_uint32.py similarity index 74% rename from pyros_msgs/opt_as_array/tests/test_opt_uint32.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_uint32.py index 8655b75..151f7df 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_uint32.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_uint32.py @@ -1,13 +1,10 @@ from __future__ import absolute_import, division, print_function - -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() +from . import msg as test_gen_msgs import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_uint32_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_uint32_as_array, ['data']) import pytest import hypothesis @@ -17,27 +14,27 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=0, max_value=4294967295), max_size=1)) def test_init_rosdata(data): """Testing that a proper data is stored as is""" - msg = gen_test_msgs.test_opt_uint32_as_array(data=data) + msg = test_gen_msgs.test_opt_uint32_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=4294967295)) def test_init_data(data): """Testing that an implicitely convertible data is stored as expected""" - msg = gen_test_msgs.test_opt_uint32_as_array(data=data) + msg = test_gen_msgs.test_opt_uint32_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=4294967295)) def test_init_raw(data): """Testing storing of data without specifying the field""" - msg = gen_test_msgs.test_opt_uint32_as_array(data) + msg = test_gen_msgs.test_opt_uint32_as_array(data) assert msg.data == [data] def test_init_default(): """Testing default value""" - msg = gen_test_msgs.test_opt_uint32_as_array() + msg = test_gen_msgs.test_opt_uint32_as_array() assert msg.data == [] @@ -50,9 +47,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_uint32_as_array(data) + test_gen_msgs.test_opt_uint32_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_array/tests/test_opt_uint64.py b/tests/test_pyros_msgs/opt_as_array/test_opt_uint64.py similarity index 74% rename from pyros_msgs/opt_as_array/tests/test_opt_uint64.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_uint64.py index f667725..0624c1e 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_uint64.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_uint64.py @@ -1,13 +1,11 @@ from __future__ import absolute_import, division, print_function +from . import msg as test_gen_msgs -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_uint64_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_uint64_as_array, ['data']) import pytest import hypothesis @@ -17,27 +15,27 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=0, max_value=18446744073709551615), max_size=1)) def test_init_rosdata(data): """Testing that a proper data is stored as is""" - msg = gen_test_msgs.test_opt_uint64_as_array(data=data) + msg = test_gen_msgs.test_opt_uint64_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=18446744073709551615)) def test_init_data(data): """Testing that an implicitely convertible data is stored as expected""" - msg = gen_test_msgs.test_opt_uint64_as_array(data=data) + msg = test_gen_msgs.test_opt_uint64_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=18446744073709551615)) def test_init_raw(data): """Testing storing of data without specifying the field""" - msg = gen_test_msgs.test_opt_uint64_as_array(data) + msg = test_gen_msgs.test_opt_uint64_as_array(data) assert msg.data == [data] def test_init_default(): """Testing default value""" - msg = gen_test_msgs.test_opt_uint64_as_array() + msg = test_gen_msgs.test_opt_uint64_as_array() assert msg.data == [] @@ -50,9 +48,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_uint64_as_array(data) + test_gen_msgs.test_opt_uint64_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_array/tests/test_opt_uint8.py b/tests/test_pyros_msgs/opt_as_array/test_opt_uint8.py similarity index 74% rename from pyros_msgs/opt_as_array/tests/test_opt_uint8.py rename to tests/test_pyros_msgs/opt_as_array/test_opt_uint8.py index d4ce481..3c46911 100644 --- a/pyros_msgs/opt_as_array/tests/test_opt_uint8.py +++ b/tests/test_pyros_msgs/opt_as_array/test_opt_uint8.py @@ -1,13 +1,11 @@ from __future__ import absolute_import, division, print_function +from . import msg as test_gen_msgs -# generating all and accessing the required message classe. -from pyros_msgs.opt_as_array.tests import msg_generate -gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() import pyros_msgs.opt_as_array # patching (need to know the field name) -pyros_msgs.opt_as_array.duck_punch(gen_test_msgs.test_opt_uint8_as_array, ['data']) +pyros_msgs.opt_as_array.duck_punch(test_gen_msgs.test_opt_uint8_as_array, ['data']) import pytest import hypothesis @@ -17,27 +15,27 @@ @hypothesis.given(hypothesis.strategies.lists(hypothesis.strategies.integers(min_value=0, max_value=255), max_size=1)) def test_init_rosdata(data): """Testing that a proper data is stored as is""" - msg = gen_test_msgs.test_opt_uint8_as_array(data=data) + msg = test_gen_msgs.test_opt_uint8_as_array(data=data) assert msg.data == data @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=255)) def test_init_data(data): """Testing that an implicitely convertible data is stored as expected""" - msg = gen_test_msgs.test_opt_uint8_as_array(data=data) + msg = test_gen_msgs.test_opt_uint8_as_array(data=data) assert msg.data == [data] @hypothesis.given(hypothesis.strategies.integers(min_value=0, max_value=255)) def test_init_raw(data): """Testing storing of data without specifying the field""" - msg = gen_test_msgs.test_opt_uint8_as_array(data) + msg = test_gen_msgs.test_opt_uint8_as_array(data) assert msg.data == [data] def test_init_default(): """Testing default value""" - msg = gen_test_msgs.test_opt_uint8_as_array() + msg = test_gen_msgs.test_opt_uint8_as_array() assert msg.data == [] @@ -50,9 +48,9 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" with pytest.raises(AttributeError) as cm: - gen_test_msgs.test_opt_uint8_as_array(data) + test_gen_msgs.test_opt_uint8_as_array(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/tests/test_pyros_msgs/opt_as_nested/__init__.py b/tests/test_pyros_msgs/opt_as_nested/__init__.py new file mode 100644 index 0000000..dddba74 --- /dev/null +++ b/tests/test_pyros_msgs/opt_as_nested/__init__.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, print_function + +import os +import sys +import site + +# This is used for message definitions, not for python code +site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'rosdeps')) + +# Using genpy directly if ROS has been setup (while using from ROS pkg) +import genpy, genmsg + +import rosimport +rosimport.activate() diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_bool_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_bool_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_bool_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_bool_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_duration_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_duration_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_duration_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_duration_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_int16_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int16_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_int16_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int16_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_int32_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int32_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_int32_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int32_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_int64_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int64_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_int64_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int64_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_int8_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int8_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_int8_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_int8_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_std_empty_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_std_empty_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_std_empty_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_std_empty_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_string_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_string_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_string_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_string_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_time_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_time_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_time_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_time_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_uint16_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint16_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_uint16_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint16_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_uint32_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint32_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_uint32_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint32_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_uint64_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint64_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_uint64_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint64_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/msg/test_opt_uint8_as_nested.msg b/tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint8_as_nested.msg similarity index 100% rename from pyros_msgs/opt_as_nested/tests/msg/test_opt_uint8_as_nested.msg rename to tests/test_pyros_msgs/opt_as_nested/msg/test_opt_uint8_as_nested.msg diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_bool.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_bool.py similarity index 74% rename from pyros_msgs/opt_as_nested/tests/test_opt_bool.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_bool.py index 3df1cee..cc69e3f 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_bool.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_bool.py @@ -2,34 +2,14 @@ # TODO : check all types -import os -import sys import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) - +from . import msg as test_gen_msgs import pyros_msgs.opt_as_nested # patching (need to know the field name) pyros_msgs.opt_as_nested.duck_punch(test_gen_msgs.test_opt_bool_as_nested, ['data']) - - - - - import hypothesis import hypothesis.strategies @@ -64,7 +44,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_bool_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_duration.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_duration.py similarity index 83% rename from pyros_msgs/opt_as_nested/tests/test_opt_duration.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_duration.py index 922e494..6558df8 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_duration.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_duration.py @@ -1,25 +1,11 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import genpy import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() +from . import msg as test_gen_msgs -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) import pyros_msgs.opt_as_nested # patching (need to know the field name) diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_int16.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_int16.py similarity index 78% rename from pyros_msgs/opt_as_nested/tests/test_opt_int16.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_int16.py index 95fa1d2..73719bb 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_int16.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_int16.py @@ -1,26 +1,10 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest +from . import msg as test_gen_msgs -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) - import pyros_msgs.opt_as_nested # patching (need to know the field name) pyros_msgs.opt_as_nested.duck_punch(test_gen_msgs.test_opt_int16_as_nested, ['data']) @@ -67,7 +51,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_int16_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_int32.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_int32.py similarity index 78% rename from pyros_msgs/opt_as_nested/tests/test_opt_int32.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_int32.py index e8f5f93..8e912de 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_int32.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_int32.py @@ -1,24 +1,10 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() +from . import msg as test_gen_msgs -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) import pyros_msgs.opt_as_nested # patching (need to know the field name) @@ -66,7 +52,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_int32_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_int64.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_int64.py similarity index 79% rename from pyros_msgs/opt_as_nested/tests/test_opt_int64.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_int64.py index 5c82303..907b066 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_int64.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_int64.py @@ -1,27 +1,10 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest +from . import msg as test_gen_msgs - -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) - import pyros_msgs.opt_as_nested # patching (need to know the field name) pyros_msgs.opt_as_nested.duck_punch(test_gen_msgs.test_opt_int64_as_nested, ['data']) @@ -68,7 +51,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_int64_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_int8.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_int8.py similarity index 78% rename from pyros_msgs/opt_as_nested/tests/test_opt_int8.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_int8.py index 34169be..a495f80 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_int8.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_int8.py @@ -1,24 +1,10 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() +from . import msg as test_gen_msgs -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) import pyros_msgs.opt_as_nested # patching (need to know the field name) @@ -66,7 +52,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_int8_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_std_empty.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_std_empty.py similarity index 63% rename from pyros_msgs/opt_as_nested/tests/test_opt_std_empty.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_std_empty.py index 55e356c..3469203 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_std_empty.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_std_empty.py @@ -1,27 +1,9 @@ from __future__ import absolute_import, division, print_function -import os -import sys - - import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs - import std_msgs.msg as std_msgs -except ImportError: # we should enter here if the message was not generated yet. - std_msgs, _ = msg_generate.generate_std_msgs() - pyros_msgs, _ = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) - +from . import msg as test_gen_msgs +import std_msgs.msg as std_msgs import pyros_msgs.opt_as_nested # patching (need to know the field name) diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_string.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_string.py similarity index 68% rename from pyros_msgs/opt_as_nested/tests/test_opt_string.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_string.py index 36be2c2..4f7dac6 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_string.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_string.py @@ -1,29 +1,14 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os import sys import pytest +from . import msg as test_gen_msgs -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() - -try: - gen_test_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) - import pyros_msgs.opt_as_nested # patching (need to know the field name) -pyros_msgs.opt_as_nested.duck_punch(gen_test_msgs.test_opt_string_as_nested, ['data']) +pyros_msgs.opt_as_nested.duck_punch(test_gen_msgs.test_opt_string_as_nested, ['data']) import hypothesis import hypothesis.strategies @@ -36,8 +21,11 @@ # hypothesis.strategies.binary() )) def test_init_rosdata(data): - msg = gen_test_msgs.test_opt_string_as_nested(data=data) - assert msg.data == data + msg = test_gen_msgs.test_opt_string_as_nested(data=data) + if sys.version_info > (3, 0): # encoding/decoding is explicit + assert msg.data.decode(sys.getdefaultencoding()) == data + else: + assert msg.data == data @hypothesis.given(hypothesis.strategies.one_of( @@ -47,8 +35,11 @@ def test_init_rosdata(data): # hypothesis.strategies.binary() )) def test_init_data(data): - msg = gen_test_msgs.test_opt_string_as_nested(data=data) - assert msg.data == data + msg = test_gen_msgs.test_opt_string_as_nested(data=data) + if sys.version_info > (3, 0): # encoding/decoding is explicit + assert msg.data.decode(sys.getdefaultencoding()) == data + else: + assert msg.data == data @hypothesis.given(hypothesis.strategies.one_of( @@ -58,12 +49,15 @@ def test_init_data(data): # hypothesis.strategies.binary() )) def test_init_raw(data): - msg = gen_test_msgs.test_opt_string_as_nested(data) - assert msg.data == data + msg = test_gen_msgs.test_opt_string_as_nested(data) + if sys.version_info > (3, 0): # encoding/decoding is explicit + assert msg.data.decode(sys.getdefaultencoding()) == data + else: + assert msg.data == data def test_init_default(): - msg = gen_test_msgs.test_opt_string_as_nested() + msg = test_gen_msgs.test_opt_string_as_nested() assert msg.data == None @@ -77,7 +71,7 @@ def test_init_default(): def test_wrong_init_except(data): """Testing we except when types do not match""" try: - gen_test_msgs.test_opt_string_as_nested(data) + test_gen_msgs.test_opt_string_as_nested(data) except AttributeError: pass except UnicodeEncodeError: diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_time.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_time.py similarity index 73% rename from pyros_msgs/opt_as_nested/tests/test_opt_time.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_time.py index 768cd11..2bc7cd8 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_time.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_time.py @@ -1,26 +1,10 @@ from __future__ import absolute_import, division, print_function -import os -import sys - import genpy import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs - import std_msgs.msg as std_msgs -except ImportError: # we should enter here if the message was not generated yet. - std_msgs, _ = msg_generate.generate_std_msgs() - pyros_msgs, _ = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) +from . import msg as test_gen_msgs + import pyros_msgs.opt_as_nested diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_uint16.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint16.py similarity index 78% rename from pyros_msgs/opt_as_nested/tests/test_opt_uint16.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_uint16.py index 1b8064b..0890e45 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_uint16.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint16.py @@ -1,24 +1,9 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest +from . import msg as test_gen_msgs -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) import pyros_msgs.opt_as_nested # patching (need to know the field name) @@ -66,7 +51,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_uint16_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_uint32.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint32.py similarity index 78% rename from pyros_msgs/opt_as_nested/tests/test_opt_uint32.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_uint32.py index 3daada2..898b2c9 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_uint32.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint32.py @@ -1,26 +1,10 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest +from . import msg as test_gen_msgs -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) - import pyros_msgs.opt_as_nested # patching (need to know the field name) pyros_msgs.opt_as_nested.duck_punch(test_gen_msgs.test_opt_uint32_as_nested, ['data']) @@ -67,7 +51,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_uint32_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_uint64.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint64.py similarity index 78% rename from pyros_msgs/opt_as_nested/tests/test_opt_uint64.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_uint64.py index ec505ba..df3af1a 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_uint64.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint64.py @@ -1,24 +1,10 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() +from . import msg as test_gen_msgs -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) import pyros_msgs.opt_as_nested # patching (need to know the field name) @@ -66,7 +52,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_uint64_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/opt_as_nested/tests/test_opt_uint8.py b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint8.py similarity index 77% rename from pyros_msgs/opt_as_nested/tests/test_opt_uint8.py rename to tests/test_pyros_msgs/opt_as_nested/test_opt_uint8.py index 3e15d86..4592b47 100644 --- a/pyros_msgs/opt_as_nested/tests/test_opt_uint8.py +++ b/tests/test_pyros_msgs/opt_as_nested/test_opt_uint8.py @@ -1,24 +1,9 @@ from __future__ import absolute_import, division, print_function # TODO : check all types - -import os -import sys import pytest -# generating all and accessing the required message class. -from pyros_msgs.opt_as_nested.tests import msg_generate - -try: - # This should succeed if the message class was already generated - import pyros_msgs.msg as pyros_msgs -except ImportError: # we should enter here if the message was not generated yet. - pyros_msgs = msg_generate.generate_pyros_msgs() - -try: - test_gen_msgs, gen_test_srvs = msg_generate.generate_test_msgs() -except Exception as e: - pytest.raises(e) +from . import msg as test_gen_msgs import pyros_msgs.opt_as_nested # patching (need to know the field name) @@ -66,7 +51,7 @@ def test_wrong_init_except(data): with pytest.raises(AttributeError) as cm: test_gen_msgs.test_opt_uint8_as_nested(data) assert isinstance(cm.value, AttributeError) - assert "does not match the accepted type schema for 'data' : Any of set" in cm.value.message + assert "does not match the accepted type schema for 'data' : Any of " in str(cm.value) # Just in case we run this directly if __name__ == '__main__': diff --git a/pyros_msgs/typecheck/tests/__init__.py b/tests/test_pyros_msgs/typecheck/__init__.py similarity index 97% rename from pyros_msgs/typecheck/tests/__init__.py rename to tests/test_pyros_msgs/typecheck/__init__.py index 2b7400e..c50a829 100644 --- a/pyros_msgs/typecheck/tests/__init__.py +++ b/tests/test_pyros_msgs/typecheck/__init__.py @@ -3,16 +3,6 @@ import pytest import sys -# try: -# import pyros_msgs -# import genpy -# except ImportError: -# import pyros_setup -# pyros_setup.configurable_import().configure().activate() -# import pyros_msgs -# import genpy - - import six from pyros_msgs.typecheck.typechecker import ( diff --git a/pyros_msgs/typecheck/tests/test_basic_ros_serialization.py b/tests/test_pyros_msgs/typecheck/test_basic_ros_serialization.py similarity index 75% rename from pyros_msgs/typecheck/tests/test_basic_ros_serialization.py rename to tests/test_pyros_msgs/typecheck/test_basic_ros_serialization.py index e67d4e5..4372c19 100644 --- a/pyros_msgs/typecheck/tests/test_basic_ros_serialization.py +++ b/tests/test_pyros_msgs/typecheck/test_basic_ros_serialization.py @@ -1,22 +1,20 @@ from __future__ import absolute_import, division, print_function -import numpy -import pytest -from StringIO import StringIO - import os import sys +import numpy +from six import BytesIO +import site +# This is used for message definitions, not for python code +site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'rosdeps')) -# generating all and accessing the required message class. -from pyros_msgs.typecheck.tests import msg_generate +import rosimport +rosimport.activate() -try: - # This should succeed if the message class was already generated - import std_msgs.msg as std_msgs -except ImportError: # we should enter here if the message was not generated yet. - std_msgs, std_srvs = msg_generate.generate_std_msgs() +# This should succeed if the message class was already generated +import std_msgs.msg as std_msgs import genpy @@ -30,7 +28,7 @@ def test_typechecker_serialize_deserialize_float32_inverse(value): """""" # sending - buff = StringIO() + buff = BytesIO() value.serialize(buff) serialized = buff.getvalue() buff.close() @@ -51,7 +49,7 @@ def test_typechecker_serialize_deserialize_time_inverse(value): """""" # sending - buff = StringIO() + buff = BytesIO() value.serialize(buff) serialized = buff.getvalue() buff.close() diff --git a/tests/test_pyros_msgs/typecheck/test_ros_mappings.py b/tests/test_pyros_msgs/typecheck/test_ros_mappings.py new file mode 100644 index 0000000..64eb153 --- /dev/null +++ b/tests/test_pyros_msgs/typecheck/test_ros_mappings.py @@ -0,0 +1,160 @@ +from __future__ import absolute_import, division, print_function + +import os +import six +import sys +import numpy +import pytest +import collections +from six import BytesIO, StringIO + +import site +# This is used for message definitions, not for python code +site.addsitedir(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'rosdeps')) + +import rosimport +rosimport.activate() + +# This should succeed if the message class was already generated +import std_msgs.msg as std_msgs + +import genpy + +from pyros_msgs.typecheck.typechecker import ( + six_long, + maybe_list, + maybe_tuple, + Sanitizer, Accepter, Array, Any, MinMax, + TypeChecker, + TypeCheckerException, +) + +from pyros_msgs.typecheck.ros_mappings import typechecker_from_rosfield_type + + +from hypothesis import given, example, settings, Verbosity +import hypothesis.strategies as st + + +# The main point here is insuring that any sanitized type will safely serialize and deserialize +# And also that any type that doesnt safely serialize / deserialize will not pass the type checker + +rosmsg_slot_types = [ + ('bool', st.booleans()), + ('int', st.integers()), + ('float', st.floats()), + ('string', st.binary()), + ('time', st.builds(genpy.Time, secs=st.integers(min_value=0), nsecs=st.integers(min_value=0))), # ROS time + ('duration', st.builds(genpy.Duration, secs=st.integers(), nsecs=st.integers())), # ROS duration +] + +rosmsg_slot_arraytypes = [ + (s[0] + '[]', st.lists(elements=s[1])) + for s in rosmsg_slot_types +] + +# TODO : is there a way to generate messages on the fly to test all possible field combinations ? + +# For now We use a set of basic messages for testing +std_msgs_types_strat_ok = collections.OrderedDict([ + ('std_msgs/Bool', st.builds(std_msgs.Bool, data=st.booleans())), + ('std_msgs/Int8', st.builds(std_msgs.Int8, data=st.one_of(st.booleans(), st.integers(min_value=-128, max_value=127)))), # in python booleans are integers + ('std_msgs/Int16', st.builds(std_msgs.Int16, data=st.one_of(st.booleans(), st.integers(min_value=-32768, max_value=32767)))), + ('std_msgs/Int32', st.builds(std_msgs.Int32, data=st.one_of(st.booleans(), st.integers(min_value=-2147483648, max_value=2147483647)))), + ('std_msgs/Int64', st.builds(std_msgs.Int64, data=st.one_of(st.booleans(), st.integers(min_value=-six_long(9223372036854775808), max_value=six_long(9223372036854775807))))), + ('std_msgs/UInt8', st.builds(std_msgs.UInt8, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=255)))), + ('std_msgs/UInt16', st.builds(std_msgs.UInt16, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=65535)))), + ('std_msgs/UInt32', st.builds(std_msgs.UInt32, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=4294967295)))), + ('std_msgs/UInt64', st.builds(std_msgs.UInt64, data=st.one_of(st.booleans(), st.integers(min_value=0, max_value=six_long(18446744073709551615))))), + # TMP : seems we have some problems with float arithmetic between numpy and hypothesis... + #'std_msgs/Float32': st.builds(std_msgs.Float32, data=st.floats(min_value=-3.4028235e+38, max_value=3.4028235e+38)), + #'std_msgs/Float64': st.builds(std_msgs.Float64, data=st.floats(min_value=-1.7976931348623157e+308, max_value=1.7976931348623157e+308, )), + #'std_msgs/String': st.builds(std_msgs.String, data=st.one_of(st.binary(), st.text(alphabet=st.characters(max_codepoint=127)))), + ('std_msgs/String', st.builds(std_msgs.String, data=st.text(alphabet=st.characters(max_codepoint=127)))), # binary can break hypothesis reporting + # CAREFUL : we need to avoid having nsecs making our secs overflow after canonization from __init__ + ('std_msgs/Time', st.builds(std_msgs.Time, data=st.builds(genpy.Time, secs=st.integers(min_value=0, max_value=4294967295 -3), nsecs=st.integers(min_value=0, max_value=4294967295)))), + ('std_msgs/Duration', st.builds(std_msgs.Duration, data=st.builds(genpy.Duration, secs=st.integers(min_value=-2147483648 +1, max_value=2147483647 -1), nsecs=st.integers(min_value=-2147483648, max_value=2147483647)))), + # TODO : add more. we should test all. +]) + +std_msgs_types_strat_broken = collections.OrderedDict([ + # everything else... + ('std_msgs/Bool', st.builds(std_msgs.Bool, data=st.one_of(st.integers(), st.floats()))), + ('std_msgs/Int8', st.builds(std_msgs.Int8, data=st.one_of(st.floats(), st.integers(min_value=127+1), st.integers(max_value=-128-1)))), + ('std_msgs/Int16', st.builds(std_msgs.Int16, data=st.one_of(st.floats(), st.integers(min_value=32767+1), st.integers(max_value=-32768-1)))), + ('std_msgs/Int32', st.builds(std_msgs.Int32, data=st.one_of(st.floats(), st.integers(min_value=2147483647+1), st.integers(max_value=-2147483648-1)))), + ('std_msgs/Int64', st.builds(std_msgs.Int64, data=st.one_of(st.floats(), st.integers(min_value=six_long(9223372036854775807+1)), st.integers(max_value=six_long(-9223372036854775808-1))))), + ('std_msgs/UInt8', st.builds(std_msgs.UInt8, data=st.one_of(st.floats(), st.integers(min_value=255+1), st.integers(max_value=-1)))), + ('std_msgs/UInt16', st.builds(std_msgs.UInt16, data=st.one_of(st.floats(), st.integers(min_value=65535+1), st.integers(max_value=-1)))), + ('std_msgs/UInt32', st.builds(std_msgs.UInt32, data=st.one_of(st.floats(), st.integers(min_value=4294967295+1), st.integers(max_value=-1)))), + ('std_msgs/UInt64', st.builds(std_msgs.UInt64, data=st.one_of(st.floats(), st.integers(min_value=six_long(18446744073709551615+1)), st.integers(max_value=-1)))), + ('std_msgs/Float32', st.builds(std_msgs.Float32, data=st.one_of(st.booleans(), st.integers()))), # st.floats(max_value=-3.4028235e+38), st.floats(min_value=3.4028235e+38))), + ('std_msgs/Float64', st.builds(std_msgs.Float64, data=st.one_of(st.booleans(), st.integers()))), # st.floats(max_value=-1.7976931348623157e+308), st.floats(min_value=1.7976931348623157e+308))), + # TODO : add more. we should test all +]) + +pyros_msgs_types_strat_ok = { + # TODO +} + +pyros_msgs_types_strat_broken = { + +} + +# We need a composite strategy to link slot type and slot value +@st.composite +@settings(verbosity=Verbosity.verbose, timeout=1) +def msg_type_and_value(draw, msgs_type_st): + msg_type = draw(st.sampled_from(msgs_type_st)) + msg_value = draw(msgs_type_st.get(msg_type)) + return msg_type, msg_value + + +@given(msg_type_and_value(std_msgs_types_strat_ok)) +@settings(verbosity=Verbosity.verbose, timeout=1) +def test_typechecker_serialize_deserialize_inverse(msg_type_and_ok_value): + """""" + tc = typechecker_from_rosfield_type(msg_type_and_ok_value[0]) + value = tc(msg_type_and_ok_value[1]) + + # sending + buff = BytesIO() + value.serialize(buff) + serialized = buff.getvalue() + buff.close() + + # receiving + received = tc() + received.deserialize(serialized) + + if isinstance(value, std_msgs.Float64): # for floats, this is only true relative to some epsilon... + numpy.testing.assert_allclose(received.data, value.data) + elif isinstance(value, std_msgs.Float32): # for floats, this is only true relative to some epsilon... + numpy.testing.assert_allclose(received.data, value.data, rtol=1e-5) + else: + assert received == msg_type_and_ok_value[1] + + +@given(msg_type_and_value(std_msgs_types_strat_broken)) +@settings(verbosity=Verbosity.verbose, timeout=1) +def test_typechecker_typechecker_prevent_broken_values(msg_type_and_bad_value): + tc = typechecker_from_rosfield_type(msg_type_and_bad_value[0]) + + # assert we have a somehow broken value : + with pytest.raises(Exception) as excinfo: + value = tc(msg_type_and_bad_value[1]) + + # sending + buff = BytesIO() + value.serialize(buff) + serialized = buff.getvalue() + buff.close() + + # receiving + received = tc() + received.deserialized(serialized) + + # assert the type checker doesnt accept it + with pytest.raises(TypeCheckerException) as excinfo: + _ = tc(msg_type_and_bad_value[1]) + assert 'is not accepted' in excinfo.value.message diff --git a/pyros_msgs/typecheck/tests/test_typechecker_arrays.py b/tests/test_pyros_msgs/typecheck/test_typechecker_arrays.py similarity index 89% rename from pyros_msgs/typecheck/tests/test_typechecker_arrays.py rename to tests/test_pyros_msgs/typecheck/test_typechecker_arrays.py index 0dc9904..911719e 100644 --- a/pyros_msgs/typecheck/tests/test_typechecker_arrays.py +++ b/tests/test_pyros_msgs/typecheck/test_typechecker_arrays.py @@ -2,16 +2,6 @@ import pytest import sys - -# try: -# import pyros_msgs -# import genpy -# except ImportError: -# import pyros_setup -# pyros_setup.configurable_import().configure().activate() -# import pyros_msgs -# import genpy - import six from pyros_msgs.typecheck.typechecker import ( @@ -62,7 +52,7 @@ def test_boolarray_typechecker_breaks_on_bad_number_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: boolarray_type_checker(value) - assert "is not accepted by Array of Accepter from " in excinfo.value.message + assert "is not accepted by Array of Accepter " in excinfo.value.message @given(proper_list_strategy_selector(intarray_type_checker)) @@ -87,7 +77,7 @@ def test_intarray_typechecker_breaks_on_bad_number_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: intarray_type_checker(value) - assert "is not accepted by Array of MinMax [-42..13835058055282163712] of Any of set" in excinfo.value.message + assert "is not accepted by Array of MinMax [-42..13835058055282163712] of Any of " in excinfo.value.message @given(proper_list_strategy_selector(floatarray_type_checker)) @@ -112,7 +102,7 @@ def test_floatarray_typechecker_breaks_on_bad_number_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: floatarray_type_checker(value) - assert "is not accepted by Array of MinMax [-42.0..1.38350580553e+19] of Accepter from " in excinfo.value.message + assert "is not accepted by Array of MinMax " in excinfo.value.message @given(proper_list_strategy_selector(stringarray_type_checker)) @@ -137,4 +127,4 @@ def test_stringarray_typechecker_breaks_on_bad_number_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: stringarray_type_checker(value) - assert "is not accepted by Array of Any of set" in excinfo.value.message + assert "is not accepted by Array of Any of " in excinfo.value.message diff --git a/pyros_msgs/typecheck/tests/test_typechecker_basic.py b/tests/test_pyros_msgs/typecheck/test_typechecker_basic.py similarity index 87% rename from pyros_msgs/typecheck/tests/test_typechecker_basic.py rename to tests/test_pyros_msgs/typecheck/test_typechecker_basic.py index 427093c..6ad24af 100644 --- a/pyros_msgs/typecheck/tests/test_typechecker_basic.py +++ b/tests/test_pyros_msgs/typecheck/test_typechecker_basic.py @@ -1,14 +1,5 @@ from __future__ import absolute_import, division, print_function, unicode_literals -# try: -# import pyros_msgs -# import genpy -# except ImportError: -# import pyros_setup -# pyros_setup.configurable_import().configure().activate() -# import pyros_msgs -# import genpy - import six from pyros_msgs.typecheck.typechecker import ( @@ -55,7 +46,7 @@ def test_breaks_on_bad_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: bool_type_checker(value) - assert "is not accepted by Accepter from " in excinfo.value.message + assert "is not accepted by Accepter " in excinfo.value.message @given(proper_basic_strategy_selector(integer_type_checker)) # where we learn that in python booleans are ints... @@ -76,7 +67,7 @@ def test_typechecker_with_any_accepter_breaks_on_bad_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: integer_type_checker(value) - assert "is not accepted by Any of set" in excinfo.value.message + assert "is not accepted by Any of " in excinfo.value.message @given(proper_basic_strategy_selector(integer_type_checker_min_max)) @@ -97,7 +88,7 @@ def test_typechecker_with_minmax_accepter_breaks_on_bad_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: integer_type_checker_min_max(value) - assert "is not accepted by MinMax [-42..13835058055282163712] of Any of set" in excinfo.value.message + assert "is not accepted by MinMax [-42..13835058055282163712] of Any of " in excinfo.value.message @given(proper_basic_strategy_selector(float_type_checker)) # where we learn that in python @@ -120,7 +111,7 @@ def test_typechecker_breaks_on_bad_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: float_type_checker(value) - assert "is not accepted by Accepter from " in excinfo.value.message + assert "is not accepted by Accepter " in excinfo.value.message @given(proper_basic_strategy_selector(float_type_checker_min_max)) @@ -141,7 +132,7 @@ def test_typechecker_with_minmax_accepter_breaks_on_bad_nonfloat_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: float_type_checker_min_max(value) - assert "is not accepted by MinMax [-42.0..1.38350580553e+19] of Accepter from " in excinfo.value.message + assert "is not accepted by MinMax " in excinfo.value.message # Separate test because of float arithemtics... @@ -154,7 +145,7 @@ def test_typechecker_with_minmax_accepter_breaks_on_bad_float_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: float_type_checker_min_max(value) - assert "is not accepted by MinMax [-42.0..1.38350580553e+19] of Accepter from " in excinfo.value.message + assert "is not accepted by MinMax " in excinfo.value.message @given(proper_basic_strategy_selector(string_type_checker)) @@ -175,7 +166,7 @@ def test_typechecker_breaks_on_bad_number_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: string_type_checker(value) - assert "is not accepted by Any of set" in excinfo.value.message + assert "is not accepted by Any of " in excinfo.value.message # Separate test for unicode fanciness @@ -187,4 +178,4 @@ def test_typechecker_breaks_on_bad_text_values(value): """ with pytest.raises(TypeCheckerException) as excinfo: string_type_checker(value) - assert "is not accepted by Any of set" in excinfo.value.message + assert "is not accepted by Any of " in excinfo.value.message diff --git a/pyros_msgs/typecheck/tests/test_typechecker_nested.py b/tests/test_pyros_msgs/typecheck/test_typechecker_nested.py similarity index 96% rename from pyros_msgs/typecheck/tests/test_typechecker_nested.py rename to tests/test_pyros_msgs/typecheck/test_typechecker_nested.py index ba9a243..115eebc 100644 --- a/pyros_msgs/typecheck/tests/test_typechecker_nested.py +++ b/tests/test_pyros_msgs/typecheck/test_typechecker_nested.py @@ -1,16 +1,5 @@ from __future__ import absolute_import, division, print_function, unicode_literals -import sys - -# try: -# import pyros_msgs -# import genpy -# except ImportError: -# import pyros_setup -# pyros_setup.configurable_import().configure().activate() -# import pyros_msgs -# import genpy - import six from pyros_msgs.typecheck.typechecker import ( diff --git a/tox.ini b/tox.ini index ac53a56..61034c5 100644 --- a/tox.ini +++ b/tox.ini @@ -1,73 +1,74 @@ -# content of: tox.ini , put in same dir as setup.py +# tox.ini , put in same dir as setup.py [tox] -envlist = py27 -# ros distro does not matter in pure python tests -# envlist = py27-{indigo,jade,kinetic} -#, py34 + +envlist = + + # based on ros distro with ubuntu debs base + py27-debs_{indigo,kinetic,lunar}, + + # based on ros distro with python2 base + py27-py_{indigo,kinetic,lunar,latest}, + + py34-debs_indigo, + py35-debs_kinetic, + + # based on ros distro with ubuntu debs base + py36-debs_{indigo,kinetic,lunar}, + + # based on ros distro with python3 base + py36-py_{indigo,kinetic,lunar,latest} #, pypy #, pypy3 -# we skip sdist since currently our sdist doesnt generate messages -# we will manually setup the package via develop in [testenv] -skipsdist=True - [travis] -2.7 = py27 - -#3.4 = py34 +python = + # we test every current ROS1 distro on python 2.7 (official python support for ROS1) + 2.7 : py27 + # specific old python supported natively on ubuntu/ROS LTS distro + 3.4 : py34 + 3.5 : py35 + # we test every current ROS1 distro on latest python (to ensure support from latest python) + 3.6 : py36 # not tested yet #pypy = pypy #pypy3 = pypy3 -# Note : We can depend on travis matrix if needed -;[travis:env] -;DJANGO = -; 1.7: django17 -; 1.8: django18, docs +# We depend on travis matrix +[travis:env] +ROS_DISTRO = + kinetic: debs_kinetic, py_kinetic + indigo: debs_indigo, py_indigo + lunar: debs_lunar, py_lunar + latest: py_latest [testenv] + +# Dependencies matching the version in each ROS distro deps = # TODO : check why / how install_requires are installed or not in tox environments... - pytest + debs_indigo: -rrequirements/indigo/debs_in_venv.txt + debs_kinetic: -rrequirements/kinetic/debs_in_venv.txt + debs_lunar: -rrequirements/lunar/debs_in_venv.txt -# to always force recreation and avoid unexpected side effects -recreate=True + py_indigo: -rrequirements/python/indigo.txt + py_indigo: -rrequirements/python/tests.txt -# to allow access to ROS packages -# sitepackages=True -# We do not want any access to system (same as basic travis python testing) + py_kinetic: -rrequirements/python/kinetic.txt + py_kinetic: -rrequirements/python/tests.txt + py_lunar: -rrequirements/python/lunar.txt + py_lunar: -rrequirements/python/tests.txt -# we need to set our ROS distro in the pythonpath for our code to rely on ROS -#TODO : not havnig this breaks pyros-setup which tries to create its config file in -# pyros_setup.configurable_import().configure().activate() -#/usr/local/lib/python2.7/dist-packages/pyros_setup/__init__.py:92: in configure -# """) -#/usr/local/lib/python2.7/dist-packages/pyros_config/confighandler.py:74: in configure_file -# os.makedirs(os.path.dirname(cfg_filename)) -#.tox/py27-indigo/lib/python2.7/os.py:157: in makedirs -# mkdir(name, mode) -#E OSError: [Errno 13] Permission denied: '/usr/local/lib/python2.7/dist-packages/instance' + py_latest: -rrequirements/python/latest.txt + py_latest: -rrequirements/python/tests.txt -setenv= - # TODO : get rid of this by removing all dependencies to ROS on system... - indigo: PYTHONPATH=/opt/ros/indigo/lib/python2.7/dist-packages - jade: PYTHONPATH=/opt/ros/jade/lib/python2.7/dist-packages - kinetic: PYTHONPATH=/opt/ros/kinetic/lib/python2.7/dist-packages +# to always force recreation and avoid unexpected side effects +recreate=True commands= - # First we need to generate our messages (just like ROS catkin build flow would) - python setup.py generatemsg - python setup.py develop - # we use the develop way documented in http://tox.readthedocs.io/en/latest/example/general.html, - # to be able to use generated messages from setup.py, as well as ros-site. - # we want to make sure python finds the installed package in tox env # and doesn't confuse with pyc generated during dev (which happens if we use self test feature here) - py.test --pyargs pyros_msgs/importer/tests {posargs} - py.test --pyargs pyros_msgs/typecheck/tests {posargs} - py.test --pyargs pyros_msgs/opt_as_array/tests {posargs} - py.test --pyargs pyros_msgs/opt_as_nested/tests {posargs} + py.test --pyargs tests {posargs} # Note : -s here might break your terminal...