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 <[email protected]>
+
+- 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 <[email protected]>]
@@ -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 <[email protected]>]
@@ -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 <[email protected]>]
@@ -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 <[email protected]>]
@@ -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 <[email protected]>]
@@ -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 <[email protected]>]
@@ -401,7 +459,7 @@
------------------
- Python 3 compat
- - QA Relase
+ - QA Release
0.3.3 (2012-09-29)
_______________________________________________
openSUSE Commits mailing list -- [email protected]
To unsubscribe, email [email protected]
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives:
https://lists.opensuse.org/archives/list/[email protected]