File pytimeparse2-1.7.1.obscpio of Package python-pytimeparse2

07070100000000000081A4000000000000000000000001645D608F000000F5000000000000000000000000000000000000001F00000000pytimeparse2-1.7.1/.coveragerc[run]
source =
    pytimeparse2
    tests
parallel = True
concurrency =
    thread
    multiprocessing
omit =
    *.tox/*
    *setup.py

[report]
fail_under = 100
show_missing = True
exclude_lines =
    pragma: no cover
    nocv
    MemoryError
07070100000001000041ED000000000000000000000002645D608F00000000000000000000000000000000000000000000001B00000000pytimeparse2-1.7.1/.github07070100000002000041ED000000000000000000000002645D608F00000000000000000000000000000000000000000000002500000000pytimeparse2-1.7.1/.github/workflows07070100000003000081A4000000000000000000000001645D608F00000274000000000000000000000000000000000000002F00000000pytimeparse2-1.7.1/.github/workflows/check.ymlname: Python package

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-20.04
    strategy:
      max-parallel: 4
      matrix:
        python-version: ['3.6.15', 3.7, 3.8, 3.9, '3.10', '3.11']

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v2
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install tox tox-gh-actions
    - name: Test with tox
      run: tox
07070100000004000081A4000000000000000000000001645D608F0000006B000000000000000000000000000000000000001E00000000pytimeparse2-1.7.1/.gitignore*.pyc
*~
*.c
.DS_Store
/.coverage
/MANIFEST
/build/
/dist/
*.egg-info/
venv
.tox
.mypy_cache
.idea
.vscode
07070100000005000081A4000000000000000000000001645D608F00000054000000000000000000000000000000000000001900000000pytimeparse2-1.7.1/.pep8[flake8]
ignore =
exclude = /.tox/*
max-line-length = 120
import-order-style = pep8
07070100000006000081A4000000000000000000000001645D608F0000043A000000000000000000000000000000000000001F00000000pytimeparse2-1.7.1/LICENSE.rstThe MIT License (MIT)

Copyright (c) 2021 Sergey Klyuykov

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
07070100000007000081A4000000000000000000000001645D608F00000039000000000000000000000000000000000000001F00000000pytimeparse2-1.7.1/MANIFEST.ininclude LICENSE.rst
include README.rst
include setup.cfg
07070100000008000081A4000000000000000000000001645D608F00000C1F000000000000000000000000000000000000001E00000000pytimeparse2-1.7.1/README.rstpytimeparse2: time expression parser
=====================================

.. image:: https://github.com/onegreyonewhite/pytimeparse2/actions/workflows/check.yml/badge.svg?branch=master
    :target: https://github.com/onegreyonewhite/pytimeparse2/actions
    :alt: Pipeline status

.. image:: https://badge.fury.io/py/pytimeparse2.svg
    :target: https://badge.fury.io/py/pytimeparse2


This is a `pytimeparse <https://github.com/wroberts/pytimeparse>`_ based project with the aim of optimizing functionality and providing stable support.

Copyright (c) 2021 Sergey Klyuykov <onegreyonewhite@mail.ru>

Licensed under the MIT License (see source file ``pytimeparse2.py`` for
details).

A small Python library to parse various kinds of time expressions,
inspired by
`this StackOverflow question <http://stackoverflow.com/questions/4628122/how-to-construct-a-timedelta-object-from-a-simple-string>`_.

The single function ``pytimeparse2.parse`` defined in the library parses time
expressions like the following:

- ``32m``
- ``2h32m``
- ``3d2h32m``
- ``1w3d2h32m``
- ``1w 3d 2h 32m``
- ``1 w 3 d 2 h 32 m``
- ``4:13``
- ``4:13:02``
- ``4:13:02.266``
- ``2:04:13:02.266``
- ``2 days,  4:13:02`` (``uptime`` format)
- ``2 days,  4:13:02.266``
- ``5hr34m56s``
- ``5 hours, 34 minutes, 56 seconds``
- ``5 hrs, 34 mins, 56 secs``
- ``2 days, 5 hours, 34 minutes, 56 seconds``
- ``1.2 m``
- ``1.2 min``
- ``1.2 mins``
- ``1.2 minute``
- ``1.2 minutes``
- ``172 hours``
- ``172 hr``
- ``172 h``
- ``172 hrs``
- ``172 hour``
- ``1.24 days``
- ``5 d``
- ``5 day``
- ``5 days``
- ``5.6 wk``
- ``5.6 week``
- ``5.6 weeks``

It returns the time as a number of seconds (an integer value if
possible, otherwise a floating-point number)::

    >>> from pytimeparse import parse
    >>> parse('1.2 minutes')
    72

For months and years, the library does not consider complications such as leap-
years and leap-seconds. Instead, it assumes "30 days for a month" and "365 days
for a year" as the basis for calculations with those units.

- ``2 mo``
- ``2 months``
- ``3y``
- ``3 years``
- ``1y2mo3w4d5h6m7s8ms``

For better capability with dates, use keyword ``as_timedelta=True`` which mark for function returns
value as ``datetime.timedelta`` or ``dateutil.relitivedelta.relativedelta`` (if installed)::

    >>> from pytimeparse import parse
    >>> parse('24h', as_timedelta=True)
    relativedelta(days=+1)

You can also forced disable dateutil support by calling ``disable_dateutil()`` before ``parse(...)``.
For returning support call ``enable_dateutil()``.

Notes
-----

A number of seconds can be converted back into a string using the
``datetime`` module in the standard library, as noted in
`this other StackOverflow question <http://stackoverflow.com/questions/538666/python-format-timedelta-to-string>`_::

    >>> from pytimeparse import parse
    >>> import datetime
    >>> parse('1 day, 14:20:16')
    138016
    >>> str(datetime.timedelta(seconds=138016))
    '1 day, 14:20:16'

Future work
-----------

1. Speed up with Cython for some python versions.
2. Use github actions for testing and releasing.
07070100000009000081ED000000000000000000000001645D608F00000184000000000000000000000000000000000000002200000000pytimeparse2-1.7.1/autorelease.sh#!/usr/bin/env bash
CURRENT_VERSION=$(python3 setup.py --version | tr -d '\n')
TAG=$(git tag -l $CURRENT_VERSION)

if [ -z "${TAG}" ]; then
    echo "Creating new tag ${CURRENT_VERSION}.";
    git tag $CURRENT_VERSION > /dev/null 2>&1;
    git push origin $CURRENT_VERSION > /dev/null 2>&1;
else
    echo "Current release ${CURRENT_VERSION} already exists. Update version to release."
fi
0707010000000A000081A4000000000000000000000001645D608F00002357000000000000000000000000000000000000002300000000pytimeparse2-1.7.1/pytimeparse2.py#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
(c) Sergey Klyuykov <onegreyonewhite@mail.ru> 3 Nov 2021

Implements a single function, `parse`, which can parse various
kinds of time expressions.
"""

# MIT LICENSE
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

__version__ = '1.7.1'

import typing
import re
from datetime import timedelta

try:
    from dateutil.relativedelta import relativedelta
    HAS_RELITIVE_TIMEDELTA = True
except ImportError:  # pragma: no cover
    HAS_RELITIVE_TIMEDELTA = False
    relativedelta = None  # type: ignore


SIGN = r'(?P<sign>[+|-]|\+)?'
YEARS = r'(?P<years>[\d.]+)\s*(?:ys?|yrs?.?|years?)'
MONTHS = r'(?P<months>[\d.]+)\s*(?:mos?.?|mths?.?|months?)'
WEEKS = r'(?P<weeks>[\d.]+)\s*(?:w|wks?|weeks?)'
DAYS = r'(?P<days>[\d.]+)\s*(?:d|dys?|days?)'
HOURS = r'(?P<hours>[\d.]+)\s*(?:h|hrs?|hours?)'
MINS = r'(?P<minutes>[\d.]+)\s*(?:m|(mins?)|(minutes?))'
SECS = r'(?P<seconds>[\d.]+)\s*(?:s|secs?|seconds?)'
MILLIS = r'(?P<milliseconds>[\d.]+)\s*(?:ms|msecs?|millis|milliseconds?)'
SEPARATORS = r'[,/]'
SECCLOCK = r':(?P<seconds>\d{2}(?:\.\d+)?)'
MINCLOCK = r'(?P<minutes>\d{1,2}):(?P<seconds>\d{2}(?:\.\d+)?)'
HOURCLOCK = r'(?P<hours>\d+):(?P<minutes>\d{2}):(?P<seconds>\d{2}(?:\.\d+)?)'
DAYCLOCK = (r'(?P<days>\d+):(?P<hours>\d{2}):'
            r'(?P<minutes>\d{2}):(?P<seconds>\d{2}(?:\.\d+)?)')

MULTIPLIERS = {
    'years': 60 * 60 * 24 * 365,
    'months': 60 * 60 * 24 * 30,
    'weeks': 60 * 60 * 24 * 7,
    'days': 60 * 60 * 24,
    'hours': 60 * 60,
    'minutes': 60,
    'seconds': 1,
    'milliseconds': 1e-3,
}


def OPT(x):
    return r'(?:{x})?'.format(x=x)


def OPTSEP(x):
    return r'(?:{x}\s*(?:{SEPARATORS}\s*)?)?'.format(x=x, SEPARATORS=SEPARATORS)


TIMEFORMATS = [
    (rf'{OPTSEP(YEARS)}\s*'
     rf'{OPTSEP(MONTHS)}\s*'
     rf'{OPTSEP(WEEKS)}\s*'
     rf'{OPTSEP(DAYS)}\s*'
     rf'{OPTSEP(HOURS)}\s*'
     rf'{OPTSEP(MINS)}\s*'
     rf'{OPT(SECS)}\s*'
     rf'{OPT(MILLIS)}'),
    rf'{OPTSEP(WEEKS)}\s*{OPTSEP(DAYS)}\s*{OPTSEP(HOURS)}\s*{OPTSEP(MINS)}\s*{OPT(SECS)}\s*{OPT(MILLIS)}',
    rf'{MINCLOCK}',
    rf'{OPTSEP(WEEKS)}\s*{OPTSEP(DAYS)}\s*{HOURCLOCK}',
    rf'{DAYCLOCK}',
    rf'{SECCLOCK}',
    rf'{YEARS}',
    rf'{MONTHS}',
]

COMPILED_SIGN = re.compile(r'\s*' + SIGN + r'\s*(?P<unsigned>.*)$')
COMPILED_TIMEFORMATS = [
    re.compile(r'\s*' + timefmt + r'\s*$', re.I)
    for timefmt in TIMEFORMATS
]


def _all_digits(mdict, delta_class):
    if HAS_RELITIVE_TIMEDELTA and issubclass(delta_class, relativedelta):
        if 'milliseconds' in mdict:
            mdict['microseconds'] = float(mdict.pop('milliseconds') or 0) * 1000
        return delta_class(**{k: float(v) for k, v in mdict.items() if v}).normalized()

    delta = delta_class(**{
        key: float(mdict.pop(key) or 0)
        for key in mdict.copy()
        if key in ('hours', 'minutes', 'days', 'milliseconds')
    })

    for time_type, value in mdict.items():
        if not value:
            continue
        if value.isdigit():
            delta += delta_class(seconds=MULTIPLIERS[time_type] * int(value, 10))
        elif value.replace('.', '', 1).isdigit():
            delta += delta_class(seconds=MULTIPLIERS[time_type] * float(value))

    return delta


def _interpret_as_minutes(sval, mdict):
    """
    Times like "1:22" are ambiguous; do they represent minutes and seconds
    or hours and minutes?  By default, parse assumes the latter.  Call
    this function after parsing out a dictionary to change that assumption.

    >>> import pprint
    >>> pprint.pprint(_interpret_as_minutes('1:24', {'seconds': '24', 'minutes': '1'}))
    {'hours': '1', 'minutes': '24'}
    """
    if sval.count(':') == 1 and '.' not in sval and (('hours' not in mdict) or (mdict['hours'] is None)) and (
            ('days' not in mdict) or (mdict['days'] is None)) and (('weeks' not in mdict) or (mdict['weeks'] is None)) \
            and (('months' not in mdict) or (mdict['months'] is None)) \
            and (('years' not in mdict) or (mdict['years'] is None)):
        mdict['hours'] = mdict['minutes']
        mdict['minutes'] = mdict['seconds']
        mdict.pop('seconds')
    return mdict


def _normilized_relativedelta(value: typing.Optional[timedelta]) -> typing.Optional[timedelta]:
    if relativedelta is not None and isinstance(value, relativedelta):
        return value.normalized()
    return value


def _parse(
        sval: typing.Union[str, int, float],
        granularity: str = 'seconds',
        delta_class: typing.Type[timedelta] = timedelta
) -> typing.Optional[timedelta]:
    if isinstance(sval, (int, float)):
        return _normilized_relativedelta(delta_class(seconds=float(sval)))
    if sval.replace('.', '', 1).replace('-', '', 1).replace('+', '', 1).isdigit():
        return _normilized_relativedelta(delta_class(seconds=float(sval)))

    match = COMPILED_SIGN.match(sval)
    sign = -1 if match.groupdict()['sign'] == '-' else 1  # type: ignore
    sval = match.groupdict()['unsigned']  # type: ignore

    for timefmt in COMPILED_TIMEFORMATS:
        match = timefmt.match(sval)

        if not (match and match.group(0).strip()):
            continue

        mdict = match.groupdict()
        if granularity == 'minutes':
            mdict = _interpret_as_minutes(sval, mdict)

        return sign * _all_digits(mdict, delta_class)

    return timedelta(seconds=float(sval)) * sign


def enable_dateutil():
    global HAS_RELITIVE_TIMEDELTA
    assert relativedelta is not None, 'Module python-dateutil should be installed before.'
    HAS_RELITIVE_TIMEDELTA = True


def disable_dateutil():
    global HAS_RELITIVE_TIMEDELTA
    HAS_RELITIVE_TIMEDELTA = False


def parse(
        sval: typing.Union[str, int, float],
        granularity: str = 'seconds',
        raise_exception: bool = False,
        as_timedelta: bool = False,
) -> typing.Optional[typing.Union[int, float, timedelta, typing.NoReturn]]:
    """
    Parse a time expression, returning it as a number of seconds.  If
    possible, the return value will be an `int`; if this is not
    possible, the return will be a `float`.  Returns `None` if a time
    expression cannot be parsed from the given string.

    Arguments:
    - `sval`: the string value to parse
    - `granularity`: minimal type of digits after last colon (default is ``seconds``)
    - `raise_exception`: raise exception on parsing errors (default is ``False``)
    - `as_timedelta`: return ``datetime.timedelta`` object instead of ``int`` (default is ``False``)

    >>> parse('1:24')
    84
    >>> parse(':22')
    22
    >>> parse('1 minute, 24 secs')
    84
    >>> parse('1m24s')
    84
    >>> parse('1.2 minutes')
    72
    >>> parse('1.2 seconds')
    1.2

    Time expressions can be signed.

    >>> parse('- 1 minute')
    -60
    >>> parse('+ 1 minute')
    60

    If granularity is specified as ``minutes``, then ambiguous digits following
    a colon will be interpreted as minutes; otherwise they are considered seconds.

    >>> parse('1:30')
    90
    >>> parse('1:30', granularity='minutes')
    5400

    If ``as_timedelta`` is specified as ``True``, then return timedelta object.

    >>> parse('24h', as_timedelta=True)
    relativedelta(days=+1)
    >>> parse('48:00', as_timedelta=True, granularity='minutes')
    relativedelta(days=+2)

    If ``raise_exception`` is specified as ``True``, then exception will raised
    on failed parsing.

    >>> parse(':1.1.1', raise_exception=True)
    Traceback (most recent call last):
        ...
    ValueError: could not convert string to float: ':1.1.1'
    """
    try:
        value = _parse(sval, granularity, relativedelta if HAS_RELITIVE_TIMEDELTA and as_timedelta else timedelta)
        if not as_timedelta and value is not None:
            new_value = value.total_seconds()
            if new_value.is_integer():
                return int(new_value)
            else:
                return new_value
        return value
    except Exception:
        if raise_exception:
            raise
        return None
0707010000000B000081A4000000000000000000000001645D608F0000051B000000000000000000000000000000000000001D00000000pytimeparse2-1.7.1/setup.cfg[metadata]
name = pytimeparse2
version = attr: pytimeparse2.__version__
description = Time expression parser.
long_description = file: README.rst
long_description_content_type = text/x-rst
license = MIT
author = Sergey Klyuykov
author_email = onegreyonewhite@mail.ru
url = https://github.com/onegreyonewhite/pytimeparse2
keywords = parsing, time, timeparsing, text
classifiers =
    Development Status :: 5 - Production/Stable
    Intended Audience :: Developers
    License :: OSI Approved :: MIT License
    Programming Language :: Python
    Programming Language :: Python :: 3
    Programming Language :: Python :: 3 :: Only
    Programming Language :: Python :: 3.6
    Programming Language :: Python :: 3.7
    Programming Language :: Python :: 3.8
    Programming Language :: Python :: 3.9
    Programming Language :: Python :: 3.10
    Programming Language :: Python :: 3.11
    Programming Language :: Python :: Implementation :: CPython
    Topic :: Software Development :: Libraries
    Topic :: Software Development :: Libraries :: Python Modules
    Topic :: Text Processing
    Topic :: Utilities

[options]
zip_safe = False
include_package_data = True
python_requires = >=3.6

[options.extras_require]
dateutil =
    python-dateutil~=2.8.2

[build_sphinx]
project = 'pytimeparse2'

[aliases]
0707010000000C000081A4000000000000000000000001645D608F00003870000000000000000000000000000000000000001C00000000pytimeparse2-1.7.1/setup.py#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
setup.py
(c) Sergey Klyuykov 3 Nov 2021

distutils setup script for pytimeparse2.
"""

# Compilation block
########################################################################################
import re
import os
import sys
import subprocess
import fnmatch
import codecs
import gzip
import shutil

# allow setup.py to be run from any path
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))

from setuptools import find_packages, setup, errors, Command
from setuptools.extension import Extension
from setuptools.command.sdist import sdist as _sdist
from setuptools.command.build_py import build_py as build_py_orig
from setuptools.command.install_lib import install_lib as _install_lib
try:
    from Cython.Build import cythonize, build_ext as _build_ext
except ImportError:
    has_cython = False
else:
    has_cython = True

try:
    from sphinx.setup_command import BuildDoc
    import sphinx  # noqa: F401
    has_sphinx = True
except ImportError:
    has_sphinx = False


ignored_keys = ['-h', '--help', '--version']
is_help = any([a for a in ignored_keys if a in sys.argv])
is_develop = 'develop' in sys.argv
is_build = (any([a for a in ['compile', 'bdist_wheel', 'bdist'] if a in sys.argv]) or is_develop) and not is_help


def get_discription(file_path='README.rst', folder=os.getcwd()):
    with codecs.open("{}/{}".format(folder, file_path), 'r', encoding='utf-8') as readme:
        return readme.read()


def load_requirements(file_name, folder=os.getcwd()):
    with codecs.open(os.path.join(folder, file_name), 'r', encoding='utf-8')as req_file:
        return req_file.read().strip().split('\n')


def get_file_ext(ext):
    file_types = [".py", ".pyx", ".c", '.cpp'] if has_cython else [".c", '.cpp', ".py"]
    for ftype in file_types:
        fname = ext.replace(".", "/") + ftype
        if os.path.exists(fname):
            return fname
    return None


def listfiles(folder):
    if not isinstance(folder, (list, tuple)):
        folder = [folder]
    folder = filter(lambda p: os.path.isdir(p), folder)
    for one_folder in folder:
        for root, folders, files in os.walk(one_folder):
            for filename in folders + files:
                yield os.path.join(root, filename)


def clear_old_extentions(extensions_list, packages):
    for filename in listfiles(packages):
        _filename, _f_ext = os.path.splitext(filename)
        if os.path.isdir(_filename) or _f_ext not in ['.c', '.cpp']:
            continue
        has_py = (
            os.path.exists('{}.py'.format(_filename)) or
            os.path.exists('{}.pyx'.format(_filename))
        )

        if has_py and filename.replace('/', '.').replace(_f_ext, '') in extensions_list:
            print('Removing old extention [{}].'.format(filename))
            os.remove(filename)


def make_extention(module_name, files, extra_compile_args, main_include_dir=os.path.join(os.getcwd(), 'include')):
    include_dirs = list(filter(
        lambda f: bool(f) and os.path.exists(f) and os.path.isdir(f),
        [os.path.join(module_name.split('.')[0], 'include'), main_include_dir]
    ))

    return Extension(
        module_name, files,
        extra_compile_args=extra_compile_args,
        include_dirs=include_dirs
    )


def make_extensions(extensions_list, packages):
    if not isinstance(extensions_list, list):
        raise Exception("Extension list should be `list`.")

    if not is_help:
        clear_old_extentions(extensions_list, packages)

    extensions_dict = {}
    for ext in extensions_list:
        files = []
        module_name = ext
        if isinstance(ext, (list, tuple)):
            module_name = ext[0]
            for file_module in ext[1]:
                file_name = get_file_ext(file_module)
                files += [file_name] if file_name else []
        else:
            file_name = get_file_ext(ext)
            files += [file_name] if file_name else []
        if files:
            extensions_dict[module_name] = files

    extra_compile_args = [
        '-g0', '-ggdb1',
        "-fno-strict-aliasing",
        "-ffast-math",
        "-fno-var-tracking-assignments",
        "-pipe", "-std=c99", '-Werror=sign-compare',
    ]
    if 'compile' in sys.argv:
        extra_compile_args.append("-DBUILD_FROM_SOURCE")
    ext_modules = list(
        make_extention(m, f, extra_compile_args)
        for m, f in extensions_dict.items()
    )
    ext_count = len(ext_modules)
    nthreads = ext_count if ext_count < 10 else 10

    language_level = 3
    if is_help:
        pass
    elif has_cython and ('compile' in sys.argv or 'bdist_wheel' in sys.argv or 'build_ext' in sys.argv):
        cy_kwargs = dict(
            nthreads=nthreads,
            force=True,
            language_level=language_level,
            compiler_directives=dict(
                linetrace='CYTHON_TRACE_NOGIL' in sys.argv,
                profile=True,
                c_string_type='str',
                c_string_encoding='utf8'
            ),
        )
        return cythonize(ext_modules, **cy_kwargs), extensions_dict
    return ext_modules, extensions_dict


def minify_js_file(js_file, jsmin_func):
    return jsmin_func(js_file, quote_chars="'\"`")


def minify_css_file(css_file, cssmin_func):
    return cssmin_func(css_file)


def minify_static_files(base_dir, files, exclude=None):
    exclude = exclude or []
    patterns = dict()
    try:
        from jsmin import jsmin as jsmin_func
        patterns['*.js'] = (minify_js_file, jsmin_func)
    except:
        pass
    try:
        from csscompressor import compress as csscompressor_func
        patterns['*.css'] = (minify_css_file, csscompressor_func)
    except:
        pass

    regex_exclude = [re.compile(r, re.MULTILINE) for r in exclude]

    for fnext, funcs in patterns.items():
        for fext_file in filter(lambda f: fnmatch.fnmatch(f, fnext), files):
            if fnmatch.fnmatch(fext_file, '*.min.*'):
                continue
            fext_file = os.path.join(base_dir, fext_file)
            if os.path.exists(fext_file):
                if not any(filter(lambda fp: bool(fp.search(fext_file)), regex_exclude)):
                    func, subfunc = funcs
                    with codecs.open(fext_file, 'r', encoding='utf-8') as static_file_fd:
                        minified = func(static_file_fd.read(), subfunc)
                    with codecs.open(fext_file, 'w', encoding='utf-8') as static_file_fd:
                        static_file_fd.write(minified)
                    print('Minfied file {fext_file}.'.format(fext_file=fext_file))
                with open(fext_file, 'rb') as f_in:
                    with gzip.open("{}.gz".format(fext_file), 'wb') as f_out:
                        shutil.copyfileobj(f_in, f_out)
                print('Compressed file {fext_file}.'.format(fext_file=fext_file))


def compile_py_func(fullname, compile_file_func):
    if compile_file_func(fullname, ddir=os.path.dirname(fullname), legacy=True, optimize=0):
        os.remove(fullname)


def compile_python_sources(base_dir, files, exclude=None):
    exclude = exclude or []
    patterns = dict()
    try:
        from compileall import compile_file
        patterns['*.py'] = (compile_py_func, compile_file)
    except:
        pass

    regex_exclude = [re.compile(r, re.MULTILINE) for r in exclude]

    for fnext, funcs in patterns.items():
        for fext_file in filter(lambda f: fnmatch.fnmatch(f, fnext), files):
            fext_file = os.path.join(base_dir, fext_file)
            if os.path.exists(fext_file):
                if not any(filter(lambda fp: bool(fp.search(fext_file)), regex_exclude)):
                    func, subfunc = funcs
                    funcs[0](fext_file, funcs[1])
                    print('Compiled {fext_file}.'.format(fext_file=fext_file))


class _Compile(_sdist):
    extensions_dict = dict()
    static_exclude = []

    def __filter_files(self, files):
        for _files in self.extensions_dict.values():
            for file in _files:
                if file in files:
                    files.remove(file)
        return files

    def make_release_tree(self, base_dir, files):
        if has_cython:
            files = self.__filter_files(files)
        _sdist.make_release_tree(self, base_dir, files)
        minify_static_files(base_dir, files, self.static_exclude)

    def run(self):
        return _sdist.run(self)


class GithubRelease(Command):
    '''
    Make release on github via githubrelease
    '''
    description = 'Make release on github via githubrelease'

    user_options = [
        ('body=', 'b', 'Body message.'),
        ('assets=', 'a', 'Release assets patterns.'),
        ('repo=', 'r', 'Repository for release.'),
        ('release=', 'R', 'Release version.'),
        ('dry-run=', 'd', 'Dry run.'),
        ('publish=', 'p', 'Publish release or just create draft.'),
    ]

    def initialize_options(self):
        self.body = None or os.getenv('CI_COMMIT_DESCRIPTION', None)
        self.assets = None
        self.repo = None
        self.dry_run = False
        self.publish = False
        self.release = None or self.distribution.metadata.version

    def finalize_options(self):
        if self.repo is None:
            raise Exception("Parameter --repo is missing")
        if self.release is None:
            raise Exception("Parameter --release is missing")
        self._gh_args = (self.repo, self.release)
        self._gh_kwargs = dict(
            publish=self.publish, name=self.release, dry_run=self.dry_run
        )
        if self.assets:
            assets = self.assets.format(release=self.release)
            assets = list(filter(bool, assets.split('\n')))
            self._gh_kwargs['asset_pattern'] = assets
        if self.body:
            self._gh_kwargs['body'] = self.body

    def run(self):
        from github_release import gh_release_create
        gh_release_create(*self._gh_args, **self._gh_kwargs)


class build_py(build_py_orig):
    exclude = []
    compile_extentions_types = ['.py', '.pyx']
    wheel_extentions_types = ['.c', '.cpp'] + compile_extentions_types

    def _filter_modules(self, module_tuple):
        pkg, mod, file = module_tuple
        try:
            file_name, file_ext = os.path.splitext(file)
            module_name = file_name.replace('/', '.')
        except:
            return True
        if 'bdist_wheel' in sys.argv:
            exclude_list = self.wheel_extentions_types
        elif 'compile' in sys.argv:
            exclude_list = self.compile_extentions_types
        else:
            return True
        if module_name in self.exclude and file_ext in exclude_list:
            return False
        return True

    def find_package_modules(self, package, package_dir):
        modules = build_py_orig.find_package_modules(self, package, package_dir)
        return list(filter(self._filter_modules, modules))


class install_lib(_install_lib):
    exclude = []
    static_exclude = []
    compile_exclude = []

    def _filter_files_with_ext(self, filename):
        _filename, _fext = os.path.splitext(filename)
        if _fext in build_py.wheel_extentions_types:
            return True
        return False

    def install(self):
        result = _install_lib.install(self)
        files = list(listfiles(self.install_dir))
        so_extentions = list(filter(lambda f: fnmatch.fnmatch(f, '*.so'), files))
        for source in filter(self._filter_files_with_ext, files):
            _source_name, _source_ext = os.path.splitext(source)
            if any(filter(lambda f: fnmatch.fnmatch(f, _source_name+"*.so"), so_extentions)):
                print('Removing extention sources [{}].'.format(source))
                os.remove(source)
        minify_static_files('', files, self.static_exclude)
        if os.getenv('BUILD_COMPILE', '') == 'true':
            compile_python_sources('', files, self.compile_exclude)
        return result


def get_compile_command(extensions_dict=None):
    extensions_dict = extensions_dict or dict()
    compile_class = _Compile
    compile_class.extensions_dict = extensions_dict
    return compile_class


def make_setup(**opts):
    if 'packages' not in opts:
        opts['packages'] = find_packages()
    ext_modules_list = opts.pop('ext_modules_list', [])
    ext_mod, ext_mod_dict = make_extensions(ext_modules_list, opts['packages'])
    opts['ext_modules'] = opts.get('ext_modules', []) + ext_mod
    cmdclass = opts.get('cmdclass', dict())
    static_exclude = opts.pop('static_exclude_min', [])
    if 'compile' not in cmdclass:
        compile_class = get_compile_command(ext_mod_dict)
        compile_class.static_exclude = static_exclude
        cmdclass.update({"compile": get_compile_command(ext_mod_dict)})
    if has_cython:
        build_py.exclude = ext_modules_list
        install_lib.static_exclude = static_exclude
        install_lib.compile_exclude = opts.pop('compile_modules_exclude', [])
        cmdclass.update({
            'build_ext': _build_ext,
            'build_py': build_py,
            'install_lib': install_lib
        })
    if has_sphinx and 'build_sphinx' not in cmdclass:
        cmdclass['build_sphinx'] = BuildDoc
    cmdclass['githubrelease'] = GithubRelease
    opts['cmdclass'] = cmdclass

    webpack_path = os.path.join(os.getcwd(), 'webpack.config.js')
    if os.path.exists(webpack_path) and is_build and os.environ.get('DONT_YARN', "") != 'true':
        try:
            subprocess.check_call(['yarn', 'install', '--pure-lockfile', '--mutex network'], stdout=sys.stdout, stderr=sys.stderr)
            subprocess.check_call(['yarn', 'devBuild' if is_develop else 'build'], stdout=sys.stdout, stderr=sys.stderr)
        except Exception as err:
            raise errors.CompileError(str(err))

    setup(**opts)

########################################################################################
# end block

ext_list = []

if 'develop' in sys.argv:
    ext_list = []


kwargs = dict(
    name='pytimeparse2',
    py_modules=['pytimeparse2'],
    ext_modules_list=ext_list,
    install_requires=[],
    project_urls={
        "Issue Tracker": "https://github.com/onegreyonewhite/pytimeparse2/-/issues",
        "Source Code": "https://github.com/onegreyonewhite/pytimeparse2.git",
        "Releases": "https://pypi.org/project/pytimeparse2/#history",
    },
)

make_setup(**kwargs)
0707010000000D000081A4000000000000000000000001645D608F0000A46A000000000000000000000000000000000000001C00000000pytimeparse2-1.7.1/tests.py#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
(c) Sergey Klyuykov <onegreyonewhite@mail.ru> 3 Nov 2021

Unit tests for the `parse` function.
"""

from __future__ import absolute_import

import datetime
import doctest
import re
import pytimeparse2 as timeparse
import unittest
from dateutil.relativedelta import relativedelta


class TestParsing(unittest.TestCase):
    """
    Unit tests for basic regex mat
    """

    def test_mins(self):
        """Test parsing minutes."""
        self.assertEqual(re.match(timeparse.MINS, '32m').groupdict(),
                         {'minutes': '32'})
        self.assertEqual(re.match(timeparse.MINS, '32min').groupdict(),
                         {'minutes': '32'})
        self.assertEqual(re.match(timeparse.MINS, '32mins').groupdict(),
                         {'minutes': '32'})
        self.assertEqual(re.match(timeparse.MINS, '32minute').groupdict(),
                         {'minutes': '32'})
        self.assertEqual(re.match(timeparse.MINS, '32minutes').groupdict(),
                         {'minutes': '32'})
        self.assertEqual(re.match(timeparse.MINS, '32mins').groupdict(),
                         {'minutes': '32'})
        self.assertEqual(re.match(timeparse.MINS, '32min').groupdict(),
                         {'minutes': '32'})

    def test_hrs(self):
        """Test parsing hours."""
        self.assertEqual(re.match(timeparse.HOURS, '32h').groupdict(),
                         {'hours': '32'})
        self.assertEqual(re.match(timeparse.HOURS, '32hr').groupdict(),
                         {'hours': '32'})
        self.assertEqual(re.match(timeparse.HOURS, '32hrs').groupdict(),
                         {'hours': '32'})
        self.assertEqual(re.match(timeparse.HOURS, '32hour').groupdict(),
                         {'hours': '32'})
        self.assertEqual(re.match(timeparse.HOURS, '32hours').groupdict(),
                         {'hours': '32'})
        self.assertEqual(re.match(timeparse.HOURS, '32 hours').groupdict(),
                         {'hours': '32'})
        self.assertEqual(re.match(timeparse.HOURS, '32 h').groupdict(),
                         {'hours': '32'})

    def test_months(self):
        """Test parsing months."""
        self.assertEqual(re.match(timeparse.MONTHS, '32mo').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '32mon').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '32month').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '32months').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '32 mo').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '32 months').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '32mos').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '32mths').groupdict(),
                         {'months': '32'})
        self.assertEqual(re.match(timeparse.MONTHS, '2.3mo').groupdict(),
                         {'months': '2.3'})
        self.assertEqual(re.match(timeparse.MONTHS, '2.5mo').groupdict(),
                         {'months': '2.5'})

    def test_years(self):
        """Test parsing years."""
        self.assertEqual(re.match(timeparse.YEARS, '32y').groupdict(),
                         {'years': '32'})
        self.assertEqual(re.match(timeparse.YEARS, '32ys').groupdict(),
                         {'years': '32'})
        self.assertEqual(re.match(timeparse.YEARS, '32yrs').groupdict(),
                         {'years': '32'})
        self.assertEqual(re.match(timeparse.YEARS, '32year').groupdict(),
                         {'years': '32'})
        self.assertEqual(re.match(timeparse.YEARS, '32years').groupdict(),
                         {'years': '32'})
        self.assertEqual(re.match(timeparse.YEARS, '32 y').groupdict(),
                         {'years': '32'})
        self.assertEqual(re.match(timeparse.YEARS, '32 years').groupdict(),
                         {'years': '32'})
        self.assertEqual(re.match(timeparse.YEARS, '2.3y').groupdict(),
                         {'years': '2.3'})
        self.assertEqual(re.match(timeparse.YEARS, '2.5y').groupdict(),
                         {'years': '2.5'})

    def test_time(self):
        """Test parsing time expression."""
        self.assertGreater(
            set(re.match(timeparse.TIMEFORMATS[0] + r'\s*$',
                         '16h32m64s  ').groupdict().items()),
            set([('hours', '16'), ('minutes', '32'), ('seconds', '64')]))



class TestNumberOutput(unittest.TestCase):
    """
    Unit tests to ensure that numerical outputs are correct
    """

    def test_timeparse_multipliers(self):
        """Test parsing time unit multipliers."""
        self.assertEqual(timeparse.parse('32 min'),
                         1920)
        self.assertEqual(timeparse.parse('1 min'),
                         60)
        self.assertEqual(timeparse.parse('1 hours'),
                         3600)
        self.assertEqual(timeparse.parse('1 day'),
                         86400)
        self.assertEqual(timeparse.parse('1 sec'),
                         1)

    def test_timeparse_signs(self):
        """Test parsing time signs."""
        self.assertEqual(timeparse.parse('+32 m 1 s'), 1921)
        self.assertEqual(timeparse.parse('+ 32 m 1 s'), 1921)
        self.assertEqual(timeparse.parse('-32 m 1 s'), -1921)
        self.assertEqual(timeparse.parse('- 32 m 1 s'), -1921)
        self.assertIsNone(timeparse.parse('32 m - 1 s'))
        self.assertIsNone(timeparse.parse('32 m + 1 s'))

    def test_timeparse_1(self):
        """timeparse test case 1."""
        self.assertEqual(timeparse.parse('32m'), 1920)
        self.assertEqual(timeparse.parse('+32m'), 1920)
        self.assertEqual(timeparse.parse('-32m'), -1920)

    def test_timeparse_2(self):
        """timeparse test case 2."""
        self.assertEqual(timeparse.parse('2h32m'), 9120)
        self.assertEqual(timeparse.parse('+2h32m'), 9120)
        self.assertEqual(timeparse.parse('-2h32m'), -9120)

    def test_timeparse_3(self):
        """timeparse test case 3."""
        self.assertEqual(timeparse.parse('3d2h32m'), 268320)
        self.assertEqual(timeparse.parse('+3d2h32m'), 268320)
        self.assertEqual(timeparse.parse('-3d2h32m'), -268320)

    def test_timeparse_4(self):
        """timeparse test case 4."""
        self.assertEqual(timeparse.parse('1w3d2h32m'), 873120)
        self.assertEqual(timeparse.parse('+1w3d2h32m'), 873120)
        self.assertEqual(timeparse.parse('-1w3d2h32m'), -873120)

    def test_timeparse_5(self):
        """timeparse test case 5."""
        self.assertEqual(timeparse.parse('1w 3d 2h 32m'), 873120)
        self.assertEqual(timeparse.parse('+1w 3d 2h 32m'), 873120)
        self.assertEqual(timeparse.parse('-1w 3d 2h 32m'), -873120)

    def test_timeparse_6(self):
        """timeparse test case 6."""
        self.assertEqual(timeparse.parse('1 w 3 d 2 h 32 m'), 873120)
        self.assertEqual(timeparse.parse('+1 w 3 d 2 h 32 m'), 873120)
        self.assertEqual(timeparse.parse('-1 w 3 d 2 h 32 m'), -873120)

    def test_timeparse_7(self):
        """timeparse test case 7."""
        self.assertEqual(timeparse.parse('4:13'), 253)
        self.assertEqual(timeparse.parse('+4:13'), 253)
        self.assertEqual(timeparse.parse('-4:13'), -253)

    def test_timeparse_bare_seconds(self):
        """timeparse test bare seconds, without minutes."""
        self.assertEqual(timeparse.parse(':13'), 13)
        self.assertEqual(timeparse.parse('+:13'), 13)
        self.assertEqual(timeparse.parse('-:13'), -13)

    def test_timeparse_8(self):
        """timeparse test case 8."""
        self.assertEqual(timeparse.parse('4:13:02'), 15182)
        self.assertEqual(timeparse.parse('+4:13:02'), 15182)
        self.assertEqual(timeparse.parse('-4:13:02'), -15182)

    def test_timeparse_9(self):
        """timeparse test case 9."""
        self.assertAlmostEqual(timeparse.parse('4:13:02.266'), 15182.266)
        self.assertAlmostEqual(timeparse.parse('+4:13:02.266'), 15182.266)
        self.assertAlmostEqual(timeparse.parse('-4:13:02.266'), -15182.266)

    def test_timeparse_10(self):
        """timeparse test case 10."""
        self.assertAlmostEqual(timeparse.parse('2:04:13:02.266'),
                               187982.266)
        self.assertAlmostEqual(timeparse.parse('+2:04:13:02.266'),
                               187982.266)
        self.assertAlmostEqual(timeparse.parse('-2:04:13:02.266'),
                               -187982.266)

    def test_timeparse_granularity_1(self):
        """Check that minute-level granularity applies correctly."""
        self.assertEqual(timeparse.parse('4:32', granularity='minutes'), 272*60)
        self.assertEqual(timeparse.parse('+4:32', granularity='minutes'), 272*60)
        self.assertEqual(timeparse.parse('-4:32', granularity='minutes'), -272*60)

    def test_timeparse_granularity_2(self):
        """Check that minute-level granularity does not apply inappropriately."""
        self.assertEqual(timeparse.parse('4:32:02', granularity='minutes'), 272*60+2)
        self.assertEqual(timeparse.parse('+4:32:02', granularity='minutes'), 272*60+2)
        self.assertEqual(timeparse.parse('-4:32:02', granularity='minutes'), -(272*60+2))

    def test_timeparse_granularity_3(self):
        """Check that minute-level granularity does not apply inappropriately."""
        self.assertAlmostEqual(timeparse.parse('7:02.223', granularity='minutes'), 7*60 + 2.223)
        self.assertAlmostEqual(timeparse.parse('+7:02.223', granularity='minutes'), 7*60 + 2.223)
        self.assertAlmostEqual(timeparse.parse('-7:02.223', granularity='minutes'), -(7*60 + 2.223))

    def test_timeparse_granularity_4(self):
        """Check that minute-level granularity does not apply inappropriately."""
        self.assertEqual(timeparse.parse('0:02', granularity='seconds'), 2)
        self.assertEqual(timeparse.parse('+0:02', granularity='seconds'), 2)
        self.assertEqual(timeparse.parse('-0:02', granularity='seconds'), -2)

    def test_timeparse_unparsed(self):
        """Check that unparsed values tries to converts into int(). """
        self.assertEqual(timeparse.parse(100), 100)
        self.assertEqual(timeparse.parse(-18.333), -18.333)
        self.assertEqual(timeparse.parse('99.1'), 99.1)
        self.assertEqual(timeparse.parse('-99.1'), -99.1)

    def test_timeparse_11(self):
        """timeparse test case 11."""
        # uptime format
        self.assertEqual(timeparse.parse('2 days,  4:13:02'), 187982)
        self.assertEqual(timeparse.parse('+2 days,  4:13:02'), 187982)
        self.assertEqual(timeparse.parse('-2 days,  4:13:02'), -187982)

    def test_timeparse_12(self):
        """timeparse test case 12."""
        self.assertAlmostEqual(timeparse.parse('2 days,  4:13:02.266'),
                               187982.266)
        self.assertAlmostEqual(timeparse.parse('+2 days,  4:13:02.266'),
                               187982.266)
        self.assertAlmostEqual(timeparse.parse('-2 days,  4:13:02.266'),
                               -187982.266)

    def test_timeparse_13(self):
        """timeparse test case 13."""
        self.assertEqual(timeparse.parse('5hr34m56s'), 20096)
        self.assertEqual(timeparse.parse('+5hr34m56s'), 20096)
        self.assertEqual(timeparse.parse('-5hr34m56s'), -20096)

    def test_timeparse_14(self):
        """timeparse test case 14."""
        self.assertEqual(timeparse.parse('5 hours, 34 minutes, 56 seconds'),
                         20096)
        self.assertEqual(timeparse.parse('+5 hours, 34 minutes, 56 seconds'),
                         20096)
        self.assertEqual(timeparse.parse('-5 hours, 34 minutes, 56 seconds'),
                         -20096)

    def test_timeparse_15(self):
        """timeparse test case 15."""
        self.assertEqual(timeparse.parse('5 hrs, 34 mins, 56 secs'), 20096)
        self.assertEqual(timeparse.parse('+5 hrs, 34 mins, 56 secs'), 20096)
        self.assertEqual(timeparse.parse('-5 hrs, 34 mins, 56 secs'), -20096)

    def test_timeparse_16(self):
        """timeparse test case 16."""
        self.assertEqual(
            timeparse.parse('2 days, 5 hours, 34 minutes, 56 seconds'),
            192896)
        self.assertEqual(
            timeparse.parse('+2 days, 5 hours, 34 minutes, 56 seconds'),
            192896)
        self.assertEqual(
            timeparse.parse('-2 days, 5 hours, 34 minutes, 56 seconds'),
            -192896)

    def test_timeparse_16b(self):
        """timeparse test case 16b."""
        self.assertAlmostEqual(timeparse.parse('1.75 s'), 1.75)
        self.assertAlmostEqual(timeparse.parse('+1.75 s'), 1.75)
        self.assertAlmostEqual(timeparse.parse('-1.75 s'), -1.75)

    def test_timeparse_16c(self):
        """timeparse test case 16c."""
        self.assertAlmostEqual(timeparse.parse('1.75 sec'), 1.75)
        self.assertAlmostEqual(timeparse.parse('+1.75 sec'), 1.75)
        self.assertAlmostEqual(timeparse.parse('-1.75 sec'), -1.75)

    def test_timeparse_16d(self):
        """timeparse test case 16d."""
        self.assertAlmostEqual(timeparse.parse('1.75 secs'), 1.75)
        self.assertAlmostEqual(timeparse.parse('+1.75 secs'), 1.75)
        self.assertAlmostEqual(timeparse.parse('-1.75 secs'), -1.75)

    def test_timeparse_16e(self):
        """timeparse test case 16e."""
        self.assertAlmostEqual(timeparse.parse('1.75 second'), 1.75)
        self.assertAlmostEqual(timeparse.parse('+1.75 second'), 1.75)
        self.assertAlmostEqual(timeparse.parse('-1.75 second'), -1.75)

    def test_timeparse_16f(self):
        """timeparse test case 16f."""
        self.assertAlmostEqual(timeparse.parse('1.75 seconds'), 1.75)
        self.assertAlmostEqual(timeparse.parse('+1.75 seconds'), 1.75)
        self.assertAlmostEqual(timeparse.parse('-1.75 seconds'), -1.75)

    def test_timeparse_17(self):
        """timeparse test case 17."""
        self.assertEqual(timeparse.parse('1.2 m'), 72)
        self.assertEqual(timeparse.parse('+1.2 m'), 72)
        self.assertEqual(timeparse.parse('-1.2 m'), -72)

    def test_timeparse_18(self):
        """timeparse test case 18."""
        self.assertEqual(timeparse.parse('1.2 min'), 72)
        self.assertEqual(timeparse.parse('+1.2 min'), 72)
        self.assertEqual(timeparse.parse('-1.2 min'), -72)

    def test_timeparse_19(self):
        """timeparse test case 19."""
        self.assertEqual(timeparse.parse('1.2 mins'), 72)
        self.assertEqual(timeparse.parse('+1.2 mins'), 72)
        self.assertEqual(timeparse.parse('-1.2 mins'), -72)

    def test_timeparse_20(self):
        """timeparse test case 20."""
        self.assertEqual(timeparse.parse('1.2 minute'), 72)
        self.assertEqual(timeparse.parse('+1.2 minute'), 72)
        self.assertEqual(timeparse.parse('-1.2 minute'), -72)

    def test_timeparse_21(self):
        """timeparse test case 21."""
        self.assertEqual(timeparse.parse('1.2 minutes'), 72)
        self.assertEqual(timeparse.parse('+1.2 minutes'), 72)
        self.assertEqual(timeparse.parse('-1.2 minutes'), -72)

    def test_timeparse_22(self):
        """timeparse test case 22."""
        self.assertEqual(timeparse.parse('172 hours'), 619200)
        self.assertEqual(timeparse.parse('+172 hours'), 619200)
        self.assertEqual(timeparse.parse('-172 hours'), -619200)

    def test_timeparse_23(self):
        """timeparse test case 23."""
        self.assertEqual(timeparse.parse('172 hr'), 619200)
        self.assertEqual(timeparse.parse('+172 hr'), 619200)
        self.assertEqual(timeparse.parse('-172 hr'), -619200)

    def test_timeparse_24(self):
        """timeparse test case 24."""
        self.assertEqual(timeparse.parse('172 h'), 619200)
        self.assertEqual(timeparse.parse('+172 h'), 619200)
        self.assertEqual(timeparse.parse('-172 h'), -619200)

    def test_timeparse_25(self):
        """timeparse test case 25."""
        self.assertEqual(timeparse.parse('172 hrs'), 619200)
        self.assertEqual(timeparse.parse('+172 hrs'), 619200)
        self.assertEqual(timeparse.parse('-172 hrs'), -619200)

    def test_timeparse_26(self):
        """timeparse test case 26."""
        self.assertEqual(timeparse.parse('172 hour'), 619200)
        self.assertEqual(timeparse.parse('+172 hour'), 619200)
        self.assertEqual(timeparse.parse('-172 hour'), -619200)

    def test_timeparse_27(self):
        """timeparse test case 27."""
        self.assertEqual(timeparse.parse('1.24 days'), 107136)
        self.assertEqual(timeparse.parse('+1.24 days'), 107136)
        self.assertEqual(timeparse.parse('-1.24 days'), -107136)

    def test_timeparse_28(self):
        """timeparse test case 28."""
        self.assertEqual(timeparse.parse('5 d'), 432000)
        self.assertEqual(timeparse.parse('+5 d'), 432000)
        self.assertEqual(timeparse.parse('-5 d'), -432000)

    def test_timeparse_29(self):
        """timeparse test case 29."""
        self.assertEqual(timeparse.parse('5 day'), 432000)
        self.assertEqual(timeparse.parse('+5 day'), 432000)
        self.assertEqual(timeparse.parse('-5 day'), -432000)

    def test_timeparse_30(self):
        """timeparse test case 30."""
        self.assertEqual(timeparse.parse('5 days'), 432000)
        self.assertEqual(timeparse.parse('+5 days'), 432000)
        self.assertEqual(timeparse.parse('-5 days'), -432000)

    def test_timeparse_31(self):
        """timeparse test case 31."""
        self.assertEqual(timeparse.parse('5.6 wk'), 3386880)
        self.assertEqual(timeparse.parse('+5.6 wk'), 3386880)
        self.assertEqual(timeparse.parse('-5.6 wk'), -3386880)

    def test_timeparse_32(self):
        """timeparse test case 32."""
        self.assertEqual(timeparse.parse('5.6 week'), 3386880)
        self.assertEqual(timeparse.parse('+5.6 week'), 3386880)
        self.assertEqual(timeparse.parse('-5.6 week'), -3386880)

    def test_timeparse_33(self):
        """timeparse test case 33."""
        self.assertEqual(timeparse.parse('5.6 weeks'), 3386880)
        self.assertEqual(timeparse.parse('+5.6 weeks'), 3386880)
        self.assertEqual(timeparse.parse('-5.6 weeks'), -3386880)

    def test_milliseconds(self):
        self.assertEqual(timeparse.parse('3 ms'), 0.003)
        self.assertEqual(timeparse.parse('3 millis'), 0.003)
        self.assertEqual(timeparse.parse('3 msecs'), 0.003)
        self.assertEqual(timeparse.parse('3 milliseconds'), 0.003)

    def test_plain_numbers(self):
        self.assertEqual(timeparse.parse('10'), 10)
        self.assertEqual(timeparse.parse('10.1'), 10.1)
        self.assertEqual(timeparse.parse('-10'), -10)
        self.assertEqual(timeparse.parse('-10.1'), -10.1)

    def test_combined(self):
        self.assertEqual(timeparse.parse('1y2mo3w4d5h6m7s8ms'), 38898367.008)




class TestRelativeDeltaOutput(unittest.TestCase):
    """
    Unit tests to ensure that numerical outputs are correct
    """

    def test_timeparse_multipliers(self):
        """Test parsing time unit multipliers."""
        self.assertEqual(timeparse.parse('32 min', as_timedelta=True), relativedelta(minutes=32))
        self.assertEqual(timeparse.parse('1 min', as_timedelta=True), relativedelta(minutes=1))
        self.assertEqual(timeparse.parse('1 hours', as_timedelta=True), relativedelta(hours=1))
        self.assertEqual(timeparse.parse('1 day', as_timedelta=True), relativedelta(days=1))
        self.assertEqual(timeparse.parse('1 sec', as_timedelta=True), relativedelta(seconds=1))

    def test_timeparse_signs(self):
        """Test parsing time signs."""
        self.assertEqual(timeparse.parse('+32 m 1 s', as_timedelta=True), relativedelta(minutes=32, seconds=1))
        self.assertEqual(timeparse.parse('+ 32 m 1 s', as_timedelta=True), relativedelta(minutes=32, seconds=1))
        self.assertEqual(timeparse.parse('-32 m 1 s', as_timedelta=True), -relativedelta(minutes=32, seconds=1))
        self.assertEqual(timeparse.parse('- 32 m 1 s', as_timedelta=True), -relativedelta(minutes=32, seconds=1))
        self.assertIsNone(timeparse.parse('32 m - 1 s', as_timedelta=True))
        self.assertIsNone(timeparse.parse('32 m + 1 s', as_timedelta=True))

    def test_timeparse_1(self):
        """timeparse test case 1."""
        self.assertEqual(timeparse.parse('32m', as_timedelta=True), relativedelta(minutes=32))
        self.assertEqual(timeparse.parse('+32m', as_timedelta=True), relativedelta(minutes=32))
        self.assertEqual(timeparse.parse('-32m', as_timedelta=True), -relativedelta(minutes=32))

    def test_timeparse_2(self):
        """timeparse test case 2."""
        self.assertEqual(timeparse.parse('2h32m', as_timedelta=True), relativedelta(hours=2, minutes=32))
        self.assertEqual(timeparse.parse('+2h32m', as_timedelta=True), relativedelta(hours=2, minutes=32))
        self.assertEqual(timeparse.parse('-2h32m', as_timedelta=True), -relativedelta(hours=2, minutes=32))

    def test_timeparse_3(self):
        """timeparse test case 3."""
        self.assertEqual(timeparse.parse('3d2h32m', as_timedelta=True), relativedelta(days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('+3d2h32m', as_timedelta=True), relativedelta(days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('-3d2h32m', as_timedelta=True), -relativedelta(days=3, hours=2, minutes=32))

    def test_timeparse_4(self):
        """timeparse test case 4."""
        self.assertEqual(timeparse.parse('1w3d2h32m', as_timedelta=True), relativedelta(weeks=1, days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('+1w3d2h32m', as_timedelta=True), relativedelta(weeks=1, days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('-1w3d2h32m', as_timedelta=True), -relativedelta(weeks=1, days=3, hours=2, minutes=32))

    def test_timeparse_5(self):
        """timeparse test case 5."""
        self.assertEqual(timeparse.parse('1w 3d 2h 32m', as_timedelta=True), relativedelta(weeks=1, days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('+1w 3d 2h 32m', as_timedelta=True), relativedelta(weeks=1, days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('-1w 3d 2h 32m', as_timedelta=True), -relativedelta(weeks=1, days=3, hours=2, minutes=32))

    def test_timeparse_6(self):
        """timeparse test case 6."""
        self.assertEqual(timeparse.parse('1 w 3 d 2 h 32 m', as_timedelta=True), relativedelta(weeks=1, days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('+1 w 3 d 2 h 32 m', as_timedelta=True), relativedelta(weeks=1, days=3, hours=2, minutes=32))
        self.assertEqual(timeparse.parse('-1 w 3 d 2 h 32 m', as_timedelta=True), -relativedelta(weeks=1, days=3, hours=2, minutes=32))

    def test_timeparse_7(self):
        """timeparse test case 7."""
        self.assertEqual(timeparse.parse('4:13', as_timedelta=True), relativedelta(minutes=4, seconds=13))
        self.assertEqual(timeparse.parse('+4:13', as_timedelta=True), relativedelta(minutes=4, seconds=13))
        self.assertEqual(timeparse.parse('-4:13', as_timedelta=True), -relativedelta(minutes=4, seconds=13))

    def test_timeparse_bare_seconds(self):
        """timeparse test bare seconds, without minutes."""
        self.assertEqual(timeparse.parse(':13', as_timedelta=True), relativedelta(seconds=13))
        self.assertEqual(timeparse.parse('+:13', as_timedelta=True), relativedelta(seconds=13))
        self.assertEqual(timeparse.parse('-:13', as_timedelta=True), -relativedelta(seconds=13))

    def test_timeparse_8(self):
        """timeparse test case 8."""
        self.assertEqual(timeparse.parse('4:13:02', as_timedelta=True), relativedelta(hours=4, minutes=13, seconds=2))
        self.assertEqual(timeparse.parse('+4:13:02', as_timedelta=True), relativedelta(hours=4, minutes=13, seconds=2))
        self.assertEqual(timeparse.parse('-4:13:02', as_timedelta=True), -relativedelta(hours=4, minutes=13, seconds=2))

    def test_timeparse_9(self):
        """timeparse test case 9."""
        self.assertEqual(timeparse.parse('4:13:02.266', as_timedelta=True), relativedelta(hours=4, minutes=13, seconds=2, microseconds=266*1000))
        self.assertEqual(timeparse.parse('+4:13:02.266', as_timedelta=True), relativedelta(hours=4, minutes=13, seconds=2, microseconds=266*1000))
        self.assertEqual(timeparse.parse('-4:13:02.266', as_timedelta=True), -relativedelta(hours=4, minutes=13, seconds=2, microseconds=266*1000))

    def test_timeparse_10(self):
        """timeparse test case 10."""
        self.assertEqual(timeparse.parse('2:04:13:02.266', as_timedelta=True), relativedelta(days=2, hours=4, minutes=13, seconds=2, microseconds=266*1000))
        self.assertEqual(timeparse.parse('+2:04:13:02.266', as_timedelta=True), relativedelta(days=2, hours=4, minutes=13, seconds=2, microseconds=266*1000))
        self.assertEqual(timeparse.parse('-2:04:13:02.266', as_timedelta=True), -relativedelta(days=2, hours=4, minutes=13, seconds=2, microseconds=266*1000))

    def test_timeparse_granularity_1(self):
        """Check that minute-level granularity applies correctly."""
        self.assertEqual(timeparse.parse('4:32', granularity='minutes', as_timedelta=True), relativedelta(hours=4, minutes=32))
        self.assertEqual(timeparse.parse('+4:32', granularity='minutes', as_timedelta=True), relativedelta(hours=4, minutes=32))
        self.assertEqual(timeparse.parse('-4:32', granularity='minutes', as_timedelta=True), -relativedelta(hours=4, minutes=32))

    def test_timeparse_granularity_2(self):
        """Check that minute-level granularity does not apply inappropriately."""
        self.assertEqual(timeparse.parse('4:32:02', granularity='minutes', as_timedelta=True), relativedelta(hours=4, minutes=32, seconds=2))
        self.assertEqual(timeparse.parse('+4:32:02', granularity='minutes', as_timedelta=True), relativedelta(hours=4, minutes=32, seconds=2))
        self.assertEqual(timeparse.parse('-4:32:02', granularity='minutes', as_timedelta=True), -relativedelta(hours=4, minutes=32, seconds=2))

    def test_timeparse_granularity_3(self):
        """Check that minute-level granularity does not apply inappropriately."""
        self.assertEqual(timeparse.parse('7:02.223', granularity='minutes', as_timedelta=True), relativedelta(minutes=7, seconds=2, microseconds=1000*223))
        self.assertEqual(timeparse.parse('+7:02.223', granularity='minutes', as_timedelta=True), relativedelta(minutes=7, seconds=2, microseconds=1000*223))
        self.assertEqual(timeparse.parse('-7:02.223', granularity='minutes', as_timedelta=True), -relativedelta(minutes=7, seconds=2, microseconds=1000*223))

    def test_timeparse_granularity_4(self):
        """Check that minute-level granularity does not apply inappropriately."""
        self.assertEqual(timeparse.parse('0:02', granularity='seconds', as_timedelta=True), relativedelta(seconds=2))
        self.assertEqual(timeparse.parse('+0:02', granularity='seconds', as_timedelta=True), relativedelta(seconds=2))
        self.assertEqual(timeparse.parse('-0:02', granularity='seconds', as_timedelta=True), -relativedelta(seconds=2))

    def test_timeparse_unparsed(self):
        """Check that unparsed values tries to converts into int(). """
        self.assertEqual(timeparse.parse(100, as_timedelta=True), relativedelta(seconds=100))
        self.assertEqual(timeparse.parse(-18.333, as_timedelta=True), -relativedelta(seconds=18, microseconds=333*1000))
        self.assertEqual(timeparse.parse('99.1', as_timedelta=True), relativedelta(seconds=99, microseconds=100*1000))
        self.assertEqual(timeparse.parse('-99.1', as_timedelta=True), -relativedelta(seconds=99, microseconds=100*1000))

    def test_timeparse_11(self):
        """timeparse test case 11."""
        # uptime format
        self.assertEqual(timeparse.parse('2 days,  4:13:02', as_timedelta=True), relativedelta(days=2, hours=4, minutes=13, seconds=2))
        self.assertEqual(timeparse.parse('+2 days,  4:13:02', as_timedelta=True), relativedelta(days=2, hours=4, minutes=13, seconds=2))
        self.assertEqual(timeparse.parse('-2 days,  4:13:02', as_timedelta=True), -relativedelta(days=2, hours=4, minutes=13, seconds=2))

    def test_timeparse_12(self):
        """timeparse test case 12."""
        self.assertEqual(timeparse.parse('2 days,  4:13:02.266', as_timedelta=True), relativedelta(days=2, hours=4, minutes=13, seconds=2, microseconds=1000*266))
        self.assertEqual(timeparse.parse('+2 days,  4:13:02.266', as_timedelta=True), relativedelta(days=2, hours=4, minutes=13, seconds=2, microseconds=1000*266))
        self.assertEqual(timeparse.parse('-2 days,  4:13:02.266', as_timedelta=True), -relativedelta(days=2, hours=4, minutes=13, seconds=2, microseconds=1000*266))

    def test_timeparse_13(self):
        """timeparse test case 13."""
        self.assertEqual(timeparse.parse('5hr34m56s', as_timedelta=True), relativedelta(hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('+5hr34m56s', as_timedelta=True), relativedelta(hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('-5hr34m56s', as_timedelta=True), -relativedelta(hours=5, minutes=34, seconds=56))

    def test_timeparse_14(self):
        """timeparse test case 14."""
        self.assertEqual(timeparse.parse('5 hours, 34 minutes, 56 seconds', as_timedelta=True), relativedelta(hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('+5 hours, 34 minutes, 56 seconds', as_timedelta=True), relativedelta(hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('-5 hours, 34 minutes, 56 seconds', as_timedelta=True), -relativedelta(hours=5, minutes=34, seconds=56))

    def test_timeparse_15(self):
        """timeparse test case 15."""
        self.assertEqual(timeparse.parse('5 hrs, 34 mins, 56 secs', as_timedelta=True), relativedelta(hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('+5 hrs, 34 mins, 56 secs', as_timedelta=True), relativedelta(hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('-5 hrs, 34 mins, 56 secs', as_timedelta=True), -relativedelta(hours=5, minutes=34, seconds=56))

    def test_timeparse_16(self):
        """timeparse test case 16."""
        self.assertEqual(timeparse.parse('2 days, 5 hours, 34 minutes, 56 seconds', as_timedelta=True), relativedelta(days=2, hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('+2 days, 5 hours, 34 minutes, 56 seconds', as_timedelta=True), relativedelta(days=2, hours=5, minutes=34, seconds=56))
        self.assertEqual(timeparse.parse('-2 days, 5 hours, 34 minutes, 56 seconds', as_timedelta=True), -relativedelta(days=2, hours=5, minutes=34, seconds=56))

    def test_timeparse_16b(self):
        """timeparse test case 16b."""
        self.assertEqual(timeparse.parse('1.75 s', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('+1.75 s', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('-1.75 s', as_timedelta=True), -relativedelta(seconds=1, microseconds=75*10000))

    def test_timeparse_16c(self):
        """timeparse test case 16c."""
        self.assertEqual(timeparse.parse('1.75 sec', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('+1.75 sec', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('-1.75 sec', as_timedelta=True), -relativedelta(seconds=1, microseconds=75*10000))

    def test_timeparse_16d(self):
        """timeparse test case 16d."""
        self.assertEqual(timeparse.parse('1.75 secs', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('+1.75 secs', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('-1.75 secs', as_timedelta=True), -relativedelta(seconds=1, microseconds=75*10000))

    def test_timeparse_16e(self):
        """timeparse test case 16e."""
        self.assertEqual(timeparse.parse('1.75 second', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('+1.75 second', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('-1.75 second', as_timedelta=True), -relativedelta(seconds=1, microseconds=75*10000))

    def test_timeparse_16f(self):
        """timeparse test case 16f."""
        self.assertEqual(timeparse.parse('1.75 seconds', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('+1.75 seconds', as_timedelta=True), relativedelta(seconds=1, microseconds=75*10000))
        self.assertEqual(timeparse.parse('-1.75 seconds', as_timedelta=True), -relativedelta(seconds=1, microseconds=75*10000))

    def test_timeparse_17(self):
        """timeparse test case 17."""
        self.assertEqual(timeparse.parse('1.2 m', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('+1.2 m', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('-1.2 m', as_timedelta=True), -relativedelta(minutes=1, seconds=12))

    def test_timeparse_18(self):
        """timeparse test case 18."""
        self.assertEqual(timeparse.parse('1.2 min', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('+1.2 min', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('-1.2 min', as_timedelta=True), -relativedelta(minutes=1, seconds=12))

    def test_timeparse_19(self):
        """timeparse test case 19."""
        self.assertEqual(timeparse.parse('1.2 mins', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('+1.2 mins', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('-1.2 mins', as_timedelta=True), -relativedelta(minutes=1, seconds=12))

    def test_timeparse_20(self):
        """timeparse test case 20."""
        self.assertEqual(timeparse.parse('1.2 minute', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('+1.2 minute', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('-1.2 minute', as_timedelta=True), -relativedelta(minutes=1, seconds=12))

    def test_timeparse_21(self):
        """timeparse test case 21."""
        self.assertEqual(timeparse.parse('1.2 minutes', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('+1.2 minutes', as_timedelta=True), relativedelta(minutes=1, seconds=12))
        self.assertEqual(timeparse.parse('-1.2 minutes', as_timedelta=True), -relativedelta(minutes=1, seconds=12))

    def test_timeparse_22(self):
        """timeparse test case 22."""
        self.assertEqual(timeparse.parse('172 hours', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('+172 hours', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('-172 hours', as_timedelta=True), -relativedelta(hours=172))

    def test_timeparse_23(self):
        """timeparse test case 23."""
        self.assertEqual(timeparse.parse('172 hr', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('+172 hr', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('-172 hr', as_timedelta=True), -relativedelta(hours=172))

    def test_timeparse_24(self):
        """timeparse test case 24."""
        self.assertEqual(timeparse.parse('172 h', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('+172 h', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('-172 h', as_timedelta=True), -relativedelta(hours=172))

    def test_timeparse_25(self):
        """timeparse test case 25."""
        self.assertEqual(timeparse.parse('172 hrs', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('+172 hrs', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('-172 hrs', as_timedelta=True), -relativedelta(hours=172))

    def test_timeparse_26(self):
        """timeparse test case 26."""
        self.assertEqual(timeparse.parse('172 hour', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('+172 hour', as_timedelta=True), relativedelta(hours=172))
        self.assertEqual(timeparse.parse('-172 hour', as_timedelta=True), -relativedelta(hours=172))

    def test_timeparse_27(self):
        """timeparse test case 27."""
        self.assertEqual(timeparse.parse('1.24 days', as_timedelta=True), relativedelta(days=1, hours=5, minutes=45, seconds=36))
        self.assertEqual(timeparse.parse('+1.24 days', as_timedelta=True), relativedelta(days=1, hours=5, minutes=45, seconds=36))
        self.assertEqual(timeparse.parse('-1.24 days', as_timedelta=True), -relativedelta(days=1, hours=5, minutes=45, seconds=36))

    def test_timeparse_28(self):
        """timeparse test case 28."""
        self.assertEqual(timeparse.parse('5 d', as_timedelta=True), relativedelta(days=5))
        self.assertEqual(timeparse.parse('+5 d', as_timedelta=True), relativedelta(days=5))
        self.assertEqual(timeparse.parse('-5 d', as_timedelta=True), -relativedelta(days=5))

    def test_timeparse_29(self):
        """timeparse test case 29."""
        self.assertEqual(timeparse.parse('5 day', as_timedelta=True), relativedelta(days=5))
        self.assertEqual(timeparse.parse('+5 day', as_timedelta=True), relativedelta(days=5))
        self.assertEqual(timeparse.parse('-5 day', as_timedelta=True), -relativedelta(days=5))

    def test_timeparse_30(self):
        """timeparse test case 30."""
        self.assertEqual(timeparse.parse('5 days', as_timedelta=True), relativedelta(days=5))
        self.assertEqual(timeparse.parse('+5 days', as_timedelta=True), relativedelta(days=5))
        self.assertEqual(timeparse.parse('-5 days', as_timedelta=True), -relativedelta(days=5))

    def test_timeparse_31(self):
        """timeparse test case 31."""
        self.assertEqual(timeparse.parse('5.6 wk', as_timedelta=True), relativedelta(days=39, hours=4, minutes=48))
        self.assertEqual(timeparse.parse('+5.6 wk', as_timedelta=True), relativedelta(days=39, hours=4, minutes=48))
        self.assertEqual(timeparse.parse('-5.6 wk', as_timedelta=True), -relativedelta(days=39, hours=4, minutes=48))

    def test_timeparse_32(self):
        """timeparse test case 32."""
        self.assertEqual(timeparse.parse('5.6 week', as_timedelta=True), relativedelta(days=39, hours=4, minutes=48))
        self.assertEqual(timeparse.parse('+5.6 week', as_timedelta=True), relativedelta(days=39, hours=4, minutes=48))
        self.assertEqual(timeparse.parse('-5.6 week', as_timedelta=True), -relativedelta(days=39, hours=4, minutes=48))

    def test_timeparse_33(self):
        """timeparse test case 33."""
        self.assertEqual(timeparse.parse('5.6 weeks', as_timedelta=True), relativedelta(days=39, hours=4, minutes=48))
        self.assertEqual(timeparse.parse('+5.6 weeks', as_timedelta=True), relativedelta(days=39, hours=4, minutes=48))
        self.assertEqual(timeparse.parse('-5.6 weeks', as_timedelta=True), -relativedelta(days=39, hours=4, minutes=48))

    def test_milliseconds(self):
        self.assertEqual(timeparse.parse('3 ms', as_timedelta=True), relativedelta(microseconds=3000))
        self.assertEqual(timeparse.parse('3 millis', as_timedelta=True), relativedelta(microseconds=3000))
        self.assertEqual(timeparse.parse('3 msecs', as_timedelta=True), relativedelta(microseconds=3000))
        self.assertEqual(timeparse.parse('3 milliseconds', as_timedelta=True), relativedelta(microseconds=3000))

    def test_plain_numbers(self):
        self.assertEqual(timeparse.parse('10', as_timedelta=True), relativedelta(seconds=10))
        self.assertEqual(timeparse.parse('10.1', as_timedelta=True), relativedelta(seconds=10, microseconds=100000))
        self.assertEqual(timeparse.parse('-10', as_timedelta=True), -relativedelta(seconds=10))
        self.assertEqual(timeparse.parse('-10.1', as_timedelta=True), -relativedelta(seconds=10, microseconds=100000))

    def test_combined(self):
        self.assertEqual(timeparse.parse('1y2mo3w4d5h6m7s8ms', as_timedelta=True), relativedelta(years=1, months=2, weeks=3, days=4, hours=5, minutes=6, seconds=7, microseconds=8000))



class MiscTests(unittest.TestCase):
    """
    Miscellaneous unit tests for the `timeparse` module.
    """

    def test_strange(self):
        self.assertIsNone(timeparse.parse('1.1.1:22'))

    def test_doctest(self):
        """Run timeparse doctests."""
        self.assertTrue(doctest.testmod(timeparse, raise_on_error=True))

    def test_disable_dateutil(self):
        self.assertNotIsInstance(timeparse.parse('10:10', as_timedelta=True), datetime.timedelta)
        timeparse.disable_dateutil()
        self.assertIsInstance(timeparse.parse('10:10', as_timedelta=True), datetime.timedelta)
        timeparse.enable_dateutil()
        self.assertNotIsInstance(timeparse.parse('10:10', as_timedelta=True), datetime.timedelta)




if __name__ == '__main__':
    unittest.main('tests')
0707010000000E000081A4000000000000000000000001645D608F000006CC000000000000000000000000000000000000001B00000000pytimeparse2-1.7.1/tox.ini[tox]
envlist = flake,mypy,py36-coverage,py3{7,8,9,10,11}-install
skipsdist = True

[gh-actions]
python =
    3.6: flake,mypy,py36-coverage
    3.7: py37-install
    3.8: py38-install
    3.9: py39-install
    3.10: py310-install
    3.11: py311-install

[testenv]
setenv =
    CCACHE_DIR = {envdir}/.ccache
passenv =
    CC
allowlist_externals =
    rm
    ls
    ln
    bash
    pwd
    cd
    find
    xargs
commands =
  pwd
  pip uninstall pytimeparse2 -y
  install: rm -rfv {envdir}/dist/
  install: python {toxinidir}/setup.py bdist_wheel --dist-dir {envdir}/dist/
  install: bash -c "pip install -U {envdir}/dist/$(ls {envdir}/dist)[dateutil]"
  coverage: python setup.py install_egg_info
  coverage: pip install -U -e .[dateutil]
  install: bash -c "cd {envdir} && python {toxinidir}/tests.py -vv --failfast"
  coverage: coverage debug sys
  coverage: coverage erase
  coverage: coverage run tests.py -vv --failfast {posargs}
  coverage: coverage combine
  coverage: coverage report
  rm -rf .eggs build pytimeparse2.egg-info {envdir}/dist
  install: pip uninstall pytimeparse2 -y
deps =
    coverage: coverage~=5.1
    mock==3.0.5

[testenv:flake]
basepython = python3.6
deps =
    flake8
commands =
  flake8 --config=.pep8 pytimeparse2.py

[testenv:mypy]
basepython = python3.6
deps =
    mypy
    types-python-dateutil
commands =
  mypy pytimeparse2.py


[testenv:contrib]
basepython = python3.6
skipsdist = True
envdir = {toxinidir}/venv
passenv = *
allowlist_externals = *
commands =
    python setup.py install_egg_info
    pip install -U -e .
deps =
   tox

[testenv:build]
passenv = *
changedir = .
allowlist_externals =
    tox
    rm
commands =
    rm -rf dist build
    tox -c tox_build.ini --workdir {toxworkdir}
deps =
0707010000000F000081A4000000000000000000000001645D608F00000121000000000000000000000000000000000000002100000000pytimeparse2-1.7.1/tox_build.ini[tox]
envlist = py36-{wheel,build}
skipsdist = True

[testenv]
passenv = *
changedir = .
whitelist_externals =
    rm
    ls
    grep
    bash
commands =
  rm -rf build
  build: python setup.py compile -v
  wheel: python setup.py bdist_wheel -v
deps =
  wheel==0.31.1
  setuptools>=40.6.3
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!151 blocks
openSUSE Build Service is sponsored by