diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 34ec5bfc..acd3f147 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -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 --------------------- diff --git a/docs/common_refs.rst b/docs/common_refs.rst new file mode 100644 index 00000000..9b402d4e --- /dev/null +++ b/docs/common_refs.rst @@ -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 ` diff --git a/docs/concepts/event-bus.rst b/docs/concepts/event-bus.rst index ee34646f..d63e84f8 100644 --- a/docs/concepts/event-bus.rst +++ b/docs/concepts/event-bus.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Open edX Event Bus #################### @@ -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** diff --git a/docs/concepts/openedx-events.rst b/docs/concepts/openedx-events.rst index 9be5583d..1c1f1fc0 100644 --- a/docs/concepts/openedx-events.rst +++ b/docs/concepts/openedx-events.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Open edX Events ################# @@ -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 diff --git a/docs/conf.py b/docs/conf.py index 501e9f33..88aa733e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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 @@ -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. @@ -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}" diff --git a/docs/how-tos/add-event-bus-support-to-an-event.rst b/docs/how-tos/add-event-bus-support-to-an-event.rst index 1283e194..f0b76f0e 100644 --- a/docs/how-tos/add-event-bus-support-to-an-event.rst +++ b/docs/how-tos/add-event-bus-support-to-an-event.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Add Event Bus Support to an Open edX Event ############################################ @@ -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: @@ -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 diff --git a/docs/how-tos/consume-an-event.rst b/docs/how-tos/consume-an-event.rst index 4e3d1089..658bb75e 100644 --- a/docs/how-tos/consume-an-event.rst +++ b/docs/how-tos/consume-an-event.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Consume an Open edX Event ########################## @@ -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 diff --git a/docs/how-tos/create-a-new-event.rst b/docs/how-tos/create-a-new-event.rst index 5ac52e2c..8ffc8001 100644 --- a/docs/how-tos/create-a-new-event.rst +++ b/docs/how-tos/create-a-new-event.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Create a New Open edX Event with Long-Term Support #################################################### @@ -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** diff --git a/docs/how-tos/use-the-event-bus-to-broadcast-and-consume-events.rst b/docs/how-tos/use-the-event-bus-to-broadcast-and-consume-events.rst index 799412af..a1fde367 100644 --- a/docs/how-tos/use-the-event-bus-to-broadcast-and-consume-events.rst +++ b/docs/how-tos/use-the-event-bus-to-broadcast-and-consume-events.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Use the Open edX Event Bus to Broadcast and Consume Events ========================================================== @@ -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/ diff --git a/docs/how-tos/use-the-event-bus.rst b/docs/how-tos/use-the-event-bus.rst index ad37e1fd..d45fe1d9 100644 --- a/docs/how-tos/use-the-event-bus.rst +++ b/docs/how-tos/use-the-event-bus.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Use the Open edX Event Bus ############################ @@ -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 diff --git a/docs/quickstarts/use-events-to-call-webhook.rst b/docs/quickstarts/use-events-to-call-webhook.rst index 4ab45336..53e1f036 100644 --- a/docs/quickstarts/use-events-to-call-webhook.rst +++ b/docs/quickstarts/use-events-to-call-webhook.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Using Open edX Events in the LMS service ======================================== @@ -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 ` are listening to the registration and enrollment events sent within the LMS service. -The following is the implementation for the `event receivers ` listening for the event ``STUDENT_REGISTRATION_COMPLETED``: +The following is the implementation for the :term:`event receivers ` listening for the event ``STUDENT_REGISTRATION_COMPLETED``: .. code-block:: python @@ -97,7 +99,7 @@ The following is the implementation for the `event receivers ` l flatten_dict(zapier_payload), ) -Those `event receivers ` work out of the box after the plugin installation. Now, we must +Those :term:`event receivers ` 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: @@ -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 `, you'll need to trigger the events +Now that you have configured both :term:`event receivers `, 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 ` 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 ` 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. diff --git a/docs/reference/architecture-subdomains.rst b/docs/reference/architecture-subdomains.rst index 38a1087c..45b6f496 100644 --- a/docs/reference/architecture-subdomains.rst +++ b/docs/reference/architecture-subdomains.rst @@ -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** diff --git a/docs/reference/real-life-use-cases.rst b/docs/reference/real-life-use-cases.rst index caf4f05f..7f06a9cd 100644 --- a/docs/reference/real-life-use-cases.rst +++ b/docs/reference/real-life-use-cases.rst @@ -1,3 +1,5 @@ +.. include:: ../common_refs.rst + Real-Life Use Cases for Open edX Events ######################################## @@ -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 diff --git a/openedx_events/__init__.py b/openedx_events/__init__.py index 2854517a..fe9c9a74 100644 --- a/openedx_events/__init__.py +++ b/openedx_events/__init__.py @@ -5,4 +5,4 @@ more information about the project. """ -__version__ = "9.18.1" +__version__ = "9.18.2"