openedx-completion-aggregator


Nameopenedx-completion-aggregator JSON
Version 4.0.3 PyPI version JSON
download
home_pagehttps://github.com/open-craft/openedx-completion-aggregator
Summaryan app that aggregates block level completion data for different block types for Open edX.
upload_time2023-10-24 21:20:26
maintainer
docs_urlNone
authorOpenCraft
requires_python
licenseAGPL 3.0
keywords django edx
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            openedx-completion-aggregator
=============================

|pypi-badge| |travis-badge| |codecov-badge| |pyversions-badge| |license-badge|

openedx-completion-aggregator is a Django app that aggregates block level completion data for different block types for Open edX.

What does that mean?

A standard Open edX installation can track the completion of individual XBlocks in a course, which is done using the `completion library <https://github.com/edx/completion#completion>`_. This completion tracking is what powers the green checkmarks shown in the course outline and course navigation as the learner completes each unit in the course:

.. image:: docs/completion.png
   :width: 100%

When completion tracking is enabled (and green checkmarks are showing, as seen above), it is only tracked at the XBlock level. You can use the Course Blocks API to check the completion status of any individual XBlock in the course, for a single user. For example, to get the completion of the XBlock with usage ID ``block-v1:OpenCraft+completion+demo+type@html+block@demo_block`` on the LMS instance ``courses.opencraft.com`` by the user ``MyUsername``, you could call this REST API::

    GET https://courses.opencraft.com/api/courses/v1/blocks/block-v1:OpenCraft+completion+demo+type@html+block@demo_block?username=MyUsername&requested_fields=completion

The response will include a ``completion`` value between ``0`` and ``1``.

However, what if you want to know the overall % completion of an entire course? ("Alex, you have completed 45% of Introduction to Statistics") Or what if you as an instructor want to get a report of how much of Section 1 every student in a course has completed? Those queries are either not possible or too slow using the APIs built in to the LMS and ``completion``.

This Open edX plugin, ``openedx-completion-aggregator`` watches course activity and asynchronously updates database tables with "aggregate" completion data. "Aggregate" data means completion data summed up over all XBlocks into a course and aggregated at higher levels, like the subsection, section, and course level. The completion aggregator provides a REST API that can provide near-instant answers to queries such as:

* What % complete are each of the courses that I'm enrolled in?
* What % of each section in Course X have my students completed?
* What is the average completion % among all enrolled students in a course?

Notes:

* This service only provides data, via a REST API. There is no user interface.
* On production instances, the answers to these "aggregate" questions may be slightly out of date, because they are computed asynchronously (see below). How often they are updated is configurable.

Synchronous vs. Asynchronous calculations
-----------------------------------------

openedx-completion-aggregator operates in one of two modes: synchronous or asynchronous.

With synchronous aggregation, each time a student completes a block, the aggregator code will re-calculate the aggregate completion values immediately. You will always have the freshest results from this API, but at a huge performance cost. Synchronous aggregation is only for development purposes and is not suitable for production. **Synchronous aggregation can cause deadlocks when users complete XBlocks, leading to a partial outage of the LMS. Do not use it on a production site.**

With asynchronous aggregation, the aggregator code will re-calculate the aggregate completion values asynchronously, at periodic intervals (e.g. every hour). How often the update can and should be run depends on many factors - you will have to experiment and find what works best and what is possible for your specific Open edX installation. (Running this too often can clog the celery tasks queue, which might require manual intervention.)

It's important to note that in both modes the single-user, single-course API endpoints will always return up-to-date data. However, data that covers multiple users or multiple courses can be slightly out of date, until the aggregates are updated asynchronously.

API Details
-----------

For details about how the completion aggregator's REST APIs can be used, please refer to `the docstrings in views.py <https://github.com/open-craft/openedx-completion-aggregator/blob/master/completion_aggregator/api/v1/views.py#L24>`_.

Installation and Configuration
------------------------------

openedx-completion-aggregator uses the pluggable django app pattern to ease installation. To use in edx-platform, do the following:

1.  Install the app into your virtualenv::

        $ pip install openedx-completion-aggregator

2.  By default, aggregate data is re-computed synchronously (with each created or updated BlockCompletion). While that is often useful for development, in most production instances, you will want to calculate aggregations asynchronously as explained above. To enable asynchronous calculation for your installation, set the following in your ``lms.yml`` file::

        ...
        COMPLETION_AGGREGATOR_ASYNC_AGGREGATION: true
        ...

    Then configure a pair of cron jobs to run ``./manage.py run_aggregator_service`` and ``./manage.py run_aggregator_cleanup`` as often as desired. (Start with hourly and daily, respectively, if you are unsure.) The ``run_aggregator_service`` task is what updates any aggregate completion data values that need to be updated since it was last run (it will in turn enqueue celery tasks to do the actual updating). The cleanup task deletes old database entries used to coordinate the aggregation updates, and which can build up over time but are no longer needed.

3. If the aggregator is installed on an existing instance, then it's sometimes desirable to fill "Aggregate" data for the existing courses. There is the ``reaggregate_course`` management command, which prepares data that will be aggregated during the next ``run_aggregator_service`` run. However, the process of aggregating data for existing courses can place extremely high loads on both your celery workers and your MySQL database, so on large instances this process must be planned with great care. For starters, we recommend you disable any associated cron jobs, scale up your celery worker pool significantly, and scale up your database cluster and storage.


Design: Technical Details
-------------------------

The completion aggregator is designed to facilitate working with course-level,
chapter-level, and other aggregated percentages of course completion as
represented by the `BlockCompletion model <https://github.com/edx/completion/blob/e1db6a137423f6/completion/models.py#L175>`_ (from the edx-completion djangoapp).
By storing these values in the database, we are able to quickly return
information for all users in a course.

Each type of XBlock (or XModule) is assigned a completion mode of
"Completable", "Aggregator", or "Excluded".

A "completable" block is one that can directly be completed, either by viewing it
on the screen, by submitting a response, or by some custom defined means.  When
completed, a BlockCompletion is created for that user with a value of 1.0
(any value between 0.0 and 1.0 is allowed).  Completable blocks always have a
maximum possible value of 1.0.

An "excluded" block is ignored for the purposes of completion.  It always has
a completion value of 0.0, and a maximum possible value of 0.0.  If an excluded
block has children, those are also ignored for the purposes of completion.

An "aggregator" block is one that contains other blocks.  It cannot be directly
completed, but has an aggregate completion value equal to the sum of the
completion values of its immediate children, and a maximum possible value equal
to the sum of the maximum possible values of its immediate children (1.0 for
completable blocks, 0.0 for excluded blocks, and the calculated maximum for any
contained aggregators).  If an aggregator has a maximum possible value of 0.0,
(either it has no children, or all its children are excluded), it is always
considered complete.

To calculate aggregations for a user, the course graph is retrieved from the
modulestore (using block transformers) to determine which blocks are contained
by each aggregator, and values are summed recursively from the course block on
down.  Values for every node in the whole tree can be calculated in a single
traversal.  These calculations can either be performed "read-only" (to get the
latest data for each user), or "read-write" to store that data in the
`completion_aggregator.Aggregator model <https://github.com/open-craft/openedx-completion-aggregator/blob/a71ab4f077/completion_aggregator/models.py#L199>`_.

During regular course interaction, a learner will calculate aggregations on the
fly to get the latest information.  However, on-the-fly calculations are too
expensive when performed for all users in a course, so periodically (e.g. every
hour, but this is configurable), a task is run to calculate all aggregators that
have gone out of date since the last run, and store those values in the database.
These stored values are then used for reporting on course-wide completion (for
course admin views).

By tracking which blocks have been changed recently (in the `StaleCompletion table <https://github.com/open-craft/openedx-completion-aggregator/blob/a71ab4f077a/completion_aggregator/models.py#L272>`_
), these stored values can also be used to shortcut calculations for
portions of the course graph that are known to be up to date.  If a user has
only completed blocks in chapter 3 of a three-chapter course since the last
time aggregations were stored, there is no need to redo the calculation for
chapter 1 or chapter 2.  The course-level aggregation can just sum the
already-stored values for chapter 1 and chapter 2 with a freshly calculated
value for chapter 3.

Currently, the major bottleneck in these calculations is creating the course
graph for each user.  We are caching the graph locally to speed things up, but
this stresses the memory capabilities of the servers.

License
-------

The code in this repository is licensed under the AGPL 3.0 unless
otherwise noted.

Please see ``LICENSE.txt`` for details.

How To Contribute
-----------------

Contributions are very welcome.

Please read our `Contributing Guideline <https://github.com/edx/edx-platform/blob/master/CONTRIBUTING.rst>`_ for details.

Reporting Security Issues
-------------------------

Please do not report security issues in public. Please email help@opencraft.com.

Getting Help
------------

Have a question about this repository, or about Open edX in general?  Please
refer to this `list of resources`_ if you need any assistance.

.. _list of resources: https://open.edx.org/getting-help


.. |pypi-badge| image:: https://img.shields.io/pypi/v/openedx-completion-aggregator.svg
    :target: https://pypi.python.org/pypi/openedx-completion-aggregator/
    :alt: PyPI

.. |travis-badge| image:: https://travis-ci.org/open-craft/openedx-completion-aggregator.svg?branch=master
    :target: https://travis-ci.org/open-craft/openedx-completion-aggregator
    :alt: Travis

.. |codecov-badge| image:: http://codecov.io/github/edx/openedx-completion-aggregator/coverage.svg?branch=master
    :target: http://codecov.io/github/open-craft/openedx-completion-aggregator?branch=master
    :alt: Codecov

.. |pyversions-badge| image:: https://img.shields.io/pypi/pyversions/openedx-completion-aggregator.svg
    :target: https://pypi.python.org/pypi/openedx-completion-aggregator/
    :alt: Supported Python versions

.. |license-badge| image:: https://img.shields.io/github/license/open-craft/openedx-completion-aggregator.svg
    :target: https://github.com/open-craft/openedx-completion-aggregator/blob/master/LICENSE.txt
    :alt: License


Change Log
----------

..
   All enhancements and patches to completion_aggregator will be documented
   in this file.  It adheres to the structure of http://keepachangelog.com/ ,
   but in reStructuredText instead of Markdown (for ease of incorporation into
   Sphinx documentation and the PyPI description).

   This project adheres to Semantic Versioning (http://semver.org/).

.. There should always be an "Unreleased" section for changes pending release.

Unreleased
~~~~~~~~~~

[4.0.3] - 2023-10-24
~~~~~~~~~~~~~~~~~~~~

* Replace `xblockutils.*` imports with `xblock.utils.*`. The old imports are
  used as a fallback for compatibility with older releases.
* Remove `xblockutils` dependency.

[4.0.2] - 2023-03-03
~~~~~~~~~~~~~~~~~~~~

* Update GitHub workflows.
* Update requirements to logically organize them and allow scheduled
  requirements updates.
* Add base requirements to `setup.py`.

[4.0.1] - 2022-07-13
~~~~~~~~~~~~~~~~~~~~

* Add `COMPLETION_AGGREGATOR_AGGREGATE_UNRELEASED_BLOCKS` setting, which
  enables the use of course blocks with a release date set to a future date in
  the course completion calculation.

[4.0.0] - 2022-06-17
~~~~~~~~~~~~~~~~~~~~

* Add Maple support.
* Drop support for Python 2.
* Drop support for Django 2.X.
* Replace Travis CI with GitHub Actions.
* Fix docs quality checks.
* Fix pylint quality checks.
* Fix the build & release pipeline.

[3.2.0] - 2021-11-26
~~~~~~~~~~~~~~~~~~~~

* Add Lilac support.

[3.1.0] - 2021-04-28
~~~~~~~~~~~~~~~~~~~~

* Add Koa support.
* Upgrade Python to 3.8.

[2.2.1] - 2020-06-05
~~~~~~~~~~~~~~~~~~~~

* Fix handling of invalid keys.

[2.1.3] - 2020-05-08
~~~~~~~~~~~~~~~~~~~~

* Fix `all` option in `reaggregate_course`.

[2.1.1] - 2020-04-20
~~~~~~~~~~~~~~~~~~~~

* Pass `user.username` to Celery task instead of `user`.
* Convert `course_key` string to `CourseKey` in `reaggregate_course`.

[2.1.0] - 2020-04-17
~~~~~~~~~~~~~~~~~~~~

* Add locking mechanism to batch operations.
* Replace `course_key` with `course` in `reaggregate_course` management command.

[2.0.1] - 2020-04-17
~~~~~~~~~~~~~~~~~~~~

* Convert `course_key` to string before sending it to Celery task.

[1.0.0] - 2018-01-04
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* First release on PyPI.
* On-demand asynchronous aggregation of xblock completion.
* Provides an API to retrieve aggregations for one or many users, for one or
  many courses.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/open-craft/openedx-completion-aggregator",
    "name": "openedx-completion-aggregator",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "Django edx",
    "author": "OpenCraft",
    "author_email": "help@opencraft.com",
    "download_url": "https://files.pythonhosted.org/packages/6e/6c/12026d1f9446a441ef3a7a78e682d0c0f6382d37bd1ac16a7430477b8311/openedx-completion-aggregator-4.0.3.tar.gz",
    "platform": null,
    "description": "openedx-completion-aggregator\n=============================\n\n|pypi-badge| |travis-badge| |codecov-badge| |pyversions-badge| |license-badge|\n\nopenedx-completion-aggregator is a Django app that aggregates block level completion data for different block types for Open edX.\n\nWhat does that mean?\n\nA standard Open edX installation can track the completion of individual XBlocks in a course, which is done using the `completion library <https://github.com/edx/completion#completion>`_. This completion tracking is what powers the green checkmarks shown in the course outline and course navigation as the learner completes each unit in the course:\n\n.. image:: docs/completion.png\n   :width: 100%\n\nWhen completion tracking is enabled (and green checkmarks are showing, as seen above), it is only tracked at the XBlock level. You can use the Course Blocks API to check the completion status of any individual XBlock in the course, for a single user. For example, to get the completion of the XBlock with usage ID ``block-v1:OpenCraft+completion+demo+type@html+block@demo_block`` on the LMS instance ``courses.opencraft.com`` by the user ``MyUsername``, you could call this REST API::\n\n    GET https://courses.opencraft.com/api/courses/v1/blocks/block-v1:OpenCraft+completion+demo+type@html+block@demo_block?username=MyUsername&requested_fields=completion\n\nThe response will include a ``completion`` value between ``0`` and ``1``.\n\nHowever, what if you want to know the overall % completion of an entire course? (\"Alex, you have completed 45% of Introduction to Statistics\") Or what if you as an instructor want to get a report of how much of Section 1 every student in a course has completed? Those queries are either not possible or too slow using the APIs built in to the LMS and ``completion``.\n\nThis Open edX plugin, ``openedx-completion-aggregator`` watches course activity and asynchronously updates database tables with \"aggregate\" completion data. \"Aggregate\" data means completion data summed up over all XBlocks into a course and aggregated at higher levels, like the subsection, section, and course level. The completion aggregator provides a REST API that can provide near-instant answers to queries such as:\n\n* What % complete are each of the courses that I'm enrolled in?\n* What % of each section in Course X have my students completed?\n* What is the average completion % among all enrolled students in a course?\n\nNotes:\n\n* This service only provides data, via a REST API. There is no user interface.\n* On production instances, the answers to these \"aggregate\" questions may be slightly out of date, because they are computed asynchronously (see below). How often they are updated is configurable.\n\nSynchronous vs. Asynchronous calculations\n-----------------------------------------\n\nopenedx-completion-aggregator operates in one of two modes: synchronous or asynchronous.\n\nWith synchronous aggregation, each time a student completes a block, the aggregator code will re-calculate the aggregate completion values immediately. You will always have the freshest results from this API, but at a huge performance cost. Synchronous aggregation is only for development purposes and is not suitable for production. **Synchronous aggregation can cause deadlocks when users complete XBlocks, leading to a partial outage of the LMS. Do not use it on a production site.**\n\nWith asynchronous aggregation, the aggregator code will re-calculate the aggregate completion values asynchronously, at periodic intervals (e.g. every hour). How often the update can and should be run depends on many factors - you will have to experiment and find what works best and what is possible for your specific Open edX installation. (Running this too often can clog the celery tasks queue, which might require manual intervention.)\n\nIt's important to note that in both modes the single-user, single-course API endpoints will always return up-to-date data. However, data that covers multiple users or multiple courses can be slightly out of date, until the aggregates are updated asynchronously.\n\nAPI Details\n-----------\n\nFor details about how the completion aggregator's REST APIs can be used, please refer to `the docstrings in views.py <https://github.com/open-craft/openedx-completion-aggregator/blob/master/completion_aggregator/api/v1/views.py#L24>`_.\n\nInstallation and Configuration\n------------------------------\n\nopenedx-completion-aggregator uses the pluggable django app pattern to ease installation. To use in edx-platform, do the following:\n\n1.  Install the app into your virtualenv::\n\n        $ pip install openedx-completion-aggregator\n\n2.  By default, aggregate data is re-computed synchronously (with each created or updated BlockCompletion). While that is often useful for development, in most production instances, you will want to calculate aggregations asynchronously as explained above. To enable asynchronous calculation for your installation, set the following in your ``lms.yml`` file::\n\n        ...\n        COMPLETION_AGGREGATOR_ASYNC_AGGREGATION: true\n        ...\n\n    Then configure a pair of cron jobs to run ``./manage.py run_aggregator_service`` and ``./manage.py run_aggregator_cleanup`` as often as desired. (Start with hourly and daily, respectively, if you are unsure.) The ``run_aggregator_service`` task is what updates any aggregate completion data values that need to be updated since it was last run (it will in turn enqueue celery tasks to do the actual updating). The cleanup task deletes old database entries used to coordinate the aggregation updates, and which can build up over time but are no longer needed.\n\n3. If the aggregator is installed on an existing instance, then it's sometimes desirable to fill \"Aggregate\" data for the existing courses. There is the ``reaggregate_course`` management command, which prepares data that will be aggregated during the next ``run_aggregator_service`` run. However, the process of aggregating data for existing courses can place extremely high loads on both your celery workers and your MySQL database, so on large instances this process must be planned with great care. For starters, we recommend you disable any associated cron jobs, scale up your celery worker pool significantly, and scale up your database cluster and storage.\n\n\nDesign: Technical Details\n-------------------------\n\nThe completion aggregator is designed to facilitate working with course-level,\nchapter-level, and other aggregated percentages of course completion as\nrepresented by the `BlockCompletion model <https://github.com/edx/completion/blob/e1db6a137423f6/completion/models.py#L175>`_ (from the edx-completion djangoapp).\nBy storing these values in the database, we are able to quickly return\ninformation for all users in a course.\n\nEach type of XBlock (or XModule) is assigned a completion mode of\n\"Completable\", \"Aggregator\", or \"Excluded\".\n\nA \"completable\" block is one that can directly be completed, either by viewing it\non the screen, by submitting a response, or by some custom defined means.  When\ncompleted, a BlockCompletion is created for that user with a value of 1.0\n(any value between 0.0 and 1.0 is allowed).  Completable blocks always have a\nmaximum possible value of 1.0.\n\nAn \"excluded\" block is ignored for the purposes of completion.  It always has\na completion value of 0.0, and a maximum possible value of 0.0.  If an excluded\nblock has children, those are also ignored for the purposes of completion.\n\nAn \"aggregator\" block is one that contains other blocks.  It cannot be directly\ncompleted, but has an aggregate completion value equal to the sum of the\ncompletion values of its immediate children, and a maximum possible value equal\nto the sum of the maximum possible values of its immediate children (1.0 for\ncompletable blocks, 0.0 for excluded blocks, and the calculated maximum for any\ncontained aggregators).  If an aggregator has a maximum possible value of 0.0,\n(either it has no children, or all its children are excluded), it is always\nconsidered complete.\n\nTo calculate aggregations for a user, the course graph is retrieved from the\nmodulestore (using block transformers) to determine which blocks are contained\nby each aggregator, and values are summed recursively from the course block on\ndown.  Values for every node in the whole tree can be calculated in a single\ntraversal.  These calculations can either be performed \"read-only\" (to get the\nlatest data for each user), or \"read-write\" to store that data in the\n`completion_aggregator.Aggregator model <https://github.com/open-craft/openedx-completion-aggregator/blob/a71ab4f077/completion_aggregator/models.py#L199>`_.\n\nDuring regular course interaction, a learner will calculate aggregations on the\nfly to get the latest information.  However, on-the-fly calculations are too\nexpensive when performed for all users in a course, so periodically (e.g. every\nhour, but this is configurable), a task is run to calculate all aggregators that\nhave gone out of date since the last run, and store those values in the database.\nThese stored values are then used for reporting on course-wide completion (for\ncourse admin views).\n\nBy tracking which blocks have been changed recently (in the `StaleCompletion table <https://github.com/open-craft/openedx-completion-aggregator/blob/a71ab4f077a/completion_aggregator/models.py#L272>`_\n), these stored values can also be used to shortcut calculations for\nportions of the course graph that are known to be up to date.  If a user has\nonly completed blocks in chapter 3 of a three-chapter course since the last\ntime aggregations were stored, there is no need to redo the calculation for\nchapter 1 or chapter 2.  The course-level aggregation can just sum the\nalready-stored values for chapter 1 and chapter 2 with a freshly calculated\nvalue for chapter 3.\n\nCurrently, the major bottleneck in these calculations is creating the course\ngraph for each user.  We are caching the graph locally to speed things up, but\nthis stresses the memory capabilities of the servers.\n\nLicense\n-------\n\nThe code in this repository is licensed under the AGPL 3.0 unless\notherwise noted.\n\nPlease see ``LICENSE.txt`` for details.\n\nHow To Contribute\n-----------------\n\nContributions are very welcome.\n\nPlease read our `Contributing Guideline <https://github.com/edx/edx-platform/blob/master/CONTRIBUTING.rst>`_ for details.\n\nReporting Security Issues\n-------------------------\n\nPlease do not report security issues in public. Please email help@opencraft.com.\n\nGetting Help\n------------\n\nHave a question about this repository, or about Open edX in general?  Please\nrefer to this `list of resources`_ if you need any assistance.\n\n.. _list of resources: https://open.edx.org/getting-help\n\n\n.. |pypi-badge| image:: https://img.shields.io/pypi/v/openedx-completion-aggregator.svg\n    :target: https://pypi.python.org/pypi/openedx-completion-aggregator/\n    :alt: PyPI\n\n.. |travis-badge| image:: https://travis-ci.org/open-craft/openedx-completion-aggregator.svg?branch=master\n    :target: https://travis-ci.org/open-craft/openedx-completion-aggregator\n    :alt: Travis\n\n.. |codecov-badge| image:: http://codecov.io/github/edx/openedx-completion-aggregator/coverage.svg?branch=master\n    :target: http://codecov.io/github/open-craft/openedx-completion-aggregator?branch=master\n    :alt: Codecov\n\n.. |pyversions-badge| image:: https://img.shields.io/pypi/pyversions/openedx-completion-aggregator.svg\n    :target: https://pypi.python.org/pypi/openedx-completion-aggregator/\n    :alt: Supported Python versions\n\n.. |license-badge| image:: https://img.shields.io/github/license/open-craft/openedx-completion-aggregator.svg\n    :target: https://github.com/open-craft/openedx-completion-aggregator/blob/master/LICENSE.txt\n    :alt: License\n\n\nChange Log\n----------\n\n..\n   All enhancements and patches to completion_aggregator will be documented\n   in this file.  It adheres to the structure of http://keepachangelog.com/ ,\n   but in reStructuredText instead of Markdown (for ease of incorporation into\n   Sphinx documentation and the PyPI description).\n\n   This project adheres to Semantic Versioning (http://semver.org/).\n\n.. There should always be an \"Unreleased\" section for changes pending release.\n\nUnreleased\n~~~~~~~~~~\n\n[4.0.3] - 2023-10-24\n~~~~~~~~~~~~~~~~~~~~\n\n* Replace `xblockutils.*` imports with `xblock.utils.*`. The old imports are\n  used as a fallback for compatibility with older releases.\n* Remove `xblockutils` dependency.\n\n[4.0.2] - 2023-03-03\n~~~~~~~~~~~~~~~~~~~~\n\n* Update GitHub workflows.\n* Update requirements to logically organize them and allow scheduled\n  requirements updates.\n* Add base requirements to `setup.py`.\n\n[4.0.1] - 2022-07-13\n~~~~~~~~~~~~~~~~~~~~\n\n* Add `COMPLETION_AGGREGATOR_AGGREGATE_UNRELEASED_BLOCKS` setting, which\n  enables the use of course blocks with a release date set to a future date in\n  the course completion calculation.\n\n[4.0.0] - 2022-06-17\n~~~~~~~~~~~~~~~~~~~~\n\n* Add Maple support.\n* Drop support for Python 2.\n* Drop support for Django 2.X.\n* Replace Travis CI with GitHub Actions.\n* Fix docs quality checks.\n* Fix pylint quality checks.\n* Fix the build & release pipeline.\n\n[3.2.0] - 2021-11-26\n~~~~~~~~~~~~~~~~~~~~\n\n* Add Lilac support.\n\n[3.1.0] - 2021-04-28\n~~~~~~~~~~~~~~~~~~~~\n\n* Add Koa support.\n* Upgrade Python to 3.8.\n\n[2.2.1] - 2020-06-05\n~~~~~~~~~~~~~~~~~~~~\n\n* Fix handling of invalid keys.\n\n[2.1.3] - 2020-05-08\n~~~~~~~~~~~~~~~~~~~~\n\n* Fix `all` option in `reaggregate_course`.\n\n[2.1.1] - 2020-04-20\n~~~~~~~~~~~~~~~~~~~~\n\n* Pass `user.username` to Celery task instead of `user`.\n* Convert `course_key` string to `CourseKey` in `reaggregate_course`.\n\n[2.1.0] - 2020-04-17\n~~~~~~~~~~~~~~~~~~~~\n\n* Add locking mechanism to batch operations.\n* Replace `course_key` with `course` in `reaggregate_course` management command.\n\n[2.0.1] - 2020-04-17\n~~~~~~~~~~~~~~~~~~~~\n\n* Convert `course_key` to string before sending it to Celery task.\n\n[1.0.0] - 2018-01-04\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* First release on PyPI.\n* On-demand asynchronous aggregation of xblock completion.\n* Provides an API to retrieve aggregations for one or many users, for one or\n  many courses.\n",
    "bugtrack_url": null,
    "license": "AGPL 3.0",
    "summary": "an app that aggregates block level completion data for different block types for Open edX.",
    "version": "4.0.3",
    "project_urls": {
        "Homepage": "https://github.com/open-craft/openedx-completion-aggregator"
    },
    "split_keywords": [
        "django",
        "edx"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9881adecdae1462f41cbbd23bf87619b77cd8a624a63e8cacbba811f7f94ee27",
                "md5": "ba7f82090895f3173db0cc9edd77ad22",
                "sha256": "ce14f3ef1d67a3f2ead6475f91353cf332fb3790bee2583dcf908e735e8752f1"
            },
            "downloads": -1,
            "filename": "openedx_completion_aggregator-4.0.3-py2.py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "ba7f82090895f3173db0cc9edd77ad22",
            "packagetype": "bdist_wheel",
            "python_version": "py2.py3",
            "requires_python": null,
            "size": 73608,
            "upload_time": "2023-10-24T21:20:25",
            "upload_time_iso_8601": "2023-10-24T21:20:25.237990Z",
            "url": "https://files.pythonhosted.org/packages/98/81/adecdae1462f41cbbd23bf87619b77cd8a624a63e8cacbba811f7f94ee27/openedx_completion_aggregator-4.0.3-py2.py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6e6c12026d1f9446a441ef3a7a78e682d0c0f6382d37bd1ac16a7430477b8311",
                "md5": "b5926061febc995cdcd7a2dff2ec47f3",
                "sha256": "4e1a76f890873bf6af4e4e164ea975c4bca045de8fcc4d5f2ef4ce615b461cc2"
            },
            "downloads": -1,
            "filename": "openedx-completion-aggregator-4.0.3.tar.gz",
            "has_sig": false,
            "md5_digest": "b5926061febc995cdcd7a2dff2ec47f3",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 79014,
            "upload_time": "2023-10-24T21:20:26",
            "upload_time_iso_8601": "2023-10-24T21:20:26.875283Z",
            "url": "https://files.pythonhosted.org/packages/6e/6c/12026d1f9446a441ef3a7a78e682d0c0f6382d37bd1ac16a7430477b8311/openedx-completion-aggregator-4.0.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-10-24 21:20:26",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "open-craft",
    "github_project": "openedx-completion-aggregator",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "tox": true,
    "lcname": "openedx-completion-aggregator"
}
        
Elapsed time: 0.14417s