[Git][debian-gis-team/trollsift][upstream] New upstream version 0.3.5
Antonio Valentino
gitlab at salsa.debian.org
Wed Feb 17 07:31:08 GMT 2021
Antonio Valentino pushed to branch upstream at Debian GIS Project / trollsift
Commits:
3105b9f3 by Antonio Valentino at 2021-02-17T06:31:22+00:00
New upstream version 0.3.5
- - - - -
18 changed files:
- + .github/workflows/ci.yaml
- + .github/workflows/deploy-sdist.yaml
- â .travis.yml
- AUTHORS.md
- CHANGELOG.md
- â appveyor.yml
- doc/source/installation.rst
- doc/source/usage.rst
- setup.py
- trollsift/parser.py
- trollsift/tests/__init__.py
- trollsift/tests/integrationtests/__init__.py
- trollsift/tests/integrationtests/test_parser.py
- trollsift/tests/regressiontests/__init__.py
- trollsift/tests/regressiontests/test_parser.py
- trollsift/tests/unittests/__init__.py
- trollsift/tests/unittests/test_parser.py
- trollsift/version.py
Changes:
=====================================
.github/workflows/ci.yaml
=====================================
@@ -0,0 +1,46 @@
+name: CI
+
+on: [push, pull_request]
+
+jobs:
+ test:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: true
+ matrix:
+ os: ["windows-latest", "ubuntu-latest", "macos-latest"]
+ python-version: ["3.7", "3.8", "3.9"]
+
+ env:
+ PYTHON_VERSION: ${{ matrix.python-version }}
+ OS: ${{ matrix.os }}
+ ACTIONS_ALLOW_UNSECURE_COMMANDS: true
+
+ steps:
+ - name: Checkout source
+ uses: actions/checkout at v2
+
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python at v2
+ with:
+ python-version: ${{ matrix.python-version }}
+
+ - name: Install dependencies
+ run: |
+ pip install -U codecov pytest pytest-cov
+
+ - name: Install trollsift
+ run: |
+ pip install --no-deps -e .
+
+ - name: Run unit tests
+ run: |
+ pytest --cov=trollsift trollsift/tests --cov-report=xml
+
+ - name: Upload unittest coverage to Codecov
+ uses: codecov/codecov-action at v1
+ with:
+ flags: unittests
+ file: ./coverage.xml
+ env_vars: OS,PYTHON_VERSION
+
=====================================
.github/workflows/deploy-sdist.yaml
=====================================
@@ -0,0 +1,25 @@
+name: Deploy sdist
+
+on:
+ release:
+ types:
+ - published
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout source
+ uses: actions/checkout at v2
+
+ - name: Create sdist
+ shell: bash -l {0}
+ run: python setup.py sdist
+
+ - name: Publish package to PyPI
+ if: github.event.action == 'published'
+ uses: pypa/gh-action-pypi-publish at v1.4.1
+ with:
+ user: __token__
+ password: ${{ secrets.pypi_password }}
\ No newline at end of file
=====================================
.travis.yml deleted
=====================================
@@ -1,42 +0,0 @@
-language: python
-env:
- global:
- - PYTHON_VERSION=$PYTHON_VERSION
- - NUMPY_VERSION=stable
- - MAIN_CMD='python setup.py'
- - CONDA_DEPENDENCIES='six coveralls coverage mock'
- - PIP_DEPENDENCIES=''
- - SETUP_XVFB=False
- - EVENT_TYPE='push pull_request'
- - SETUP_CMD='test'
- - CONDA_CHANNELS='conda-forge'
-matrix:
- include:
- - env: PYTHON_VERSION=2.7
- os: linux
- - env: PYTHON_VERSION=2.7
- os: osx
- language: generic
- - env: PYTHON_VERSION=3.6
- os: linux
- - env: PYTHON_VERSION=3.6
- os: osx
- language: generic
-install:
-#- git clone --depth 1 git://github.com/astropy/ci-helpers.git
-- git clone --depth 1 -b all-the-fixes git://github.com/djhoese/ci-helpers.git
-- source ci-helpers/travis/setup_conda.sh
-script:
-- coverage run --source=trollsift setup.py test
-after_success:
-- if [[ $PYTHON_VERSION == 3.6 ]]; then coveralls; fi
-deploy:
- - provider: pypi
- user: dhoese
- password:
- secure: OZ5xq8R4zSo4m1luNUmo2q2jriu5cmSjrRp/2OKyKmuB09SjO4/jxEIzPP6hfgqV5h/m/3uOtYpLXQBeMf0xX0EZqmsOL0BaRQfDNuaxoVEoGBPC/04Zh6567sjDv615awHw6QTIE0Yw891dy3pun+E1yX1zKtQ9hcDKQ3ZFImg=
- distributions: sdist bdist_wheel
- skip_existing: true
- on:
- tags: true
- repo: pytroll/trollsift
=====================================
AUTHORS.md
=====================================
@@ -9,3 +9,4 @@ The following people have made contributions to this project:
- [Panu Lahtinen (pnuu)](https://github.com/pnuu)
- [Martin Raspaud (mraspaud)](https://github.com/mraspaud)
- [Hrobjartur Thorsteinsson (thorsteinssonh)](https://github.com/thorsteinssonh)
+- [Stephan Finkensieper (sfinkens)](https://github.com/sfinkens)
=====================================
CHANGELOG.md
=====================================
@@ -1,3 +1,28 @@
+## Version 0.3.5 (2021/02/15)
+
+### Issues Closed
+
+* [Issue 27](https://github.com/pytroll/trollsift/issues/27) - Parsing zero padded floats
+* [Issue 26](https://github.com/pytroll/trollsift/issues/26) - MNT: Stop using ci-helpers in appveyor.yml
+* [Issue 23](https://github.com/pytroll/trollsift/issues/23) - Bug when parsing leap day when you dont have year
+* [Issue 20](https://github.com/pytroll/trollsift/issues/20) - Special conversion specifiers do not work ([PR 21](https://github.com/pytroll/trollsift/pull/21))
+
+In this release 4 issues were closed.
+
+### Pull Requests Merged
+
+#### Bugs fixed
+
+* [PR 21](https://github.com/pytroll/trollsift/pull/21) - Fix typo in string formatting usage example and drop Python 2.7 tests ([20](https://github.com/pytroll/trollsift/issues/20))
+
+#### Features added
+
+* [PR 29](https://github.com/pytroll/trollsift/pull/29) - GitHub actions
+* [PR 25](https://github.com/pytroll/trollsift/pull/25) - Add lru_cache to parsing for improved performance
+
+In this release 3 pull requests were closed.
+
+
## Version 0.3.4 (2019/12/18)
### Issues Closed
=====================================
appveyor.yml deleted
=====================================
@@ -1,44 +0,0 @@
-environment:
- global:
- PYTHON: "C:\\conda"
- MINICONDA_VERSION: "latest"
- CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\ci-helpers\\appveyor\\windows_sdk.cmd"
- CONDA_DEPENDENCIES: "coverage mock"
- PIP_DEPENDENCIES: ""
- CONDA_CHANNELS: "conda-forge"
-
- matrix:
- - PYTHON: "C:\\Python27_64"
- PYTHON_VERSION: "2.7"
- PYTHON_ARCH: "64"
- NUMPY_VERSION: "stable"
-
- - PYTHON: "C:\\Python36_64"
- PYTHON_VERSION: "3.6"
- PYTHON_ARCH: "64"
- NUMPY_VERSION: "stable"
-
-install:
-# - "git clone --depth 1 git://github.com/astropy/ci-helpers.git"
- - "git clone --depth 1 -b all-the-fixes git://github.com/djhoese/ci-helpers.git"
- - "powershell ci-helpers/appveyor/install-miniconda.ps1"
- - "conda activate test"
-
-build: false # Not a C# project, build stuff at the test step instead.
-
-test_script:
- # Build the compiled extension and run the project tests
- - "%CMD_IN_ENV% python setup.py test"
-
-after_test:
- # If tests are successful, create a whl package for the project.
- - "%CMD_IN_ENV% python setup.py bdist_wheel bdist_wininst"
- - ps: "ls dist"
-
-artifacts:
- # Archive the generated wheel package in the ci.appveyor.com build report.
- - path: dist\*
-
-#on_success:
-# - TODO: upload the content of dist/*.whl to a public wheelhouse
-#
=====================================
doc/source/installation.rst
=====================================
@@ -7,20 +7,35 @@
Installation
------------
-You can download the trollsift source code from github,::
+Trollsift is available from PyPI::
+
+ $ pip install trollsift
+
+Alternatively, you can install it into a conda environment by using the
+conda-forge channel::
+
+ $ conda install -c conda-forge trollsift
+
+Or you can install it directly from the GitHub repository::
+
+ $ pip install git+https://github.com/pytroll/trollsift.git
+
+Developer Installation
+++++++++++++++++++++++
+
+You can download the trollsift source code from github::
$ git clone https://github.com/pytroll/trollsift.git
and then run::
- $ python setup.py install
+ $ pip install -e .
Testing
++++++++
To check if your python setup is compatible with trollsift,
-you can run the test suite using nosetests,::
+you can run the test suite using pytest::
- $ cd trollsift
- $ nosetests -v tests/
+ $ pytest trollsift/tests
=====================================
doc/source/usage.rst
=====================================
@@ -21,9 +21,9 @@ The Parser object holds a format string, allowing us to parse and compose string
>>>
>>> p = Parser("/somedir/{directory}/hrpt_{platform:4s}{platnum:2s}_{time:%Y%m%d_%H%M}_{orbit:05d}.l1b")
>>> data = p.parse("/somedir/otherdir/hrpt_noaa16_20140210_1004_69022.l1b")
- >>> print(data)
+ >>> print(data) # doctest: +NORMALIZE_WHITESPACE
{'directory': 'otherdir', 'platform': 'noaa', 'platnum': '16',
- 'time': datetime.datetime(2014,02,12,14,12), 'orbit':69022}
+ 'time': datetime.datetime(2014, 2, 10, 10, 4), 'orbit': 69022}
Parsing in trollsift is not "greedy". This means that in the case of ambiguous
patterns it will match the shortest portion of the string possible. For example:
@@ -40,9 +40,15 @@ parsing chose the shorter possible match of "abc".
composing
^^^^^^^^^
-The reverse operation is called 'compose', and is equivalent to the Python string
-class format method. Here we change the time stamp of the data, and write out
-a new file name,
+The reverse operation is called 'compose', and is equivalent to the Python
+string class format method. Here we take the filename pattern from earlier,
+change the time stamp of the data, and write out a new file name,
+
+.. doctest::
+ :hide:
+ >>> p = Parser("/somedir/{directory}/hrpt_{platform:4s}{platnum:2s}_{time:%Y%m%d_%H%M}_{orbit:05d}.l1b")
+ >>> data = p.parse("/somedir/otherdir/hrpt_noaa16_20140210_1004_69022.l1b")
+
>>> from datetime import datetime
>>> data['time'] = datetime(2012, 1, 1, 1, 1)
@@ -52,7 +58,7 @@ a new file name,
In addition to python's builtin string formatting functionality trollsift also
provides extra conversion options such as making all characters lowercase:
- >>> my_parser = Parser("{platform_name:l}")
+ >>> my_parser = Parser("{platform_name!l}")
>>> my_parser.compose({'platform_name': 'NPP'})
'npp'
=====================================
setup.py
=====================================
@@ -1,28 +1,26 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
+#
# Copyright (c) 2014, 2015
-
+#
# Author(s):
-
+#
# Panu Lahtinen <panu.lahtinen at fmi.fi>
# Hróbjartur Thorsteinsson <hroi at vedur.is>
-
+#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
-
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-
+#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""Setup for trollsift.
-"""
+"""Setup for trollsift."""
from setuptools import setup
import versioneer
@@ -36,7 +34,7 @@ setup(name="trollsift",
long_description=README,
author='Panu Lahtinen',
author_email='panu.lahtinen at fmi.fi',
- classifiers=["Development Status :: 3 - Alpha",
+ classifiers=["Development Status :: 5 - Production/Stable",
"Intended Audience :: Science/Research",
"License :: OSI Approved :: GNU General Public License v3 " +
"or later (GPLv3+)",
@@ -49,5 +47,5 @@ setup(name="trollsift",
keywords=["string parsing", "string formatting", "pytroll"],
zip_safe=False,
install_requires=[],
- test_suite='trollsift.tests.suite',
+ tests_require=['pytest']
)
=====================================
trollsift/parser.py
=====================================
@@ -1,39 +1,31 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014, 2015
-
-# Author(s):
-
-# Panu Lahtinen <panu.lahtinen at fmi.fi>
-# Hróbjartur Thorsteinsson <thorsteinssonh at gmail.com>
-
+#
+# Copyright (c) 2014-2020 Trollsift Developers
+#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
-
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-
+#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-
-"""Parser class
-"""
+"""Main parsing and formatting functionality."""
import re
import datetime as dt
import random
import string
+from functools import lru_cache
class Parser(object):
- """Parser class
- """
+ """Class-based interface to parsing and formatting functionality."""
def __init__(self, fmt):
self.fmt = fmt
@@ -141,7 +133,16 @@ formatter = StringFormatter()
spec_regexes = {
'c': r'.',
'd': r'[-+]?\d',
- 'f': r'[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?',
+ 'f': {
+ # Naive fixed point format specifier (e.g. {foo:f})
+ 'naive': r'[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?',
+ # Fixed point format specifier including width and precision
+ # (e.g. {foo:4.2f}). The lookahead (?=.{width}) makes sure that the
+ # subsequent pattern is only matched if the string has the required
+ # (minimum) width.
+ 'precision': r'(?=.{{{width}}})([-+]?([\d ]+(\.\d{{{decimals}}})+|\.\d{{{decimals}}})([eE][-+]?\d+)?)'
+
+ },
'i': r'[-+]?(0[xX][\dA-Fa-f]+|0[0-7]*|\d+)',
'o': r'[-+]?[0-7]',
's': r'\S',
@@ -152,6 +153,7 @@ spec_regexes['E'] = spec_regexes['f']
spec_regexes['g'] = spec_regexes['f']
spec_regexes['X'] = spec_regexes['x']
allow_multiple = ['c', 'd', 'o', 's', 'x', 'X']
+fixed_point_types = ['f', 'e', 'E', 'g']
# format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
# https://docs.python.org/3.4/library/string.html#format-specification-mini-language
fmt_spec_regex = re.compile(
@@ -159,6 +161,26 @@ fmt_spec_regex = re.compile(
r'(?P<comma>,)?(?P<precision>.\d+)?(?P<type>[bcdeEfFgGnosxX%])')
+def _get_fixed_point_regex(regex_dict, width, precision):
+ """Get regular expression for fixed point numbers.
+
+ Args:
+ width: Total width of the string representation.
+ precision: Number of decimals.
+ """
+ if width or precision:
+ if precision is None:
+ precision = '0,'
+ else:
+ precision = precision.strip('.')
+ if width is None:
+ width = '1,'
+ return regex_dict['precision'].format(
+ width=width, decimals=precision)
+ else:
+ return regex_dict['naive']
+
+
class RegexFormatter(string.Formatter):
"""String formatter that converts a format string to a regular expression.
@@ -188,7 +210,7 @@ class RegexFormatter(string.Formatter):
# special string to mark a parameter not being specified
UNPROVIDED_VALUE = '<trollsift unprovided value>'
ESCAPE_CHARACTERS = ['\\'] + [x for x in string.punctuation if x not in '\\%']
- ESCAPE_SETS = [(c, '\{}'.format(c)) for c in ESCAPE_CHARACTERS]
+ ESCAPE_SETS = [(c, '\\' + c) for c in ESCAPE_CHARACTERS]
def __init__(self):
# hold on to fields we've seen already so we can reuse their
@@ -196,6 +218,7 @@ class RegexFormatter(string.Formatter):
self._cached_fields = {}
super(RegexFormatter, self).__init__()
+ @lru_cache()
def format(*args, **kwargs):
try:
# super() doesn't seem to work here
@@ -255,6 +278,7 @@ class RegexFormatter(string.Formatter):
ftype = regex_dict['type']
width = regex_dict['width']
align = regex_dict['align']
+ precision = regex_dict['precision']
# NOTE: does not properly handle `=` alignment
if fill is None:
if width is not None and width[0] == '0':
@@ -263,13 +287,19 @@ class RegexFormatter(string.Formatter):
fill = ' '
char_type = spec_regexes[ftype]
+ if ftype in fixed_point_types:
+ char_type = _get_fixed_point_regex(
+ char_type,
+ width=width,
+ precision=precision
+ )
if ftype == 's' and align and align.endswith('='):
raise ValueError("Invalid format specification: '{}'".format(format_spec))
final_regex = char_type
if ftype in allow_multiple and (not width or width == '0'):
final_regex += r'*?'
elif width and width != '0':
- if not fill:
+ if not fill and ftype not in fixed_point_types:
# we know we have exactly this many characters
final_regex += r'{{{}}}'.format(int(width))
elif fill:
@@ -346,28 +376,15 @@ def _get_number_from_fmt(fmt):
def _convert(convdef, stri):
"""Convert the string *stri* to the given conversion definition *convdef*."""
+ is_fixed_point = any([ftype in convdef for ftype in fixed_point_types])
if '%' in convdef:
result = dt.datetime.strptime(stri, convdef)
- elif 'd' in convdef or 's' in convdef:
- regex_match = fmt_spec_regex.match(convdef)
- match_dict = regex_match.groupdict() if regex_match else {}
- align = match_dict.get('align')
- pad = match_dict.get('fill')
- if align:
- # align character is the last one
- align = align[-1]
- if align and align in '<>^' and not pad:
- pad = ' '
-
- if align == '>':
- stri = stri.lstrip(pad)
- elif align == '<':
- stri = stri.rstrip(pad)
- elif align == '^':
- stri = stri.strip(pad)
-
+ elif 'd' in convdef or 's' in convdef or is_fixed_point:
+ stri = _strip_padding(convdef, stri)
if 'd' in convdef:
result = int(stri)
+ elif is_fixed_point:
+ result = float(stri)
else:
result = stri
else:
@@ -375,6 +392,31 @@ def _convert(convdef, stri):
return result
+def _strip_padding(convdef, stri):
+ """Strip padding from the given string.
+
+ Args:
+ convdef: Conversion definition (indicates the padding)
+ stri: String to be modified
+ """
+ regex_match = fmt_spec_regex.match(convdef)
+ match_dict = regex_match.groupdict() if regex_match else {}
+ align = match_dict.get('align')
+ pad = match_dict.get('fill')
+ if align:
+ # align character is the last one
+ align = align[-1]
+ if align and align in '<>^' and not pad:
+ pad = ' '
+ if align == '>':
+ stri = stri.lstrip(pad)
+ elif align == '<':
+ stri = stri.rstrip(pad)
+ elif align == '^':
+ stri = stri.strip(pad)
+ return stri
+
+ at lru_cache()
def get_convert_dict(fmt):
"""Retrieve parse definition from the format string `fmt`."""
convdef = {}
@@ -588,3 +630,14 @@ def is_one2one(fmt):
return False
# all checks passed, so just return True
return True
+
+
+def purge():
+ """Clear internal caches.
+
+ Not needed normally, but can be used to force cache clear when memory
+ is very limited.
+
+ """
+ regex_formatter.format.cache_clear()
+ get_convert_dict.cache_clear()
=====================================
trollsift/tests/__init__.py
=====================================
@@ -1,25 +1,2 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
-import sys
-from trollsift.tests import unittests, regressiontests, integrationtests
-
-if sys.version_info < (2, 7):
- import unittest2 as unittest
-else:
- import unittest
-
-
-def suite():
- """The global test suite.
- """
- mysuite = unittest.TestSuite()
- mysuite.addTests(unittests.suite())
- mysuite.addTests(regressiontests.suite())
- mysuite.addTests(integrationtests.suite())
-
- return mysuite
-
-
-def load_tests(loader, tests, pattern):
- return suite()
=====================================
trollsift/tests/integrationtests/__init__.py
=====================================
@@ -1,40 +1,18 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014 Panu Lahtinen
-
-# Author(s):
-
-# Panu Lahtinen <panu.lahtinen at fmi.fi>
-
+#
+# Copyright (c) 2014-2020 Panu Lahtinen
+#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
-
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-
+#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""The tests package.
-"""
-
-from . import test_parser
-import unittest
-import doctest
-
-def suite():
- """The global test suite.
- """
- mysuite = unittest.TestSuite()
- # Use the unittests also
- mysuite.addTests(test_parser.suite())
-
- return mysuite
-
-if __name__ == '__main__':
- unittest.TextTestRunner(verbosity=2).run(suite())
+"""Integration tests for the trollsift package."""
=====================================
trollsift/tests/integrationtests/test_parser.py
=====================================
@@ -1,3 +1,21 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2014-2020 Martin Raspaud
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+"""Parser integration tests."""
import os
import unittest
import datetime as dt
@@ -22,6 +40,18 @@ class TestParser(unittest.TestCase):
# Assert
self.assertDictEqual(result, self.data)
+ def test_cache_clear(self):
+ """Test we can clear the internal cache properly"""
+ from trollsift.parser import purge
+ from trollsift.parser import regex_formatter
+ # Run
+ result = self.p.parse(self.string)
+ # Assert
+ self.assertDictEqual(result, self.data)
+ assert regex_formatter.format.cache_info()[-1] != 0
+ purge()
+ assert regex_formatter.format.cache_info()[-1] == 0
+
def test_compose(self):
# Run
result = self.p.compose(self.data)
@@ -121,13 +151,3 @@ class TestParserVariousFormats(unittest.TestCase):
p = Parser(fmt)
result = p.parse(filename)
self.assertEqual(result['version_number'], '1')
-
-
-def suite():
- """The suite for test_parser
- """
- loader = unittest.TestLoader()
- mysuite = unittest.TestSuite()
- mysuite.addTest(loader.loadTestsFromTestCase(TestParser))
- mysuite.addTest(loader.loadTestsFromTestCase(TestParserVariousFormats))
- return mysuite
=====================================
trollsift/tests/regressiontests/__init__.py
=====================================
@@ -1,39 +1,18 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014 Martin Raspaud
-
-# Author(s):
-
-# Martin Raspaud <martin.raspaud at smhi.se>
-
+#
+# Copyright (c) 2014-2020 Martin Raspaud
+#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
-
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-
+#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""
-"""
-from . import test_parser
-import unittest
-
-
-def suite():
- """The global test suite.
- """
- mysuite = unittest.TestSuite()
- # Use the unittests also
- mysuite.addTests(test_parser.suite())
-
- return mysuite
-
-if __name__ == '__main__':
- unittest.TextTestRunner(verbosity=2).run(suite())
+"""Regression tests for the trollsift package."""
=====================================
trollsift/tests/regressiontests/test_parser.py
=====================================
@@ -1,27 +1,21 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014 Martin Raspaud
-
-# Author(s):
-
-# Martin Raspaud <martin.raspaud at smhi.se>
-
+#
+# Copyright (c) 2014-2020 Martin Raspaud
+#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
-
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-
+#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""
-"""
+"""Parser regression tests."""
import unittest
import datetime as dt
@@ -37,12 +31,3 @@ class TestParser(unittest.TestCase):
self.assertEqual(res, {'orbit_number': 29889,
'satellite': 'NOAA-19',
'start_time': dt.datetime(2014, 11, 26, 10, 12)})
-
-
-def suite():
- """The suite for test_parser
- """
- loader = unittest.TestLoader()
- mysuite = unittest.TestSuite()
- mysuite.addTest(loader.loadTestsFromTestCase(TestParser))
- return mysuite
\ No newline at end of file
=====================================
trollsift/tests/unittests/__init__.py
=====================================
@@ -1,40 +1,18 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-
-# Copyright (c) 2014 Panu Lahtinen
-
-# Author(s):
-
-# Panu Lahtinen <panu.lahtinen at fmi.fi>
-
+#
+# Copyright (c) 2014-2020 Panu Lahtinen
+#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
-
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-
+#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""The tests package.
-"""
-
-from . import test_parser
-import unittest
-import doctest
-
-def suite():
- """The global test suite.
- """
- mysuite = unittest.TestSuite()
- # Use the unittests also
- mysuite.addTests(test_parser.suite())
-
- return mysuite
-
-if __name__ == '__main__':
- unittest.TextTestRunner(verbosity=2).run(suite())
+"""Unit tests for the trollsift package."""
=====================================
trollsift/tests/unittests/test_parser.py
=====================================
@@ -1,9 +1,10 @@
import unittest
import datetime as dt
+import pytest
from trollsift.parser import get_convert_dict, regex_formatter
from trollsift.parser import _convert
-from trollsift.parser import parse, globify, validate, is_one2one
+from trollsift.parser import parse, globify, validate, is_one2one, compose
class TestParser(unittest.TestCase):
@@ -273,7 +274,6 @@ class TestParser(unittest.TestCase):
def test_compose(self):
"""Test the compose method's custom conversion options."""
- from trollsift import compose
key_vals = {'a': 'this Is A-Test b_test c test'}
new_str = compose("{a!c}", key_vals)
@@ -322,10 +322,70 @@ class TestParser(unittest.TestCase):
self.assertEqual(exp, res_dict)
-def suite():
- """The suite for test_parser
- """
- loader = unittest.TestLoader()
- mysuite = unittest.TestSuite()
- mysuite.addTest(loader.loadTestsFromTestCase(TestParser))
- return mysuite
+class TestParserFixedPoint:
+ """Test parsing of fixed point numbers."""
+
+ @pytest.mark.parametrize(
+ ('fmt', 'string', 'expected'),
+ [
+ # Naive
+ ('{foo:f}', '12.34', 12.34),
+ # Including width and precision
+ ('{foo:5.2f}', '12.34', 12.34),
+ ('{foo:5.2f}', '-1.23', -1.23),
+ ('{foo:5.2f}', '12.34', 12.34),
+ ('{foo:5.2f}', '123.45', 123.45),
+ # Whitespace padded
+ ('{foo:5.2f}', ' 1.23', 1.23),
+ ('{foo:5.2f}', ' 12.34', 12.34),
+ # Zero padded
+ ('{foo:05.2f}', '01.23', 1.23),
+ ('{foo:05.2f}', '012.34', 12.34),
+ # Only precision, no width
+ ('{foo:.2f}', '12.34', 12.34),
+ # Only width, no precision
+ ('{foo:16f}', ' 1.12', 1.12),
+ # No digits before decimal point
+ ('{foo:3.2f}', '.12', 0.12),
+ ('{foo:4.2f}', '-.12', -0.12),
+ ('{foo:4.2f}', ' .12', 0.12),
+ ('{foo:4.2f}', ' .12', 0.12),
+ ('{foo:16f}', ' .12', 0.12),
+ # Exponential format
+ ('{foo:7.2e}', '-1.23e4', -1.23e4)
+ ]
+ )
+ def test_match(self, fmt, string, expected):
+ """Test cases expected to be matched."""
+
+ # Test parsed value
+ parsed = parse(fmt, string)
+ assert parsed['foo'] == expected
+
+ # Test round trip
+ composed = compose(fmt, {'foo': expected})
+ parsed = parse(fmt, composed)
+ assert parsed['foo'] == expected
+
+ @pytest.mark.parametrize(
+ ('fmt', 'string'),
+ [
+ # Decimals incorrect
+ ('{foo:5.2f}', '12345'),
+ ('{foo:5.2f}', '1234.'),
+ ('{foo:5.2f}', '1.234'),
+ ('{foo:5.2f}', '123.4'),
+ ('{foo:.2f}', '12.345'),
+ # Decimals correct, but width too short
+ ('{foo:5.2f}', '1.23'),
+ ('{foo:5.2f}', '.23'),
+ ('{foo:10.2e}', '1.23e4'),
+ # Invalid
+ ('{foo:5.2f}', '12_34'),
+ ('{foo:5.2f}', 'aBcD'),
+ ]
+ )
+ def test_no_match(self, fmt, string):
+ """Test cases expected to not be matched."""
+ with pytest.raises(ValueError):
+ parse(fmt, string)
=====================================
trollsift/version.py
=====================================
@@ -23,9 +23,9 @@ def get_keywords():
# setup.py/versioneer.py will grep for the variable names, so they must
# each be defined on a line of their own. _version.py will just call
# get_keywords().
- git_refnames = " (HEAD -> master, tag: v0.3.4)"
- git_full = "c37ad63f1ab71d3b0ae75a3c04d4a24bc6b2e899"
- git_date = "2019-12-18 07:46:35 -0600"
+ git_refnames = " (HEAD -> master, tag: v0.3.5)"
+ git_full = "30caabdd6b30892380e0223a1f46394b835831a1"
+ git_date = "2021-02-15 11:11:18 +0100"
keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
return keywords
View it on GitLab: https://salsa.debian.org/debian-gis-team/trollsift/-/commit/3105b9f3be3594274dc460cedbb750e6a8372f91
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/trollsift/-/commit/3105b9f3be3594274dc460cedbb750e6a8372f91
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20210217/87e34967/attachment-0001.html>
More information about the Pkg-grass-devel
mailing list