Merge branch 'dev' into 'master'

Release 0.3.3

See merge request s3lph/icalendar-timeseries-server!8
This commit is contained in:
s3lph 2020-06-18 22:42:06 +00:00
commit 59ea26514c
9 changed files with 38 additions and 16 deletions

View file

@ -57,7 +57,7 @@ build_debian:
Section: web Section: web
Priority: optional Priority: optional
Architecture: all Architecture: all
Depends: python3 (>= 3.7), python3-jinja2, python3-bottle, python3-dateutil, python3-icalendar, python3-isodate, python3-tz Depends: python3 (>= 3.7), python3-jinja2, python3-bottle, python3-dateutil, python3-icalendar, python3-isodate
Description: Scrape iCalendar endpoints and present their data in a Description: Scrape iCalendar endpoints and present their data in a
timeseries format. A small service that scrapes iCalendar files timeseries format. A small service that scrapes iCalendar files
served over HTTP, parses their contents and returns a timeseries served over HTTP, parses their contents and returns a timeseries

View file

@ -1,6 +1,19 @@
# iCalendar Timeseries Server Changelog # iCalendar Timeseries Server Changelog
<!-- BEGIN RELEASE v0.3.3 -->
## Version 0.3.3
### Changes
<!-- BEGIN CHANGES 0.3.3 -->
- Fix type confusion bug in recurring events
- Remove pytz dependency in favor of dateutil.tz
<!-- END CHANGES 0.3.3 -->
<!-- END RELEASE v0.3.3 -->
<!-- BEGIN RELEASE v0.3.2 --> <!-- BEGIN RELEASE v0.3.2 -->
## Version 0.3.2 ## Version 0.3.2

View file

@ -78,7 +78,6 @@ The server would transform this into the following API response:
- `icalendar`: Parse iCalendar - `icalendar`: Parse iCalendar
- `isodate`: Parse ISO-8601 time periods - `isodate`: Parse ISO-8601 time periods
- `jinja2`: Template value replacements - `jinja2`: Template value replacements
- `pytz`: Work with timezones
## Configuration ## Configuration

View file

@ -1,2 +1,2 @@
__version__ = '0.3.2' __version__ = '0.3.3'

View file

@ -26,6 +26,8 @@ def _parse_recurring(event: cal.Event, start: datetime, end: datetime, duration:
occurences: List[datetime] = [] occurences: List[datetime] = []
evstart = event.get('dtstart').dt evstart = event.get('dtstart').dt
if isinstance(evstart, date) and not isinstance(evstart, datetime):
evstart = datetime(evstart.year, evstart.month, evstart.day, tzinfo=start.tzinfo)
# First occurence lies in the future; no need to process further # First occurence lies in the future; no need to process further
if evstart >= end: if evstart >= end:
return occurences return occurences

View file

@ -8,9 +8,10 @@ import urllib.request
import sys import sys
import logging import logging
import pytz
import jinja2 import jinja2
from isodate import Duration, parse_duration from isodate import Duration, parse_duration
from dateutil import tz
from datetime import tzinfo
from icalendar_timeseries_server import __version__ from icalendar_timeseries_server import __version__
@ -93,7 +94,7 @@ class Config:
config = dict() config = dict()
self._addr: str = _keycheck('addr', config, str, '', default_value='127.0.0.1') self._addr: str = _keycheck('addr', config, str, '', default_value='127.0.0.1')
self._port: int = _keycheck('port', config, int, '', default_value=8090) self._port: int = _keycheck('port', config, int, '', default_value=8090)
self._tz: pytz.tzinfo = _parse_timezone('tz', config, '', default_value='UTC') self._tz: tzinfo = _parse_timezone('tz', config, '', default_value='UTC')
self._start_delta: Duration = _parse_timedelta('start_delta', config, '', default_value='PT') self._start_delta: Duration = _parse_timedelta('start_delta', config, '', default_value='PT')
self._end_delta: Duration = _parse_timedelta('end_delta', config, '', default_value='P30D') self._end_delta: Duration = _parse_timedelta('end_delta', config, '', default_value='P30D')
self._calendars: Dict[str, CalendarConfig] = self._parse_calendars_config('calendars', config, '') self._calendars: Dict[str, CalendarConfig] = self._parse_calendars_config('calendars', config, '')
@ -120,7 +121,7 @@ class Config:
return self._port return self._port
@property @property
def tz(self) -> pytz.tzinfo: def tz(self) -> tzinfo:
return self._tz return self._tz
@property @property
@ -185,7 +186,10 @@ def _parse_timezone(key: str,
path: str, path: str,
default_value: Any = None) -> Any: default_value: Any = None) -> Any:
zonename: str = _keycheck(key, config, str, path, default_value=default_value) zonename: str = _keycheck(key, config, str, path, default_value=default_value)
return pytz.timezone(zonename) zone: zoneinfo = tz.gettz(zonename)
if zone is None:
raise ValueError(f'Unknown timezone: {zonename}')
return zone
def _parse_key_replace(key: str, def _parse_key_replace(key: str,

View file

@ -2,9 +2,9 @@
import unittest import unittest
import json import json
import pytz from datetime import timedelta, tzinfo
from datetime import timedelta
from dateutil import tz
from isodate.duration import Duration from isodate.duration import Duration
from icalendar_timeseries_server.config import _keycheck, _parse_timedelta, _parse_timezone, Config from icalendar_timeseries_server.config import _keycheck, _parse_timedelta, _parse_timezone, Config
@ -113,10 +113,10 @@ class ConfigTest(unittest.TestCase):
'tz': 'Europe/Zurich', 'tz': 'Europe/Zurich',
'notz': 'North/Winterfell' 'notz': 'North/Winterfell'
} }
self.assertEqual(_parse_timezone('tz', config, ''), pytz.timezone('Europe/Zurich')) self.assertEqual(_parse_timezone('tz', config, ''), tz.gettz('Europe/Zurich'))
self.assertEqual(_parse_timezone('def', config, '', default_value='Europe/Berlin'), self.assertEqual(_parse_timezone('def', config, '', default_value='Europe/Berlin'),
pytz.timezone('Europe/Berlin')) tz.gettz('Europe/Berlin'))
with self.assertRaises(pytz.exceptions.UnknownTimeZoneError): with self.assertRaises(ValueError):
_parse_timezone('notz', config, '') _parse_timezone('notz', config, '')
def test_parse_full_config_valid(self): def test_parse_full_config_valid(self):
@ -125,7 +125,7 @@ class ConfigTest(unittest.TestCase):
self.assertEqual(config.port, 8090) self.assertEqual(config.port, 8090)
self.assertEqual(config.start_delta, Duration(hours=-3)) self.assertEqual(config.start_delta, Duration(hours=-3))
self.assertEqual(config.end_delta, Duration(days=30)) self.assertEqual(config.end_delta, Duration(days=30))
self.assertEqual(config.tz, pytz.timezone('Europe/Zurich')) self.assertEqual(config.tz, tz.gettz('Europe/Zurich'))
def test_parse_calendars(self): def test_parse_calendars(self):
config = Config(json.loads(_CONFIG_VALID)) config = Config(json.loads(_CONFIG_VALID))

View file

@ -17,4 +17,9 @@ if [[ "$1" == "configure" ]]; then
systemctl daemon-reload || true systemctl daemon-reload || true
if [[ "$2" != "" ]]; then
# Restart after upgrading the package
systemctl restart icalendar-timeseries-server.service
fi
fi fi

View file

@ -18,11 +18,10 @@ setup(
python_requires='>=3.6', python_requires='>=3.6',
install_requires=[ install_requires=[
'bottle', 'bottle',
'python-dateutil', 'python-dateutil>=2.8',
'icalendar', 'icalendar',
'isodate', 'isodate',
'jinja2', 'jinja2'
'pytz'
], ],
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [