Hello community,

here is the log from the commit of package python-croniter for openSUSE:Factory 
checked in at 2020-11-26 23:15:17
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-croniter (Old)
 and      /work/SRC/openSUSE:Factory/.python-croniter.new.5913 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-croniter"

Thu Nov 26 23:15:17 2020 rev:14 rq:850942 version:0.3.36

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-croniter/python-croniter.changes  
2020-07-17 20:51:49.208981002 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-croniter.new.5913/python-croniter.changes    
    2020-11-26 23:16:11.877075064 +0100
@@ -1,0 +2,12 @@
+Thu Nov 26 09:22:47 UTC 2020 - Dirk Mueller <dmuel...@suse.com>
+
+- update to 0.3.36:
+- Updated docs section regarding ``max_years_between_matches`` to be more 
shorter and hopefully more relevant.
+- Add a new initialization parameter ``max_years_between_matches`` to support 
finding the next/previous date beyond the default 1 year window, if so desired. 
 Updated README to include additional notes and example of this usage.  Fixes 
#145.
+- The ``croniter_range()`` function was updated to automatically determines 
the appropriate ``max_years_between_matches`` value, this preventing handling 
of the ``CroniterBadDateError`` exception.
+- Updated exception handling classes:  ``CroniterBadDateError`` now only
+  applies during date finding operations (next/prev), and all parsing errors 
can now be caught using ``CroniterBadCronError``.  The 
``CroniterNotAlphaError`` exception is now a subclass of 
``CroniterBadCronError``.  A brief description of each exception class was 
added as an inline docstring.
+- Updated iterable interfaces to replace the ``CroniterBadDateError`` with 
``StopIteration`` if (and only if) the ``max_years_between_matches`` argument 
is provided.  The rationale here is that if the user has specified the max 
tolerance between matches, then there's no need to further inform them of no 
additional matches.  Just stop the iteration.  This also keeps backwards 
compatibility.
+- Minor docs update
+
+-------------------------------------------------------------------

Old:
----
  croniter-0.3.34.tar.gz

New:
----
  croniter-0.3.36.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-croniter.spec ++++++
--- /var/tmp/diff_new_pack.dM8S6n/_old  2020-11-26 23:16:12.485075536 +0100
+++ /var/tmp/diff_new_pack.dM8S6n/_new  2020-11-26 23:16:12.489075539 +0100
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-croniter
-Version:        0.3.34
+Version:        0.3.36
 Release:        0
 Summary:        Python iterators for datetime objects with cron-like format
 License:        MIT

++++++ croniter-0.3.34.tar.gz -> croniter-0.3.36.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/croniter-0.3.34/PKG-INFO new/croniter-0.3.36/PKG-INFO
--- old/croniter-0.3.34/PKG-INFO        2020-06-19 15:28:16.774030200 +0200
+++ new/croniter-0.3.36/PKG-INFO        2020-11-02 17:09:51.354224200 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: croniter
-Version: 0.3.34
+Version: 0.3.36
 Summary: croniter provides iteration for datetime object with cron like format
 Home-page: http://github.com/kiorky/croniter
 Author: Matsumoto Taichi, kiorky
@@ -144,10 +144,37 @@
             >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0, 
0), day_or=False) # 04:02 on every 1st day of the month if it is a Wednesday
             False
         
+        Gaps between date matches
+        =========================
+        For performance reasons, croniter limits the amount of CPU cycles 
spent attempting to find the next match.
+        Starting in v0.3.35, this behavior is configurable via the 
``max_years_between_matches`` parameter, and the default window has been 
increased from 1 year to 50 years.
+        
+        The defaults should be fine for many use cases.
+        Applications that evaluate multiple cron expressions or handle cron 
expressions from untrusted sources or end-users should use this parameter.
+        Iterating over sparse cron expressions can result in increased CPU 
consumption or a raised ``CroniterBadDateError`` exception which indicates that 
croniter has given up attempting to find the next (or previous) match.
+        Explicitly specifying ``max_years_between_matches`` provides a way to 
limit CPU utilization and simplifies the iterable interface by eliminating the 
need for ``CroniterBadDateError``.
+        The difference in the iterable interface is based on the reasoning 
that whenever ``max_years_between_matches`` is explicitly agreed upon, there is 
no need for croniter to signal that it has given up; simply stopping the 
iteration is preferable.
+        
+        This example matches 4 AM Friday, January 1st.
+        Since January 1st isn't often a Friday, there may be a few years 
between each occurrence.
+        Setting the limit to 15 years ensures all matches::
+        
+            >>> it = croniter("0 4 1 1 fri", datetime(2000,1,1), day_or=False, 
max_years_between_matches=15).all_next(datetime)
+            >>> for i in range(5):
+            ...     print(next(it))
+            ...
+            2010-01-01 04:00:00
+            2016-01-01 04:00:00
+            2021-01-01 04:00:00
+            2027-01-01 04:00:00
+            2038-01-01 04:00:00
+        
+        However, when only concerned with dates within the next 5 years, 
simply set ``max_years_between_matches=5`` in the above example.
+        This will result in no matches found, but no additional cycles will be 
wasted on unwanted matches far in the future.
         
         Iterating over a range using cron
         =================================
-        Finding all matching times in at time range can be handled with the 
``croniter_range()`` function.  This is much like the builtin 
``range(start,stop,step)`` function, but for dates using a cron expression as 
"step".
+        Find matches within a range using the ``croniter_range()`` function.  
This is much like the builtin ``range(start,stop,step)`` function, but for 
dates.  The `step` argument is a cron expression.
         Added in (>=0.3.34)
         
         List the first Saturday of every month in 2019::
@@ -156,6 +183,7 @@
             >>> for dt in croniter_range(datetime(2019, 1, 1), datetime(2019, 
12, 31), "0 0 * * sat#1"):
             >>>     print(dt)
         
+        
         Develop this package
         ====================
         
@@ -197,18 +225,48 @@
             - chris-baynes
             - ipartola
             - yuzawa-san
+            - lowell80 (Kintyre)
+            - scop
         
         
         Changelog
         ==============
         
+        0.3.36 (2020-11-02)
+        -------------------
+        
+        - Nothing changed yet.
+        - Updated docs section regarding ``max_years_between_matches`` to be 
more shorter and hopefully more relevant.
+          [Kintyre]
+        - Don't install tests
+          [scop]
+        
+        
+        0.3.35 (2020-10-11)
+        -------------------
+        
+        - Handle L in ranges. This fixes #142.
+          [kiorky]
+        - Add a new initialization parameter ``max_years_between_matches`` to 
support finding the next/previous date beyond the default 1 year window, if so 
desired.  Updated README to include additional notes and example of this usage. 
 Fixes #145.
+          [Kintyre]
+        - The ``croniter_range()`` function was updated to automatically 
determines the appropriate ``max_years_between_matches`` value, this preventing 
handling of the ``CroniterBadDateError`` exception.
+          [Kintyre]
+        - Updated exception handling classes:  ``CroniterBadDateError`` now 
only
+          applies during date finding operations (next/prev), and all parsing 
errors can now be caught using ``CroniterBadCronError``.  The 
``CroniterNotAlphaError`` exception is now a subclass of 
``CroniterBadCronError``.  A brief description of each exception class was 
added as an inline docstring.
+          [Kintyre]
+        - Updated iterable interfaces to replace the ``CroniterBadDateError`` 
with ``StopIteration`` if (and only if) the ``max_years_between_matches`` 
argument is provided.  The rationale here is that if the user has specified the 
max tolerance between matches, then there's no need to further inform them of 
no additional matches.  Just stop the iteration.  This also keeps backwards 
compatibility.
+          [Kintyre]
+        - Minor docs update
+          [Kintyre]
+        
+        
         0.3.34 (2020-06-19)
         -------------------
         
-        - Feat croniter_range(start, stop, cron)
-          [Kintyr]
+        - Feat ``croniter_range(start, stop, cron)``
+          [Kintyre]
         - Optimization for poorly written cron expression
-          [Kintyr]
+          [Kintyre]
         
         0.3.33 (2020-06-15)
         -------------------
@@ -268,7 +326,7 @@
         0.3.23 (2018-05-23)
         -------------------
         
-        - fix ``get_next`` while perserving the fix of ``get_prev`` in 
7661c2aaa
+        - fix ``get_next`` while preserving the fix of ``get_prev`` in 
7661c2aaa
           [Avikam Agur <avi...@pagaya-inv.com>]
         
         
@@ -360,7 +418,7 @@
         0.3.10 (2015-11-29)
         -------------------
         
-        - The fuctionality of 'l' as day of month was broken, since the month 
variable
+        - The functionality of 'l' as day of month was broken, since the month 
variable
           was not properly updated
           [Iddo Aviram <iddo.avi...@similarweb.com>]
         
@@ -401,7 +459,7 @@
         ------------------
         
         - Python 3 compat
-        - QA Relase
+        - QA Release
         
         
         0.3.3 (2012-09-29)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/croniter-0.3.34/README.rst 
new/croniter-0.3.36/README.rst
--- old/croniter-0.3.34/README.rst      2020-06-19 15:28:16.000000000 +0200
+++ new/croniter-0.3.36/README.rst      2020-11-02 17:09:51.000000000 +0100
@@ -136,10 +136,37 @@
     >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0, 0), 
day_or=False) # 04:02 on every 1st day of the month if it is a Wednesday
     False
 
+Gaps between date matches
+=========================
+For performance reasons, croniter limits the amount of CPU cycles spent 
attempting to find the next match.
+Starting in v0.3.35, this behavior is configurable via the 
``max_years_between_matches`` parameter, and the default window has been 
increased from 1 year to 50 years.
+
+The defaults should be fine for many use cases.
+Applications that evaluate multiple cron expressions or handle cron 
expressions from untrusted sources or end-users should use this parameter.
+Iterating over sparse cron expressions can result in increased CPU consumption 
or a raised ``CroniterBadDateError`` exception which indicates that croniter 
has given up attempting to find the next (or previous) match.
+Explicitly specifying ``max_years_between_matches`` provides a way to limit 
CPU utilization and simplifies the iterable interface by eliminating the need 
for ``CroniterBadDateError``.
+The difference in the iterable interface is based on the reasoning that 
whenever ``max_years_between_matches`` is explicitly agreed upon, there is no 
need for croniter to signal that it has given up; simply stopping the iteration 
is preferable.
+
+This example matches 4 AM Friday, January 1st.
+Since January 1st isn't often a Friday, there may be a few years between each 
occurrence.
+Setting the limit to 15 years ensures all matches::
+
+    >>> it = croniter("0 4 1 1 fri", datetime(2000,1,1), day_or=False, 
max_years_between_matches=15).all_next(datetime)
+    >>> for i in range(5):
+    ...     print(next(it))
+    ...
+    2010-01-01 04:00:00
+    2016-01-01 04:00:00
+    2021-01-01 04:00:00
+    2027-01-01 04:00:00
+    2038-01-01 04:00:00
+
+However, when only concerned with dates within the next 5 years, simply set 
``max_years_between_matches=5`` in the above example.
+This will result in no matches found, but no additional cycles will be wasted 
on unwanted matches far in the future.
 
 Iterating over a range using cron
 =================================
-Finding all matching times in at time range can be handled with the 
``croniter_range()`` function.  This is much like the builtin 
``range(start,stop,step)`` function, but for dates using a cron expression as 
"step".
+Find matches within a range using the ``croniter_range()`` function.  This is 
much like the builtin ``range(start,stop,step)`` function, but for dates.  The 
`step` argument is a cron expression.
 Added in (>=0.3.34)
 
 List the first Saturday of every month in 2019::
@@ -148,6 +175,7 @@
     >>> for dt in croniter_range(datetime(2019, 1, 1), datetime(2019, 12, 31), 
"0 0 * * sat#1"):
     >>>     print(dt)
 
+
 Develop this package
 ====================
 
@@ -189,3 +217,5 @@
     - chris-baynes
     - ipartola
     - yuzawa-san
+    - lowell80 (Kintyre)
+    - scop
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/croniter-0.3.34/docs/CHANGES.rst 
new/croniter-0.3.36/docs/CHANGES.rst
--- old/croniter-0.3.34/docs/CHANGES.rst        2020-06-19 15:28:16.000000000 
+0200
+++ new/croniter-0.3.36/docs/CHANGES.rst        2020-11-02 17:09:51.000000000 
+0100
@@ -1,13 +1,41 @@
 Changelog
 ==============
 
+0.3.36 (2020-11-02)
+-------------------
+
+- Nothing changed yet.
+- Updated docs section regarding ``max_years_between_matches`` to be more 
shorter and hopefully more relevant.
+  [Kintyre]
+- Don't install tests
+  [scop]
+
+
+0.3.35 (2020-10-11)
+-------------------
+
+- Handle L in ranges. This fixes #142.
+  [kiorky]
+- Add a new initialization parameter ``max_years_between_matches`` to support 
finding the next/previous date beyond the default 1 year window, if so desired. 
 Updated README to include additional notes and example of this usage.  Fixes 
#145.
+  [Kintyre]
+- The ``croniter_range()`` function was updated to automatically determines 
the appropriate ``max_years_between_matches`` value, this preventing handling 
of the ``CroniterBadDateError`` exception.
+  [Kintyre]
+- Updated exception handling classes:  ``CroniterBadDateError`` now only
+  applies during date finding operations (next/prev), and all parsing errors 
can now be caught using ``CroniterBadCronError``.  The 
``CroniterNotAlphaError`` exception is now a subclass of 
``CroniterBadCronError``.  A brief description of each exception class was 
added as an inline docstring.
+  [Kintyre]
+- Updated iterable interfaces to replace the ``CroniterBadDateError`` with 
``StopIteration`` if (and only if) the ``max_years_between_matches`` argument 
is provided.  The rationale here is that if the user has specified the max 
tolerance between matches, then there's no need to further inform them of no 
additional matches.  Just stop the iteration.  This also keeps backwards 
compatibility.
+  [Kintyre]
+- Minor docs update
+  [Kintyre]
+
+
 0.3.34 (2020-06-19)
 -------------------
 
-- Feat croniter_range(start, stop, cron)
-  [Kintyr]
+- Feat ``croniter_range(start, stop, cron)``
+  [Kintyre]
 - Optimization for poorly written cron expression
-  [Kintyr]
+  [Kintyre]
 
 0.3.33 (2020-06-15)
 -------------------
@@ -67,7 +95,7 @@
 0.3.23 (2018-05-23)
 -------------------
 
-- fix ``get_next`` while perserving the fix of ``get_prev`` in 7661c2aaa
+- fix ``get_next`` while preserving the fix of ``get_prev`` in 7661c2aaa
   [Avikam Agur <avi...@pagaya-inv.com>]
 
 
@@ -159,7 +187,7 @@
 0.3.10 (2015-11-29)
 -------------------
 
-- The fuctionality of 'l' as day of month was broken, since the month variable
+- The functionality of 'l' as day of month was broken, since the month variable
   was not properly updated
   [Iddo Aviram <iddo.avi...@similarweb.com>]
 
@@ -200,7 +228,7 @@
 ------------------
 
 - Python 3 compat
-- QA Relase
+- QA Release
 
 
 0.3.3 (2012-09-29)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/croniter-0.3.34/setup.py new/croniter-0.3.36/setup.py
--- old/croniter-0.3.34/setup.py        2020-06-19 15:28:16.000000000 +0200
+++ new/croniter-0.3.36/setup.py        2020-11-02 17:09:51.000000000 +0100
@@ -23,7 +23,7 @@
 
 setup(
     name='croniter',
-    version='0.3.34',
+    version='0.3.36',
     py_modules=['croniter', ],
     description=(
         'croniter provides iteration for datetime '
@@ -52,7 +52,8 @@
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: 3.7",
         "Topic :: Software Development :: Libraries :: Python Modules"],
-    packages=find_packages('src'),
+    packages=find_packages('src', exclude=['tests*', '*.tests*']),
     package_dir={'': 'src'},
     include_package_data=True,
+    exclude_package_data={'croniter': ['tests/*']},
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/croniter-0.3.34/src/croniter/croniter.py 
new/croniter-0.3.36/src/croniter/croniter.py
--- old/croniter-0.3.34/src/croniter/croniter.py        2020-06-19 
15:28:16.000000000 +0200
+++ new/croniter-0.3.36/src/croniter/croniter.py        2020-11-02 
17:09:51.000000000 +0100
@@ -21,18 +21,22 @@
 
 
 class CroniterError(ValueError):
+    """ General top-level Croniter base exception """
     pass
 
 
 class CroniterBadCronError(CroniterError):
+    """ Syntax, unknown value, or range error within a cron expression """
     pass
 
 
 class CroniterBadDateError(CroniterError):
+    """ Unable to find next/prev timestamp match """
     pass
 
 
-class CroniterNotAlphaError(CroniterError):
+class CroniterNotAlphaError(CroniterBadCronError):
+    """ Cron syntax contains an invalid day or month abreviation """
     pass
 
 
@@ -51,12 +55,15 @@
     )
 
     ALPHACONV = (
-        {},
-        {},
-        {"l": "l"},
+        {},  # 0: min
+        {},  # 1: hour
+        {"l": "l"},  # 2: dom
+        # 3: mon
         {'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'may': 5, 'jun': 6,
          'jul': 7, 'aug': 8, 'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12},
+        # 4: dow
         {'sun': 0, 'mon': 1, 'tue': 2, 'wed': 3, 'thu': 4, 'fri': 5, 'sat': 6},
+        # command/user
         {}
     )
 
@@ -82,10 +89,16 @@
                  'expression.'
 
     def __init__(self, expr_format, start_time=None, ret_type=float,
-                 day_or=True):
+                 day_or=True, max_years_between_matches=None, is_prev=False):
         self._ret_type = ret_type
         self._day_or = day_or
 
+        self._max_years_btw_matches_explicitly_set = (
+            max_years_between_matches is not None)
+        if not self._max_years_btw_matches_explicitly_set:
+            max_years_between_matches = 50
+        self._max_years_between_matches = max(int(max_years_between_matches), 
1)
+
         if start_time is None:
             start_time = time()
 
@@ -97,6 +110,7 @@
         self.set_current(start_time)
 
         self.expanded, self.nth_weekday_of_month = self.expand(expr_format)
+        self._is_prev = is_prev
 
     @classmethod
     def _alphaconv(cls, index, key, expressions):
@@ -161,30 +175,10 @@
         return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) \
             / 10**6
 
-    # iterator protocol, to enable direct use of croniter
-    # objects in a loop, like "for dt in croniter('5 0 * * *'): ..."
-    # or for combining multiple croniters into single
-    # dates feed using 'itertools' module
-    def __iter__(self):
-        return self
-    __next__ = next = get_next
-
-    def all_next(self, ret_type=None):
-        '''Generator of all consecutive dates. Can be used instead of
-        implicit call to __iter__, whenever non-default
-        'ret_type' has to be specified.
-        '''
-        while True:
-            yield self._get_next(ret_type or self._ret_type, is_prev=False)
-
-    def all_prev(self, ret_type=None):
-        '''Generator of all previous dates.'''
-        while True:
-            yield self._get_next(ret_type or self._ret_type, is_prev=True)
-
-    iter = all_next  # alias, you can call .iter() instead of .all_next()
-
-    def _get_next(self, ret_type=None, is_prev=False):
+    def _get_next(self, ret_type=None, is_prev=None):
+        if is_prev is None:
+            is_prev = self._is_prev
+        self._is_prev = is_prev
         expanded = self.expanded[:]
         nth_weekday_of_month = self.nth_weekday_of_month.copy()
 
@@ -242,6 +236,45 @@
             result = dtresult
         return result
 
+    # iterator protocol, to enable direct use of croniter
+    # objects in a loop, like "for dt in croniter('5 0 * * *'): ..."
+    # or for combining multiple croniters into single
+    # dates feed using 'itertools' module
+    def all_next(self, ret_type=None):
+        '''Generator of all consecutive dates. Can be used instead of
+        implicit call to __iter__, whenever non-default
+        'ret_type' has to be specified.
+        '''
+        # In a Python 3.7+ world:  contextlib.supress and 
contextlib.nullcontext could be used instead
+        try:
+            while True:
+                self._is_prev = False
+                yield self._get_next(ret_type or self._ret_type)
+        except CroniterBadDateError:
+            if self._max_years_btw_matches_explicitly_set:
+                return
+            else:
+                raise
+
+    def all_prev(self, ret_type=None):
+        '''Generator of all previous dates.'''
+        try:
+            while True:
+                self._is_prev = True
+                yield self._get_next(ret_type or self._ret_type)
+        except CroniterBadDateError:
+            if self._max_years_btw_matches_explicitly_set:
+                return
+            else:
+                raise
+
+    def iter(self, *args, **kwargs):
+        return (self._is_prev and self.all_prev or self.all_next)
+
+    def __iter__(self):
+        return self
+    __next__ = next = _get_next
+
     def _calc(self, now, expanded, nth_weekday_of_month, is_prev):
         if is_prev:
             now = math.ceil(now)
@@ -414,7 +447,7 @@
                  proc_minute,
                  proc_second]
 
-        while abs(year - current_year) <= 1:
+        while abs(year - current_year) <= self._max_years_between_matches:
             next = False
             for proc in procs:
                 (changed, dst) = proc(dst)
@@ -502,7 +535,7 @@
                 if i == 4:
                     e, sep, nth = str(e).partition('#')
                     if nth and not re.match(r'[1-5]', nth):
-                        raise CroniterBadDateError(
+                        raise CroniterBadCronError(
                             "[{0}] is not acceptable".format(expr_format))
 
                 t = re.sub(r'^\*(\/.+)$', r'%d-%d\1' % (
@@ -519,6 +552,8 @@
 
                 if m:
                     (low, high, step) = m.group(1), m.group(2), m.group(4) or 1
+                    if i == 2 and high == 'l':
+                        high = '31'
 
                     if not any_int_re.search(low):
                         low = "{0}".format(cls._alphaconv(i, low, expressions))
@@ -534,7 +569,7 @@
                             # handle -Sun notation -> 7
                             high = '7'
                         else:
-                            raise CroniterBadDateError(
+                            raise CroniterBadCronError(
                                 "[{0}] is not acceptable".format(expr_format))
 
                     low, high, step = map(int, [low, high, step])
@@ -633,7 +668,9 @@
         else:               # Reverse time order
             start += ms1
             stop -= ms1
-    ic = croniter(expr_format, start, ret_type=datetime.datetime, 
day_or=day_or)
+    year_span = math.floor(abs(stop.year - start.year)) + 1
+    ic = croniter(expr_format, start, ret_type=datetime.datetime, 
day_or=day_or,
+                  max_years_between_matches=year_span)
     # define a continue (cont) condition function and step function for the 
main while loop
     if start < stop:        # Forward
         def cont(v):
@@ -643,11 +680,14 @@
         def cont(v):
             return v > stop
         step = ic.get_prev
-
-    dt = step()
-    while cont(dt):
-        if ret_type is float:
-            yield ic.get_current(float)
-        else:
-            yield dt
+    try:
         dt = step()
+        while cont(dt):
+            if ret_type is float:
+                yield ic.get_current(float)
+            else:
+                yield dt
+            dt = step()
+    except CroniterBadDateError:
+        # Stop iteration when this exception is raised; no match found within 
the given year range
+        return
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/croniter-0.3.34/src/croniter/tests/test_croniter.py 
new/croniter-0.3.36/src/croniter/tests/test_croniter.py
--- old/croniter-0.3.34/src/croniter/tests/test_croniter.py     2020-06-19 
15:28:16.000000000 +0200
+++ new/croniter-0.3.36/src/croniter/tests/test_croniter.py     2020-11-02 
17:09:51.000000000 +0100
@@ -6,6 +6,7 @@
 from functools import partial
 from time import sleep
 import pytz
+import croniter as cr
 from croniter import croniter, croniter_range, CroniterBadDateError, 
CroniterBadCronError, CroniterNotAlphaError
 from croniter.tests import base
 from tzlocal import get_localzone
@@ -303,7 +304,7 @@
         """ Non-optimal cron expressions that can be simplified."""
         wildcard = ['*']
         m, h, d, mon, dow, s = range(6)
-        # Test each field individually 
+        # Test each field individually
         self.assertEqual(croniter('0-59 0 0 0 0').expanded[m], wildcard)
         self.assertEqual(croniter('0 0-23 0 0 0').expanded[h], wildcard)
         self.assertEqual(croniter('0 0 0-31 0 0').expanded[d], wildcard)
@@ -1182,6 +1183,108 @@
             "2020-03-09T03:00:00-04:00",
             "2020-03-10T03:00:00-04:00"])
 
+    def test_issue_142_dow(self):
+        ret = []
+        for i in range(1, 31):
+            ret.append((i,
+                croniter('35 * 0-l/8 * *', datetime(2020, 1, i),
+                         ret_type=datetime).get_next())
+            )
+            i += 1
+        self.assertEqual(
+            ret,
+            [(1, datetime(2020, 1, 1, 0, 35)),
+             (2, datetime(2020, 1, 8, 0, 35)),
+             (3, datetime(2020, 1, 8, 0, 35)),
+             (4, datetime(2020, 1, 8, 0, 35)),
+             (5, datetime(2020, 1, 8, 0, 35)),
+             (6, datetime(2020, 1, 8, 0, 35)),
+             (7, datetime(2020, 1, 8, 0, 35)),
+             (8, datetime(2020, 1, 8, 0, 35)),
+             (9, datetime(2020, 1, 16, 0, 35)),
+             (10, datetime(2020, 1, 16, 0, 35)),
+             (11, datetime(2020, 1, 16, 0, 35)),
+             (12, datetime(2020, 1, 16, 0, 35)),
+             (13, datetime(2020, 1, 16, 0, 35)),
+             (14, datetime(2020, 1, 16, 0, 35)),
+             (15, datetime(2020, 1, 16, 0, 35)),
+             (16, datetime(2020, 1, 16, 0, 35)),
+             (17, datetime(2020, 1, 24, 0, 35)),
+             (18, datetime(2020, 1, 24, 0, 35)),
+             (19, datetime(2020, 1, 24, 0, 35)),
+             (20, datetime(2020, 1, 24, 0, 35)),
+             (21, datetime(2020, 1, 24, 0, 35)),
+             (22, datetime(2020, 1, 24, 0, 35)),
+             (23, datetime(2020, 1, 24, 0, 35)),
+             (24, datetime(2020, 1, 24, 0, 35)),
+             (25, datetime(2020, 2, 1, 0, 35)),
+             (26, datetime(2020, 2, 1, 0, 35)),
+             (27, datetime(2020, 2, 1, 0, 35)),
+             (28, datetime(2020, 2, 1, 0, 35)),
+             (29, datetime(2020, 2, 1, 0, 35)),
+             (30, datetime(2020, 2, 1, 0, 35))])
+
+    def test_issue145_getnext(self):
+        # Example of quarterly event cron schedule
+        start = datetime(2020, 9, 24)
+        cron = "0 13 8 1,4,7,10 wed"
+        with self.assertRaises(CroniterBadDateError):
+            it = croniter(cron, start, day_or=False, 
max_years_between_matches=1)
+            it.get_next()
+        # New functionality (0.3.35) allowing croniter to find spare matches 
of cron patterns across multiple years
+        it = croniter(cron, start, day_or=False, max_years_between_matches=5)
+        self.assertEqual(it.get_next(datetime), datetime(2025, 1, 8, 13))
+
+    def test_issue145_range(self):
+        cron = "0 13 8 1,4,7,10 wed"
+        matches = list(croniter_range(datetime(2020, 1, 1), datetime(2020, 12, 
31), cron, day_or=False))
+        self.assertEqual(len(matches), 3)
+        self.assertEqual(matches[0], datetime(2020, 1, 8, 13))
+        self.assertEqual(matches[1], datetime(2020, 4, 8, 13))
+        self.assertEqual(matches[2], datetime(2020, 7, 8, 13))
+
+        # No matches within this range; therefore expect empty list
+        matches = list(croniter_range(datetime(2020, 9, 30), datetime(2020, 
10, 30), cron, day_or=False))
+        self.assertEqual(len(matches), 0)
+
+    def test_explicit_year_forward(self):
+        start = datetime(2020, 9, 24)
+        cron = "0 13 8 1,4,7,10 wed"
+
+        # Expect exception because no explict range was provided.  Therefore, 
the caller should be made aware that an implicit limit was hit.
+        ccron = croniter(cron, start, day_or=False)
+        ccron._max_years_between_matches = 1
+        iterable = ccron.all_next()
+        with self.assertRaises(CroniterBadDateError):
+            next(iterable)
+
+        iterable = croniter(cron, start, day_or=False, 
max_years_between_matches=5).all_next(datetime)
+        n = next(iterable)
+        self.assertEqual(n, datetime(2025, 1, 8, 13))
+
+        # If the explictly given lookahead isn't enough to reach the next 
date, that's fine.  The caller specified the maximum gap, so no just stop 
iteration
+        iterable = croniter(cron, start, day_or=False, 
max_years_between_matches=2).all_next(datetime)
+        with self.assertRaises(StopIteration):
+            next(iterable)
+
+    def test_explicit_year_reverse(self):
+        start = datetime(2025, 1, 1)
+        cron = "0 13 8 1,4,7,10 wed"
+
+        ccron = croniter(cron, start, day_or=False)
+        ccron._max_years_between_matches = 1
+        iterable = ccron.all_prev()
+        with self.assertRaises(CroniterBadDateError):
+            next(iterable)
+
+        iterable = croniter(cron, start, day_or=False, 
max_years_between_matches=5).all_prev(datetime)
+        n = next(iterable)
+        self.assertEqual(n, datetime(2020, 7, 8, 13))
+
+        iterable = croniter(cron, start, day_or=False, 
max_years_between_matches=2).all_prev()
+        with self.assertRaises(StopIteration):
+            next(iterable)
+
 
 if __name__ == '__main__':
     unittest.main()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/croniter-0.3.34/src/croniter.egg-info/PKG-INFO 
new/croniter-0.3.36/src/croniter.egg-info/PKG-INFO
--- old/croniter-0.3.34/src/croniter.egg-info/PKG-INFO  2020-06-19 
15:28:16.000000000 +0200
+++ new/croniter-0.3.36/src/croniter.egg-info/PKG-INFO  2020-11-02 
17:09:51.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: croniter
-Version: 0.3.34
+Version: 0.3.36
 Summary: croniter provides iteration for datetime object with cron like format
 Home-page: http://github.com/kiorky/croniter
 Author: Matsumoto Taichi, kiorky
@@ -144,10 +144,37 @@
             >>> croniter.match("2 4 1 * wed", datetime(2019, 1, 1, 4, 2, 0, 
0), day_or=False) # 04:02 on every 1st day of the month if it is a Wednesday
             False
         
+        Gaps between date matches
+        =========================
+        For performance reasons, croniter limits the amount of CPU cycles 
spent attempting to find the next match.
+        Starting in v0.3.35, this behavior is configurable via the 
``max_years_between_matches`` parameter, and the default window has been 
increased from 1 year to 50 years.
+        
+        The defaults should be fine for many use cases.
+        Applications that evaluate multiple cron expressions or handle cron 
expressions from untrusted sources or end-users should use this parameter.
+        Iterating over sparse cron expressions can result in increased CPU 
consumption or a raised ``CroniterBadDateError`` exception which indicates that 
croniter has given up attempting to find the next (or previous) match.
+        Explicitly specifying ``max_years_between_matches`` provides a way to 
limit CPU utilization and simplifies the iterable interface by eliminating the 
need for ``CroniterBadDateError``.
+        The difference in the iterable interface is based on the reasoning 
that whenever ``max_years_between_matches`` is explicitly agreed upon, there is 
no need for croniter to signal that it has given up; simply stopping the 
iteration is preferable.
+        
+        This example matches 4 AM Friday, January 1st.
+        Since January 1st isn't often a Friday, there may be a few years 
between each occurrence.
+        Setting the limit to 15 years ensures all matches::
+        
+            >>> it = croniter("0 4 1 1 fri", datetime(2000,1,1), day_or=False, 
max_years_between_matches=15).all_next(datetime)
+            >>> for i in range(5):
+            ...     print(next(it))
+            ...
+            2010-01-01 04:00:00
+            2016-01-01 04:00:00
+            2021-01-01 04:00:00
+            2027-01-01 04:00:00
+            2038-01-01 04:00:00
+        
+        However, when only concerned with dates within the next 5 years, 
simply set ``max_years_between_matches=5`` in the above example.
+        This will result in no matches found, but no additional cycles will be 
wasted on unwanted matches far in the future.
         
         Iterating over a range using cron
         =================================
-        Finding all matching times in at time range can be handled with the 
``croniter_range()`` function.  This is much like the builtin 
``range(start,stop,step)`` function, but for dates using a cron expression as 
"step".
+        Find matches within a range using the ``croniter_range()`` function.  
This is much like the builtin ``range(start,stop,step)`` function, but for 
dates.  The `step` argument is a cron expression.
         Added in (>=0.3.34)
         
         List the first Saturday of every month in 2019::
@@ -156,6 +183,7 @@
             >>> for dt in croniter_range(datetime(2019, 1, 1), datetime(2019, 
12, 31), "0 0 * * sat#1"):
             >>>     print(dt)
         
+        
         Develop this package
         ====================
         
@@ -197,18 +225,48 @@
             - chris-baynes
             - ipartola
             - yuzawa-san
+            - lowell80 (Kintyre)
+            - scop
         
         
         Changelog
         ==============
         
+        0.3.36 (2020-11-02)
+        -------------------
+        
+        - Nothing changed yet.
+        - Updated docs section regarding ``max_years_between_matches`` to be 
more shorter and hopefully more relevant.
+          [Kintyre]
+        - Don't install tests
+          [scop]
+        
+        
+        0.3.35 (2020-10-11)
+        -------------------
+        
+        - Handle L in ranges. This fixes #142.
+          [kiorky]
+        - Add a new initialization parameter ``max_years_between_matches`` to 
support finding the next/previous date beyond the default 1 year window, if so 
desired.  Updated README to include additional notes and example of this usage. 
 Fixes #145.
+          [Kintyre]
+        - The ``croniter_range()`` function was updated to automatically 
determines the appropriate ``max_years_between_matches`` value, this preventing 
handling of the ``CroniterBadDateError`` exception.
+          [Kintyre]
+        - Updated exception handling classes:  ``CroniterBadDateError`` now 
only
+          applies during date finding operations (next/prev), and all parsing 
errors can now be caught using ``CroniterBadCronError``.  The 
``CroniterNotAlphaError`` exception is now a subclass of 
``CroniterBadCronError``.  A brief description of each exception class was 
added as an inline docstring.
+          [Kintyre]
+        - Updated iterable interfaces to replace the ``CroniterBadDateError`` 
with ``StopIteration`` if (and only if) the ``max_years_between_matches`` 
argument is provided.  The rationale here is that if the user has specified the 
max tolerance between matches, then there's no need to further inform them of 
no additional matches.  Just stop the iteration.  This also keeps backwards 
compatibility.
+          [Kintyre]
+        - Minor docs update
+          [Kintyre]
+        
+        
         0.3.34 (2020-06-19)
         -------------------
         
-        - Feat croniter_range(start, stop, cron)
-          [Kintyr]
+        - Feat ``croniter_range(start, stop, cron)``
+          [Kintyre]
         - Optimization for poorly written cron expression
-          [Kintyr]
+          [Kintyre]
         
         0.3.33 (2020-06-15)
         -------------------
@@ -268,7 +326,7 @@
         0.3.23 (2018-05-23)
         -------------------
         
-        - fix ``get_next`` while perserving the fix of ``get_prev`` in 
7661c2aaa
+        - fix ``get_next`` while preserving the fix of ``get_prev`` in 
7661c2aaa
           [Avikam Agur <avi...@pagaya-inv.com>]
         
         
@@ -360,7 +418,7 @@
         0.3.10 (2015-11-29)
         -------------------
         
-        - The fuctionality of 'l' as day of month was broken, since the month 
variable
+        - The functionality of 'l' as day of month was broken, since the month 
variable
           was not properly updated
           [Iddo Aviram <iddo.avi...@similarweb.com>]
         
@@ -401,7 +459,7 @@
         ------------------
         
         - Python 3 compat
-        - QA Relase
+        - QA Release
         
         
         0.3.3 (2012-09-29)
_______________________________________________
openSUSE Commits mailing list -- commit@lists.opensuse.org
To unsubscribe, email commit-le...@lists.opensuse.org
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives: 
https://lists.opensuse.org/archives/list/commit@lists.opensuse.org

Reply via email to