From f61a65588c38e7578ca3fca773994b89b72d7090 Mon Sep 17 00:00:00 2001 From: Eric Herrera Date: Sun, 12 Jul 2020 21:54:45 -0500 Subject: [PATCH] Add support for Django 1.11. Fix tests for Django 1.11. Upgrade requirements. Add constraint. --- notifier/digest.py | 5 +- notifier/management/commands/forums_digest.py | 73 ++++++++----------- notifier/management/commands/scheduler.py | 2 +- notifier/settings.py | 23 ++++++ notifier/tests/test_digest.py | 2 +- requirements/base.txt | 14 ++-- requirements/constraints.txt | 5 +- requirements/dev.txt | 27 ++++--- requirements/django.txt | 2 +- requirements/pip_tools.txt | 4 +- requirements/quality.txt | 16 ++-- requirements/test.txt | 12 +-- requirements/travis.txt | 16 ++-- 13 files changed, 108 insertions(+), 93 deletions(-) diff --git a/notifier/digest.py b/notifier/digest.py index 31c7a8f..e1994bf 100644 --- a/notifier/digest.py +++ b/notifier/digest.py @@ -10,7 +10,6 @@ from django.conf import settings from django.template.loader import get_template -from django.template import Context from django.utils.html import strip_tags from django.utils.translation import ugettext as _, activate, deactivate from opaque_keys.edx.keys import CourseKey @@ -228,7 +227,7 @@ def render_digest(user, digest, title, description): Returns two strings: (text_body, html_body). """ logger.info("rendering email message: {user_id: %s}", user['id']) - context = Context({ + context = { 'user': user, 'digest': digest, 'title': title, @@ -239,7 +238,7 @@ def render_digest(user, digest, title, description): 'logo_image_url': settings.LOGO_IMAGE_URL, 'unsubscribe_url': _get_unsubscribe_url(user), 'postal_address': settings.EMAIL_SENDER_POSTAL_ADDRESS, - }) + } with _activate_user_lang(user): text = get_template('digest-email.txt').render(context) diff --git a/notifier/management/commands/forums_digest.py b/notifier/management/commands/forums_digest.py index 267e539..1e70619 100644 --- a/notifier/management/commands/forums_digest.py +++ b/notifier/management/commands/forums_digest.py @@ -5,17 +5,13 @@ from __future__ import unicode_literals import datetime -import celery + from dateutil.parser import parse as date_parse from django.conf import settings -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from django.core.serializers.json import DjangoJSONEncoder import json import logging -from optparse import make_option -import pytz -import requests -import sys from notifier.digest import render_digest, Digest, DigestCourse, DigestThread, DigestItem from notifier.pull import generate_digest_content @@ -39,45 +35,34 @@ class Command(BaseCommand): """ """ + def add_arguments(self, parser): + """Add comand arguments.""" + parser.add_argument('--to_datetime', + help='datetime as of which to generate digest content, in ISO-8601 format (UTC). Defaults to today at 00:00 (UTC).'), + parser.add_argument('--minutes', + type='int', + default=1440, + help='number of minutes up to TO_DATETIME for which to generate digest content. Defaults to 1440 (one day).'), + parser.add_argument('--users', + dest='users_str', + help='send digests for the specified users only (regardless of opt-out settings!)'), + parser.add_argument('--show-content', + action='store_true', + dest='show_content', + help='output the retrieved content only (don\'t send anything)'), + parser.add_argument('--show-users', + action='store_true', + dest='show_users', + help='output the retrieved users only (don\'t fetch content or send anything)'), + parser.add_argument('--show-text', + action='store_true', + dest='show_text', + help='output the rendered text body of the first user-digest generated, and exit (don\'t send anything)'), + parser.add_argument('--show-html', + action='store_true', + dest='show_html', + help='output the rendered html body of the first user-digest generated, and exit (don\'t send anything)'), - option_list = BaseCommand.option_list + ( - make_option('--to_datetime', - action='store', - dest='to_datetime', - default=None, - help='datetime as of which to generate digest content, in ISO-8601 format (UTC). Defaults to today at 00:00 (UTC).'), - make_option('--minutes', - action='store', - dest='minutes', - type='int', - default=1440, - help='number of minutes up to TO_DATETIME for which to generate digest content. Defaults to 1440 (one day).'), - make_option('--users', - action='store', - dest='users_str', - default=None, - help='send digests for the specified users only (regardless of opt-out settings!)'), - make_option('--show-content', - action='store_true', - dest='show_content', - default=None, - help='output the retrieved content only (don\'t send anything)'), - make_option('--show-users', - action='store_true', - dest='show_users', - default=None, - help='output the retrieved users only (don\'t fetch content or send anything)'), - make_option('--show-text', - action='store_true', - dest='show_text', - default=None, - help='output the rendered text body of the first user-digest generated, and exit (don\'t send anything)'), - make_option('--show-html', - action='store_true', - dest='show_html', - default=None, - help='output the rendered html body of the first user-digest generated, and exit (don\'t send anything)'), - ) def get_specific_users(self, user_ids): # this makes an individual HTTP request for each user - diff --git a/notifier/management/commands/scheduler.py b/notifier/management/commands/scheduler.py index ac5fa64..2c5f6d2 100644 --- a/notifier/management/commands/scheduler.py +++ b/notifier/management/commands/scheduler.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from apscheduler.schedulers.blocking import BlockingScheduler from django.conf import settings -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from notifier.tasks import do_forums_digests diff --git a/notifier/settings.py b/notifier/settings.py index 0abc8fe..f7b07ff 100644 --- a/notifier/settings.py +++ b/notifier/settings.py @@ -1,10 +1,15 @@ from __future__ import absolute_import from __future__ import unicode_literals from datetime import timedelta +from os.path import abspath, dirname, join import logging import os import platform +here = lambda *x: join(abspath(dirname(__file__)), *x) +PROJECT_ROOT = here('..') +root = lambda *x: abspath(join(abspath(PROJECT_ROOT), *x)) + DATABASES = { 'default': { # Database backend defaults to 'sqlite3', but 'mysql' is also supported. @@ -30,6 +35,24 @@ SERVICE_NAME = 'notifier' +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'APP_DIRS': True, + 'DIRS': ( + root('templates'), + ), + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + # Misc. Notifier Formatting FORUM_DIGEST_EMAIL_SENDER = os.getenv('FORUM_DIGEST_EMAIL_SENDER', 'notifications@example.org') diff --git a/notifier/tests/test_digest.py b/notifier/tests/test_digest.py index f8c5081..8f47a5d 100644 --- a/notifier/tests/test_digest.py +++ b/notifier/tests/test_digest.py @@ -123,7 +123,7 @@ def test_user_lang_pref_supported(self, mock_activate, mock_deactivate): self.user["preferences"][LANGUAGE_PREFERENCE_KEY] = user_lang render_digest(self.user, self.digest, "dummy", "dummy") mock_activate.assert_called_with(user_lang) - mock_deactivate.assert_called() + self.assertTrue(mock_deactivate.called) @patch("notifier.digest.activate") def test_user_lang_pref_unsupported(self, mock_activate): diff --git a/requirements/base.txt b/requirements/base.txt index 7f589ee..a338a7b 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -11,17 +11,17 @@ apscheduler==3.6.3 # via -r requirements/base.in billiard==3.3.0.23 # via -r requirements/base.in, celery boto==2.49.0 # via -r requirements/base.in, django-ses celery==3.1.26.post2 # via -r requirements/base.in, django-celery -certifi==2020.4.5.1 # via requests +certifi==2020.6.20 # via requests chardet==3.0.4 # via requests django-celery==3.3.1 # via -r requirements/base.in django-configurations==2.2 # via -r requirements/base.in django-coverage==1.2.4 # via -r requirements/base.in django-ses==0.8.14 # via -r requirements/base.in -django==1.8.18 # via -c requirements/constraints.txt, -r requirements/base.in, django-celery +django==1.11.29 # via -c requirements/constraints.txt, -r requirements/base.in, django-celery funcsigs==1.0.2 # via apscheduler future==0.18.2 # via django-ses futures==3.3.0 ; python_version == "2.7" # via -c requirements/constraints.txt, apscheduler -idna==2.9 # via requests +idna==2.10 # via requests kombu==3.0.37 # via -r requirements/base.in, celery logilab-astng==0.24.3 # via -r requirements/base.in logilab-common==1.4.4 # via -r requirements/base.in, logilab-astng @@ -29,10 +29,10 @@ mysqlclient==1.4.6 # via -r requirements/base.in pbr==5.4.5 # via stevedore pymongo==3.10.1 # via edx-opaque-keys python-dateutil==2.8.1 # via -r requirements/base.in -pytz==2020.1 # via -r requirements/base.in, apscheduler, celery, django-ses, tzlocal -redis==3.5.2 # via -r requirements/base.in -requests==2.23.0 # via -r requirements/base.in -six==1.14.0 # via -r requirements/base.in, apscheduler, django-configurations, edx-opaque-keys, logilab-common, python-dateutil, stevedore +pytz==2020.1 # via -r requirements/base.in, apscheduler, celery, django, django-ses, tzlocal +redis==3.5.3 # via -r requirements/base.in +requests==2.24.0 # via -r requirements/base.in +six==1.15.0 # via -r requirements/base.in, apscheduler, django-configurations, edx-opaque-keys, logilab-common, python-dateutil, stevedore stevedore==1.32.0 # via edx-opaque-keys tzlocal==2.1 # via apscheduler urllib3==1.25.9 # via requests diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 36a0b97..7a976ab 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -11,10 +11,13 @@ # TODO: Many pinned dependencies should be unpinned and/or moved to this constraints file. # Use latest Django LTS version -Django<1.8.19 +Django<2 # mock version 4.0.0 drops support for python 3.5 mock<4.0.0 +# edx-lint remove support for python 2 after this version +edx-lint<1.5.0 + # Already in python3 standard library futures; python_version == "2.7" diff --git a/requirements/dev.txt b/requirements/dev.txt index 5ec8657..b339fec 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -8,21 +8,23 @@ amqp==1.4.9 # via -r requirements/base.txt, kombu anyjson==0.3.3 # via -r requirements/base.txt, kombu apscheduler==3.6.3 # via -r requirements/base.txt -autopep8==1.5.2 # via -r requirements/dev.in +autopep8==1.5.3 # via -r requirements/dev.in billiard==3.3.0.23 # via -r requirements/base.txt, celery boto==2.49.0 # via -r requirements/base.txt, django-ses celery==3.1.26.post2 # via -r requirements/base.txt, django-celery -certifi==2020.4.5.1 # via -r requirements/base.txt, requests +certifi==2020.6.20 # via -r requirements/base.txt, requests chardet==3.0.4 # via -r requirements/base.txt, requests django-celery==3.3.1 # via -r requirements/base.txt django-configurations==2.2 # via -r requirements/base.txt django-coverage==1.2.4 # via -r requirements/base.txt django-ses==0.8.14 # via -r requirements/base.txt -django==1.8.18 # via -c requirements/constraints.txt, -r requirements/base.txt, django-celery +django==1.11.29 # via -c requirements/constraints.txt, -r requirements/base.txt, django-celery funcsigs==1.0.2 # via -r requirements/base.txt, apscheduler future==0.18.2 # via -r requirements/base.txt, django-ses futures==3.3.0 ; python_version == "2.7" # via -c requirements/constraints.txt, -r requirements/base.txt, apscheduler -idna==2.9 # via -r requirements/base.txt, requests +gitdb2==2.0.6 # via gitpython +gitpython==2.1.15 # via transifex-client +idna==2.10 # via -r requirements/base.txt, requests kombu==3.0.37 # via -r requirements/base.txt, celery logilab-astng==0.24.3 # via -r requirements/base.txt logilab-common==1.4.4 # via -r requirements/base.txt, logilab-astng @@ -31,15 +33,18 @@ pbr==5.4.5 # via -r requirements/base.txt, stevedore pycodestyle==2.6.0 # via autopep8 pymongo==3.10.1 # via -r requirements/base.txt, edx-opaque-keys python-dateutil==2.8.1 # via -r requirements/base.txt -python-slugify==1.2.6 # via transifex-client -pytz==2020.1 # via -r requirements/base.txt, apscheduler, celery, django-ses, tzlocal -redis==3.5.2 # via -r requirements/base.txt -requests==2.23.0 # via -r requirements/base.txt, transifex-client -six==1.14.0 # via -r requirements/base.txt, apscheduler, django-configurations, edx-opaque-keys, logilab-common, python-dateutil, stevedore, transifex-client +python-slugify==4.0.1 # via transifex-client +pytz==2020.1 # via -r requirements/base.txt, apscheduler, celery, django, django-ses, tzlocal +redis==3.5.3 # via -r requirements/base.txt +requests==2.24.0 # via -r requirements/base.txt, transifex-client +six==1.15.0 # via -r requirements/base.txt, apscheduler, django-configurations, edx-opaque-keys, logilab-common, python-dateutil, stevedore, transifex-client +smmap2==3.0.1 # via gitdb2 +smmap==3.0.4 # via smmap2 stevedore==1.32.0 # via -r requirements/base.txt, edx-opaque-keys -transifex-client==0.13.9 # via -r requirements/dev.in +text-unidecode==1.3 # via python-slugify +toml==0.10.1 # via autopep8 +transifex-client==0.13.11 # via -r requirements/dev.in tzlocal==2.1 # via -r requirements/base.txt, apscheduler -unidecode==1.1.1 # via python-slugify urllib3==1.25.9 # via -r requirements/base.txt, requests, transifex-client # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/django.txt b/requirements/django.txt index 7530cd3..3d5e362 100644 --- a/requirements/django.txt +++ b/requirements/django.txt @@ -1 +1 @@ -django==1.8.18 # via -c requirements/constraints.txt, -r requirements/base.in, -r requirements/base.txt, django-celery +django==1.11.29 # via -c requirements/constraints.txt, -r requirements/base.in, -r requirements/base.txt, django-celery diff --git a/requirements/pip_tools.txt b/requirements/pip_tools.txt index 937f1d6..279019f 100644 --- a/requirements/pip_tools.txt +++ b/requirements/pip_tools.txt @@ -5,8 +5,8 @@ # make upgrade # click==7.1.2 # via pip-tools -pip-tools==5.1.2 # via -r requirements/pip_tools.in -six==1.14.0 # via pip-tools +pip-tools==5.2.1 # via -r requirements/pip_tools.in +six==1.15.0 # via pip-tools # The following packages are considered to be unsafe in a requirements file: # pip diff --git a/requirements/quality.txt b/requirements/quality.txt index 0a897c1..f41d584 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -8,20 +8,20 @@ argparse==1.4.0 # via caniusepython3 astroid==1.6.6 # via pylint, pylint-celery backports.functools-lru-cache==1.6.1 # via astroid, caniusepython3, isort, pylint caniusepython3==7.2.0 # via -r requirements/quality.in -certifi==2020.4.5.1 # via requests +certifi==2020.6.20 # via requests chardet==3.0.4 # via requests click-log==0.3.2 # via edx-lint click==7.1.2 # via click-log, edx-lint configparser==4.0.2 # via pydocstyle, pylint -distlib==0.3.0 # via caniusepython3 -edx-lint==1.4.1 # via -r requirements/quality.in +distlib==0.3.1 # via caniusepython3 +edx-lint==1.4.1 # via -c requirements/constraints.txt, -r requirements/quality.in enum34==1.1.10 # via astroid futures==3.3.0 ; python_version == "2.7" # via -c requirements/constraints.txt, caniusepython3, isort -idna==2.9 # via requests +idna==2.10 # via requests isort==4.3.21 # via -r requirements/quality.in, pylint -lazy-object-proxy==1.4.3 # via astroid +lazy-object-proxy==1.5.0 # via astroid mccabe==0.6.1 # via pylint -packaging==20.3 # via caniusepython3 +packaging==20.4 # via caniusepython3 pycodestyle==2.6.0 # via -r requirements/quality.in pydocstyle==3.0.0 # via -r requirements/quality.in pylint-celery==0.3 # via edx-lint @@ -29,9 +29,9 @@ pylint-django==0.11.1 # via edx-lint pylint-plugin-utils==0.6 # via pylint-celery, pylint-django pylint==1.9.5 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils pyparsing==2.4.7 # via packaging -requests==2.23.0 # via caniusepython3 +requests==2.24.0 # via caniusepython3 singledispatch==3.4.0.3 # via astroid, pylint -six==1.14.0 # via astroid, edx-lint, packaging, pydocstyle, pylint, singledispatch +six==1.15.0 # via astroid, edx-lint, packaging, pydocstyle, pylint, singledispatch snowballstemmer==2.0.0 # via pydocstyle urllib3==1.25.9 # via requests wrapt==1.12.1 # via astroid diff --git a/requirements/test.txt b/requirements/test.txt index cafae9d..ec05cae 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -11,7 +11,7 @@ apscheduler==3.6.3 # via -r requirements/base.in, -r requirements/base.tx billiard==3.3.0.23 # via -r requirements/base.in, -r requirements/base.txt, celery boto==2.49.0 # via -r requirements/base.in, -r requirements/base.txt, django-ses celery==3.1.26.post2 # via -r requirements/base.in, -r requirements/base.txt, django-celery -certifi==2020.4.5.1 # via -r requirements/base.txt, requests +certifi==2020.6.20 # via -r requirements/base.txt, requests chardet==3.0.4 # via -r requirements/base.txt, requests django-celery==3.3.1 # via -r requirements/base.in, -r requirements/base.txt django-configurations==2.2 # via -r requirements/base.in, -r requirements/base.txt @@ -20,7 +20,7 @@ django-ses==0.8.14 # via -r requirements/base.in, -r requirements/base.tx funcsigs==1.0.2 # via -r requirements/base.txt, apscheduler, mock future==0.18.2 # via -r requirements/base.txt, django-ses futures==3.3.0 ; python_version == "2.7" # via -c requirements/constraints.txt, -r requirements/base.txt, apscheduler -idna==2.9 # via -r requirements/base.txt, requests +idna==2.10 # via -r requirements/base.txt, requests kombu==3.0.37 # via -r requirements/base.in, -r requirements/base.txt, celery logilab-astng==0.24.3 # via -r requirements/base.in, -r requirements/base.txt logilab-common==1.4.4 # via -r requirements/base.in, -r requirements/base.txt, logilab-astng @@ -29,10 +29,10 @@ mysqlclient==1.4.6 # via -r requirements/base.in, -r requirements/base.tx pbr==5.4.5 # via -r requirements/base.txt, stevedore pymongo==3.10.1 # via -r requirements/base.txt, edx-opaque-keys python-dateutil==2.8.1 # via -r requirements/base.in, -r requirements/base.txt -pytz==2020.1 # via -r requirements/base.in, -r requirements/base.txt, apscheduler, celery, django-ses, tzlocal -redis==3.5.2 # via -r requirements/base.in, -r requirements/base.txt -requests==2.23.0 # via -r requirements/base.in, -r requirements/base.txt -six==1.14.0 # via -r requirements/base.in, -r requirements/base.txt, apscheduler, django-configurations, edx-opaque-keys, logilab-common, mock, python-dateutil, stevedore +pytz==2020.1 # via -r requirements/base.in, -r requirements/base.txt, apscheduler, celery, django, django-ses, tzlocal +redis==3.5.3 # via -r requirements/base.in, -r requirements/base.txt +requests==2.24.0 # via -r requirements/base.in, -r requirements/base.txt +six==1.15.0 # via -r requirements/base.in, -r requirements/base.txt, apscheduler, django-configurations, edx-opaque-keys, logilab-common, mock, python-dateutil, stevedore stevedore==1.32.0 # via -r requirements/base.txt, edx-opaque-keys tzlocal==2.1 # via -r requirements/base.txt, apscheduler urllib3==1.25.9 # via -r requirements/base.txt, requests diff --git a/requirements/travis.txt b/requirements/travis.txt index 812dce8..f644d83 100644 --- a/requirements/travis.txt +++ b/requirements/travis.txt @@ -11,23 +11,23 @@ apscheduler==3.6.3 # via -r requirements/test.txt billiard==3.3.0.23 # via -r requirements/test.txt, celery boto==2.49.0 # via -r requirements/test.txt, django-ses celery==3.1.26.post2 # via -r requirements/test.txt, django-celery -certifi==2020.4.5.1 # via -r requirements/test.txt, requests, urllib3 +certifi==2020.6.20 # via -r requirements/test.txt, requests, urllib3 cffi==1.14.0 # via cryptography chardet==3.0.4 # via -r requirements/test.txt, requests -coverage==5.1 # via coveralls +coverage==5.2 # via coveralls coveralls==1.11.1 # via -r requirements/travis.in cryptography==2.9.2 # via pyopenssl, urllib3 django-celery==3.3.1 # via -r requirements/test.txt django-configurations==2.2 # via -r requirements/test.txt django-coverage==1.2.4 # via -r requirements/test.txt django-ses==0.8.14 # via -r requirements/test.txt -django==1.8.18 # via -c requirements/constraints.txt, -r requirements/test.txt, django-celery +django==1.11.29 # via -c requirements/constraints.txt, -r requirements/test.txt, django-celery docopt==0.6.2 # via coveralls enum34==1.1.10 # via cryptography funcsigs==1.0.2 # via -r requirements/test.txt, apscheduler, mock future==0.18.2 # via -r requirements/test.txt, django-ses futures==3.3.0 ; python_version == "2.7" # via -c requirements/constraints.txt, -r requirements/test.txt, apscheduler -idna==2.9 # via -r requirements/test.txt, requests, urllib3 +idna==2.10 # via -r requirements/test.txt, requests, urllib3 ipaddress==1.0.23 # via cryptography, urllib3 kombu==3.0.37 # via -r requirements/test.txt, celery logilab-astng==0.24.3 # via -r requirements/test.txt @@ -39,10 +39,10 @@ pycparser==2.20 # via cffi pymongo==3.10.1 # via -r requirements/test.txt, edx-opaque-keys pyopenssl==19.1.0 # via urllib3 python-dateutil==2.8.1 # via -r requirements/test.txt -pytz==2020.1 # via -r requirements/test.txt, apscheduler, celery, django-ses, tzlocal -redis==3.5.2 # via -r requirements/test.txt -requests==2.23.0 # via -r requirements/test.txt, coveralls -six==1.14.0 # via -r requirements/test.txt, apscheduler, cryptography, django-configurations, edx-opaque-keys, logilab-common, mock, pyopenssl, python-dateutil, stevedore +pytz==2020.1 # via -r requirements/test.txt, apscheduler, celery, django, django-ses, tzlocal +redis==3.5.3 # via -r requirements/test.txt +requests==2.24.0 # via -r requirements/test.txt, coveralls +six==1.15.0 # via -r requirements/test.txt, apscheduler, cryptography, django-configurations, edx-opaque-keys, logilab-common, mock, pyopenssl, python-dateutil, stevedore stevedore==1.32.0 # via -r requirements/test.txt, edx-opaque-keys tzlocal==2.1 # via -r requirements/test.txt, apscheduler urllib3[secure]==1.25.9 # via -r requirements/test.txt, coveralls, requests