Skip to content

Commit 612ecc7

Browse files
authored
Merge pull request #182 from kuzmoyev/dev
v2.3.0
2 parents 6ce3a81 + edb0eea commit 612ecc7

File tree

18 files changed

+402
-59
lines changed

18 files changed

+402
-59
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ If applicable, add screenshots to help explain your problem.
5050

5151
- OS: [e.g. Linux/Windows/MacOS]
5252
- GCSA version: [e.g. 2.0.1]
53-
- Python version: [e.g. 3.11]
53+
- Python version: [e.g. 3.12]
5454

5555
## Additional context
5656

.github/workflows/code-cov.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
- name: Set up Python
1414
uses: actions/setup-python@v2
1515
with:
16-
python-version: '3.11'
16+
python-version: '3.12'
1717

1818
- name: Install dependencies
1919
run: pip install tox

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ]
15+
python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12' ]
1616
include:
17-
- python-version: '3.11'
17+
- python-version: '3.12'
1818
note: with-style-and-docs-checks
1919

2020
steps:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ build
99
dist
1010
.eggs
1111
gcsa.egg-info
12+
docs/html
1213

1314
example.py
1415
coverage.xml

.readthedocs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: 2
33
build:
44
os: ubuntu-22.04
55
tools:
6-
python: "3.11"
6+
python: "3.12"
77

88
sphinx:
99
configuration: docs/source/conf.py

docs/source/attendees.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,5 +61,21 @@ or
6161
6262
event.add_attendee('attendee@gmail.com')
6363
64+
to add a single attendee.
65+
66+
Use :py:meth:`~gcsa.event.Event.add_attendees` method to add multiple at once:
67+
68+
.. code-block:: python
69+
70+
event.add_attendees(
71+
[
72+
Attendee('attendee@gmail.com',
73+
display_name='Friend',
74+
additional_guests=3
75+
),
76+
'attendee_by_email1@gmail.com',
77+
'attendee_by_email2@gmail.com'
78+
]
79+
)
6480
6581
Update event using :py:meth:`~gcsa.google_calendar.GoogleCalendar.update_event` method to save the changes.

docs/source/change_log.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,26 @@
33
Change log
44
==========
55

6+
v2.3.0
7+
~~~~~~
8+
9+
API
10+
---
11+
* Adds `add_attendees` method to the `Event` for adding multiple attendees
12+
* Add specific time reminders (N days before at HH:MM)
13+
* Support Python3.12
14+
* Allow service account credentials in `GoogleCalendar`
15+
16+
Core
17+
----
18+
* Don't evaluate default arguments in code docs (primarily for `timezone=get_localzone_name()`)
19+
20+
Backward compatibility
21+
----------------------
22+
* If token is expired but doesn't have refresh token, raises `google.auth.exceptions.RefreshError`
23+
instead of sending the request
24+
25+
626
v2.2.0
727
~~~~~~
828

docs/source/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,5 @@
186186
'css/custom.css',
187187
'css/colors.css',
188188
]
189+
190+
autodoc_preserve_defaults = True

docs/source/reminders.rst

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,60 @@ To use default reminders of the calendar, set ``default_reminders`` parameter of
5656
to ``True``.
5757

5858
.. note:: You can add up to 5 reminders to one event.
59+
60+
Specific time reminders
61+
~~~~~~~~~~~~~~~~~~~~~~~
62+
63+
You can also set specific time for a reminder.
64+
65+
.. code-block:: python
66+
67+
from datetime import time
68+
69+
event = Event(
70+
'Meeting',
71+
start=(22/Apr/2019)[12:00],
72+
reminders=[
73+
# Day before the event at 13:30
74+
EmailReminder(days_before=1, at=time(13, 30)),
75+
# 2 days before the event at 19:15
76+
PopupReminder(days_before=2, at=time(19, 15))
77+
]
78+
)
79+
80+
event.add_popup_reminder(days_before=3, at=time(8, 30))
81+
event.add_email_reminder(days_before=4, at=time(9, 0))
82+
83+
84+
.. note:: Google calendar API only works with ``minutes_before_start``.
85+
The GCSA's interface that uses ``days_before`` and ``at`` arguments is only a convenient way of setting specific time.
86+
GCSA will convert ``days_before`` and ``at`` to ``minutes_before_start`` during API requests.
87+
So after you add or update the event, it will have reminders with only ``minutes_before_start`` set even if they
88+
were initially created with ``days_before`` and ``at``.
89+
90+
.. code-block:: python
91+
92+
from datetime import time
93+
94+
event = Event(
95+
'Meeting',
96+
start=(22/Apr/2019)[12:00],
97+
reminders=[
98+
# Day before the event at 12:00
99+
EmailReminder(days_before=1, at=time(12, 00))
100+
]
101+
)
102+
103+
event.reminders[0].minutes_before_start is None
104+
event.reminders[0].days_before == 1
105+
event.reminders[0].at == time(12, 00)
106+
107+
event = gc.add_event(event)
108+
109+
event.reminders[0].minutes_before_start == 24 * 60 # exactly one day before
110+
event.reminders[0].days_before is None
111+
event.reminders[0].at is None
112+
113+
GCSA does not convert ``minutes_before_start`` to ``days_before`` and ``at`` (even for the whole-day events)
114+
for backwards compatibility reasons.
115+

gcsa/_services/authentication.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from googleapiclient import discovery
77
from google_auth_oauthlib.flow import InstalledAppFlow
88
from google.auth.transport.requests import Request
9-
from google.oauth2.credentials import Credentials
9+
from google.auth.credentials import Credentials
1010

1111

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

5458
if credentials:
@@ -66,7 +70,8 @@ def __init__(
6670
scopes,
6771
save_token,
6872
authentication_flow_host,
69-
authentication_flow_port
73+
authentication_flow_port,
74+
authentication_flow_bind_addr
7075
)
7176

7277
self.service = discovery.build('calendar', 'v3', credentials=self.credentials)
@@ -75,7 +80,7 @@ def __init__(
7580
def _ensure_refreshed(
7681
credentials: Credentials
7782
) -> Credentials:
78-
if not credentials.valid and credentials.expired and credentials.refresh_token:
83+
if not credentials.valid and credentials.expired:
7984
credentials.refresh(Request())
8085
return credentials
8186

@@ -87,7 +92,8 @@ def _get_credentials(
8792
scopes: List[str],
8893
save_token: bool,
8994
host: str,
90-
port: int
95+
port: int,
96+
bind_addr: str
9197
) -> Credentials:
9298
credentials = None
9399

@@ -101,7 +107,7 @@ def _get_credentials(
101107
else:
102108
credentials_path = os.path.join(credentials_dir, credentials_file)
103109
flow = InstalledAppFlow.from_client_secrets_file(credentials_path, scopes)
104-
credentials = flow.run_local_server(host=host, port=port)
110+
credentials = flow.run_local_server(host=host, port=port, bind_addr=bind_addr)
105111

106112
if save_token:
107113
with open(token_path, 'wb') as token_file:

0 commit comments

Comments
 (0)