Skip to content

Commit

Permalink
Merge pull request #182 from kuzmoyev/dev
Browse files Browse the repository at this point in the history
v2.3.0
  • Loading branch information
kuzmoyev authored May 10, 2024
2 parents 6ce3a81 + edb0eea commit 612ecc7
Show file tree
Hide file tree
Showing 18 changed files with 402 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ If applicable, add screenshots to help explain your problem.

- OS: [e.g. Linux/Windows/MacOS]
- GCSA version: [e.g. 2.0.1]
- Python version: [e.g. 3.11]
- Python version: [e.g. 3.12]

## Additional context

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/code-cov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.11'
python-version: '3.12'

- name: Install dependencies
run: pip install tox
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ]
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12' ]
include:
- python-version: '3.11'
- python-version: '3.12'
note: with-style-and-docs-checks

steps:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ build
dist
.eggs
gcsa.egg-info
docs/html

example.py
coverage.xml
Expand Down
2 changes: 1 addition & 1 deletion .readthedocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version: 2
build:
os: ubuntu-22.04
tools:
python: "3.11"
python: "3.12"

sphinx:
configuration: docs/source/conf.py
Expand Down
16 changes: 16 additions & 0 deletions docs/source/attendees.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,21 @@ or
event.add_attendee('[email protected]')
to add a single attendee.

Use :py:meth:`~gcsa.event.Event.add_attendees` method to add multiple at once:

.. code-block:: python
event.add_attendees(
[
Attendee('[email protected]',
display_name='Friend',
additional_guests=3
),
'[email protected]',
'[email protected]'
]
)
Update event using :py:meth:`~gcsa.google_calendar.GoogleCalendar.update_event` method to save the changes.
20 changes: 20 additions & 0 deletions docs/source/change_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@
Change log
==========

v2.3.0
~~~~~~

API
---
* Adds `add_attendees` method to the `Event` for adding multiple attendees
* Add specific time reminders (N days before at HH:MM)
* Support Python3.12
* Allow service account credentials in `GoogleCalendar`

Core
----
* Don't evaluate default arguments in code docs (primarily for `timezone=get_localzone_name()`)

Backward compatibility
----------------------
* If token is expired but doesn't have refresh token, raises `google.auth.exceptions.RefreshError`
instead of sending the request


v2.2.0
~~~~~~

Expand Down
2 changes: 2 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,5 @@
'css/custom.css',
'css/colors.css',
]

autodoc_preserve_defaults = True
57 changes: 57 additions & 0 deletions docs/source/reminders.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,60 @@ To use default reminders of the calendar, set ``default_reminders`` parameter of
to ``True``.

.. note:: You can add up to 5 reminders to one event.

Specific time reminders
~~~~~~~~~~~~~~~~~~~~~~~

You can also set specific time for a reminder.

.. code-block:: python
from datetime import time
event = Event(
'Meeting',
start=(22/Apr/2019)[12:00],
reminders=[
# Day before the event at 13:30
EmailReminder(days_before=1, at=time(13, 30)),
# 2 days before the event at 19:15
PopupReminder(days_before=2, at=time(19, 15))
]
)
event.add_popup_reminder(days_before=3, at=time(8, 30))
event.add_email_reminder(days_before=4, at=time(9, 0))
.. note:: Google calendar API only works with ``minutes_before_start``.
The GCSA's interface that uses ``days_before`` and ``at`` arguments is only a convenient way of setting specific time.
GCSA will convert ``days_before`` and ``at`` to ``minutes_before_start`` during API requests.
So after you add or update the event, it will have reminders with only ``minutes_before_start`` set even if they
were initially created with ``days_before`` and ``at``.

.. code-block:: python
from datetime import time
event = Event(
'Meeting',
start=(22/Apr/2019)[12:00],
reminders=[
# Day before the event at 12:00
EmailReminder(days_before=1, at=time(12, 00))
]
)
event.reminders[0].minutes_before_start is None
event.reminders[0].days_before == 1
event.reminders[0].at == time(12, 00)
event = gc.add_event(event)
event.reminders[0].minutes_before_start == 24 * 60 # exactly one day before
event.reminders[0].days_before is None
event.reminders[0].at is None
GCSA does not convert ``minutes_before_start`` to ``days_before`` and ``at`` (even for the whole-day events)
for backwards compatibility reasons.

18 changes: 12 additions & 6 deletions gcsa/_services/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from googleapiclient import discovery
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google.auth.credentials import Credentials


class AuthenticatedService:
Expand All @@ -24,7 +24,8 @@ def __init__(
save_token: bool = True,
read_only: bool = False,
authentication_flow_host: str = 'localhost',
authentication_flow_port: int = 8080
authentication_flow_port: int = 8080,
authentication_flow_bind_addr: str = None
):
"""
Specify ``credentials`` to use in requests or ``credentials_path`` and ``token_path`` to get credentials from.
Expand All @@ -49,6 +50,9 @@ def __init__(
Host to receive response during authentication flow
:param authentication_flow_port:
Port to receive response during authentication flow
:param authentication_flow_bind_addr:
Optional IP address for the redirect server to listen on when it is not the same as host
(e.g. in a container)
"""

if credentials:
Expand All @@ -66,7 +70,8 @@ def __init__(
scopes,
save_token,
authentication_flow_host,
authentication_flow_port
authentication_flow_port,
authentication_flow_bind_addr
)

self.service = discovery.build('calendar', 'v3', credentials=self.credentials)
Expand All @@ -75,7 +80,7 @@ def __init__(
def _ensure_refreshed(
credentials: Credentials
) -> Credentials:
if not credentials.valid and credentials.expired and credentials.refresh_token:
if not credentials.valid and credentials.expired:
credentials.refresh(Request())
return credentials

Expand All @@ -87,7 +92,8 @@ def _get_credentials(
scopes: List[str],
save_token: bool,
host: str,
port: int
port: int,
bind_addr: str
) -> Credentials:
credentials = None

Expand All @@ -101,7 +107,7 @@ def _get_credentials(
else:
credentials_path = os.path.join(credentials_dir, credentials_file)
flow = InstalledAppFlow.from_client_secrets_file(credentials_path, scopes)
credentials = flow.run_local_server(host=host, port=port)
credentials = flow.run_local_server(host=host, port=port, bind_addr=bind_addr)

if save_token:
with open(token_path, 'wb') as token_file:
Expand Down
23 changes: 18 additions & 5 deletions gcsa/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from beautiful_date import BeautifulDate
from tzlocal import get_localzone_name
from datetime import datetime, date, timedelta
from datetime import datetime, date, timedelta, time

from ._resource import Resource
from .attachment import Attachment
Expand Down Expand Up @@ -223,6 +223,15 @@ def add_attendee(
Attendee may be given as email string or :py:class:`~gcsa.attendee.Attendee` object."""
self.attendees.append(self._ensure_attendee_from_email(attendee))

def add_attendees(
self,
attendees: List[Union[str, Attendee]]
):
"""Adds multiple attendees to an event. See :py:class:`~gcsa.attendee.Attendee`.
Each attendee may be given as email string or :py:class:`~gcsa.attendee.Attendee` object."""
for a in attendees:
self.add_attendee(a)

def add_attachment(
self,
file_url: str,
Expand All @@ -234,17 +243,21 @@ def add_attachment(

def add_email_reminder(
self,
minutes_before_start: int = 60
minutes_before_start: int = None,
days_before: int = None,
at: time = None
):
"""Adds email reminder to an event. See :py:class:`~gcsa.reminders.EmailReminder`"""
self.add_reminder(EmailReminder(minutes_before_start))
self.add_reminder(EmailReminder(minutes_before_start, days_before, at))

def add_popup_reminder(
self,
minutes_before_start: int = 30
minutes_before_start: int = None,
days_before: int = None,
at: time = None
):
"""Adds popup reminder to an event. See :py:class:`~gcsa.reminders.PopupReminder`"""
self.add_reminder(PopupReminder(minutes_before_start))
self.add_reminder(PopupReminder(minutes_before_start, days_before, at))

def add_reminder(
self,
Expand Down
9 changes: 7 additions & 2 deletions gcsa/google_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ def __init__(
save_token: bool = True,
read_only: bool = False,
authentication_flow_host: str = 'localhost',
authentication_flow_port: int = 8080
authentication_flow_port: int = 8080,
authentication_flow_bind_addr: str = None
):
"""
Specify ``credentials`` to use in requests or ``credentials_path`` and ``token_path`` to get credentials from.
Expand Down Expand Up @@ -63,6 +64,9 @@ def __init__(
Host to receive response during authentication flow
:param authentication_flow_port:
Port to receive response during authentication flow
:param authentication_flow_bind_addr:
Optional IP address for the redirect server to listen on when it is not the same as host
(e.g. in a container)
"""
super().__init__(
default_calendar=default_calendar,
Expand All @@ -72,5 +76,6 @@ def __init__(
save_token=save_token,
read_only=read_only,
authentication_flow_host=authentication_flow_host,
authentication_flow_port=authentication_flow_port
authentication_flow_port=authentication_flow_port,
authentication_flow_bind_addr=authentication_flow_bind_addr
)
Loading

0 comments on commit 612ecc7

Please sign in to comment.