From 250a462f03e9c54f88c99b402c3d7f2a300a7b4b Mon Sep 17 00:00:00 2001 From: Kevin Wurster Date: Fri, 18 Sep 2015 16:36:20 -0400 Subject: [PATCH 1/5] Operational driver. --- gpsdio_nmea_driver/__init__.py | 32 ++++++++++++++ gpsdio_nmea_driver/core.py | 76 ++++++++++++++++++++++++++++++++++ tests/conftest.py | 23 ++++++++++ tests/test_core.py | 49 ++++++++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 gpsdio_nmea_driver/__init__.py create mode 100644 gpsdio_nmea_driver/core.py create mode 100644 tests/conftest.py create mode 100644 tests/test_core.py diff --git a/gpsdio_nmea_driver/__init__.py b/gpsdio_nmea_driver/__init__.py new file mode 100644 index 0000000..4fd35c6 --- /dev/null +++ b/gpsdio_nmea_driver/__init__.py @@ -0,0 +1,32 @@ +""" +A gpsdio driver for parsing NMEA sentences directly into GPSd messages. +""" + +import logging + + +logger = logging.getLogger('gpsdio-nmea') + + +__version__ = '0.1' +__author__ = 'Kevin Wurster' +__email__ = 'kevin@skytruth.org' +__source__ = 'https://github.com/SkyTruth/gpsdio-nmea-driver' +__license__ = """ +Copyright 2014-2015 SkyTruth + +Authors: +Kevin Wurster + +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/gpsdio_nmea_driver/core.py b/gpsdio_nmea_driver/core.py new file mode 100644 index 0000000..4cc8840 --- /dev/null +++ b/gpsdio_nmea_driver/core.py @@ -0,0 +1,76 @@ +""" +gpsdio NMEA driver +""" + + +import codecs + +import ais.compatibility.gpsd +import ais.stream +from gpsdio.base import BaseDriver +import six + + +def parse_ais_stream(msg_stream): + + """ + Parse a stream of NMEA sentences, convert to GPSd, and yield. + Parameters + ---------- + msg_stream : iter + An iterable producing one NMEA sentence per iteration. + Yields + ------ + dict + """ + + args = { + 'ignore_tagblock_station': True, + 'allow_unknown': True, + 'allow_missing_timestamps': True + } + + gpsd_mangle = ais.compatibility.gpsd.Mangler(copy_tagblock_timestamp=True) + for msg in map(gpsd_mangle, ais.stream.decode(msg_stream, **args)): + yield msg + + +class _NMEAParser(object): + + """ + File-like object for interacting with the parser. + """ + + def __init__(self, f): + if isinstance(f, six.string_types): + self._f = codecs.open(f, encoding='utf-8') + else: + self._f = f + self._parser = parse_ais_stream(self._f) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + def __iter__(self): + return self + + def __next__(self): + return next(self._parser) + + next = __next__ + + def __getattr__(self, item): + return getattr(self._f, item) + + +class NMEA(BaseDriver): + + io_modes = 'r', + extensions = 'nmea', + driver_name = 'NMEA' + + def open(self, name, mode='r'): + return _NMEAParser(name) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..5a609df --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,23 @@ +""" +Fixtures +""" + + +import os + +import pytest + + +@pytest.fixture(scope='function') +def types_nmea_path(): + return os.path.join('tests', 'data', 'types.nmea') + + +@pytest.fixture(scope='function') +def types_json_path(): + return os.path.join('tests', 'data', 'types.json') + + +@pytest.fixture(scope='function') +def types_nmea_gz_path(): + return os.path.join('tests', 'data', 'types.nmea.gz') diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..d084bbf --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,49 @@ +""" +Unittests for gpsdio_nmea_driver.core +""" + + +import gpsdio +import gpsdio.drivers +from gpsdio_nmea_driver import core + + +def validate_stream(stream): + for msg in stream: + assert 'mmsi' in msg and 'type' in msg + +def test_registered(): + assert 'NMEA' in gpsdio.drivers.registered_drivers + assert gpsdio.drivers.registered_drivers['NMEA'] is core.NMEA + + +def test_read(types_nmea_path): + with gpsdio.open(types_nmea_path) as src: + validate_stream(src) + + +def test_read_compressed(types_nmea_gz_path): + with gpsdio.open(types_nmea_gz_path) as src: + idx = 0 + for idx, msg in enumerate(src): + assert 'mmsi' in msg and 'type' in msg + assert idx > 0 + + +def test_read_both(types_nmea_path, types_nmea_gz_path): + with gpsdio.open(types_nmea_path) as dsrc, gpsdio.open(types_nmea_gz_path) as csrc: + for idx, (d, c) in enumerate(zip(dsrc, csrc)): + assert d == c + assert 'mmsi' in d and 'type' in d + assert 'mmsi' in c and 'type' in c + assert idx > 0 + + +def test_driver_directly(types_nmea_path): + with core.NMEA(types_nmea_path) as src: + validate_stream(src) + + +def test_file_obj_directly_str(types_nmea_path): + with core._NMEAParser(types_nmea_path) as src: + validate_stream(src) From e66e3fb8dbca41dae34c6aff23f5f41a2e630709 Mon Sep 17 00:00:00 2001 From: Kevin Wurster Date: Fri, 18 Sep 2015 16:37:51 -0400 Subject: [PATCH 2/5] Build on Travis --- .travis.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a5f69e2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +language: python + +python: + - 2.7 + - 3.3 + - 3.4 + +install: + - pip install -e .\[dev\] + - pip install git+git://github.com/SkyTruth/gpsdio.git --upgrade + - pip install git+git://github.com/schwehr/libais.git --upgrade + +script: + - py.test tests --cov gpsdio_nmea_driver --cov-report term-missing + +after_success: + - coveralls + +notifications: + flowdock: + secure: sSDUIIuldA7tWGqgexf+nmeC/+Htm97bwcPaZOHv2+/c3jKsxUoMMnwkcT3ChqPTEvqs2pGoAYuSDDOWXYUZTpETmZyfECmSqPdfD9nePdqDCum8Q909jlttJWR4jmMuhToNifXdwIkPjnspnLrnxCj92/9/Nx/9uSo/+JfPfE0= From de509e7dc134718b0affaac5b9c84e8847cad028 Mon Sep 17 00:00:00 2001 From: Kevin Wurster Date: Fri, 18 Sep 2015 16:37:57 -0400 Subject: [PATCH 3/5] Packaging and docs. --- CHANGES.md | 7 +++++ LICENSE.txt | 17 +++++++++++ MANIFEST.in | 5 +++ README.rst | 59 ++++++++++++++++++++++++++++++++++++ setup.py | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+) create mode 100644 CHANGES.md create mode 100644 LICENSE.txt create mode 100644 MANIFEST.in create mode 100644 README.rst create mode 100644 setup.py diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..12d23f4 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,7 @@ +Changes +======= + +0.1 (2015-09-18) +---------------- + +- Initial release. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..685c886 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,17 @@ +Copyright 2015 SkyTruth + +Authors: + +Kevin Wurster + +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/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..faa9fa0 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include CHANGES.md +include LICENSE.txt +include MANIFEST.in +include README.rst +include setup.py diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..f3522ad --- /dev/null +++ b/README.rst @@ -0,0 +1,59 @@ +================== +gpsdio-nmea-driver +================== + +An **experimental** gpsdio driver for parsing NMEA sentences directly into GPSd messages with `libais `_. + +.. image:: https://travis-ci.org/SkyTruth/gpsdio-nmea-driver.svg?branch=master + :target: https://travis-ci.org/SkyTruth/gpsdio-nmea-driver + +.. image:: https://coveralls.io/repos/SkyTruth/gpsdio-nmea-driver/badge.svg?branch=master + :target: https://coveralls.io/r/SkyTruth/gpsdio-nmea-driver + + +Installation +------------ + +**NOTE:** This driver is experimental and requires an unreleased version of ``libais`` and ``gpsdio``. + +With pip: + +.. code-block:: console + + $ pip install git+git://github.com/schwehr/libais.git --upgrade + $ pip install gpsdio-nmea-driver + +From source: + +.. code-block:: console + + $ git clone https://github.com/SkyTruth/gpsdio + $ cd gpsdio-nmea-driver + $ python setup.py install + $ pip install git+git://github.com/schwehr/libais.git --upgrade + $ pip install git+git://github.com/schwehr/libais.git --upgrade + + +Developing +---------- + +.. code-block:: console + + $ git clone https://github.com/SkyTruth/gpsdio-nmea-driver.git + $ cd gpsdio-nmea-driver + $ virtualenv venv + $ source venv/bin/activate + $ pip install -e .\[dev\] + $ py.test tests --cov gpsdio-nmea-driver --cov-report term-missing + + +Changelog +--------- + +See ``CHANGES.md`` + + +License +------- + +See ``LICENSE.txt`` diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..9d5f649 --- /dev/null +++ b/setup.py @@ -0,0 +1,87 @@ +#!/usr/bin/python + + +""" +Setup script for gpsdio-nmea-driver +""" + + +import os +import sys + +from setuptools.command.test import test as TestCommand +from setuptools import find_packages +from setuptools import setup + + +# https://pytest.org/latest/goodpractises.html +class PyTest(TestCommand): + user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")] + + def initialize_options(self): + TestCommand.initialize_options(self) + self.pytest_args = ['tests'] + + def finalize_options(self): + TestCommand.finalize_options(self) + self.test_args = [] + self.test_suite = True + + def run_tests(self): + # Import here, because outside the eggs aren't loaded + import pytest + errno = pytest.main(self.pytest_args) + sys.exit(errno) + + +with open('README.rst') as f: + readme = f.read().strip() + + +version = None +author = None +email = None +source = None +with open(os.path.join('gpsdio_nmea_driver', '__init__.py')) as f: + for line in f: + if line.strip().startswith('__version__'): + version = line.split('=')[1].strip().replace('"', '').replace("'", '') + elif line.strip().startswith('__author__'): + author = line.split('=')[1].strip().replace('"', '').replace("'", '') + elif line.strip().startswith('__email__'): + email = line.split('=')[1].strip().replace('"', '').replace("'", '') + elif line.strip().startswith('__source__'): + source = line.split('=')[1].strip().replace('"', '').replace("'", '') + elif None not in (version, author, email, source): + break + + +setup( + author=author, + author_email=email, + cmdclass={'test': PyTest}, + description="A gpsdio driver for parsing NMEA sentences directly into GPSd messages.", + entry_points=''' + [gpsdio.driver_plugins] + NMEA=gpsdio_nmea_driver.core:NMEA + ''', + extras_require={ + 'dev': [ + 'pytest', + 'pytest-cov', + ] + }, + install_requires=[ + 'libais>=0.15', + 'gpsdio>=0.0.7', + 'six' + ], + license='Apache 2.0', + long_description=readme, + include_package_data=True, + keywords="gpsdio NMEA driver AIS libais", + name="gpsdio-nmea-driver", + packages=find_packages(exclude=['test']), + url=source, + version=version, +) From ebe090e5decb5bf6c64fea576c672f62e1cc3c6e Mon Sep 17 00:00:00 2001 From: Kevin Wurster Date: Fri, 18 Sep 2015 16:40:22 -0400 Subject: [PATCH 4/5] libais build weirdness. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a5f69e2..690290f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,9 @@ python: - 3.4 install: + - sudo apt-get install -qq gcc-4.8 g++-4.8 - pip install -e .\[dev\] - - pip install git+git://github.com/SkyTruth/gpsdio.git --upgrade + - CC=g++-4.8 pip install git+git://github.com/SkyTruth/gpsdio.git --upgrade - pip install git+git://github.com/schwehr/libais.git --upgrade script: From 15ec8069c2fd19f31d2e0a149708d355f24c17e8 Mon Sep 17 00:00:00 2001 From: Kevin Wurster Date: Fri, 18 Sep 2015 16:45:06 -0400 Subject: [PATCH 5/5] Build the right way on all libais installs. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 690290f..6e5160b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,9 @@ python: install: - sudo apt-get install -qq gcc-4.8 g++-4.8 - - pip install -e .\[dev\] - - CC=g++-4.8 pip install git+git://github.com/SkyTruth/gpsdio.git --upgrade - - pip install git+git://github.com/schwehr/libais.git --upgrade + - CC=g++-4.8 pip install -e .\[dev\] + - CC=g++-4.8 pip install git+git://github.com/schwehr/libais.git --upgrade + - pip install git+git://github.com/SkyTruth/gpsdio.git --upgrade script: - py.test tests --cov gpsdio_nmea_driver --cov-report term-missing