calendar

BSD calendar reimplementation
git clone https://git.ce9e.org/calendar.git

commit
8b21c1b6efa2db806f9d883135d444eba10ebee1
parent
ba88811233a4cf28432ca3b89aa47b1670b3198c
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2020-04-23 08:06
rm python implementation

Diffstat

D cal.py 285 ------------------------------------------------------------
D setup.py 51 ---------------------------------------------------
D test.py 296 ------------------------------------------------------------
D tox.ini 19 -------------------

4 files changed, 0 insertions, 651 deletions


diff --git a/cal.py b/cal.py

@@ -1,285 +0,0 @@
    1    -1 #!/usr/bin/env python
    2    -1 """BSD calendar reimplementation
    3    -1 
    4    -1 The calendar utility reads events from plain text files and outputs today's
    5    -1 events. The files look something like this::
    6    -1 
    7    -1     #include <holiday>
    8    -1     #include <birthday>
    9    -1 
   10    -1     06/15\tJune 15
   11    -1     Thu\tEvery Thursday.
   12    -1     15\t15th of every month.
   13    -1 
   14    -1     05/Sun+2\tsecond Sunday in May (Muttertag)
   15    -1     04/Sun-1\tlast Sunday in April
   16    -1 
   17    -1     Easter-2\tGood Friday (2 days before Easter)
   18    -1     Paskha\tOrthodox Easter
   19    -1 
   20    -1 This implementation adds some new features while dropping others, most notably,
   21    -1 the date formats are not completely compatible::
   22    -1 
   23    -1     # added formats
   24    -1     1999/06/15\tJune 15 1999
   25    -1     1999/06/15*\tJune 15 (usefull for birthdays)
   26    -1     1999/05/Sun+2\tsecond Sunday in May 1999
   27    -1     1999/06/15+2\tJune 15 1999 and every second week since then
   28    -1 
   29    -1     # removed formats (mostly alternative formats)
   30    -1     Jun. 15\t06/15
   31    -1     15 June\t06/15
   32    -1     Thursday\tThu
   33    -1     June\t06/01
   34    -1     15 *\t15
   35    -1 
   36    -1     May Sun+2\t05/Sun+2
   37    -1     04/SunLast\t04/Sun-1
   38    -1 """
   39    -1 
   40    -1 import os
   41    -1 import re
   42    -1 import argparse
   43    -1 import subprocess
   44    -1 import datetime
   45    -1 
   46    -1 __version__ = '0.0.0'
   47    -1 
   48    -1 TODAY = datetime.date.today()
   49    -1 
   50    -1 
   51    -1 def easter(year, paskha=False):
   52    -1 	# https://de.wikipedia.org/wiki/Gau%C3%9Fsche_Osterformel#Eine_erg.C3.A4nzte_Osterformel
   53    -1 	k = int(year / 100)
   54    -1 	if paskha:
   55    -1 		s = 0
   56    -1 		m = 15
   57    -1 	else:
   58    -1 		s = 2 - int((3 * k + 3) / 4)
   59    -1 		m = 17 - s - int((8 * k + 13) / 25)
   60    -1 	a = year % 19
   61    -1 	d = (19 * a + m) % 30
   62    -1 	r = int((d + int(a / 11)) / 29)
   63    -1 	og = 21 + d - r
   64    -1 	sz = 7 - (year + int(year / 4) + s) % 7
   65    -1 	oe = 7 - (og - sz) % 7
   66    -1 	os = og + oe
   67    -1 
   68    -1 	if paskha:
   69    -1 		os += k - int(year / 400) - 2
   70    -1 
   71    -1 	return datetime.date(year, 3, 1) + datetime.timedelta(os - 1)
   72    -1 
   73    -1 
   74    -1 def is_match(tpl, date):
   75    -1 	if 'repeat' in tpl:
   76    -1 		if 'day' in tpl and 'month' in tpl and 'year' in tpl:
   77    -1 			reference = datetime.date(tpl['year'], tpl['month'], tpl['day'])
   78    -1 			delta = date - reference
   79    -1 			if delta.days % (7 * tpl['repeat']) != 0:
   80    -1 				return False
   81    -1 		else:
   82    -1 			raise ValueError('repeat used without day, month and year')
   83    -1 	else:
   84    -1 		if 'day' in tpl and date.day != tpl['day']:
   85    -1 			return False
   86    -1 		if 'month' in tpl and date.month != tpl['month']:
   87    -1 			return False
   88    -1 		if 'year' in tpl and date.year != tpl['year']:
   89    -1 			return False
   90    -1 
   91    -1 	if 'weekday' in tpl and date.weekday() != tpl['weekday']:
   92    -1 		return False
   93    -1 
   94    -1 	if 'nth_of_month' in tpl:
   95    -1 		a = tpl['nth_of_month']
   96    -1 		outside = date - datetime.timedelta(a * 7)
   97    -1 		if outside.month == date.month:
   98    -1 			return False
   99    -1 		b = a + 1 if a < 0 else a - 1
  100    -1 		inside = date - datetime.timedelta(b * 7)
  101    -1 		if inside.month != date.month:
  102    -1 			return False
  103    -1 
  104    -1 	if 'from_easter' in tpl:
  105    -1 		d = date - datetime.timedelta(tpl['from_easter'])
  106    -1 		if easter(d.year) != d:
  107    -1 			return False
  108    -1 
  109    -1 	if 'from_paskha' in tpl:
  110    -1 		d = date - datetime.timedelta(tpl['from_paskha'])
  111    -1 		if easter(d.year, paskha=True) != d:
  112    -1 			return False
  113    -1 
  114    -1 	return True
  115    -1 
  116    -1 
  117    -1 def parse_weekday(s):
  118    -1 	_d = datetime.datetime.strptime(s + ' 01', '%a %U')
  119    -1 	return _d.weekday()
  120    -1 
  121    -1 
  122    -1 def parse_date(s):
  123    -1 	m = re.match('^(.*)([+-]\d+)$', s)
  124    -1 	if m:
  125    -1 		s = m.groups()[0]
  126    -1 		n = int(m.groups()[1] or 0)
  127    -1 	else:
  128    -1 		n = None
  129    -1 
  130    -1 	# easter
  131    -1 	if s == 'Easter':
  132    -1 		return {'from_easter': n or 0}
  133    -1 
  134    -1 	if s == 'Paskha':
  135    -1 		return {'from_paskha': n or 0}
  136    -1 
  137    -1 	# date
  138    -1 	try:
  139    -1 		a = s.rstrip('*')
  140    -1 		_d = datetime.datetime.strptime(a, '%d')
  141    -1 		tpl = {'day': _d.day}
  142    -1 		if not s.endswith('*'):
  143    -1 			tpl['year'] = TODAY.year
  144    -1 		return tpl
  145    -1 	except ValueError:
  146    -1 		pass
  147    -1 
  148    -1 	try:
  149    -1 		a = s.rstrip('*')
  150    -1 		_d = datetime.datetime.strptime(a, '%m/%d')
  151    -1 		tpl = {'day': _d.day, 'month': _d.month}
  152    -1 		if not s.endswith('*'):
  153    -1 			tpl['year'] = TODAY.year
  154    -1 			if _d.month < TODAY.month:
  155    -1 				tpl['year'] += 1
  156    -1 		return tpl
  157    -1 	except ValueError:
  158    -1 		pass
  159    -1 
  160    -1 	try:
  161    -1 		a = s.rstrip('*')
  162    -1 		_d = datetime.datetime.strptime(a, '%Y/%m/%d')
  163    -1 		tpl = {'day': _d.day, 'month': _d.month}
  164    -1 		if not s.endswith('*'):
  165    -1 			tpl['year'] = _d.year
  166    -1 		if n is not None:
  167    -1 			tpl['repeat'] = n
  168    -1 		return tpl
  169    -1 	except ValueError:
  170    -1 		pass
  171    -1 
  172    -1 	# weekday
  173    -1 	try:
  174    -1 		tpl = {'weekday': parse_weekday(s)}
  175    -1 		if n is not None:
  176    -1 			tpl['nth_of_month'] = n
  177    -1 		return tpl
  178    -1 	except ValueError:
  179    -1 		pass
  180    -1 
  181    -1 	try:
  182    -1 		d, w = s.rsplit('/', 1)
  183    -1 		_d = datetime.datetime.strptime(d, '%m')
  184    -1 		tpl = {'month': _d.month, 'weekday': parse_weekday(w)}
  185    -1 		if n is not None:
  186    -1 			tpl['nth_of_month'] = n
  187    -1 		return tpl
  188    -1 	except ValueError:
  189    -1 		pass
  190    -1 
  191    -1 	try:
  192    -1 		d, w = s.rsplit('/', 1)
  193    -1 		_d = datetime.datetime.strptime(d, '%Y/%m')
  194    -1 		tpl = {'month': _d.month, 'year': _d.year, 'weekday': parse_weekday(w)}
  195    -1 		if n is not None:
  196    -1 			tpl['nth_of_month'] = n
  197    -1 		return tpl
  198    -1 	except ValueError:
  199    -1 		pass
  200    -1 
  201    -1 	raise ValueError('Invalid date template: %s', s)
  202    -1 
  203    -1 
  204    -1 def parse_line(line):
  205    -1 	s_date, desc = line.split('\t', 1)
  206    -1 	return parse_date(s_date), desc
  207    -1 
  208    -1 
  209    -1 def get_calendar(path):
  210    -1 	abspath = os.path.abspath(path)
  211    -1 	paths = [
  212    -1 		os.path.dirname(abspath),
  213    -1 		os.path.expanduser('~/.calendar'),
  214    -1 		'/etc/calendar',
  215    -1 		'/usr/share/calendar',
  216    -1 	]
  217    -1 	cmd = ['cpp', '-P', '-traditional'] + ['-I' + p for p in paths] + [abspath]
  218    -1 	return subprocess.check_output(cmd).decode('utf8')
  219    -1 
  220    -1 
  221    -1 def get_entries(path):
  222    -1 	lines = get_calendar(path).split('\n')
  223    -1 	return [parse_line(l) for l in lines if l]
  224    -1 
  225    -1 
  226    -1 def _parse_args(argv=None):
  227    -1 	parser = argparse.ArgumentParser(description=__doc__.split('\n')[0])
  228    -1 	parser.add_argument('--version', '-V', action='version', version=__version__)
  229    -1 	parser.add_argument('-A', type=int, dest='days_after', default=1,
  230    -1 		help='Print lines from today and next num days (forward, future).')
  231    -1 	parser.add_argument('-B', type=int, dest='days_before', default=0,
  232    -1 		help='Print lines from today and previous num days (backward, past).')
  233    -1 	parser.add_argument('-f', dest='file', metavar='calendarfile',
  234    -1 		default=os.path.expanduser('~/.calendar/calendar'))
  235    -1 	parser.add_argument('-t', dest='today', metavar='yyyy.mm.dd',
  236    -1 		help='Act like the specified value is "today" instead of using the '
  237    -1 		'current date.')
  238    -1 	parser.add_argument('--by-day', '-b', action='store_true',
  239    -1 		help='Print a single line for each day')
  240    -1 	return parser.parse_args(argv)
  241    -1 
  242    -1 
  243    -1 def parse_args(argv=None):
  244    -1 	args = _parse_args(argv)
  245    -1 
  246    -1 	replace = {}
  247    -1 
  248    -1 	if args.today:
  249    -1 		replace['day'] = int(args.today[-2:])
  250    -1 
  251    -1 		if len(args.today) >= 4:
  252    -1 			replace['month'] = int(args.today[-4:-2])
  253    -1 		if len(args.today) == 8:
  254    -1 			replace['year'] = int(args.today[-8:-4])
  255    -1 
  256    -1 	args.d_today = TODAY.replace(**replace)
  257    -1 	args.d_start = args.d_today - datetime.timedelta(args.days_before)
  258    -1 	args.d_end = args.d_today + datetime.timedelta(args.days_after)
  259    -1 
  260    -1 	return args
  261    -1 
  262    -1 
  263    -1 def main():
  264    -1 	args = parse_args()
  265    -1 	entries = get_entries(args.file)
  266    -1 
  267    -1 	date = args.d_start
  268    -1 	while date <= args.d_end:
  269    -1 		ds = date.strftime('%a %b %d')
  270    -1 		if args.by_day:
  271    -1 			events = []
  272    -1 			for tpl, desc in entries:
  273    -1 				if is_match(tpl, date):
  274    -1 					events.append(desc)
  275    -1 			print(ds + '\t' + '; '.join(events))
  276    -1 		else:
  277    -1 			for tpl, desc in entries:
  278    -1 				if is_match(tpl, date):
  279    -1 					star = '' if 'year' in tpl else '*'
  280    -1 					print(ds + star + '\t' + desc)
  281    -1 		date = date + datetime.timedelta(1)
  282    -1 
  283    -1 
  284    -1 if __name__ == '__main__':
  285    -1 	main()

diff --git a/setup.py b/setup.py

@@ -1,51 +0,0 @@
    1    -1 #!/usr/bin/env python
    2    -1 
    3    -1 from setuptools import setup
    4    -1 
    5    -1 
    6    -1 with open('cal.py') as fh:
    7    -1     docstring = []
    8    -1     docstring_started = False
    9    -1     docstring_done = False
   10    -1 
   11    -1     for line in fh:
   12    -1         line = line.rstrip()
   13    -1 
   14    -1         if line.startswith('__version__ = '):
   15    -1             version = line.strip()[15:-1]
   16    -1 
   17    -1         if docstring_started:
   18    -1             if line == '"""':
   19    -1                 docstring_done = True
   20    -1             elif not docstring_done:
   21    -1                 docstring.append(line)
   22    -1         elif line.startswith('"""'):
   23    -1             docstring_started = True
   24    -1             docstring.append(line[3:])
   25    -1 
   26    -1     description = docstring[0]
   27    -1     docstring = '\n'.join(docstring[2:])
   28    -1 
   29    -1 
   30    -1 setup(
   31    -1     name='bsd-calendar',
   32    -1     version=version,
   33    -1     description=description,
   34    -1     long_description=docstring,
   35    -1     url='https://github.com/xi/calendar',
   36    -1     author='Tobias Bengfort',
   37    -1     author_email='tobias.bengfort@posteo.de',
   38    -1     py_modules=['cal'],
   39    -1     entry_points={'console_scripts': [
   40    -1         'calendar=cal:main',
   41    -1     ]},
   42    -1     license='BSD',
   43    -1     classifiers=[
   44    -1         'Development Status :: 3 - Alpha',
   45    -1         'Environment :: Console',
   46    -1         'Intended Audience :: End Users/Desktop',
   47    -1         'Operating System :: OS Independent',
   48    -1         'Programming Language :: Python :: 3.4',
   49    -1         'License :: OSI Approved :: BSD License',
   50    -1         'Topic :: Utilities',
   51    -1     ])

diff --git a/test.py b/test.py

@@ -1,296 +0,0 @@
    1    -1 import sys
    2    -1 import os
    3    -1 import unittest
    4    -1 from datetime import date
    5    -1 
    6    -1 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    7    -1 sys.path.insert(0, root)
    8    -1 
    9    -1 import cal
   10    -1 
   11    -1 TODAY = date.today()
   12    -1 
   13    -1 
   14    -1 class TestEaster(unittest.TestCase):
   15    -1 	def test_easter(self):
   16    -1 		self.assertEqual(cal.easter(2000), date(2000, 4, 23))
   17    -1 		self.assertEqual(cal.easter(2001), date(2001, 4, 15))
   18    -1 		self.assertEqual(cal.easter(2002), date(2002, 3, 31))
   19    -1 		self.assertEqual(cal.easter(2003), date(2003, 4, 20))
   20    -1 		self.assertEqual(cal.easter(2004), date(2004, 4, 11))
   21    -1 		self.assertEqual(cal.easter(2005), date(2005, 3, 27))
   22    -1 		self.assertEqual(cal.easter(2006), date(2006, 4, 16))
   23    -1 		self.assertEqual(cal.easter(2007), date(2007, 4, 8))
   24    -1 		self.assertEqual(cal.easter(2008), date(2008, 3, 23))
   25    -1 		self.assertEqual(cal.easter(2009), date(2009, 4, 12))
   26    -1 		self.assertEqual(cal.easter(2010), date(2010, 4, 4))
   27    -1 		self.assertEqual(cal.easter(2011), date(2011, 4, 24))
   28    -1 		self.assertEqual(cal.easter(2012), date(2012, 4, 8))
   29    -1 		self.assertEqual(cal.easter(2013), date(2013, 3, 31))
   30    -1 		self.assertEqual(cal.easter(2014), date(2014, 4, 20))
   31    -1 		self.assertEqual(cal.easter(2015), date(2015, 4, 5))
   32    -1 		self.assertEqual(cal.easter(2016), date(2016, 3, 27))
   33    -1 		self.assertEqual(cal.easter(2017), date(2017, 4, 16))
   34    -1 		self.assertEqual(cal.easter(2018), date(2018, 4, 1))
   35    -1 		self.assertEqual(cal.easter(2019), date(2019, 4, 21))
   36    -1 		self.assertEqual(cal.easter(2020), date(2020, 4, 12))
   37    -1 		self.assertEqual(cal.easter(2021), date(2021, 4, 4))
   38    -1 		self.assertEqual(cal.easter(2022), date(2022, 4, 17))
   39    -1 		self.assertEqual(cal.easter(2023), date(2023, 4, 9))
   40    -1 		self.assertEqual(cal.easter(2024), date(2024, 3, 31))
   41    -1 		self.assertEqual(cal.easter(2025), date(2025, 4, 20))
   42    -1 		self.assertEqual(cal.easter(2026), date(2026, 4, 5))
   43    -1 		self.assertEqual(cal.easter(2027), date(2027, 3, 28))
   44    -1 		self.assertEqual(cal.easter(2028), date(2028, 4, 16))
   45    -1 		self.assertEqual(cal.easter(2029), date(2029, 4, 1))
   46    -1 		self.assertEqual(cal.easter(2030), date(2030, 4, 21))
   47    -1 
   48    -1 	def test_paskha(self):
   49    -1 		self.assertEqual(cal.easter(2000, paskha=True), date(2000, 4, 30))
   50    -1 		self.assertEqual(cal.easter(2001, paskha=True), date(2001, 4, 15))
   51    -1 		self.assertEqual(cal.easter(2002, paskha=True), date(2002, 5, 5))
   52    -1 		self.assertEqual(cal.easter(2003, paskha=True), date(2003, 4, 27))
   53    -1 		self.assertEqual(cal.easter(2004, paskha=True), date(2004, 4, 11))
   54    -1 		self.assertEqual(cal.easter(2005, paskha=True), date(2005, 5, 1))
   55    -1 		self.assertEqual(cal.easter(2006, paskha=True), date(2006, 4, 23))
   56    -1 		self.assertEqual(cal.easter(2007, paskha=True), date(2007, 4, 8))
   57    -1 		self.assertEqual(cal.easter(2008, paskha=True), date(2008, 4, 27))
   58    -1 		self.assertEqual(cal.easter(2009, paskha=True), date(2009, 4, 19))
   59    -1 		self.assertEqual(cal.easter(2010, paskha=True), date(2010, 4, 4))
   60    -1 		self.assertEqual(cal.easter(2011, paskha=True), date(2011, 4, 24))
   61    -1 		self.assertEqual(cal.easter(2012, paskha=True), date(2012, 4, 15))
   62    -1 		self.assertEqual(cal.easter(2013, paskha=True), date(2013, 5, 5))
   63    -1 		self.assertEqual(cal.easter(2014, paskha=True), date(2014, 4, 20))
   64    -1 		self.assertEqual(cal.easter(2015, paskha=True), date(2015, 4, 12))
   65    -1 		self.assertEqual(cal.easter(2016, paskha=True), date(2016, 5, 1))
   66    -1 		self.assertEqual(cal.easter(2017, paskha=True), date(2017, 4, 16))
   67    -1 		self.assertEqual(cal.easter(2018, paskha=True), date(2018, 4, 8))
   68    -1 		self.assertEqual(cal.easter(2019, paskha=True), date(2019, 4, 28))
   69    -1 		self.assertEqual(cal.easter(2020, paskha=True), date(2020, 4, 19))
   70    -1 		self.assertEqual(cal.easter(2021, paskha=True), date(2021, 5, 2))
   71    -1 		self.assertEqual(cal.easter(2022, paskha=True), date(2022, 4, 24))
   72    -1 		self.assertEqual(cal.easter(2023, paskha=True), date(2023, 4, 16))
   73    -1 		self.assertEqual(cal.easter(2024, paskha=True), date(2024, 5, 5))
   74    -1 		self.assertEqual(cal.easter(2025, paskha=True), date(2025, 4, 20))
   75    -1 		self.assertEqual(cal.easter(2026, paskha=True), date(2026, 4, 12))
   76    -1 		self.assertEqual(cal.easter(2027, paskha=True), date(2027, 5, 2))
   77    -1 		self.assertEqual(cal.easter(2028, paskha=True), date(2028, 4, 16))
   78    -1 		self.assertEqual(cal.easter(2029, paskha=True), date(2029, 4, 8))
   79    -1 		self.assertEqual(cal.easter(2030, paskha=True), date(2030, 4, 28))
   80    -1 
   81    -1 
   82    -1 class TestParseDate(unittest.TestCase):
   83    -1 	def test_dd(self):
   84    -1 		tpl = cal.parse_date('13')
   85    -1 		self.assertEqual(tpl, {
   86    -1 			'day': 13,
   87    -1 			'year': TODAY.year,
   88    -1 		})
   89    -1 
   90    -1 	def test_dd_star(self):
   91    -1 		tpl = cal.parse_date('13*')
   92    -1 		self.assertEqual(tpl, {
   93    -1 			'day': 13,
   94    -1 		})
   95    -1 
   96    -1 	def test_mmdd(self):
   97    -1 		tpl = cal.parse_date('02/13')
   98    -1 		self.assertEqual(tpl, {
   99    -1 			'day': 13,
  100    -1 			'month': 2,
  101    -1 			'year': TODAY.year + (1 if TODAY.month > 2 else 0),
  102    -1 		})
  103    -1 
  104    -1 	def test_mmdd_star(self):
  105    -1 		tpl = cal.parse_date('02/13*')
  106    -1 		self.assertEqual(tpl, {
  107    -1 			'day': 13,
  108    -1 			'month': 2,
  109    -1 		})
  110    -1 
  111    -1 	def test_yyyymmdd(self):
  112    -1 		tpl = cal.parse_date('1999/02/13')
  113    -1 		self.assertEqual(tpl, {
  114    -1 			'day': 13,
  115    -1 			'month': 2,
  116    -1 			'year': 1999,
  117    -1 		})
  118    -1 
  119    -1 	def test_yyyymmdd_star(self):
  120    -1 		tpl = cal.parse_date('1999/02/13*')
  121    -1 		self.assertEqual(tpl, {
  122    -1 			'day': 13,
  123    -1 			'month': 2,
  124    -1 		})
  125    -1 
  126    -1 	def test_yyyymmdd_repeat(self):
  127    -1 		tpl = cal.parse_date('1999/02/13+2')
  128    -1 		self.assertEqual(tpl, {
  129    -1 			'day': 13,
  130    -1 			'month': 2,
  131    -1 			'year': 1999,
  132    -1 			'repeat': 2,
  133    -1 		})
  134    -1 
  135    -1 	def test_weekday(self):
  136    -1 		tpl = cal.parse_date('Sat')
  137    -1 		self.assertEqual(tpl, {
  138    -1 			'weekday': 5,
  139    -1 		})
  140    -1 
  141    -1 	def test_weekday_with_nth_of_month(self):
  142    -1 		tpl = cal.parse_date('Sat-1')
  143    -1 		self.assertEqual(tpl, {
  144    -1 			'weekday': 5,
  145    -1 			'nth_of_month': -1,
  146    -1 		})
  147    -1 
  148    -1 	def test_mm_weekday(self):
  149    -1 		tpl = cal.parse_date('02/Sat+2')
  150    -1 		self.assertEqual(tpl, {
  151    -1 			'month': 2,
  152    -1 			'weekday': 5,
  153    -1 			'nth_of_month': 2,
  154    -1 		})
  155    -1 
  156    -1 	def test_yyyymm_weekday(self):
  157    -1 		tpl = cal.parse_date('1999/02/Sat+2')
  158    -1 		self.assertEqual(tpl, {
  159    -1 			'month': 2,
  160    -1 			'year': 1999,
  161    -1 			'weekday': 5,
  162    -1 			'nth_of_month': 2,
  163    -1 		})
  164    -1 
  165    -1 	def test_easter(self):
  166    -1 		tpl = cal.parse_date('Easter')
  167    -1 		self.assertEqual(tpl, {
  168    -1 			'from_easter': 0,
  169    -1 		})
  170    -1 
  171    -1 	def test_easter_with_offset(self):
  172    -1 		tpl = cal.parse_date('Easter+30')
  173    -1 		self.assertEqual(tpl, {
  174    -1 			'from_easter': 30,
  175    -1 		})
  176    -1 
  177    -1 	def test_paskha(self):
  178    -1 		tpl = cal.parse_date('Paskha')
  179    -1 		self.assertEqual(tpl, {
  180    -1 			'from_paskha': 0,
  181    -1 		})
  182    -1 
  183    -1 	def test_paskha_with_offset(self):
  184    -1 		tpl = cal.parse_date('Paskha+30')
  185    -1 		self.assertEqual(tpl, {
  186    -1 			'from_paskha': 30,
  187    -1 		})
  188    -1 
  189    -1 
  190    -1 class TestIsMatch(unittest.TestCase):
  191    -1 	def test_dd(self):
  192    -1 		tpl = {
  193    -1 			'day': 13,
  194    -1 		}
  195    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  196    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  197    -1 
  198    -1 	def test_mmdd(self):
  199    -1 		tpl = {
  200    -1 			'day': 13,
  201    -1 			'month': 2,
  202    -1 		}
  203    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  204    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  205    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 3, 13)))
  206    -1 
  207    -1 	def test_yyyymmdd(self):
  208    -1 		tpl = {
  209    -1 			'day': 13,
  210    -1 			'month': 2,
  211    -1 			'year': 1999,
  212    -1 		}
  213    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  214    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  215    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 3, 13)))
  216    -1 		self.assertFalse(cal.is_match(tpl, date(2000, 2, 13)))
  217    -1 
  218    -1 	def test_yyyymmdd_repeat(self):
  219    -1 		tpl = {
  220    -1 			'day': 13,
  221    -1 			'month': 2,
  222    -1 			'year': 1999,
  223    -1 			'repeat': 2,
  224    -1 		}
  225    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  226    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 27)))
  227    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  228    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 20)))
  229    -1 
  230    -1 	def test_weekday(self):
  231    -1 		tpl = {
  232    -1 			'weekday': 5,
  233    -1 		}
  234    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  235    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  236    -1 
  237    -1 	def test_weekday_with_nth_of_month(self):
  238    -1 		tpl = {
  239    -1 			'weekday': 5,
  240    -1 			'nth_of_month': 2,
  241    -1 		}
  242    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  243    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  244    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 20)))
  245    -1 
  246    -1 	def test_mm_weekday(self):
  247    -1 		tpl = {
  248    -1 			'month': 2,
  249    -1 			'weekday': 5,
  250    -1 			'nth_of_month': 2,
  251    -1 		}
  252    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  253    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  254    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 20)))
  255    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 3, 13)))
  256    -1 
  257    -1 	def test_yyyymm_weekday(self):
  258    -1 		tpl = {
  259    -1 			'month': 2,
  260    -1 			'year': 1999,
  261    -1 			'weekday': 5,
  262    -1 			'nth_of_month': 2,
  263    -1 		}
  264    -1 		self.assertTrue(cal.is_match(tpl, date(1999, 2, 13)))
  265    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 14)))
  266    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 2, 20)))
  267    -1 		self.assertFalse(cal.is_match(tpl, date(1999, 3, 13)))
  268    -1 		self.assertFalse(cal.is_match(tpl, date(2000, 2, 12)))
  269    -1 
  270    -1 	def test_easter(self):
  271    -1 		tpl = {
  272    -1 			'from_easter': 0,
  273    -1 		}
  274    -1 		self.assertTrue(cal.is_match(tpl, date(2000, 4, 23)))
  275    -1 		self.assertFalse(cal.is_match(tpl, date(2000, 4, 25)))
  276    -1 
  277    -1 	def test_easter_with_offset(self):
  278    -1 		tpl = {
  279    -1 			'from_easter': 2,
  280    -1 		}
  281    -1 		self.assertTrue(cal.is_match(tpl, date(2000, 4, 25)))
  282    -1 		self.assertFalse(cal.is_match(tpl, date(2000, 4, 23)))
  283    -1 
  284    -1 	def test_paskha(self):
  285    -1 		tpl = {
  286    -1 			'from_paskha': 0,
  287    -1 		}
  288    -1 		self.assertTrue(cal.is_match(tpl, date(2000, 4, 30)))
  289    -1 		self.assertFalse(cal.is_match(tpl, date(2000, 4, 28)))
  290    -1 
  291    -1 	def test_paskha_with_offset(self):
  292    -1 		tpl = {
  293    -1 			'from_paskha': -2,
  294    -1 		}
  295    -1 		self.assertTrue(cal.is_match(tpl, date(2000, 4, 28)))
  296    -1 		self.assertFalse(cal.is_match(tpl, date(2000, 4, 30)))

diff --git a/tox.ini b/tox.ini

@@ -1,19 +0,0 @@
    1    -1 # Tox (http://tox.testrun.org/) is a tool for running tests
    2    -1 # in multiple virtualenvs. This configuration file will run the
    3    -1 # test suite on all supported python versions. To use it, "pip install tox"
    4    -1 # and then run "tox" from this directory.
    5    -1 
    6    -1 [tox]
    7    -1 envlist = py2, py3, pypy
    8    -1 
    9    -1 [testenv]
   10    -1 
   11    -1 commands =
   12    -1     flake8
   13    -1     nosetests
   14    -1 deps =
   15    -1     flake8
   16    -1     nose
   17    -1 
   18    -1 [flake8]
   19    -1 filename=cal.py