[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