diff --git a/common/djangoapps/entitlements/migrations/0011_historicalcourseentitlement.py b/common/djangoapps/entitlements/migrations/0011_historicalcourseentitlement.py new file mode 100644 index 0000000000..9981d8e834 --- /dev/null +++ b/common/djangoapps/entitlements/migrations/0011_historicalcourseentitlement.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-05-30 21:13 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import model_utils.fields +import simple_history.models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('student', '0021_historicalcourseenrollment'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('entitlements', '0010_backfill_refund_lock'), + ] + + operations = [ + migrations.CreateModel( + name='HistoricalCourseEntitlement', + fields=[ + ('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')), + ('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')), + ('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ('course_uuid', models.UUIDField(help_text=b'UUID for the Course, not the Course Run')), + ('expired_at', models.DateTimeField(blank=True, help_text=b'The date that an entitlement expired, if NULL the entitlement has not expired.', null=True)), + ('mode', models.CharField(help_text=b'The mode of the Course that will be applied on enroll.', max_length=100)), + ('order_number', models.CharField(max_length=128, null=True)), + ('refund_locked', models.BooleanField(default=False)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField()), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('_policy', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='entitlements.CourseEntitlementPolicy')), + ('enrollment_course_run', models.ForeignKey(blank=True, db_constraint=False, help_text=b'The current Course enrollment for this entitlement. If NULL the Learner has not enrolled.', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='student.CourseEnrollment')), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': 'history_date', + 'verbose_name': 'historical course entitlement', + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + ] diff --git a/common/djangoapps/entitlements/models.py b/common/djangoapps/entitlements/models.py index e0c1c98297..3f20ca975c 100644 --- a/common/djangoapps/entitlements/models.py +++ b/common/djangoapps/entitlements/models.py @@ -12,6 +12,7 @@ from django.db import IntegrityError, models, transaction from django.utils.timezone import now from model_utils import Choices from model_utils.models import TimeStampedModel +from simple_history.models import HistoricalRecords from course_modes.models import CourseMode from entitlements.utils import is_course_run_entitlement_fulfillable @@ -173,6 +174,8 @@ class CourseEntitlement(TimeStampedModel): refund_locked = models.BooleanField(default=False) _policy = models.ForeignKey(CourseEntitlementPolicy, null=True, blank=True, on_delete=models.CASCADE) + history = HistoricalRecords() + @property def expired_at_datetime(self): """ diff --git a/requirements/constraints.txt b/requirements/constraints.txt index e6af8f52ba..bc5824569f 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -48,3 +48,11 @@ python3-saml==1.5.0 # version 1.3.0 breaks make upgrade, as it requires py3.5 or above scipy<=1.2.1 + +# Leaving this unpinned breaks make upgrade, since several packages require <1.0.0, but pip-compile +# will find and select 1.0.0 for paver.txt and terminate unsuccessfully. +edx-opaque-keys==0.4.4 + +# Unless we constrain pytest to <4.6.0, it may break all tests inside of +# xmodule.tests.test_resource_templates.ResourceTemplatesTests See TE-2391 for details. +pytest<4.6.0 diff --git a/requirements/edx-sandbox/base.txt b/requirements/edx-sandbox/base.txt index 743f702a68..4a90ee3808 100644 --- a/requirements/edx-sandbox/base.txt +++ b/requirements/edx-sandbox/base.txt @@ -8,10 +8,12 @@ common/lib/chem common/lib/sandbox-packages common/lib/symmath asn1crypto==0.24.0 +backports-abc==0.5 # via tornado git+https://github.com/edx/openedx-calc.git@e9b698c85ad1152002bc0868f475f153dce88952#egg=calc==0.4 cffi==1.12.3 -cryptography==2.6.1 +cryptography==2.7 enum34==1.1.6 +futures==3.2.0 ; python_version == "2.7" # via tornado ipaddress==1.0.22 lxml==3.8.0 markupsafe==1.1.1 diff --git a/requirements/edx-sandbox/shared.txt b/requirements/edx-sandbox/shared.txt index f65abee471..d72caefc73 100644 --- a/requirements/edx-sandbox/shared.txt +++ b/requirements/edx-sandbox/shared.txt @@ -6,7 +6,7 @@ # asn1crypto==0.24.0 # via cryptography cffi==1.12.3 # via cryptography -cryptography==2.6.1 +cryptography==2.7 enum34==1.1.6 # via cryptography ipaddress==1.0.22 # via cryptography lxml==3.8.0 diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 3021c9bac5..70b2718db7 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -46,11 +46,11 @@ click==7.0 # via user-util coreapi==2.3.3 # via django-rest-swagger, openapi-codec coreschema==0.0.4 # via coreapi git+https://github.com/edx/crowdsourcehinter.git@518605f0a95190949fe77bd39158450639e2e1dc#egg=crowdsourcehinter-xblock==0.1 -cryptography==2.6.1 +cryptography==2.7 cssutils==1.0.2 # via pynliner ddt==1.2.1 decorator==4.4.0 # via pycontracts -defusedxml==0.6.0 +defusedxml==0.5.0 django-appconf==1.0.3 # via django-statici18n django-babel-underscore==0.5.2 django-babel==0.6.2 # via django-babel-underscore @@ -84,7 +84,7 @@ django-simple-history==2.7.0 django-splash==0.2.2 django-statici18n==1.4.0 django-storages==1.4.1 -django-user-tasks==0.1.5 +django-user-tasks==0.1.7 django-waffle==0.12.0 django-webpack-loader==0.6.0 django==1.11.21 @@ -103,16 +103,16 @@ edx-django-oauth2-provider==1.3.5 edx-django-release-util==0.3.1 edx-django-sites-extensions==2.3.1 edx-django-utils==1.0.3 -edx-drf-extensions==2.2.1 -edx-enterprise==1.6.0 +edx-drf-extensions==2.3.0 +edx-enterprise==1.6.2 edx-i18n-tools==0.4.8 edx-milestones==0.1.13 edx-oauth2-provider==1.2.2 edx-opaque-keys[django]==0.4.4 -edx-organizations==2.0.2 +edx-organizations==2.0.3 edx-proctoring-proctortrack==1.0.5 edx-proctoring==2.0.3 -edx-rbac==0.2.1 # via edx-enterprise +edx-rbac==1.0.1 # via edx-enterprise edx-rest-api-client==1.9.2 edx-search==1.2.2 git+https://github.com/mitodl/edx-sga.git@3828ba9e413080a81b907a3381e5ffa05e063f81#egg=edx-sga==0.8.3 @@ -137,6 +137,7 @@ html5lib==1.0.1 httplib2==0.12.3 # via oauth2, zendesk idna==2.8 ipaddress==1.0.22 +isodate==0.6.0 # via python3-saml itypes==1.1.0 # via coreapi jinja2==2.10.1 # via coreschema jmespath==0.9.4 # via boto3, botocore @@ -164,7 +165,7 @@ networkx==1.7 newrelic==4.20.0.120 nltk==3.4.1 nodeenv==1.1.1 -numpy==1.16.3 +numpy==1.16.4 oauth2==1.9.0.post1 oauthlib==2.1.0 openapi-codec==1.3.2 # via django-rest-swagger @@ -172,19 +173,20 @@ git+https://github.com/edx/edx-ora2.git@2.2.3#egg=ora2==2.2.3 path.py==8.2.1 pathtools==0.1.2 paver==1.3.4 -pbr==5.2.0 +pbr==5.2.1 pdfminer.six==20181108 piexif==1.0.2 pillow==6.0.0 +pkgconfig==1.5.1 # via xmlsec polib==1.1.0 # via edx-i18n-tools psutil==1.2.1 py2neo==3.1.2 pycontracts==1.7.1 pycountry==18.12.8 pycparser==2.19 -pycryptodome==3.8.1 # via pdfminer.six +pycryptodome==3.8.2 # via pdfminer.six pycryptodomex==3.4.7 -pygments==2.4.1 +pygments==2.4.2 pygraphviz==1.5 pyjwkest==1.3.2 pyjwt==1.5.2 @@ -203,7 +205,7 @@ pyuca==1.1 pyyaml==5.1 git+https://github.com/edx/RecommenderXBlock.git@1.4.0#egg=recommender-xblock==1.4.0 redis==2.10.6 -reportlab==3.5.21 +reportlab==3.5.23 requests-oauthlib==1.1.0 requests==2.22.0 rest-condition==1.0.3 @@ -242,4 +244,5 @@ git+https://github.com/edx-solutions/xblock-drag-and-drop-v2@v2.2.1#egg=xblock-d git+https://github.com/open-craft/xblock-poll@add89e14558c30f3c8dc7431e5cd6536fff6d941#egg=xblock-poll==1.5.1 xblock-utils==1.2.1 xblock==1.2.2 +xmlsec==1.3.3 # via python3-saml zendesk==1.1.1 diff --git a/requirements/edx/coverage.txt b/requirements/edx/coverage.txt index e28ffece8c..09cbd1446f 100644 --- a/requirements/edx/coverage.txt +++ b/requirements/edx/coverage.txt @@ -10,5 +10,5 @@ inflect==2.1.0 # via jinja2-pluralize jinja2-pluralize==0.3.0 # via diff-cover jinja2==2.10.1 # via diff-cover, jinja2-pluralize markupsafe==1.1.1 # via jinja2 -pygments==2.4.1 # via diff-cover +pygments==2.4.2 # via diff-cover six==1.11.0 diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 269d568fd6..a4f2ab6960 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -33,7 +33,6 @@ argh==0.26.2 argparse==1.4.0 asn1crypto==0.24.0 astroid==1.5.3 -atomicwrites==1.3.0 attrs==17.4.0 babel==1.3 backports.functools-lru-cache==1.5 @@ -56,16 +55,17 @@ click==7.0 code-annotations==0.3.1 colorama==0.4.1 configparser==3.7.4 +contextlib2==0.5.5 coreapi==2.3.3 coreschema==0.0.4 coverage==4.4 git+https://github.com/edx/crowdsourcehinter.git@518605f0a95190949fe77bd39158450639e2e1dc#egg=crowdsourcehinter-xblock==0.1 -cryptography==2.6.1 +cryptography==2.7 cssselect==1.0.3 cssutils==1.0.2 ddt==1.2.1 decorator==4.4.0 -defusedxml==0.6.0 +defusedxml==0.5.0 dicttoxml==1.7.4 diff-cover==0.9.8 distlib==0.2.9.post0 @@ -103,7 +103,7 @@ django-simple-history==2.7.0 django-splash==0.2.2 django-statici18n==1.4.0 django-storages==1.4.1 -django-user-tasks==0.1.5 +django-user-tasks==0.1.7 django-waffle==0.12.0 django-webpack-loader==0.6.0 django==1.11.21 @@ -122,17 +122,17 @@ edx-django-oauth2-provider==1.3.5 edx-django-release-util==0.3.1 edx-django-sites-extensions==2.3.1 edx-django-utils==1.0.3 -edx-drf-extensions==2.2.1 -edx-enterprise==1.6.0 +edx-drf-extensions==2.3.0 +edx-enterprise==1.6.2 edx-i18n-tools==0.4.8 edx-lint==1.2.1 edx-milestones==0.1.13 edx-oauth2-provider==1.2.2 edx-opaque-keys[django]==0.4.4 -edx-organizations==2.0.2 +edx-organizations==2.0.3 edx-proctoring-proctortrack==1.0.5 edx-proctoring==2.0.3 -edx-rbac==0.2.1 +edx-rbac==1.0.1 edx-rest-api-client==1.9.2 edx-search==1.2.2 git+https://github.com/mitodl/edx-sga.git@3828ba9e413080a81b907a3381e5ffa05e063f81#egg=edx-sga==0.8.3 @@ -154,10 +154,9 @@ firebase-token-generator==1.3.2 flake8-polyfill==1.0.2 flake8==3.7.7 flask==1.0.3 -freezegun==0.3.11 +freezegun==0.3.12 fs-s3fs==0.1.8 fs==2.0.18 -funcsigs==1.0.2 functools32==3.2.3.post2 ; python_version == "2.7" future==0.17.1 futures==3.2.0 ; python_version == "2.7" @@ -170,8 +169,10 @@ httplib2==0.12.3 httpretty==0.9.6 idna==2.8 imagesize==1.1.0 # via sphinx +importlib-metadata==0.17 inflect==2.1.0 ipaddress==1.0.22 +isodate==0.6.0 isort==4.3.20 itsdangerous==1.1.0 itypes==1.1.0 @@ -200,7 +201,6 @@ mock==1.0.1 modernize==0.7 git+https://github.com/edx/MongoDBProxy.git@25b99097615bda06bd7cdfe5669ed80dc2a7fed0#egg=MongoDBProxy==0.1.0 mongoengine==0.10.0 -more-itertools==5.0.0 moto==0.3.1 mpmath==1.1.0 mysqlclient==1.4.2.post1 @@ -208,7 +208,7 @@ networkx==1.7 newrelic==4.20.0.120 nltk==3.4.1 nodeenv==1.1.1 -numpy==1.16.3 +numpy==1.16.4 oauth2==1.9.0.post1 oauthlib==2.1.0 openapi-codec==1.3.2 @@ -218,12 +218,13 @@ path.py==8.2.1 pathlib2==2.3.3 pathtools==0.1.2 paver==1.3.4 -pbr==5.2.0 +pbr==5.2.1 pdfminer.six==20181108 piexif==1.0.2 pillow==6.0.0 pip-tools==3.7.0 -pluggy==0.11.0 +pkgconfig==1.5.1 +pluggy==0.12.0 polib==1.1.0 psutil==1.2.1 py2neo==3.1.2 @@ -232,10 +233,10 @@ pycodestyle==2.5.0 pycontracts==1.7.1 pycountry==18.12.8 pycparser==2.19 -pycryptodome==3.8.1 +pycryptodome==3.8.2 pycryptodomex==3.4.7 pyflakes==2.1.1 -pygments==2.4.1 +pygments==2.4.2 pygraphviz==1.5 pyinotify==0.9.6 pyjwkest==1.3.2 @@ -252,7 +253,7 @@ pysqlite==2.8.3 ; python_version == "2.7" pysrt==1.1.1 pytest-attrib==0.1.3 pytest-cov==2.7.1 -pytest-django==3.4.8 +pytest-django==3.5.0 pytest-forked==1.0.2 pytest-randomly==1.2.3 pytest-xdist==1.28.0 @@ -270,7 +271,7 @@ pyyaml==5.1 radon==3.0.3 git+https://github.com/edx/RecommenderXBlock.git@1.4.0#egg=recommender-xblock==1.4.0 redis==2.10.6 -reportlab==3.5.21 +reportlab==3.5.23 requests-oauthlib==1.1.0 requests==2.22.0 rest-condition==1.0.3 @@ -317,7 +318,6 @@ virtualenv==16.6.0 voluptuous==0.11.5 vulture==1.0 watchdog==0.9.0 -wcwidth==0.1.7 web-fragments==0.3.0 webencodings==0.5.1 webob==1.8.5 @@ -327,5 +327,7 @@ git+https://github.com/edx-solutions/xblock-drag-and-drop-v2@v2.2.1#egg=xblock-d git+https://github.com/open-craft/xblock-poll@add89e14558c30f3c8dc7431e5cd6536fff6d941#egg=xblock-poll==1.5.1 xblock-utils==1.2.1 xblock==1.2.2 +xmlsec==1.3.3 xmltodict==0.12.0 zendesk==1.1.1 +zipp==0.5.1 diff --git a/requirements/edx/paver.txt b/requirements/edx/paver.txt index 063650a1d8..6555983821 100644 --- a/requirements/edx/paver.txt +++ b/requirements/edx/paver.txt @@ -16,7 +16,7 @@ mock==1.0.1 path.py==8.2.1 pathtools==0.1.2 # via watchdog paver==1.3.4 -pbr==5.2.0 # via stevedore +pbr==5.2.1 # via stevedore psutil==1.2.1 pymongo==2.9.1 python-memcached==1.59 diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index c77ca79115..2b6f9bc878 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -31,7 +31,6 @@ argh==0.26.2 argparse==1.4.0 # via caniusepython3 asn1crypto==0.24.0 astroid==1.5.3 # via pylint, pylint-celery -atomicwrites==1.3.0 # via pytest attrs==17.4.0 babel==1.3 backports.functools-lru-cache==1.5 @@ -53,17 +52,18 @@ click-log==0.3.2 # via edx-lint click==7.0 code-annotations==0.3.1 colorama==0.4.1 # via radon -configparser==3.7.4 # via entrypoints, flake8, pylint +configparser==3.7.4 # via entrypoints, flake8, importlib-metadata, pylint +contextlib2==0.5.5 # via importlib-metadata coreapi==2.3.3 coreschema==0.0.4 coverage==4.4 git+https://github.com/edx/crowdsourcehinter.git@518605f0a95190949fe77bd39158450639e2e1dc#egg=crowdsourcehinter-xblock==0.1 -cryptography==2.6.1 +cryptography==2.7 cssselect==1.0.3 cssutils==1.0.2 ddt==1.2.1 decorator==4.4.0 -defusedxml==0.6.0 +defusedxml==0.5.0 dicttoxml==1.7.4 # via moto diff-cover==0.9.8 distlib==0.2.9.post0 # via caniusepython3 @@ -100,7 +100,7 @@ django-simple-history==2.7.0 django-splash==0.2.2 django-statici18n==1.4.0 django-storages==1.4.1 -django-user-tasks==0.1.5 +django-user-tasks==0.1.7 django-waffle==0.12.0 django-webpack-loader==0.6.0 djangorestframework-jwt==1.11.0 @@ -118,17 +118,17 @@ edx-django-oauth2-provider==1.3.5 edx-django-release-util==0.3.1 edx-django-sites-extensions==2.3.1 edx-django-utils==1.0.3 -edx-drf-extensions==2.2.1 -edx-enterprise==1.6.0 +edx-drf-extensions==2.3.0 +edx-enterprise==1.6.2 edx-i18n-tools==0.4.8 edx-lint==1.2.1 edx-milestones==0.1.13 edx-oauth2-provider==1.2.2 edx-opaque-keys[django]==0.4.4 -edx-organizations==2.0.2 +edx-organizations==2.0.3 edx-proctoring-proctortrack==1.0.5 edx-proctoring==2.0.3 -edx-rbac==0.2.1 +edx-rbac==1.0.1 edx-rest-api-client==1.9.2 edx-search==1.2.2 git+https://github.com/mitodl/edx-sga.git@3828ba9e413080a81b907a3381e5ffa05e063f81#egg=edx-sga==0.8.3 @@ -149,10 +149,9 @@ firebase-token-generator==1.3.2 flake8-polyfill==1.0.2 # via radon flake8==3.7.7 # via flake8-polyfill flask==1.0.3 # via moto -freezegun==0.3.11 +freezegun==0.3.12 fs-s3fs==0.1.8 fs==2.0.18 -funcsigs==1.0.2 # via pytest functools32==3.2.3.post2 ; python_version == "2.7" # via flake8 future==0.17.1 futures==3.2.0 ; python_version == "2.7" @@ -164,8 +163,10 @@ html5lib==1.0.1 httplib2==0.12.3 httpretty==0.9.6 idna==2.8 +importlib-metadata==0.17 # via pluggy inflect==2.1.0 ipaddress==1.0.22 +isodate==0.6.0 isort==4.3.20 itsdangerous==1.1.0 # via flask itypes==1.1.0 @@ -193,7 +194,6 @@ mccabe==0.6.1 # via flake8, pylint mock==1.0.1 git+https://github.com/edx/MongoDBProxy.git@25b99097615bda06bd7cdfe5669ed80dc2a7fed0#egg=MongoDBProxy==0.1.0 mongoengine==0.10.0 -more-itertools==5.0.0 # via pytest moto==0.3.1 mpmath==1.1.0 mysqlclient==1.4.2.post1 @@ -201,33 +201,34 @@ networkx==1.7 newrelic==4.20.0.120 nltk==3.4.1 nodeenv==1.1.1 -numpy==1.16.3 +numpy==1.16.4 oauth2==1.9.0.post1 oauthlib==2.1.0 openapi-codec==1.3.2 git+https://github.com/edx/edx-ora2.git@2.2.3#egg=ora2==2.2.3 packaging==19.0 # via caniusepython3 path.py==8.2.1 -pathlib2==2.3.3 # via pytest, pytest-django +pathlib2==2.3.3 # via importlib-metadata, pytest-django pathtools==0.1.2 paver==1.3.4 -pbr==5.2.0 +pbr==5.2.1 pdfminer.six==20181108 piexif==1.0.2 pillow==6.0.0 -pluggy==0.11.0 # via pytest, tox +pkgconfig==1.5.1 +pluggy==0.12.0 # via tox polib==1.1.0 psutil==1.2.1 py2neo==3.1.2 -py==1.8.0 # via pytest, tox +py==1.8.0 # via tox pycodestyle==2.5.0 pycontracts==1.7.1 pycountry==18.12.8 pycparser==2.19 -pycryptodome==3.8.1 +pycryptodome==3.8.2 pycryptodomex==3.4.7 pyflakes==2.1.1 # via flake8 -pygments==2.4.1 +pygments==2.4.2 pygraphviz==1.5 pyjwkest==1.3.2 pyjwt==1.5.2 @@ -243,7 +244,7 @@ pysqlite==2.8.3 ; python_version == "2.7" pysrt==1.1.1 pytest-attrib==0.1.3 pytest-cov==2.7.1 -pytest-django==3.4.8 +pytest-django==3.5.0 pytest-forked==1.0.2 # via pytest-xdist pytest-randomly==1.2.3 pytest-xdist==1.28.0 @@ -261,7 +262,7 @@ pyyaml==5.1 radon==3.0.3 git+https://github.com/edx/RecommenderXBlock.git@1.4.0#egg=recommender-xblock==1.4.0 redis==2.10.6 -reportlab==3.5.21 +reportlab==3.5.23 requests-oauthlib==1.1.0 requests==2.22.0 rest-condition==1.0.3 @@ -303,7 +304,6 @@ user-util==0.1.5 virtualenv==16.6.0 # via tox voluptuous==0.11.5 watchdog==0.9.0 -wcwidth==0.1.7 # via pytest web-fragments==0.3.0 webencodings==0.5.1 webob==1.8.5 @@ -313,5 +313,7 @@ git+https://github.com/edx-solutions/xblock-drag-and-drop-v2@v2.2.1#egg=xblock-d git+https://github.com/open-craft/xblock-poll@add89e14558c30f3c8dc7431e5cd6536fff6d941#egg=xblock-poll==1.5.1 xblock-utils==1.2.1 xblock==1.2.2 +xmlsec==1.3.3 xmltodict==0.12.0 # via moto zendesk==1.1.1 +zipp==0.5.1 # via importlib-metadata