Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions docs/community/monthly-meeting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ Monthly meetings are held on the first Tuesday of the month
on the `Discord server <https://discord.gg/sMWqvzXvde>`_ and last one hour.
Check the agenda or Discourse announcement to verify the start time.

+-----------------+--------------+--------------+
| Period | Even months | Odd months |
+=================+==============+==============+
| April-October | 19:00 UTC | 16:00 UTC |
+-----------------+--------------+--------------+
| November-March | 20:00 UTC | 17:00 UTC |
+-----------------+--------------+--------------+
Upcoming meetings:

.. meeting-dates::

`Download calendar (ICS) </docs-community-meetings.ics>`_

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

Meetings follow the pattern:

+-----------------+--------------+--------------+
| Period | Even months | Odd months |
+=================+==============+==============+
| April-October | 19:00 UTC | 16:00 UTC |
+-----------------+--------------+--------------+
| November-March | 20:00 UTC | 17:00 UTC |
+-----------------+--------------+--------------+

Minutes template
----------------
Expand Down
9 changes: 9 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration

# A list of strings that are module names of Sphinx extensions
import os
import sys

sys.path.append(os.path.abspath("tools/"))

extensions = [
"sphinx_copybutton",
"sphinx.ext.intersphinx",
"myst_parser",
"meeting_dates",
]

myst_enable_extensions = ["linkify"]
Expand Down Expand Up @@ -68,6 +74,9 @@
r"https://plausible.io/docs.python.org",
r"https://plausible.io/packaging.python.org",
r"https://us.pycon.org/2024/registration/category/4",
r"https://arewemeetingyet.com/.*",
# Generated at build time
r"/docs-community-meetings.ics",
]

# A list of document names to exclude from linkcheck
Expand Down
90 changes: 90 additions & 0 deletions docs/tools/meeting_dates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""Sphinx extension to generate a list of upcoming meeting dates."""

import datetime as dt
import os

from docutils import nodes
from sphinx.util.docutils import SphinxDirective


def utc_hour(date):
if 4 <= date.month <= 10:
# Daylight saving time in Europe and the US
return 19 if date.month % 2 == 0 else 16
else:
# Winter time in Europe and the US
return 20 if date.month % 2 == 0 else 17


def first_tuesday(year, month):
first = dt.date(year, month, 1)
days_ahead = (1 - first.weekday()) % 7
return first + dt.timedelta(days=days_ahead)


def upcoming_meetings(today):
meetings = []
year, month = today.year, today.month
while len(meetings) < 6: # Max of six meeting entries
meeting_date = first_tuesday(year, month)
if meeting_date >= today:
meetings.append((meeting_date, utc_hour(meeting_date)))
month += 1
if month > 12:
month = 1
year += 1
return meetings


class MeetingDatesDirective(SphinxDirective):
has_content = False

def run(self):
bullets = nodes.bullet_list()
for date, hour in upcoming_meetings(dt.date.today()):
item = nodes.list_item()
text = f"{date.strftime('%B %d, %Y')} - {hour:02d}:00 UTC"
url = f"https://arewemeetingyet.com/UTC/{date.isoformat()}/{hour}:00/Docs Community Meeting"

paragraph = nodes.paragraph()
ref = nodes.reference("", text, refuri=url)
paragraph += ref
item += paragraph
bullets += item

return [bullets]


def generate_ics(app, exception):
if exception:
return

lines = [
"BEGIN:VCALENDAR",
"VERSION:2.0",
"PRODID:-//Python Docs Community//Meeting Dates//EN",
]
for date, hour in upcoming_meetings(dt.date.today()):
start = dt.datetime(date.year, date.month, date.day, hour, 0, 0)
end = start + dt.timedelta(hours=1)
lines += [
"BEGIN:VEVENT",
f"DTSTART:{start.strftime('%Y%m%dT%H%M%SZ')}",
f"DTEND:{end.strftime('%Y%m%dT%H%M%SZ')}",
"SUMMARY:Docs Community Meeting",
f"URL:https://arewemeetingyet.com/UTC/{date.isoformat()}/{hour}:00/Docs Community Meeting",
"END:VEVENT",
]
lines += ["END:VCALENDAR"]
ics = (
"\r\n".join(lines) + "\r\n"
) # Required by spec for some reason: https://datatracker.ietf.org/doc/html/rfc5545#section-3.1

with open(os.path.join(app.outdir, "docs-community-meetings.ics"), "w") as f:
f.write(ics)


def setup(app):
app.add_directive("meeting-dates", MeetingDatesDirective)
app.connect("build-finished", generate_ics)
return {"version": "1.0", "parallel_read_safe": True}
Loading