Skip to content

Commit 924a758

Browse files
Add extension to generate a table of future meeting dates and times
1 parent b080c57 commit 924a758

File tree

3 files changed

+117
-7
lines changed

3 files changed

+117
-7
lines changed

docs/community/monthly-meeting.rst

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ Monthly meetings are held on the first Tuesday of the month
77
on the `Discord server <https://discord.gg/sMWqvzXvde>`_ and last one hour.
88
Check the agenda or Discourse announcement to verify the start time.
99

10-
+-----------------+--------------+--------------+
11-
| Period | Even months | Odd months |
12-
+=================+==============+==============+
13-
| April-October | 19:00 UTC | 16:00 UTC |
14-
+-----------------+--------------+--------------+
15-
| November-March | 20:00 UTC | 17:00 UTC |
16-
+-----------------+--------------+--------------+
10+
Upcoming meetings:
11+
12+
.. meeting-dates::
13+
14+
`Download calendar (ICS) </docs-community-meetings.ics>`_
1715

1816
The agenda and later the meeting minutes are written in the `HackMD <https://hackmd.io/@encukou/pydocswg1>`_.
1917
To edit notes, click the “pencil” or “split view” button on the `HackMD Document <https://hackmd.io/@encukou/pydocswg1>`_.
@@ -27,6 +25,15 @@ By participating in meetings, you are agreeing to abide by and uphold the
2725
`PSF Code of Conduct <https://policies.python.org/python.org/code-of-conduct/>`_.
2826
Please take a second to read through it!
2927

28+
Meetings follow the pattern:
29+
30+
+-----------------+--------------+--------------+
31+
| Period | Even months | Odd months |
32+
+=================+==============+==============+
33+
| April-October | 19:00 UTC | 16:00 UTC |
34+
+-----------------+--------------+--------------+
35+
| November-March | 20:00 UTC | 17:00 UTC |
36+
+-----------------+--------------+--------------+
3037

3138
Minutes template
3239
----------------

docs/conf.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,16 @@
1111
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
1212

1313
# A list of strings that are module names of Sphinx extensions
14+
import os
15+
import sys
16+
17+
sys.path.append(os.path.abspath("tools/"))
18+
1419
extensions = [
1520
"sphinx_copybutton",
1621
"sphinx.ext.intersphinx",
1722
"myst_parser",
23+
"meeting_dates",
1824
]
1925

2026
myst_enable_extensions = ["linkify"]

docs/tools/meeting_dates.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""Sphinx extension to generate a list of upcoming meeting dates."""
2+
3+
import datetime as dt
4+
import os
5+
6+
from docutils import nodes
7+
from sphinx.util.docutils import SphinxDirective
8+
9+
10+
def utc_hour(date):
11+
if 4 <= date.month <= 10:
12+
# Daylight saving time in Europe and the US
13+
return 19 if date.month % 2 == 0 else 16
14+
else:
15+
# Winter time in Europe and the US
16+
return 20 if date.month % 2 == 0 else 17
17+
18+
19+
def first_tuesday(year, month):
20+
first = dt.date(year, month, 1)
21+
days_ahead = (1 - first.weekday()) % 7
22+
return first + dt.timedelta(days=days_ahead)
23+
24+
25+
def upcoming_meetings(today):
26+
meetings = []
27+
year, month = today.year, today.month
28+
while len(meetings) < 6: # Max of six meeting entries
29+
meeting_date = first_tuesday(year, month)
30+
if meeting_date >= today:
31+
meetings.append((meeting_date, utc_hour(meeting_date)))
32+
month += 1
33+
if month > 12:
34+
month = 1
35+
year += 1
36+
return meetings
37+
38+
39+
class MeetingDatesDirective(SphinxDirective):
40+
has_content = False
41+
42+
def run(self):
43+
today = dt.date.today()
44+
meetings = upcoming_meetings(today)
45+
self.env.meeting_dates = meetings
46+
47+
bullets = nodes.bullet_list()
48+
for date, hour in meetings:
49+
item = nodes.list_item()
50+
text = f"{date.strftime('%B %d, %Y')} - {hour:02d}:00 UTC"
51+
url = f"https://arewemeetingyet.com/UTC/{date.isoformat()}/{hour}:00/Docs Community Meeting"
52+
53+
paragraph = nodes.paragraph()
54+
ref = nodes.reference("", text, refuri=url)
55+
paragraph += ref
56+
item += paragraph
57+
bullets += item
58+
59+
return [bullets]
60+
61+
62+
def generate_ics(app, exception):
63+
if exception:
64+
return
65+
66+
meetings = app.env.meeting_dates
67+
68+
lines = [
69+
"BEGIN:VCALENDAR",
70+
"VERSION:2.0",
71+
"PRODID:-//Python Docs Community//Meeting Dates//EN",
72+
]
73+
for date, hour in meetings:
74+
start = dt.datetime(date.year, date.month, date.day, hour, 0, 0)
75+
end = start + dt.timedelta(hours=1)
76+
lines += [
77+
"BEGIN:VEVENT",
78+
f"DTSTART:{start.strftime('%Y%m%dT%H%M%SZ')}",
79+
f"DTEND:{end.strftime('%Y%m%dT%H%M%SZ')}",
80+
"SUMMARY:Docs Community Meeting",
81+
f"URL:https://arewemeetingyet.com/UTC/{date.isoformat()}/{hour}:00/Docs Community Meeting",
82+
"END:VEVENT",
83+
]
84+
lines += ["END:VCALENDAR"]
85+
ics = (
86+
"\r\n".join(lines) + "\r\n"
87+
) # Required by spec for some reason: https://datatracker.ietf.org/doc/html/rfc5545#section-3.1
88+
89+
path = os.path.join(app.outdir, "docs-community-meetings.ics")
90+
with open(path, "w") as f:
91+
f.write(ics)
92+
93+
94+
def setup(app):
95+
app.add_directive("meeting-dates", MeetingDatesDirective)
96+
app.connect("build-finished", generate_ics)
97+
return {"version": "1.0", "parallel_read_safe": True}

0 commit comments

Comments
 (0)