Source code for calendarapi
import datetime
import multiprocessing
import queue
[docs]class CalendarApiWrapper:
"""Google Calendar API wrapper for performing asynchronous calls."""
def __init__(self):
self._input_queue = multiprocessing.Queue(maxsize=1)
self._output_queue = multiprocessing.Queue(maxsize=1)
self._api_call_process = multiprocessing.Process(target=calendar_api_call,
daemon=True,
args=(self._input_queue,
self._output_queue,))
[docs] def call_calendar_api(self, service):
"""Starts asynchronous api call.
Only one request can be processed at the same time for each
instance of CalendarApiWrapper.
To obtain results get_upcoming_events() has to be called.
Args:
service: googleapiclient discovery's service object built
for calendar v3 api with which the call will be made.
Returns:
0 if api was successfully called or 1 if api call is
already processing
Raises:
ValueError: if impossible behaviour occurred.
"""
if not self._api_call_process.is_alive():
try:
# Api process is not running so we put arguments
# into the input queue.
self._input_queue.put(service, block=False)
except queue.Full:
raise ValueError('Input queue was full. This should never happen.')
try:
self._api_call_process.start()
except AssertionError:
# This exception means that our process was already
# started and finished execution so we join it and
# then create and start a new one.
self._api_call_process.join()
self._api_call_process = multiprocessing.Process(target=calendar_api_call,
daemon=True,
args=(self._input_queue,
self._output_queue,))
self._api_call_process.start()
return 0
return 1
[docs] def get_upcoming_events(self):
"""Checks availability and returns api call results.
Returns:
-1 if api's function was not called, 0 if api call
finished and returned results or 1 if api call is being
processed.
upcoming_events: list of upcoming events.
events_colours: dictionary containing calendar's colours
data.
"""
upcoming_events = None
events_colours = None
if self._api_call_process.is_alive():
returncode = 1
else:
try:
upcoming_events, events_colours = self._output_queue.get(block=False)
self._api_call_process.join()
returncode = 0
except queue.Empty:
returncode = -1
return returncode, upcoming_events, events_colours
[docs]def calendar_api_call(input_queue, output_queue):
"""Callback function calling calendar api for upcoming events.
Input should be added to the queue before this callback starts
execution.
Args:
input_queue: queue for passing input. This function expects to
get googleapiclient discovery's service object from this
queue.
output_queue: queue for passing call's results. Results are
returned as a single 2 element tuple. First element is a
list of upcoming calendar events, the second one is a dict
containing calendar's color definitions.
Raises:
ValueError: if no arguments were passed through input queue.
"""
try:
service = input_queue.get(block=True, timeout=1)
except queue.Empty:
raise ValueError('Input queue empty.')
lower_time_bound = datetime.datetime.utcnow().isoformat() + 'Z'
upper_time_bound = datetime.datetime.utcnow()
upper_time_bound = upper_time_bound.replace(hour=23, minute=59, second=59)
upper_time_bound = upper_time_bound.isoformat() + 'Z'
calendar_list = service.events().list(calendarId='primary', timeMin=lower_time_bound,
timeMax=upper_time_bound, maxResults=10,
singleEvents=True, orderBy='startTime').execute()
upcoming_events = calendar_list.get('items', [])
events_colours = service.colors().get().execute()
try:
output_queue.put((upcoming_events, events_colours), block=False)
except queue.Full:
# This exception will occur if previous request's results were
# not collected with get_upcoming_events(). Replacing old
# results with new.
output_queue.get(block=True, timeout=1)
output_queue.put((upcoming_events, events_colours), block=False)