diff --git a/tracetools_read/.gitignore b/tracetools_read/.gitignore
new file mode 100644
index 0000000..eef29c1
--- /dev/null
+++ b/tracetools_read/.gitignore
@@ -0,0 +1,3 @@
+*~
+*.pyc
+
diff --git a/tracetools_read/package.xml b/tracetools_read/package.xml
new file mode 100644
index 0000000..eaf6c87
--- /dev/null
+++ b/tracetools_read/package.xml
@@ -0,0 +1,22 @@
+
+
+
+ tracetools_read
+ 0.0.1
+ Tools for reading traces
+ Christophe Bedard
+ Ingo Lütkebohle
+ Apache 2.0
+ Christophe Bedard
+
+ python3-babeltrace
+
+ ament_copyright
+ ament_flake8
+ ament_pep257
+ python3-pytest
+
+
+ ament_python
+
+
diff --git a/tracetools_read/setup.cfg b/tracetools_read/setup.cfg
new file mode 100644
index 0000000..955cbe6
--- /dev/null
+++ b/tracetools_read/setup.cfg
@@ -0,0 +1,4 @@
+[develop]
+script-dir=$base/lib/tracetools_read
+[install]
+install-scripts=$base/lib/tracetools_read
diff --git a/tracetools_read/setup.py b/tracetools_read/setup.py
new file mode 100644
index 0000000..25b8a77
--- /dev/null
+++ b/tracetools_read/setup.py
@@ -0,0 +1,29 @@
+from setuptools import find_packages
+from setuptools import setup
+
+package_name = 'tracetools_read'
+
+setup(
+ name=package_name,
+ version='0.0.1',
+ packages=find_packages(exclude=['test']),
+ data_files=[
+ ('share/' + package_name, ['package.xml']),
+ ],
+ install_requires=['setuptools'],
+ maintainer=(
+ 'Christophe Bedard, '
+ 'Ingo Lütkebohle'
+ ),
+ maintainer_email=(
+ 'fixed-term.christophe.bourquebedard@de.bosch.com, '
+ 'ingo.luetkebohle@de.bosch.com'
+ ),
+ author='Christophe Bedard',
+ author_email='fixed-term.christophe.bourquebedard@de.bosch.com',
+ # url='',
+ keywords=['ROS'],
+ description='Tools for reading trace',
+ license='Apache 2.0',
+ tests_require=['pytest'],
+)
diff --git a/tracetools_read/test/test_copyright.py b/tracetools_read/test/test_copyright.py
new file mode 100644
index 0000000..cf0fae3
--- /dev/null
+++ b/tracetools_read/test/test_copyright.py
@@ -0,0 +1,23 @@
+# Copyright 2017 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ament_copyright.main import main
+import pytest
+
+
+@pytest.mark.copyright
+@pytest.mark.linter
+def test_copyright():
+ rc = main(argv=['.', 'test'])
+ assert rc == 0, 'Found errors'
diff --git a/tracetools_read/test/test_flake8.py b/tracetools_read/test/test_flake8.py
new file mode 100644
index 0000000..eff8299
--- /dev/null
+++ b/tracetools_read/test/test_flake8.py
@@ -0,0 +1,23 @@
+# Copyright 2017 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ament_flake8.main import main
+import pytest
+
+
+@pytest.mark.flake8
+@pytest.mark.linter
+def test_flake8():
+ rc = main(argv=[])
+ assert rc == 0, 'Found errors'
diff --git a/tracetools_read/test/test_pep257.py b/tracetools_read/test/test_pep257.py
new file mode 100644
index 0000000..3aeb4d3
--- /dev/null
+++ b/tracetools_read/test/test_pep257.py
@@ -0,0 +1,23 @@
+# Copyright 2015 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ament_pep257.main import main
+import pytest
+
+
+@pytest.mark.linter
+@pytest.mark.pep257
+def test_pep257():
+ rc = main(argv=[])
+ assert rc == 0, 'Found code style errors / warnings'
diff --git a/tracetools_read/tracetools_read/__init__.py b/tracetools_read/tracetools_read/__init__.py
new file mode 100644
index 0000000..4b18865
--- /dev/null
+++ b/tracetools_read/tracetools_read/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2019 Robert Bosch GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tracetools_read/tracetools_read/utils.py b/tracetools_read/tracetools_read/utils.py
new file mode 100644
index 0000000..5c0b839
--- /dev/null
+++ b/tracetools_read/tracetools_read/utils.py
@@ -0,0 +1,101 @@
+# Copyright 2019 Robert Bosch GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module with functions for reading traces."""
+
+from typing import Any
+from typing import Dict
+from typing import Iterable
+from typing import List
+
+import babeltrace
+
+
+DictEvent = Dict[str, Any]
+
+
+def _get_trace_ctf_events(trace_directory: str) -> Iterable[babeltrace.babeltrace.Event]:
+ """
+ Get the events of a trace.
+
+ :param trace_directory: the path to the main/top trace directory
+ :return: events iterable
+ """
+ tc = babeltrace.TraceCollection()
+ tc.add_traces_recursive(trace_directory, 'ctf')
+ return tc.events
+
+
+def get_trace_events(trace_directory: str) -> List[DictEvent]:
+ """
+ Get the events of a trace.
+
+ :param trace_directory: the path to the main/top trace directory
+ :return: events
+ """
+ return [event_to_dict(event) for event in _get_trace_ctf_events(trace_directory)]
+
+
+# List of ignored CTF fields
+_IGNORED_FIELDS = [
+ 'content_size',
+ 'cpu_id',
+ 'events_discarded',
+ 'id',
+ 'packet_size',
+ 'packet_seq_num',
+ 'stream_id',
+ 'stream_instance_id',
+ 'timestamp_end',
+ 'timestamp_begin',
+ 'magic',
+ 'uuid',
+ 'v',
+]
+_DISCARD = 'events_discarded'
+
+
+def event_to_dict(event: babeltrace.babeltrace.Event) -> DictEvent:
+ """
+ Convert name, timestamp, and all other keys except those in IGNORED_FIELDS into a dictionary.
+
+ :param event: the event to convert
+ :return: the event as a dictionary
+ """
+ d = {'_name': event.name, '_timestamp': event.timestamp}
+ if hasattr(event, _DISCARD) and event[_DISCARD] > 0:
+ print(event[_DISCARD])
+ for key in [key for key in event.keys() if key not in _IGNORED_FIELDS]:
+ d[key] = event[key]
+ return d
+
+
+def get_field(event: DictEvent, field_name: str, default=None, raise_if_not_found=True) -> Any:
+ field_value = event.get(field_name, default)
+ # If enabled, raise exception as soon as possible to avoid headaches
+ if raise_if_not_found and field_value is None:
+ raise AttributeError(f'event field "{field_name}" not found!')
+ return field_value
+
+
+def get_event_name(event: DictEvent) -> str:
+ return event['_name']
+
+
+def get_event_timestamp(event: DictEvent) -> int:
+ return event['_timestamp']
+
+
+def get_procname(event: DictEvent) -> str:
+ return event['procname']
diff --git a/tracetools_test/package.xml b/tracetools_test/package.xml
index 4228906..abb7cc7 100644
--- a/tracetools_test/package.xml
+++ b/tracetools_test/package.xml
@@ -27,6 +27,7 @@
python3-pytest
tracetools
tracetools_trace
+ tracetools_read
ament_cmake
diff --git a/tracetools_test/tracetools_test/case.py b/tracetools_test/tracetools_test/case.py
index 3e53c49..b0c9219 100644
--- a/tracetools_test/tracetools_test/case.py
+++ b/tracetools_test/tracetools_test/case.py
@@ -20,14 +20,15 @@ from typing import List
from typing import Union
import unittest
+from tracetools_read.utils import DictEvent
+from tracetools_read.utils import get_event_name
+from tracetools_read.utils import get_event_timestamp
+from tracetools_read.utils import get_field
+from tracetools_read.utils import get_procname
+from tracetools_read.utils import get_trace_events
+
from .utils import cleanup_trace
-from .utils import DictEvent
-from .utils import get_event_name
from .utils import get_event_names
-from .utils import get_event_timestamp
-from .utils import get_field
-from .utils import get_procname
-from .utils import get_trace_events
from .utils import run_and_trace
diff --git a/tracetools_test/tracetools_test/utils.py b/tracetools_test/tracetools_test/utils.py
index de4dc11..c670820 100644
--- a/tracetools_test/tracetools_test/utils.py
+++ b/tracetools_test/tracetools_test/utils.py
@@ -17,16 +17,15 @@
import os
import shutil
import time
-from typing import Any
-from typing import Dict
from typing import List
from typing import Tuple
-import babeltrace
from launch import LaunchDescription
from launch import LaunchService
from launch_ros import get_default_launch_description
import launch_ros.actions
+from tracetools_read.utils import DictEvent
+from tracetools_read.utils import get_event_name
from tracetools_trace.tools import lttng
@@ -82,81 +81,11 @@ def cleanup_trace(full_path: str) -> None:
shutil.rmtree(full_path)
-DictEvent = Dict[str, Any]
-
-
-def get_trace_events(trace_directory: str) -> List[DictEvent]:
- """
- Get the events of a trace.
-
- :param trace_directory: the path to the main/top trace directory
- :return: events
- """
- tc = babeltrace.TraceCollection()
- tc.add_traces_recursive(trace_directory, 'ctf')
-
- return [_event_to_dict(event) for event in tc.events]
-
-
-# List of ignored CTF fields
-_IGNORED_FIELDS = [
- 'content_size',
- 'cpu_id',
- 'events_discarded',
- 'id',
- 'packet_size',
- 'packet_seq_num',
- 'stream_id',
- 'stream_instance_id',
- 'timestamp_end',
- 'timestamp_begin',
- 'magic',
- 'uuid',
- 'v',
-]
-_DISCARD = 'events_discarded'
-
-
-def _event_to_dict(event: babeltrace.babeltrace.Event) -> DictEvent:
- """
- Convert name, timestamp, and all other keys except those in IGNORED_FIELDS into a dictionary.
-
- :param event: the event to convert
- :return: the event as a dictionary
- """
- d = {'_name': event.name, '_timestamp': event.timestamp}
- if hasattr(event, _DISCARD) and event[_DISCARD] > 0:
- print(event[_DISCARD])
- for key in [key for key in event.keys() if key not in _IGNORED_FIELDS]:
- d[key] = event[key]
- return d
-
-
def get_event_names(events: List[DictEvent]) -> List[str]:
"""
- Get a list of names of the events in the trace.
+ Get a list of events names from a list of events.
:param events: the events of the trace
:return: the list of event names
"""
return [get_event_name(e) for e in events]
-
-
-def get_field(event: DictEvent, field_name: str, default=None, raise_if_not_found=True) -> Any:
- field_value = event.get(field_name, default)
- # If enabled, raise exception as soon as possible to avoid headaches
- if raise_if_not_found and field_value is None:
- raise AttributeError(f'event field "{field_name}" not found!')
- return field_value
-
-
-def get_event_name(event: DictEvent) -> str:
- return event['_name']
-
-
-def get_event_timestamp(event: DictEvent) -> int:
- return event['_timestamp']
-
-
-def get_procname(event: DictEvent) -> str:
- return event['procname']