Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add link code extension #469

Merged
merged 5 commits into from
Feb 18, 2025
Merged
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
9 changes: 9 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ Change Log
Unreleased
__________

[9.18.2] - 2025-02-18
---------------------

Changed
~~~~~~~

* Added linkcode Sphinx extension to the documentation.
* Added common_refs.rst file to reuse common references in the documentation.

[9.18.1] - 2025-02-13
---------------------

Expand Down
9 changes: 9 additions & 0 deletions docs/common_refs.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. _Tutor: https://docs.tutor.edly.io/
.. _event-bus-redis: https://github.com/openedx/event-bus-redis
.. _event-bus-kafka: https://github.com/openedx/event-bus-kafka
.. _Django Signals Documentation: https://docs.djangoproject.com/en/4.2/topics/signals/
.. _openedx-events-2-zapier: https://github.com/eduNEXT/openedx-events-2-zapier
.. _Open edX Events To Zapier: https://github.com/eduNEXT/openedx-events-2-zapier

.. Replaces
.. |OpenEdxPublicSignal| replace:: :class:`OpenEdxPublicSignal <openedx_events.tooling.OpenEdxPublicSignal>`
4 changes: 2 additions & 2 deletions docs/concepts/event-bus.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Open edX Event Bus
####################

Expand Down Expand Up @@ -127,8 +129,6 @@ We encourage you to review the :doc:`../reference/real-life-use-cases` page for
.. _EventProducer: https://github.com/openedx/openedx-events/blob/main/openedx_events/event_bus/__init__.py#L71-L91
.. _EventConsumer: https://github.com/openedx/openedx-events/blob/main/openedx_events/event_bus/__init__.py#L128-L139
.. _publish/subscribe messaging pattern: https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern
.. _event-bus-redis: https://github.com/openedx/event-bus-redis/
.. _event-bus-kafka: https://github.com/openedx/event-bus-kafka/

**Maintenance chart**

Expand Down
4 changes: 2 additions & 2 deletions docs/concepts/openedx-events.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Open edX Events
#################

Expand Down Expand Up @@ -81,8 +83,6 @@ As mentioned previously, developers can listen to Open edX Events by registering

For more information on using Open edX Events, refer to the :doc:`../how-tos/create-a-new-event` how-to guide. We also encourage you to explore the :doc:`../reference/real-life-use-cases` section for real-life examples of how Open edX Events are used by the community.


.. _Django Signals Documentation: https://docs.djangoproject.com/en/4.2/topics/signals/
.. _triggering the COURSE_ENROLLMENT_CREATED event: https://github.com/openedx/edx-platform/blob/master/common/djangoapps/student/models/course_enrollment.py#L777-L795
.. _course_enrollment_post_save receiver: https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/notifications/handlers.py#L38-L53
.. _Django signals registry mechanism: https://docs.djangoproject.com/en/4.2/topics/signals/#listening-to-signals
Expand Down
76 changes: 76 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import inspect
import os
import re
import sys
from os.path import dirname, relpath

import git

Expand Down Expand Up @@ -46,6 +48,7 @@
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.napoleon',
'sphinx.ext.linkcode',
]

# Add any paths that contain templates here, relative to this directory.
Expand Down Expand Up @@ -157,3 +160,76 @@
settings_source_path = str(root)
settings_repo_url = "https://github.com/openedx/openedx-events"
settings_repo_version = openedx_event_version
openedxevents_repo_url = settings_repo_url

# Linkcode Extension Configuration

REPO_URL = "https://github.com/openedx/openedx-events/blob/main"

def linkcode_resolve(domain: str, info: dict[str, str]) -> str | None:
"""
Resolves source code links for Python objects in Sphinx documentation.
This function is based on the `linkcode_resolve` function in the SciPy project.

Args:
domain (str): The language domain of the object. Only processes Python objects ('py')
info (dict[str, str]): Dictionary containing information about the object to link.
Must contain:
- 'module': Name of the module containing the object
- 'fullname': Complete name of the object including its path

Returns:
str | None: URL to the source code on GitHub with specific line numbers,
or None if the link cannot be resolved
"""
if domain != "py":
return None

modname = info["module"]
fullname = info["fullname"]

submod = sys.modules.get(modname)
if submod is None:
return None

obj = submod
for part in fullname.split("."):
try:
obj = getattr(obj, part)
except Exception:
return None

# Use the original function object if it is wrapped.
while hasattr(obj, "__wrapped__"):
obj = obj.__wrapped__

# Get the file path where the object is defined
try:
# Try to get the file path of the object directly
file_path = inspect.getsourcefile(obj)
except Exception:
try:
# If that fails, try to get the file path of the module where the object is defined
file_path = inspect.getsourcefile(sys.modules[obj.__module__])
except Exception:
# If both attempts fail, set file_path to None
file_path = None
if not file_path:
return None

try:
source, start_line = inspect.getsourcelines(obj)
except Exception:
start_line = None

if start_line:
linespec = f"#L{start_line}-L{start_line + len(source) - 1}"
else:
linespec = ""

import openedx_events

start_dir = os.path.abspath(os.path.join(dirname(openedx_events.__file__), ".."))
file_path = relpath(file_path, start=start_dir).replace(os.path.sep, "/")

return f"{REPO_URL}/{file_path}{linespec}"
5 changes: 3 additions & 2 deletions docs/how-tos/add-event-bus-support-to-an-event.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Add Event Bus Support to an Open edX Event
############################################

Expand Down Expand Up @@ -30,7 +32,7 @@ Step 2: Define the Event Payload

An Open edX Event is compatible with the event bus when its payload can be serialized, sent, and deserialized by other services. The payload, structured as `attrs data classes`_, must align with the event bus schema format, which in this case is the :term:`Avro Schema`. This schema is used to serialize and deserialize the :term:`Event Payload` when sending it across services.

This ensures the event can be sent by the producer and then re-emitted by the same instance of `OpenEdxPublicSignal`_ on the consumer side, guaranteeing that the data sent and received is identical. Serializing this way should prevent data inconsistencies between services, e.g., timezone issues and precision loss. For more information on the event bus schema format, refer to the :doc:`../decisions/0004-external-event-bus-and-django-signal-events` and :doc:`../decisions/0005-external-event-schema-format` decision records.
This ensures the event can be sent by the producer and then re-emitted by the same instance of |OpenEdxPublicSignal| on the consumer side, guaranteeing that the data sent and received is identical. Serializing this way should prevent data inconsistencies between services, e.g., timezone issues and precision loss. For more information on the event bus schema format, refer to the :doc:`../decisions/0004-external-event-bus-and-django-signal-events` and :doc:`../decisions/0005-external-event-schema-format` decision records.

The data types used in the attrs classes that the current Open edX Event Bus with the chosen schema are:

Expand Down Expand Up @@ -129,7 +131,6 @@ To validate that you can consume the event emitted by a service through the even
.. note:: If you implemented a custom serializer for a type in the :term:`Event Payload`, the custom serializer support must be included in both the producer and consumer sides before it can be used.

.. _Avro: https://avro.apache.org/
.. _OpenEdxPublicSignal: https://github.com/openedx/openedx-events/blob/main/openedx_events/tooling.py#L37
.. _attrs data classes: https://www.attrs.org/en/stable/overview.html
.. _serialize_event_data_to_bytes: https://github.com/openedx/openedx-events/blob/main/openedx_events/event_bus/avro/serializer.py#L82-L98
.. _deserialize_bytes_to_event_data: https://github.com/openedx/openedx-events/blob/main/openedx_events/event_bus/avro/deserializer.py#L86-L98
Expand Down
5 changes: 2 additions & 3 deletions docs/how-tos/consume-an-event.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Consume an Open edX Event
##########################

Expand Down Expand Up @@ -122,9 +124,6 @@ You can review this example to understand how you can test the event receiver an

This way you can ensure that the event receiver is working as expected and that the custom logic is executed when the event is triggered. If the event definition or payload changes in any way, you can catch the error in the test suite instead of in production.

.. _Tutor: https://docs.tutor.edly.io/
.. _Django Signals Documentation: https://docs.djangoproject.com/en/4.2/topics/signals/
.. _openedx-events-2-zapier: https://github.com/eduNEXT/openedx-events-2-zapier
.. _Open edX Django plugin: https://docs.openedx.org/en/latest/developers/concepts/platform_overview.html#new-plugin
.. _OEP-49: https://docs.openedx.org/projects/openedx-proposals/en/latest/best-practices/oep-0049-django-app-patterns.html#signals
.. _list of events: https://docs.openedx.org/projects/openedx-events/en/latest/reference/events.html
Expand Down
3 changes: 2 additions & 1 deletion docs/how-tos/create-a-new-event.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Create a New Open edX Event with Long-Term Support
####################################################

Expand Down Expand Up @@ -320,7 +322,6 @@ For more details on how the contribution flow works, refer to the :doc:`docs.ope
.. _Add Program Certificate events: https://github.com/openedx/openedx-events/issues/250
.. _attrs: https://www.attrs.org/en/stable/
.. _Tutor: https://docs.tutor.edly.io/
.. _Django Signals Documentation: https://docs.djangoproject.com/en/4.2/topics/signals/
.. _OpenEdxPublicSignal: https://github.com/openedx/openedx-events/blob/main/openedx_events/tooling.py#L37

**Maintenance chart**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Use the Open edX Event Bus to Broadcast and Consume Events
==========================================================

Expand Down Expand Up @@ -94,10 +96,7 @@ To consume events, Open edX Events provides a management command called `consume
You can find more a concrete example of how to produce and consume events in the `event-bus-redis`_ documentation.

.. _consume_events: https://github.com/openedx/openedx-events/blob/main/openedx_events/management/commands/consume_events.py
.. _event-bus-redis: https://github.com/openedx/event-bus-redis
.. _event-bus-kafka: https://github.com/openedx/event-bus-kafka
.. _run the consumer locally without tutor: https://github.com/openedx/event-bus-redis/?tab=readme-ov-file#testing-locally
.. _run the consumer locally with tutor: https://github.com/openedx/event-bus-redis/blob/main/docs/tutor_installation.rst#setup-example-with-openedx-course-discovery-and-tutor
.. _general_signal_handler: https://github.com/openedx/openedx-events/blob/main/openedx_events/apps.py#L16-L44
.. _consumer using Tutor hosted in Kubernetes: https://github.com/openedx/tutor-contrib-aspects/blob/master/tutoraspects/patches/k8s-deployments#L535-L588
.. _Tutor: https://docs.tutor.edly.io/
4 changes: 2 additions & 2 deletions docs/how-tos/use-the-event-bus.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Use the Open edX Event Bus
############################

Expand Down Expand Up @@ -81,8 +83,6 @@ To consume events, Open edX Events provides a management command called `consume
You can find more concrete examples of how to produce and consume events in the `event-bus-redis`_ documentation.

.. _consume_events: https://github.com/openedx/openedx-events/blob/main/openedx_events/management/commands/consume_events.py
.. _event-bus-redis: https://github.com/openedx/event-bus-redis
.. _event-bus-kafka: https://github.com/openedx/event-bus-kafka
.. _run the consumer locally without tutor: https://github.com/openedx/event-bus-redis/?tab=readme-ov-file#testing-locally
.. _run the consumer locally with tutor: https://github.com/openedx/event-bus-redis/blob/main/docs/tutor_installation.rst#setup-example-with-openedx-course-discovery-and-tutor
.. _general_signal_handler: https://github.com/openedx/openedx-events/blob/main/openedx_events/apps.py#L16-L44
Expand Down
12 changes: 6 additions & 6 deletions docs/quickstarts/use-events-to-call-webhook.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Using Open edX Events in the LMS service
========================================

Expand Down Expand Up @@ -34,7 +36,7 @@ The package we just installed is a `Django plugin`_, which adds additional
configurations to our working environment thanks to the extension mechanisms put in place. Now,
:term:`event receivers <Event Receiver>` are listening to the registration and enrollment events sent within the LMS service.

The following is the implementation for the `event receivers <Event Receiver>` listening for the event ``STUDENT_REGISTRATION_COMPLETED``:
The following is the implementation for the :term:`event receivers <Event Receiver>` listening for the event ``STUDENT_REGISTRATION_COMPLETED``:

.. code-block:: python

Expand Down Expand Up @@ -97,7 +99,7 @@ The following is the implementation for the `event receivers <Event Receiver>` l
flatten_dict(zapier_payload),
)

Those `event receivers <Event Receiver>` work out of the box after the plugin installation. Now, we must
Those :term:`event receivers <Event Receiver>` work out of the box after the plugin installation. Now, we must
set the plugin settings which indicate where to send the events data. For this,
go to ``env/apps/openedx/settings/development.py`` and add your Zapier configuration:

Expand All @@ -109,13 +111,11 @@ go to ``env/apps/openedx/settings/development.py`` and add your Zapier configura
Getting data from Zapier
------------------------

Now that you have configured both `event receivers <Event Receiver>`, you'll need to trigger the events
Now that you have configured both :term:`event receivers <Event Receiver>`, you'll need to trigger the events
so you receive the events data in Zapier. Try it out!

.. _openedx-events-2-zapier: https://github.com/eduNEXT/openedx-events-2-zapier
.. _Tutor: https://github.com/overhangio/tutor
.. _Django plugin: https://github.com/openedx/edx-django-utils/blob/master/edx_django_utils/plugins/README.rst

.. warning::
The `event receiver <Event Receiver>` function implemented in this tutorial was intended to be lightweight, just to serve as an example for event receivers. However, in production
The :term:`event receiver <Event Receiver>` function implemented in this tutorial was intended to be lightweight, just to serve as an example for event receivers. However, in production
settings, we encourage the use of asynchronous tasks to avoid creating bottlenecks.
6 changes: 3 additions & 3 deletions docs/reference/architecture-subdomains.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ Here we list useful information about Open edX architecture subdomains and their

.. _Events Naming and Versioning: https://github.com/openedx/openedx-events/blob/main/docs/decisions/0002-events-naming-and-versioning.rst#L1
.. _edX Domain Driven Design documentation: https://openedx.atlassian.net/wiki/spaces/AC/pages/213910332/Domain-Driven+Design
.. _`Subdomains from OEP-41`: https://docs.openedx.org/projects/openedx-proposals/en/latest/architectural-decisions/oep-0041-arch-async-server-event-messaging.html#subdomain-from-domain-driven-design
.. _`Message Content Data Guidelines`: https://docs.openedx.org/projects/openedx-proposals/en/latest/architectural-decisions/oep-0041-arch-async-server-event-messaging.html?highlight=subdomain#message-content-data-guidelines
.. _`Notes on events design and subdomains`: https://github.com/openedx/openedx-events/issues/72#issuecomment-1179291340
.. _Subdomains from OEP-41: https://docs.openedx.org/projects/openedx-proposals/en/latest/architectural-decisions/oep-0041-arch-async-server-event-messaging.html#subdomain-from-domain-driven-design
.. _Message Content Data Guidelines: https://docs.openedx.org/projects/openedx-proposals/en/latest/architectural-decisions/oep-0041-arch-async-server-event-messaging.html?highlight=subdomain#message-content-data-guidelines
.. _Notes on events design and subdomains: https://github.com/openedx/openedx-events/issues/72#issuecomment-1179291340
.. _architecture subdomains: https://microservices.io/patterns/decomposition/decompose-by-subdomain.html

**Maintenance chart**
Expand Down
3 changes: 2 additions & 1 deletion docs/reference/real-life-use-cases.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. include:: ../common_refs.rst

Real-Life Use Cases for Open edX Events
########################################

Expand Down Expand Up @@ -155,7 +157,6 @@ Here are some additional use cases that can be implemented using Open edX Events
.. _Forum Emails Notifier: https://github.com/eduNEXT/platform-plugin-forum-email-notifier
.. _Webhooks: https://github.com/aulasneo/openedx-webhooks?tab=readme-ov-file#introduction
.. _Open edX Events Sender: https://github.com/open-craft/openedx-events-sender:
.. _Open edX Events To Zapier: https://github.com/eduNEXT/openedx-events-2-zapier:
.. _Send ORA Submissions to Third-Party Plagiarism Services: https://github.com/eduNEXT/platform-plugin-turnitin/blob/main/platform_plugin_turnitin/handlers.py#L9-L26
.. _Linking In-Context Discussions to Units: https://github.com/openedx/edx-platform/blob/master/openedx/core/djangoapps/discussions/docs/decisions/0004-in-context-discussions-linking.rst
.. _Send Staff Notification: https://github.com/openedx/edx-ora2/pull/2201
Expand Down
2 changes: 1 addition & 1 deletion openedx_events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
more information about the project.
"""

__version__ = "9.18.1"
__version__ = "9.18.2"