commit dcc8d3d2b18ecb3eea0ec734397981567136a6dd
parent cf2cc3fdc40c4173eee00bfa981f3c9da7c1abda
Author: Matthias Balk <matthias.balk@fotopuzzle.de>
Date: Wed, 8 May 2019 14:23:57 +0200
use virtualenv
Diffstat:
11 files changed, 192 insertions(+), 163 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,2 +1,3 @@
__pycache__
tags
+env
diff --git a/Makefile b/Makefile
@@ -0,0 +1,3 @@
+setup:
+ virtualenv -p python3 env
+ . env/bin/activate && pip install -r requirements-freeze.txt
diff --git a/README.rst b/README.rst
@@ -21,8 +21,7 @@ Features to be implemented
Requirements
~~~~~~~~~~~~
- Python3
-- Python dateutil
-- Python vobject
+- virtualenv
Installation and setup
~~~~~~~~~~~~~~~~~~~~~~
@@ -30,7 +29,7 @@ Get ya3 and place it where you like:
$ cd /path/where/ya3/shall/be/put
$ git pull .... ya3
-Edit configuration in config.py to fit your needs.
+Edit configuration in src/config.py to fit your needs.
Usage
~~~~~
diff --git a/commands.py b/commands.py
@@ -1,120 +0,0 @@
-# Copyright 2018 Matthias Balk
-#
-# This file is part of ya3 (yet another appointment application).
-#
-# ya3 is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Affero General Public License as published by the Free
-# Software Foundation, either version 3 of the License, or (at your option) any
-# later version.
-#
-# ya3 is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with ya3. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-import re
-import time
-import uuid
-from collections import OrderedDict
-from datetime import datetime
-
-import vobject
-from dateutil.parser import parse
-from dateutil.tz import gettz
-
-import config
-
-
-def _localtime2utc(datetimestr):
- local = parse('%s %s' % (datetimestr, time.tzname[0]))
- return local - local.utcoffset()
-
-
-def _get_input(key):
- if key in config.DEFAULTS:
- i = input('%s: [%s] ' % (key, config.DEFAULTS[key]))
- return i if i.strip() is not '' else config.DEFAULTS[key]
- return input('%s: ' % key)
-
-
-def _event2file(event):
- filename = '%s-%s.ics' % (event['DTSTART'].strftime('%Y-%m-%d'),
- re.sub(r'\s+', '-', event['SUMMARY'].lower()))
- f = open(os.path.join(config.CAL_DIR, filename), 'w')
- f.write('BEGIN:VCALENDAR\nVERSION:2.0\n')
- f.write('PRODID:-//ya3//yet another appointment application//\n')
-
- def item2str(key, value):
- if isinstance(value, datetime):
- return '%s:%s\n' % (key, value.strftime('%Y%m%dT%H%M%SZ'))
- return '%s:%s\n' % (key, value)
-
- for key in event:
- f.write(item2str(key, event[key]))
-
- f.write('END:VCALENDAR\n')
- f.close()
-
-
-def create_event():
- event = OrderedDict([
- ('BEGIN', 'VEVENT'),
- ('DTSTART', None),
- ('DTEND', None),
- ('LOCATION', None),
- ('SUMMARY', None),
- ('UID', str(uuid.uuid4())),
- ('END', 'VEVENT'),
- ])
-
- for key in ['DTSTART', 'DTEND', 'LOCATION', 'SUMMARY']:
- event[key] = _get_input(key)
- if re.match('DT', key):
- event[key] = _localtime2utc(event[key])
-
- _event2file(event)
-
-
-def _conv2local(dt):
- if not isinstance(dt, datetime):
- return datetime(dt.year, dt.month, dt.day, tzinfo=gettz())
- if dt.tzinfo is None:
- return datetime(dt.year, dt.month, dt.day,
- dt.hour, dt.minute, dt.second,
- tzinfo=gettz())
- return dt.astimezone(gettz())
-
-
-def print_events(icsfilenames):
-
- def _is_in_range(event):
- start = _conv2local(event.dtstart.value)
- end = _conv2local(event.dtend.value)
- return (end >= datetime.now(gettz()) - config.MAX_AGE and
- start < datetime.now(gettz()) + config.MAX_AHEAD)
-
- def _print(event):
- start = _conv2local(event.dtstart.value)
- end = _conv2local(event.dtend.value)
-
- try:
- location = " (" + event.location.value + ")"
- except AttributeError:
- location = ""
-
- print('%s - %s %s%s' % (start.strftime('%Y-%m-%d %H:%M'),
- end.strftime('%H:%M'),
- event.summary.value,
- location))
-
- events = []
- for filename in icsfilenames:
- with open(filename) as f:
- for cal in vobject.readComponents(f):
- events.extend(filter(_is_in_range, cal.vevent_list))
- for event in sorted(events, key=lambda ev: _conv2local(ev.dtstart.value)):
- _print(event)
diff --git a/config.py b/config.py
@@ -1,12 +0,0 @@
-from datetime import timedelta
-from os import path
-
-CAL_DIR = path.expanduser('~/.ya3/calendars/')
-
-DEFAULTS = {
- 'LOCATION': 'Besprechungsraum',
- 'SUMMARY': 'Meeting'
-}
-
-MAX_AGE = timedelta(days=1)
-MAX_AHEAD = timedelta(days=14)
diff --git a/requirements-freeze.txt b/requirements-freeze.txt
@@ -0,0 +1,3 @@
+python-dateutil==2.8.0
+six==1.12.0
+vobject==0.9.6.1
diff --git a/requirements.txt b/requirements.txt
@@ -0,0 +1,2 @@
+python-dateutil
+vobject
diff --git a/src/commands.py b/src/commands.py
@@ -0,0 +1,120 @@
+# Copyright 2018, 2019 Matthias Balk
+#
+# This file is part of ya3 (yet another appointment application).
+#
+# ya3 is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# ya3 is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with ya3. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import re
+import time
+import uuid
+from collections import OrderedDict
+from datetime import datetime
+
+import vobject
+from dateutil.parser import parse
+from dateutil.tz import gettz
+
+import config
+
+
+def _localtime2utc(datetimestr):
+ local = parse('%s %s' % (datetimestr, time.tzname[0]))
+ return local - local.utcoffset()
+
+
+def _get_input(key):
+ if key in config.DEFAULTS:
+ i = input('%s: [%s] ' % (key, config.DEFAULTS[key]))
+ return i if i.strip() is not '' else config.DEFAULTS[key]
+ return input('%s: ' % key)
+
+
+def _event2file(event):
+ filename = '%s-%s.ics' % (event['DTSTART'].strftime('%Y-%m-%d'),
+ re.sub(r'\s+', '-', event['SUMMARY'].lower()))
+ f = open(os.path.join(config.CAL_DIR, filename), 'w')
+ f.write('BEGIN:VCALENDAR\nVERSION:2.0\n')
+ f.write('PRODID:-//ya3//yet another appointment application//\n')
+
+ def item2str(key, value):
+ if isinstance(value, datetime):
+ return '%s:%s\n' % (key, value.strftime('%Y%m%dT%H%M%SZ'))
+ return '%s:%s\n' % (key, value)
+
+ for key in event:
+ f.write(item2str(key, event[key]))
+
+ f.write('END:VCALENDAR\n')
+ f.close()
+
+
+def create_event():
+ event = OrderedDict([
+ ('BEGIN', 'VEVENT'),
+ ('DTSTART', None),
+ ('DTEND', None),
+ ('LOCATION', None),
+ ('SUMMARY', None),
+ ('UID', str(uuid.uuid4())),
+ ('END', 'VEVENT'),
+ ])
+
+ for key in ['DTSTART', 'DTEND', 'LOCATION', 'SUMMARY']:
+ event[key] = _get_input(key)
+ if re.match('DT', key):
+ event[key] = _localtime2utc(event[key])
+
+ _event2file(event)
+
+
+def _conv2local(dt):
+ if not isinstance(dt, datetime):
+ return datetime(dt.year, dt.month, dt.day, tzinfo=gettz())
+ if dt.tzinfo is None:
+ return datetime(dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second,
+ tzinfo=gettz())
+ return dt.astimezone(gettz())
+
+
+def print_events(icsfilenames):
+
+ def _is_in_range(event):
+ start = _conv2local(event.dtstart.value)
+ end = _conv2local(event.dtend.value)
+ return (end >= datetime.now(gettz()) - config.MAX_AGE and
+ start < datetime.now(gettz()) + config.MAX_AHEAD)
+
+ def _print(event):
+ start = _conv2local(event.dtstart.value)
+ end = _conv2local(event.dtend.value)
+
+ try:
+ location = " (" + event.location.value + ")"
+ except AttributeError:
+ location = ""
+
+ print('%s - %s %s%s' % (start.strftime('%Y-%m-%d %H:%M'),
+ end.strftime('%H:%M'),
+ event.summary.value,
+ location))
+
+ events = []
+ for filename in icsfilenames:
+ with open(filename) as f:
+ for cal in vobject.readComponents(f):
+ events.extend(filter(_is_in_range, cal.vevent_list))
+ for event in sorted(events, key=lambda ev: _conv2local(ev.dtstart.value)):
+ _print(event)
diff --git a/src/config.py b/src/config.py
@@ -0,0 +1,12 @@
+from datetime import timedelta
+from os import path
+
+CAL_DIR = path.expanduser('~/.ya3/')
+
+DEFAULTS = {
+ 'LOCATION': 'Besprechungsraum I',
+ 'SUMMARY': 'Meeting'
+}
+
+MAX_AGE = timedelta(hours=6)
+MAX_AHEAD = timedelta(days=14)
diff --git a/src/ya3 b/src/ya3
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+
+# Copyright 2018, 2019 Matthias Balk
+#
+# This file is part of ya3 (yet another appointment application).
+#
+# ya3 is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# ya3 is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with ya3. If not, see <http://www.gnu.org/licenses/>.
+
+"""ya3 -- yet another appointment application"""
+
+import glob
+import os.path
+from optparse import OptionParser
+
+import commands
+import config
+
+
+usage = """%prog <command>
+ commands: create|add, print"""
+parser = OptionParser(usage=usage)
+(options, args) = parser.parse_args()
+
+if len(args) != 1:
+ parser.print_help()
+else:
+ command = args[0]
+
+ if command == 'create' or command == 'add':
+ commands.create_event()
+ elif command == 'print':
+ commands.print_events(glob.glob(os.path.join(config.CAL_DIR, '*.ics')))
+ else:
+ parser.print_help()
diff --git a/ya3 b/ya3
@@ -1,6 +1,6 @@
-#!/usr/bin/env python3
+#!/bin/sh
-# Copyright 2018 Matthias Balk
+# Copyright 2018, 2019 Matthias Balk
#
# This file is part of ya3 (yet another appointment application).
#
@@ -17,29 +17,5 @@
# You should have received a copy of the GNU Affero General Public License
# along with ya3. If not, see <http://www.gnu.org/licenses/>.
-"""ya3 -- yet another appointment application"""
-
-import glob
-import os.path
-from optparse import OptionParser
-
-import commands
-import config
-
-
-usage = """%prog <command>
- commands: create|add, print"""
-parser = OptionParser(usage=usage)
-(options, args) = parser.parse_args()
-
-if len(args) != 1:
- parser.print_help()
-else:
- command = args[0]
-
- if command == 'create' or command == 'add':
- commands.create_event()
- elif command == 'print':
- commands.print_events(glob.glob(os.path.join(config.CAL_DIR, '*.ics')))
- else:
- parser.print_help()
+. $(dirname `readlink -f $0`)/env/bin/activate
+$(dirname `readlink -f $0`)/src/ya3 $@