From f33f12bbeae0a46c95acb64b1330cf40e118bd5a Mon Sep 17 00:00:00 2001 From: edX requirements bot <49161187+edx-requirements-bot@users.noreply.github.com> Date: Mon, 22 Feb 2021 05:42:21 -0500 Subject: [PATCH] BOM-2358 : Pyupgrade in dashboard, debug, discussion apps (#26529) * Python code cleanup by the cleanup-python-code Jenkins job. This pull request was generated by the cleanup-python-code Jenkins job, which ran ``` cd lms/djangoapps/dashboard; find . -type f -name '*.py' | while read fname; do sed -i 's/ # lint-amnesty, pylint: disable=super-with-arguments//; s/ # lint-amnesty, pylint: disable=import-error, wrong-import-order//; s/ # lint-amnesty, pylint: disable=wrong-import-order//' "$fname"; done; find . -type f -name '*.py' | while read fname; do pyupgrade --exit-zero-even-if-changed --py3-plus --py36-plus --py38-plus "$fname"; done; isort --recursive . ``` The following packages were installed: `pyupgrade,isort` * feedback done Co-authored-by: Zulqarnain <muhammad.zulqarnain@arbisoft.com> --- lms/djangoapps/dashboard/git_import.py | 54 ++-- .../management/commands/git_add_course.py | 8 +- .../commands/tests/test_git_add_course.py | 31 ++- lms/djangoapps/dashboard/models.py | 1 - lms/djangoapps/dashboard/sysadmin.py | 60 +++-- .../dashboard/tests/test_sysadmin.py | 34 ++- .../management/commands/dump_xml_courses.py | 14 +- lms/djangoapps/debug/views.py | 6 +- lms/djangoapps/discussion/apps.py | 12 +- .../base/event_transformers.py | 9 +- .../django_comment_client/base/tests.py | 238 +++++++++--------- .../django_comment_client/base/views.py | 15 +- .../django_comment_client/middleware.py | 5 +- .../django_comment_client/permissions.py | 5 +- .../django_comment_client/tests/factories.py | 4 +- .../django_comment_client/tests/group_id.py | 2 +- .../tests/mock_cs_server/mock_cs_server.py | 8 +- .../mock_cs_server/test_mock_cs_server.py | 6 +- .../tests/test_middleware.py | 7 +- .../tests/test_models.py | 4 +- .../django_comment_client/tests/test_utils.py | 62 ++--- .../django_comment_client/tests/unicode.py | 14 +- .../django_comment_client/tests/utils.py | 18 +- .../discussion/django_comment_client/utils.py | 47 ++-- .../commands/assign_roles_for_course.py | 4 +- .../commands/create_roles_for_existing.py | 4 +- .../commands/get_discussion_link.py | 2 +- .../management/commands/reload_forum_users.py | 2 +- .../management/commands/show_permissions.py | 8 +- .../discussion/notification_prefs/tests.py | 15 +- .../discussion/notification_prefs/views.py | 9 +- lms/djangoapps/discussion/plugins.py | 2 +- lms/djangoapps/discussion/rest_api/api.py | 24 +- lms/djangoapps/discussion/rest_api/forms.py | 15 +- .../discussion/rest_api/pagination.py | 4 +- .../discussion/rest_api/serializers.py | 20 +- .../discussion/rest_api/tests/test_api.py | 177 ++++++------- .../discussion/rest_api/tests/test_forms.py | 6 +- .../discussion/rest_api/tests/test_render.py | 12 +- .../rest_api/tests/test_serializers.py | 53 ++-- .../discussion/rest_api/tests/test_views.py | 182 +++++++------- .../discussion/rest_api/tests/utils.py | 35 ++- lms/djangoapps/discussion/rest_api/urls.py | 4 +- lms/djangoapps/discussion/rest_api/views.py | 22 +- lms/djangoapps/discussion/signals/handlers.py | 11 +- lms/djangoapps/discussion/tasks.py | 13 +- .../discussion/discussion_board_js.template | 3 +- .../discussion/discussion_profile_page.html | 3 +- .../discussion/tests/test_signals.py | 2 - lms/djangoapps/discussion/tests/test_tasks.py | 15 +- lms/djangoapps/discussion/tests/test_views.py | 190 +++++++------- lms/djangoapps/discussion/views.py | 23 +- 52 files changed, 728 insertions(+), 796 deletions(-) diff --git a/lms/djangoapps/dashboard/git_import.py b/lms/djangoapps/dashboard/git_import.py index 279fb72a98e..4a7d46ce973 100644 --- a/lms/djangoapps/dashboard/git_import.py +++ b/lms/djangoapps/dashboard/git_import.py @@ -17,9 +17,9 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from opaque_keys.edx.locator import CourseLocator from six import StringIO +from xmodule.util.sandboxing import DEFAULT_PYTHON_LIB_FILENAME from lms.djangoapps.dashboard.models import CourseImportLog -from xmodule.util.sandboxing import DEFAULT_PYTHON_LIB_FILENAME log = logging.getLogger(__name__) @@ -35,7 +35,7 @@ class GitImportError(Exception): def __init__(self, message=None): if message is None: message = self.MESSAGE - super(GitImportError, self).__init__(message) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(message) class GitImportErrorNoDir(GitImportError): @@ -43,11 +43,11 @@ class GitImportErrorNoDir(GitImportError): GitImportError when no directory exists at the specified path. """ def __init__(self, repo_dir): - super(GitImportErrorNoDir, self).__init__( # lint-amnesty, pylint: disable=super-with-arguments + super().__init__( _( - u"Path {0} doesn't exist, please create it, " - u"or configure a different path with " - u"GIT_REPO_DIR" + "Path {0} doesn't exist, please create it, " + "or configure a different path with " + "GIT_REPO_DIR" ).format(repo_dir) ) @@ -118,8 +118,8 @@ def cmd_log(cmd, cwd): """ output = subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT).decode('utf-8') - log.debug(u'Command was: %r. Working directory was: %r', ' '.join(cmd), cwd) - log.debug(u'Command output was: %r', output) + log.debug('Command was: %r. Working directory was: %r', ' '.join(cmd), cwd) + log.debug('Command output was: %r', output) return output @@ -135,15 +135,15 @@ def switch_branch(branch, rdir): try: cmd_log(['git', 'fetch', ], rdir) except subprocess.CalledProcessError as ex: - log.exception(u'Unable to fetch remote: %r', ex.output) + log.exception('Unable to fetch remote: %r', ex.output) raise GitImportErrorCannotBranch() # lint-amnesty, pylint: disable=raise-missing-from # Check if the branch is available from the remote. - cmd = ['git', 'ls-remote', 'origin', '-h', 'refs/heads/{0}'.format(branch), ] + cmd = ['git', 'ls-remote', 'origin', '-h', f'refs/heads/{branch}', ] try: output = cmd_log(cmd, rdir) except subprocess.CalledProcessError as ex: - log.exception(u'Getting a list of remote branches failed: %r', ex.output) + log.exception('Getting a list of remote branches failed: %r', ex.output) raise GitImportErrorCannotBranch() # lint-amnesty, pylint: disable=raise-missing-from if branch not in output: raise GitImportErrorRemoteBranchMissing() @@ -152,7 +152,7 @@ def switch_branch(branch, rdir): try: output = cmd_log(cmd, rdir) except subprocess.CalledProcessError as ex: - log.exception(u'Getting a list of local branches failed: %r', ex.output) + log.exception('Getting a list of local branches failed: %r', ex.output) raise GitImportErrorCannotBranch() # lint-amnesty, pylint: disable=raise-missing-from branches = [] for line in output.split('\n'): @@ -161,18 +161,18 @@ def switch_branch(branch, rdir): if branch not in branches: # Checkout with -b since it is remote only cmd = ['git', 'checkout', '--force', '--track', - '-b', branch, 'origin/{0}'.format(branch), ] + '-b', branch, f'origin/{branch}', ] try: cmd_log(cmd, rdir) except subprocess.CalledProcessError as ex: - log.exception(u'Unable to checkout remote branch: %r', ex.output) + log.exception('Unable to checkout remote branch: %r', ex.output) raise GitImportErrorCannotBranch() # lint-amnesty, pylint: disable=raise-missing-from # Go ahead and reset hard to the newest version of the branch now that we know # it is local. try: - cmd_log(['git', 'reset', '--hard', 'origin/{0}'.format(branch), ], rdir) + cmd_log(['git', 'reset', '--hard', f'origin/{branch}', ], rdir) except subprocess.CalledProcessError as ex: - log.exception(u'Unable to reset to branch: %r', ex.output) + log.exception('Unable to reset to branch: %r', ex.output) raise GitImportErrorCannotBranch() # lint-amnesty, pylint: disable=raise-missing-from @@ -215,9 +215,9 @@ def add_repo(repo, rdir_in, branch=None): rdir = os.path.basename(rdir_in) else: rdir = repo.rsplit('/', 1)[-1].rsplit('.git', 1)[0] - log.debug(u'rdir = %s', rdir) + log.debug('rdir = %s', rdir) - rdirp = '{0}/{1}'.format(git_repo_dir, rdir) + rdirp = f'{git_repo_dir}/{rdir}' if os.path.exists(rdirp): log.info('directory already exists, doing a git pull instead ' 'of git clone') @@ -231,7 +231,7 @@ def add_repo(repo, rdir_in, branch=None): try: ret_git = cmd_log(cmd, cwd=cwd) except subprocess.CalledProcessError as ex: - log.exception(u'Error running git pull: %r', ex.output) + log.exception('Error running git pull: %r', ex.output) raise GitImportErrorCannotPull() # lint-amnesty, pylint: disable=raise-missing-from if branch: @@ -242,10 +242,10 @@ def add_repo(repo, rdir_in, branch=None): try: commit_id = cmd_log(cmd, cwd=rdirp) except subprocess.CalledProcessError as ex: - log.exception(u'Unable to get git log: %r', ex.output) + log.exception('Unable to get git log: %r', ex.output) raise GitImportErrorBadRepo() # lint-amnesty, pylint: disable=raise-missing-from - ret_git += u'\nCommit ID: {0}'.format(commit_id) + ret_git += f'\nCommit ID: {commit_id}' # get branch cmd = ['git', 'symbolic-ref', '--short', 'HEAD', ] @@ -254,10 +254,10 @@ def add_repo(repo, rdir_in, branch=None): except subprocess.CalledProcessError as ex: # I can't discover a way to excercise this, but git is complex # so still logging and raising here in case. - log.exception(u'Unable to determine branch: %r', ex.output) + log.exception('Unable to determine branch: %r', ex.output) raise GitImportErrorBadRepo() # lint-amnesty, pylint: disable=raise-missing-from - ret_git += u'{0}Branch: {1}'.format(' \n', branch) + ret_git += '{}Branch: {}'.format(' \n', branch) # Get XML logging logger and capture debug to parse results output = StringIO() @@ -306,8 +306,8 @@ def add_repo(repo, rdir_in, branch=None): # We want set course id in CourseImportLog as CourseLocator. So that in split module # environment course id remain consistent as CourseLocator instance. course_key = CourseLocator(*course_id) - cdir = '{0}/{1}'.format(git_repo_dir, course_key.course) - log.debug(u'Studio course dir = %s', cdir) + cdir = f'{git_repo_dir}/{course_key.course}' + log.debug('Studio course dir = %s', cdir) if os.path.exists(cdir) and not os.path.islink(cdir): log.debug(' -> exists, but is not symlink') @@ -319,7 +319,7 @@ def add_repo(repo, rdir_in, branch=None): log.exception('Failed to remove course directory') if not os.path.exists(cdir): - log.debug(u' -> creating symlink between %s and %s', rdirp, cdir) + log.debug(' -> creating symlink between %s and %s', rdirp, cdir) try: os.symlink(os.path.abspath(rdirp), os.path.abspath(cdir)) except OSError: @@ -348,5 +348,5 @@ def add_repo(repo, rdir_in, branch=None): ) cil.save() - log.debug(u'saved CourseImportLog for %s', cil.course_id) + log.debug('saved CourseImportLog for %s', cil.course_id) mdb.close() diff --git a/lms/djangoapps/dashboard/management/commands/git_add_course.py b/lms/djangoapps/dashboard/management/commands/git_add_course.py index dfd28543804..331079a00bf 100644 --- a/lms/djangoapps/dashboard/management/commands/git_add_course.py +++ b/lms/djangoapps/dashboard/management/commands/git_add_course.py @@ -7,11 +7,11 @@ import logging from django.core.management.base import BaseCommand, CommandError from django.utils.translation import ugettext as _ - -from lms.djangoapps.dashboard import git_import from xmodule.modulestore.django import modulestore from xmodule.modulestore.xml import XMLModuleStore +from lms.djangoapps.dashboard import git_import + log = logging.getLogger(__name__) @@ -26,8 +26,8 @@ class Command(BaseCommand): # to store the courses for use on the Web site. help = ('Usage: ' 'git_add_course repository_url [directory to check out into] [repository_branch] ' - '\n{0}'.format(_('Import the specified git repository and optional branch into the ' - 'modulestore and optionally specified directory.'))) + '\n{}'.format(_('Import the specified git repository and optional branch into the ' + 'modulestore and optionally specified directory.'))) def add_arguments(self, parser): # Positional arguments diff --git a/lms/djangoapps/dashboard/management/commands/tests/test_git_add_course.py b/lms/djangoapps/dashboard/management/commands/tests/test_git_add_course.py index baddfdb1c3c..65bb015620e 100644 --- a/lms/djangoapps/dashboard/management/commands/tests/test_git_add_course.py +++ b/lms/djangoapps/dashboard/management/commands/tests/test_git_add_course.py @@ -16,6 +16,10 @@ from django.core.management.base import CommandError from django.test.utils import override_settings from opaque_keys.edx.keys import CourseKey from six import StringIO +from xmodule.modulestore import ModuleStoreEnum +from xmodule.modulestore.django import modulestore +from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase +from xmodule.modulestore.tests.mongo_connection import MONGO_HOST, MONGO_PORT_NUM import lms.djangoapps.dashboard.git_import as git_import from lms.djangoapps.dashboard.git_import import ( @@ -26,10 +30,6 @@ from lms.djangoapps.dashboard.git_import import ( GitImportErrorRemoteBranchMissing, GitImportErrorUrlBad ) -from xmodule.modulestore import ModuleStoreEnum -from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase -from xmodule.modulestore.tests.mongo_connection import MONGO_HOST, MONGO_PORT_NUM TEST_MONGODB_LOG = { 'host': MONGO_HOST, 'port': MONGO_PORT_NUM, @@ -41,7 +41,7 @@ TEST_MONGODB_LOG = { @override_settings( MONGODB_LOG=TEST_MONGODB_LOG, - GIT_REPO_DIR=settings.TEST_ROOT / "course_repos_{}".format(uuid4().hex) + GIT_REPO_DIR=settings.TEST_ROOT / f"course_repos_{uuid4().hex}" ) @unittest.skipUnless(settings.FEATURES.get('ENABLE_SYSADMIN_DASHBOARD'), "ENABLE_SYSADMIN_DASHBOARD not set") @@ -57,7 +57,7 @@ class TestGitAddCourse(SharedModuleStoreTestCase): ENABLED_CACHES = ['default', 'mongo_metadata_inheritance', 'loc_cache'] def setUp(self): - super(TestGitAddCourse, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.git_repo_dir = settings.GIT_REPO_DIR def assertCommandFailureRegexp(self, regex, *args): @@ -72,17 +72,14 @@ class TestGitAddCourse(SharedModuleStoreTestCase): Validate argument checking """ # No argument given. - if six.PY2: - self.assertCommandFailureRegexp('Error: too few arguments') - else: - self.assertCommandFailureRegexp('Error: the following arguments are required: repository_url') + self.assertCommandFailureRegexp('Error: the following arguments are required: repository_url') # Extra/Un-named arguments given. self.assertCommandFailureRegexp( 'Error: unrecognized arguments: blah blah blah', 'blah', 'blah', 'blah', 'blah') # Not a valid path. self.assertCommandFailureRegexp( - u'Path {0} doesn\'t exist, please create it,'.format(self.git_repo_dir), + f'Path {self.git_repo_dir} doesn\'t exist, please create it,', 'blah') # Test successful import from command if not os.path.isdir(self.git_repo_dir): @@ -119,14 +116,14 @@ class TestGitAddCourse(SharedModuleStoreTestCase): git_import.add_repo('file:///foobar.git', None, None) # Test git repo that exists, but is "broken" - bare_repo = os.path.abspath('{0}/{1}'.format(settings.TEST_ROOT, 'bare.git')) + bare_repo = os.path.abspath('{}/{}'.format(settings.TEST_ROOT, 'bare.git')) os.mkdir(bare_repo) self.addCleanup(shutil.rmtree, bare_repo) subprocess.check_output(['git', '--bare', 'init', ], stderr=subprocess.STDOUT, cwd=bare_repo) with pytest.raises(GitImportErrorBadRepo): - git_import.add_repo('file://{0}'.format(bare_repo), None, None) + git_import.add_repo(f'file://{bare_repo}', None, None) def test_detached_repo(self): """ @@ -188,7 +185,7 @@ class TestGitAddCourse(SharedModuleStoreTestCase): This wil create conditions to exercise bad paths in the switch_branch function. """ # create bare repo that we can mess with and attempt an import - bare_repo = os.path.abspath('{0}/{1}'.format(settings.TEST_ROOT, 'bare.git')) + bare_repo = os.path.abspath('{}/{}'.format(settings.TEST_ROOT, 'bare.git')) os.mkdir(bare_repo) self.addCleanup(shutil.rmtree, bare_repo) subprocess.check_output(['git', '--bare', 'init', ], stderr=subprocess.STDOUT, @@ -202,7 +199,7 @@ class TestGitAddCourse(SharedModuleStoreTestCase): rdir = '{0}/bare'.format(repo_dir) with pytest.raises(GitImportErrorBadRepo): - git_import.add_repo('file://{0}'.format(bare_repo), None, None) + git_import.add_repo(f'file://{bare_repo}', None, None) # Get logger for checking strings in logs output = StringIO() @@ -212,12 +209,12 @@ class TestGitAddCourse(SharedModuleStoreTestCase): glog.addHandler(test_log_handler) # Move remote so fetch fails - shutil.move(bare_repo, '{0}/not_bare.git'.format(settings.TEST_ROOT)) + shutil.move(bare_repo, f'{settings.TEST_ROOT}/not_bare.git') try: git_import.switch_branch('master', rdir) except GitImportError: assert 'Unable to fetch remote' in output.getvalue() - shutil.move('{0}/not_bare.git'.format(settings.TEST_ROOT), bare_repo) + shutil.move(f'{settings.TEST_ROOT}/not_bare.git', bare_repo) output.truncate(0) # Replace origin with a different remote diff --git a/lms/djangoapps/dashboard/models.py b/lms/djangoapps/dashboard/models.py index cd3d2de20cb..9196f5ecea5 100644 --- a/lms/djangoapps/dashboard/models.py +++ b/lms/djangoapps/dashboard/models.py @@ -2,7 +2,6 @@ import mongoengine - from xmodule.modulestore.mongoengine_fields import CourseKeyField diff --git a/lms/djangoapps/dashboard/sysadmin.py b/lms/djangoapps/dashboard/sysadmin.py index 3c498bc5933..656d45b6032 100644 --- a/lms/djangoapps/dashboard/sysadmin.py +++ b/lms/djangoapps/dashboard/sysadmin.py @@ -2,13 +2,12 @@ This module creates a sysadmin dashboard for managing and viewing courses. """ - - import json import logging import os import subprocess import warnings +from io import StringIO import mongoengine from django.conf import settings @@ -26,18 +25,17 @@ from django.views.decorators.http import condition from django.views.generic.base import TemplateView from opaque_keys.edx.keys import CourseKey from path import Path as path -from six import StringIO, text_type +from xmodule.modulestore.django import modulestore import lms.djangoapps.dashboard.git_import as git_import +from common.djangoapps.edxmako.shortcuts import render_to_response +from common.djangoapps.student.models import CourseEnrollment, Registration, UserProfile +from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole from common.djangoapps.track import views as track_views +from lms.djangoapps.courseware.courses import get_course_by_id from lms.djangoapps.dashboard.git_import import GitImportError from lms.djangoapps.dashboard.models import CourseImportLog -from common.djangoapps.edxmako.shortcuts import render_to_response -from lms.djangoapps.courseware.courses import get_course_by_id from openedx.core.djangolib.markup import HTML -from common.djangoapps.student.models import CourseEnrollment, Registration, UserProfile -from common.djangoapps.student.roles import CourseInstructorRole, CourseStaffRole -from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) @@ -56,9 +54,9 @@ class SysadminDashboardView(TemplateView): warnings.warn("Sysadmin Dashboard is deprecated. See DEPR-118.", DeprecationWarning) self.def_ms = modulestore() - self.msg = u'' + self.msg = '' self.datatable = [] - super(SysadminDashboardView, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(**kwargs) @method_decorator(ensure_csrf_cookie) @method_decorator(login_required) @@ -66,7 +64,7 @@ class SysadminDashboardView(TemplateView): must_revalidate=True)) @method_decorator(condition(etag_func=None)) def dispatch(self, *args, **kwargs): - return super(SysadminDashboardView, self).dispatch(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + return super().dispatch(*args, **kwargs) def get_courses(self): """ Get an iterable list of courses.""" @@ -88,7 +86,7 @@ class Users(SysadminDashboardView): if not name: return _('Must provide full name') - msg = u'' + msg = '' if not password: return _('Password must be supplied') @@ -104,7 +102,7 @@ class Users(SysadminDashboardView): try: user.save() except IntegrityError: - msg += _(u'Oops, failed to create user {user}, {error}').format( + msg += _('Oops, failed to create user {user}, {error}').format( user=user, error="IntegrityError" ) @@ -117,7 +115,7 @@ class Users(SysadminDashboardView): profile.name = name profile.save() - msg += _(u'User {user} created successfully!').format(user=user) + msg += _('User {user} created successfully!').format(user=user) return msg def delete_user(self, uname): @@ -129,19 +127,19 @@ class Users(SysadminDashboardView): try: user = User.objects.get(email=uname) except User.DoesNotExist as err: - msg = _(u'Cannot find user with email address {email_addr}').format(email_addr=uname) + msg = _('Cannot find user with email address {email_addr}').format(email_addr=uname) return msg else: try: user = User.objects.get(username=uname) except User.DoesNotExist as err: - msg = _(u'Cannot find user with username {username} - {error}').format( + msg = _('Cannot find user with username {username} - {error}').format( username=uname, error=str(err) ) return msg user.delete() - return _(u'Deleted user {username}').format(username=uname) + return _('Deleted user {username}').format(username=uname) def make_datatable(self): """ @@ -185,12 +183,12 @@ class Users(SysadminDashboardView): uname = request.POST.get('student_uname', '').strip() name = request.POST.get('student_fullname', '').strip() password = request.POST.get('student_password', '').strip() - self.msg = HTML(u'<h4>{0}</h4><p>{1}</p><hr />{2}').format( + self.msg = HTML('<h4>{0}</h4><p>{1}</p><hr />{2}').format( _('Create User Results'), self.create_user(uname, name, password), self.msg) elif action == 'del_user': uname = request.POST.get('student_uname', '').strip() - self.msg = HTML(u'<h4>{0}</h4><p>{1}</p><hr />{2}').format( + self.msg = HTML('<h4>{0}</h4><p>{1}</p><hr />{2}').format( _('Delete User Results'), self.delete_user(uname), self.msg) context = { 'datatable': self.make_datatable(), @@ -222,14 +220,14 @@ class Courses(SysadminDashboardView): return info cmd = ['git', 'log', '-1', - u'--format=format:{ "commit": "%H", "author": "%an %ae", "date": "%ad"}', ] + '--format=format:{ "commit": "%H", "author": "%an %ae", "date": "%ad"}', ] try: output_json = json.loads(subprocess.check_output(cmd, cwd=gdir).decode('utf-8')) info = [output_json['commit'], output_json['date'], output_json['author'], ] except OSError as error: - log.warning(text_type(u"Error fetching git data: %s - %s"), text_type(cdir), text_type(error)) + log.warning("Error fetching git data: %s - %s", str(cdir), str(error)) except (ValueError, subprocess.CalledProcessError): pass @@ -251,9 +249,9 @@ class Courses(SysadminDashboardView): at debug level for display in template """ - msg = u'' + msg = '' - log.debug(u'Adding course using git repo %s', gitloc) + log.debug('Adding course using git repo %s', gitloc) # Grab logging output for debugging imports output = StringIO() @@ -291,8 +289,8 @@ class Courses(SysadminDashboardView): msg_header = _('Added Course') color = 'blue' - msg = HTML(u"<h4 style='color:{0}'>{1}</h4>").format(color, msg_header) - msg += HTML(u"<pre>{0}</pre>").format(escape(ret)) + msg = HTML("<h4 style='color:{0}'>{1}</h4>").format(color, msg_header) + msg += HTML("<pre>{0}</pre>").format(escape(ret)) return msg def make_datatable(self, courses=None): @@ -302,7 +300,7 @@ class Courses(SysadminDashboardView): courses = courses or self.get_courses() for course in courses: gdir = course.id.course - data.append([course.display_name, text_type(course.id)] + data.append([course.display_name, str(course.id)] + self.git_info_for_course(gdir)) return dict(header=[_('Course Name'), @@ -357,7 +355,7 @@ class Courses(SysadminDashboardView): course_found = True except Exception as err: # pylint: disable=broad-except self.msg += _( # lint-amnesty, pylint: disable=translation-of-non-string - HTML(u'Error - cannot get course with ID {0}<br/><pre>{1}</pre>') + HTML('Error - cannot get course with ID {0}<br/><pre>{1}</pre>') ).format( course_key, escape(str(err)) @@ -368,8 +366,8 @@ class Courses(SysadminDashboardView): self.def_ms.delete_course(course.id, request.user.id) # don't delete user permission groups, though self.msg += \ - HTML(u"<font color='red'>{0} {1} = {2} ({3})</font>").format( - _('Deleted'), text_type(course.location), text_type(course.id), course.display_name) + HTML("<font color='red'>{0} {1} = {2} ({3})</font>").format( + _('Deleted'), str(course.location), str(course.id), course.display_name) context = { 'datatable': self.make_datatable(list(courses.values())), @@ -477,7 +475,7 @@ class GitLogs(TemplateView): cilset = CourseImportLog.objects.filter( course_id=course_id ).order_by('-created') - log.debug(u'cilset length=%s', len(cilset)) + log.debug('cilset length=%s', len(cilset)) # Paginate the query set paginator = Paginator(cilset, page_size) @@ -494,7 +492,7 @@ class GitLogs(TemplateView): mdb.close() context = { 'logs': logs, - 'course_id': text_type(course_id) if course_id else None, + 'course_id': str(course_id) if course_id else None, 'error_msg': error_msg, 'page_size': page_size } diff --git a/lms/djangoapps/dashboard/tests/test_sysadmin.py b/lms/djangoapps/dashboard/tests/test_sysadmin.py index 2b80beaf670..a179debfa95 100644 --- a/lms/djangoapps/dashboard/tests/test_sysadmin.py +++ b/lms/djangoapps/dashboard/tests/test_sysadmin.py @@ -1,8 +1,6 @@ """ Provide tests for sysadmin dashboard feature in sysadmin.py """ - - import glob import os import re @@ -18,18 +16,16 @@ from django.test.utils import override_settings from django.urls import reverse from opaque_keys.edx.locator import CourseLocator from pytz import UTC -from six import text_type -from six.moves import range +from xmodule.modulestore.django import modulestore +from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, SharedModuleStoreTestCase +from xmodule.modulestore.tests.mongo_connection import MONGO_HOST, MONGO_PORT_NUM -from lms.djangoapps.dashboard.git_import import GitImportErrorNoDir -from lms.djangoapps.dashboard.models import CourseImportLog -from openedx.core.djangolib.markup import Text from common.djangoapps.student.roles import CourseStaffRole, GlobalStaff from common.djangoapps.student.tests.factories import UserFactory from common.djangoapps.util.date_utils import DEFAULT_DATE_TIME_FORMAT, get_time_display -from xmodule.modulestore.django import modulestore -from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, SharedModuleStoreTestCase -from xmodule.modulestore.tests.mongo_connection import MONGO_HOST, MONGO_PORT_NUM +from lms.djangoapps.dashboard.git_import import GitImportErrorNoDir +from lms.djangoapps.dashboard.models import CourseImportLog +from openedx.core.djangolib.markup import Text TEST_MONGODB_LOG = { 'host': MONGO_HOST, @@ -52,7 +48,7 @@ class SysadminBaseTestCase(SharedModuleStoreTestCase): def setUp(self): """Setup test case by adding primary user.""" - super(SysadminBaseTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(username='test_user', email='test_user+sysadmin@edx.org', password='foo') @@ -73,7 +69,7 @@ class SysadminBaseTestCase(SharedModuleStoreTestCase): def _rm_edx4edx(self): """Deletes the sample course from the XML store""" def_ms = modulestore() - course_path = '{0}/edx4edx_lite'.format( + course_path = '{}/edx4edx_lite'.format( os.path.abspath(settings.DATA_DIR)) try: # using XML store @@ -86,11 +82,11 @@ class SysadminBaseTestCase(SharedModuleStoreTestCase): response = self.client.post( reverse('sysadmin_courses'), { - 'course_id': text_type(course.id), + 'course_id': str(course.id), 'action': 'del_course', } ) - self.addCleanup(self._rm_glob, '{0}_deleted_*'.format(course_path)) + self.addCleanup(self._rm_glob, f'{course_path}_deleted_*') return response @@ -112,7 +108,7 @@ class SysadminBaseTestCase(SharedModuleStoreTestCase): @override_settings( MONGODB_LOG=TEST_MONGODB_LOG, - GIT_REPO_DIR=settings.TEST_ROOT / "course_repos_{}".format(uuid4().hex) + GIT_REPO_DIR=settings.TEST_ROOT / f"course_repos_{uuid4().hex}" ) @unittest.skipUnless(settings.FEATURES.get('ENABLE_SYSADMIN_DASHBOARD'), "ENABLE_SYSADMIN_DASHBOARD not set") @@ -124,7 +120,7 @@ class TestSysAdminMongoCourseImport(SysadminBaseTestCase): @classmethod def tearDownClass(cls): """Delete mongo log entries after test.""" - super(TestSysAdminMongoCourseImport, cls).tearDownClass() + super().tearDownClass() try: mongoengine.connect(TEST_MONGODB_LOG['db']) CourseImportLog.objects.all().delete() @@ -153,7 +149,7 @@ class TestSysAdminMongoCourseImport(SysadminBaseTestCase): # Create git loaded course response = self._add_edx4edx() - self.assertContains(response, Text(text_type(GitImportErrorNoDir(settings.GIT_REPO_DIR)))) + self.assertContains(response, Text(str(GitImportErrorNoDir(settings.GIT_REPO_DIR)))) def test_mongo_course_add_delete(self): """ @@ -182,7 +178,7 @@ class TestSysAdminMongoCourseImport(SysadminBaseTestCase): # Regex of first 3 columns of course information table row for # test course loaded from git. Would not have sha1 if # git_info_for_course failed. - table_re = re.compile(u""" + table_re = re.compile(""" <tr>\\s+ <td>edX\\sAuthor\\sCourse</td>\\s+ # expected test git course name <td>course-v1:MITx\\+edx4edx\\+edx4edx</td>\\s+ # expected test git course_id @@ -314,7 +310,7 @@ class TestSysAdminMongoCourseImport(SysadminBaseTestCase): page ) ) - self.assertContains(response, u'Page {} of 2'.format(expected)) + self.assertContains(response, f'Page {expected} of 2') CourseImportLog.objects.delete() diff --git a/lms/djangoapps/debug/management/commands/dump_xml_courses.py b/lms/djangoapps/debug/management/commands/dump_xml_courses.py index 56b1e7b6b5f..3c92c9258a8 100644 --- a/lms/djangoapps/debug/management/commands/dump_xml_courses.py +++ b/lms/djangoapps/debug/management/commands/dump_xml_courses.py @@ -6,15 +6,11 @@ For each of the courses, it loops through all of the modules, and dumps each as a separate output file containing the json representation of each of its fields (including those fields that are set as default values). """ - - import json -import six from django.conf import settings from django.core.management.base import BaseCommand, CommandError from path import Path as path -from six import text_type from xmodule.modulestore.xml import XMLModuleStore @@ -28,7 +24,7 @@ class Command(BaseCommand): def handle(self, *args, **options): if len(args) != 1: - raise CommandError(u'Must called with arguments: {}'.format(self.args)) + raise CommandError(f'Must called with arguments: {self.args}') xml_module_store = XMLModuleStore( data_dir=settings.DATA_DIR, @@ -40,12 +36,12 @@ class Command(BaseCommand): export_dir = path(args[0]) - for course_id, course_modules in six.iteritems(xml_module_store.modules): + for course_id, course_modules in xml_module_store.modules.items(): course_path = course_id.replace('/', '_') - for location, descriptor in six.iteritems(course_modules): - location_path = text_type(location).replace('/', '_') + for location, descriptor in course_modules.items(): + location_path = str(location).replace('/', '_') data = {} - for field_name, field in six.iteritems(descriptor.fields): + for field_name, field in descriptor.fields.items(): try: data[field_name] = field.read_json(descriptor) except Exception as exc: # pylint: disable=broad-except diff --git a/lms/djangoapps/debug/views.py b/lms/djangoapps/debug/views.py index 7bf403fd72b..8d43c67385c 100644 --- a/lms/djangoapps/debug/views.py +++ b/lms/djangoapps/debug/views.py @@ -4,12 +4,12 @@ import pprint import traceback +from codejail.safe_exec import safe_exec from django.contrib.auth.decorators import login_required from django.http import Http404, HttpResponse from django.utils.html import escape from django.views.decorators.csrf import ensure_csrf_cookie -from codejail.safe_exec import safe_exec from common.djangoapps.edxmako.shortcuts import render_to_response from openedx.core.djangolib.markup import HTML @@ -52,7 +52,7 @@ def show_parameters(request): """A page that shows what parameters were on the URL and post.""" html_list = [] for name, value in sorted(request.GET.items()): - html_list.append(escape(u"GET {}: {!r}".format(name, value))) + html_list.append(escape(f"GET {name}: {value!r}")) for name, value in sorted(request.POST.items()): - html_list.append(escape(u"POST {}: {!r}".format(name, value))) + html_list.append(escape(f"POST {name}: {value!r}")) return HttpResponse("\n".join(HTML("<p>{}</p>").format(h) for h in html_list)) diff --git a/lms/djangoapps/discussion/apps.py b/lms/djangoapps/discussion/apps.py index 033c0af98b7..775ad9d03e7 100644 --- a/lms/djangoapps/discussion/apps.py +++ b/lms/djangoapps/discussion/apps.py @@ -17,21 +17,21 @@ class DiscussionConfig(AppConfig): Application Configuration for Discussion. """ - name = u'lms.djangoapps.discussion' + name = 'lms.djangoapps.discussion' plugin_app = { PluginURLs.CONFIG: { ProjectType.LMS: { - PluginURLs.NAMESPACE: u'', - PluginURLs.REGEX: r'^courses/{}/discussion/forum/'.format(COURSE_ID_PATTERN), - PluginURLs.RELATIVE_PATH: u'urls', + PluginURLs.NAMESPACE: '', + PluginURLs.REGEX: fr'^courses/{COURSE_ID_PATTERN}/discussion/forum/', + PluginURLs.RELATIVE_PATH: 'urls', } }, PluginSettings.CONFIG: { ProjectType.CMS: { - SettingsType.COMMON: {PluginSettings.RELATIVE_PATH: u'settings.common'}, + SettingsType.COMMON: {PluginSettings.RELATIVE_PATH: 'settings.common'}, }, ProjectType.LMS: { - SettingsType.COMMON: {PluginSettings.RELATIVE_PATH: u'settings.common'}, + SettingsType.COMMON: {PluginSettings.RELATIVE_PATH: 'settings.common'}, }, } } diff --git a/lms/djangoapps/discussion/django_comment_client/base/event_transformers.py b/lms/djangoapps/discussion/django_comment_client/base/event_transformers.py index efea25403c4..1341a1392a1 100644 --- a/lms/djangoapps/discussion/django_comment_client/base/event_transformers.py +++ b/lms/djangoapps/discussion/django_comment_client/base/event_transformers.py @@ -2,20 +2,17 @@ """ Transformers for Discussion-related events. """ - - -import six from django.contrib.auth.models import User from django.urls import NoReverseMatch, reverse from eventtracking.processors.exceptions import EventEmissionExit from opaque_keys import InvalidKeyError from opaque_keys.edx.locator import CourseLocator +from common.djangoapps.track.transformers import EventTransformer, EventTransformerRegistry +from common.djangoapps.track.views.segmentio import BI_SCREEN_VIEWED_EVENT_NAME, FORUM_THREAD_VIEWED_EVENT_LABEL from lms.djangoapps.discussion.django_comment_client.base.views import add_truncated_title_to_event_data from lms.djangoapps.discussion.django_comment_client.permissions import get_team from lms.djangoapps.discussion.django_comment_client.utils import get_cached_discussion_id_map_by_course_id -from common.djangoapps.track.transformers import EventTransformer, EventTransformerRegistry -from common.djangoapps.track.views.segmentio import BI_SCREEN_VIEWED_EVENT_NAME, FORUM_THREAD_VIEWED_EVENT_LABEL def _get_string(dictionary, key, del_if_bad=True): @@ -28,7 +25,7 @@ def _get_string(dictionary, key, del_if_bad=True): """ if key in dictionary: value = dictionary[key] - if isinstance(value, six.string_types): + if isinstance(value, str): return value else: if del_if_bad: diff --git a/lms/djangoapps/discussion/django_comment_client/base/tests.py b/lms/djangoapps/discussion/django_comment_client/base/tests.py index f1cd61297ff..e8ab0838aab 100644 --- a/lms/djangoapps/discussion/django_comment_client/base/tests.py +++ b/lms/djangoapps/discussion/django_comment_client/base/tests.py @@ -1,6 +1,5 @@ import pytest # pylint: skip-file -# -*- coding: utf-8 -*- """Tests for django comment client views.""" @@ -10,7 +9,6 @@ from contextlib import contextmanager import ddt import mock -import six from django.contrib.auth.models import User from django.core.management import call_command from django.test.client import RequestFactory @@ -18,12 +16,16 @@ from django.urls import reverse from eventtracking.processors.exceptions import EventEmissionExit from mock import ANY, Mock, patch from opaque_keys.edx.keys import CourseKey -from six import text_type -from six.moves import range -from common.test.utils import MockSignalHandlerMixin, disable_signal from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.roles import CourseStaffRole, UserBasedRole +from common.djangoapps.student.tests.factories import CourseAccessRoleFactory, CourseEnrollmentFactory, UserFactory +from common.djangoapps.track.middleware import TrackMiddleware +from common.djangoapps.track.views import segmentio +from common.djangoapps.track.views.tests.base import SEGMENTIO_TEST_USER_ID, SegmentIOTrackingTestCaseBase +from common.djangoapps.util.testing import UrlResetMixin +from common.test.utils import MockSignalHandlerMixin, disable_signal from lms.djangoapps.discussion.django_comment_client.base import views from lms.djangoapps.discussion.django_comment_client.tests.group_id import ( CohortedTopicGroupIdTestMixin, @@ -49,12 +51,6 @@ from openedx.core.djangoapps.django_comment_common.utils import ( ) from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES from openedx.core.lib.teams_config import TeamsConfig -from common.djangoapps.student.roles import CourseStaffRole, UserBasedRole -from common.djangoapps.student.tests.factories import CourseAccessRoleFactory, CourseEnrollmentFactory, UserFactory -from common.djangoapps.track.middleware import TrackMiddleware -from common.djangoapps.track.views import segmentio -from common.djangoapps.track.views.tests.base import SEGMENTIO_TEST_USER_ID, SegmentIOTrackingTestCaseBase -from common.djangoapps.util.testing import UrlResetMixin from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase @@ -71,7 +67,7 @@ QUERY_COUNT_TABLE_BLACKLIST = WAFFLE_TABLES # pylint: disable=missing-docstring -class MockRequestSetupMixin(object): +class MockRequestSetupMixin: def _create_response_mock(self, data): return Mock( text=json.dumps(data), @@ -103,7 +99,7 @@ class CreateThreadGroupIdTestCase( return views.create_thread( request, - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), commentable_id=commentable_id ) @@ -150,7 +146,7 @@ class ThreadActionGroupIdTestCase( return getattr(views, view_name)( request, - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), thread_id="dummy", **(view_args or {}) ) @@ -209,7 +205,7 @@ class ThreadActionGroupIdTestCase( ) -class ViewsTestCaseMixin(object): +class ViewsTestCaseMixin: def set_up_course(self, module_count=0): """ @@ -230,13 +226,13 @@ class ViewsTestCaseMixin(object): ItemFactory.create( parent_location=self.course.location, category='discussion', - discussion_id='id_module_{}'.format(i), - discussion_category=u'Category {}'.format(i), - discussion_target=u'Discussion {}'.format(i) + discussion_id=f'id_module_{i}', + discussion_category=f'Category {i}', + discussion_target=f'Discussion {i}' ) # seed the forums permissions and roles - call_command('seed_permissions_roles', six.text_type(self.course_id)) + call_command('seed_permissions_roles', str(self.course_id)) # Patch the comment client user save method so it does not try # to create a new cc user when creating a django user @@ -322,24 +318,24 @@ class ViewsTestCaseMixin(object): if extra_request_data: thread.update(extra_request_data) url = reverse('create_thread', kwargs={'commentable_id': 'i4x-MITx-999-course-Robot_Super_Course', - 'course_id': six.text_type(self.course_id)}) + 'course_id': str(self.course_id)}) response = self.client.post(url, data=thread) assert mock_request.called expected_data = { 'thread_type': 'discussion', - 'body': u'this is a post', + 'body': 'this is a post', 'context': ThreadContext.COURSE, 'anonymous_to_peers': False, 'user_id': 1, - 'title': u'Hello', - 'commentable_id': u'i4x-MITx-999-course-Robot_Super_Course', + 'title': 'Hello', + 'commentable_id': 'i4x-MITx-999-course-Robot_Super_Course', 'anonymous': False, - 'course_id': six.text_type(self.course_id), + 'course_id': str(self.course_id), } if extra_response_data: expected_data.update(extra_response_data) mock_request.assert_called_with( 'post', - '{prefix}/i4x-MITx-999-course-Robot_Super_Course/threads'.format(prefix=CS_PREFIX), + f'{CS_PREFIX}/i4x-MITx-999-course-Robot_Super_Course/threads', data=expected_data, params={'request_id': ANY}, headers=ANY, @@ -360,7 +356,7 @@ class ViewsTestCaseMixin(object): response = self.client.post( reverse("update_thread", kwargs={ "thread_id": "dummy", - "course_id": six.text_type(self.course_id) + "course_id": str(self.course_id) }), data={"body": "foo", "title": "foo", "commentable_id": "some_topic"} ) @@ -389,7 +385,7 @@ class ViewsQueryCountTestCase( @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(ViewsQueryCountTestCase, self).setUp() + super().setUp() def count_queries(func): # pylint: disable=no-self-argument """ @@ -438,7 +434,7 @@ class ViewsTestCase( @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(ViewsTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create( org='MITx', course='999', discussion_topics={"Some Topic": {"id": "some_topic"}}, @@ -447,19 +443,19 @@ class ViewsTestCase( @classmethod def setUpTestData(cls): - super(ViewsTestCase, cls).setUpTestData() + super().setUpTestData() cls.course_id = cls.course.id # seed the forums permissions and roles - call_command('seed_permissions_roles', six.text_type(cls.course_id)) + call_command('seed_permissions_roles', str(cls.course_id)) @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): # Patching the ENABLE_DISCUSSION_SERVICE value affects the contents of urls.py, # so we need to call super.setUp() which reloads urls.py (because # of the UrlResetMixin) - super(ViewsTestCase, self).setUp() + super().setUp() # Patch the comment client user save method so it does not try # to create a new cc user when creating a django user @@ -523,7 +519,7 @@ class ViewsTestCase( response = self.client.post( reverse( view_name, - kwargs={"course_id": six.text_type(self.course_id), "thread_id": 'i4x-MITx-999-course-Robot_Super_Course'} + kwargs={"course_id": str(self.course_id), "thread_id": 'i4x-MITx-999-course-Robot_Super_Course'} ) ) assert response.status_code == 200 @@ -540,7 +536,7 @@ class ViewsTestCase( with self.assert_discussion_signals('thread_deleted'): response = views.delete_thread( request, - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), thread_id=test_thread_id ) assert response.status_code == 200 @@ -558,14 +554,14 @@ class ViewsTestCase( with self.assert_discussion_signals('comment_deleted'): response = views.delete_comment( request, - course_id=six.text_type(self.course.id), + course_id=str(self.course.id), comment_id=test_comment_id ) assert response.status_code == 200 assert mock_request.called args = mock_request.call_args[0] assert args[0] == 'delete' - assert args[1].endswith('/{}'.format(test_comment_id)) + assert args[1].endswith(f"/{test_comment_id}") def _test_request_error(self, view_name, view_kwargs, data, mock_request): """ @@ -583,7 +579,7 @@ class ViewsTestCase( def test_create_thread_no_title(self, mock_request): self._test_request_error( "create_thread", - {"commentable_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"commentable_id": "dummy", "course_id": str(self.course_id)}, {"body": "foo"}, mock_request ) @@ -591,7 +587,7 @@ class ViewsTestCase( def test_create_thread_empty_title(self, mock_request): self._test_request_error( "create_thread", - {"commentable_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"commentable_id": "dummy", "course_id": str(self.course_id)}, {"body": "foo", "title": " "}, mock_request ) @@ -599,7 +595,7 @@ class ViewsTestCase( def test_create_thread_no_body(self, mock_request): self._test_request_error( "create_thread", - {"commentable_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"commentable_id": "dummy", "course_id": str(self.course_id)}, {"title": "foo"}, mock_request ) @@ -607,7 +603,7 @@ class ViewsTestCase( def test_create_thread_empty_body(self, mock_request): self._test_request_error( "create_thread", - {"commentable_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"commentable_id": "dummy", "course_id": str(self.course_id)}, {"body": " ", "title": "foo"}, mock_request ) @@ -615,7 +611,7 @@ class ViewsTestCase( def test_update_thread_no_title(self, mock_request): self._test_request_error( "update_thread", - {"thread_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"thread_id": "dummy", "course_id": str(self.course_id)}, {"body": "foo"}, mock_request ) @@ -623,7 +619,7 @@ class ViewsTestCase( def test_update_thread_empty_title(self, mock_request): self._test_request_error( "update_thread", - {"thread_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"thread_id": "dummy", "course_id": str(self.course_id)}, {"body": "foo", "title": " "}, mock_request ) @@ -631,7 +627,7 @@ class ViewsTestCase( def test_update_thread_no_body(self, mock_request): self._test_request_error( "update_thread", - {"thread_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"thread_id": "dummy", "course_id": str(self.course_id)}, {"title": "foo"}, mock_request ) @@ -639,7 +635,7 @@ class ViewsTestCase( def test_update_thread_empty_body(self, mock_request): self._test_request_error( "update_thread", - {"thread_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"thread_id": "dummy", "course_id": str(self.course_id)}, {"body": " ", "title": "foo"}, mock_request ) @@ -655,7 +651,7 @@ class ViewsTestCase( def test_update_thread_wrong_commentable_id(self, mock_get_discussion_id_map, mock_request): self._test_request_error( "update_thread", - {"thread_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"thread_id": "dummy", "course_id": str(self.course_id)}, {"body": "foo", "title": "foo", "commentable_id": "wrong_commentable"}, mock_request ) @@ -666,7 +662,7 @@ class ViewsTestCase( response = self.client.post( reverse( "create_comment", - kwargs={"course_id": six.text_type(self.course_id), "thread_id": "dummy"} + kwargs={"course_id": str(self.course_id), "thread_id": "dummy"} ), data={"body": "body"} ) @@ -675,7 +671,7 @@ class ViewsTestCase( def test_create_comment_no_body(self, mock_request): self._test_request_error( "create_comment", - {"thread_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"thread_id": "dummy", "course_id": str(self.course_id)}, {}, mock_request ) @@ -683,7 +679,7 @@ class ViewsTestCase( def test_create_comment_empty_body(self, mock_request): self._test_request_error( "create_comment", - {"thread_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"thread_id": "dummy", "course_id": str(self.course_id)}, {"body": " "}, mock_request ) @@ -691,7 +687,7 @@ class ViewsTestCase( def test_create_sub_comment_no_body(self, mock_request): self._test_request_error( "create_sub_comment", - {"comment_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"comment_id": "dummy", "course_id": str(self.course_id)}, {}, mock_request ) @@ -699,7 +695,7 @@ class ViewsTestCase( def test_create_sub_comment_empty_body(self, mock_request): self._test_request_error( "create_sub_comment", - {"comment_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"comment_id": "dummy", "course_id": str(self.course_id)}, {"body": " "}, mock_request ) @@ -707,7 +703,7 @@ class ViewsTestCase( def test_update_comment_no_body(self, mock_request): self._test_request_error( "update_comment", - {"comment_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"comment_id": "dummy", "course_id": str(self.course_id)}, {}, mock_request ) @@ -715,7 +711,7 @@ class ViewsTestCase( def test_update_comment_empty_body(self, mock_request): self._test_request_error( "update_comment", - {"comment_id": "dummy", "course_id": six.text_type(self.course_id)}, + {"comment_id": "dummy", "course_id": str(self.course_id)}, {"body": " "}, mock_request ) @@ -728,14 +724,14 @@ class ViewsTestCase( response = self.client.post( reverse( "update_comment", - kwargs={"course_id": six.text_type(self.course_id), "comment_id": comment_id} + kwargs={"course_id": str(self.course_id), "comment_id": comment_id} ), data={"body": updated_body} ) assert response.status_code == 200 mock_request.assert_called_with( "put", - "{prefix}/comments/{comment_id}".format(prefix=CS_PREFIX, comment_id=comment_id), + f"{CS_PREFIX}/comments/{comment_id}", headers=ANY, params=ANY, timeout=ANY, @@ -779,14 +775,14 @@ class ViewsTestCase( }) url = reverse('flag_abuse_for_thread', kwargs={ 'thread_id': '518d4237b023791dca00000d', - 'course_id': six.text_type(self.course_id) + 'course_id': str(self.course_id) }) response = self.client.post(url) assert mock_request.called call_list = [ ( - ('get', '{prefix}/threads/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/threads/518d4237b023791dca00000d'), { 'data': None, 'params': {'mark_as_read': True, 'request_id': ANY, 'with_responses': False}, @@ -795,7 +791,7 @@ class ViewsTestCase( } ), ( - ('put', '{prefix}/threads/518d4237b023791dca00000d/abuse_flag'.format(prefix=CS_PREFIX)), + ('put', f'{CS_PREFIX}/threads/518d4237b023791dca00000d/abuse_flag'), { 'data': {'user_id': '1'}, 'params': {'request_id': ANY}, @@ -804,7 +800,7 @@ class ViewsTestCase( } ), ( - ('get', '{prefix}/threads/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/threads/518d4237b023791dca00000d'), { 'data': None, 'params': {'mark_as_read': True, 'request_id': ANY, 'with_responses': False}, @@ -856,14 +852,14 @@ class ViewsTestCase( }) url = reverse('un_flag_abuse_for_thread', kwargs={ 'thread_id': '518d4237b023791dca00000d', - 'course_id': six.text_type(self.course_id) + 'course_id': str(self.course_id) }) response = self.client.post(url) assert mock_request.called call_list = [ ( - ('get', '{prefix}/threads/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/threads/518d4237b023791dca00000d'), { 'data': None, 'params': {'mark_as_read': True, 'request_id': ANY, 'with_responses': False}, @@ -872,7 +868,7 @@ class ViewsTestCase( } ), ( - ('put', '{prefix}/threads/518d4237b023791dca00000d/abuse_unflag'.format(prefix=CS_PREFIX)), + ('put', f'{CS_PREFIX}/threads/518d4237b023791dca00000d/abuse_unflag'), { 'data': {'user_id': '1'}, 'params': {'request_id': ANY}, @@ -881,7 +877,7 @@ class ViewsTestCase( } ), ( - ('get', '{prefix}/threads/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/threads/518d4237b023791dca00000d'), { 'data': None, 'params': {'mark_as_read': True, 'request_id': ANY, 'with_responses': False}, @@ -927,14 +923,14 @@ class ViewsTestCase( }) url = reverse('flag_abuse_for_comment', kwargs={ 'comment_id': '518d4237b023791dca00000d', - 'course_id': six.text_type(self.course_id) + 'course_id': str(self.course_id) }) response = self.client.post(url) assert mock_request.called call_list = [ ( - ('get', '{prefix}/comments/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/comments/518d4237b023791dca00000d'), { 'data': None, 'params': {'request_id': ANY}, @@ -943,7 +939,7 @@ class ViewsTestCase( } ), ( - ('put', '{prefix}/comments/518d4237b023791dca00000d/abuse_flag'.format(prefix=CS_PREFIX)), + ('put', f'{CS_PREFIX}/comments/518d4237b023791dca00000d/abuse_flag'), { 'data': {'user_id': '1'}, 'params': {'request_id': ANY}, @@ -952,7 +948,7 @@ class ViewsTestCase( } ), ( - ('get', '{prefix}/comments/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/comments/518d4237b023791dca00000d'), { 'data': None, 'params': {'request_id': ANY}, @@ -998,14 +994,14 @@ class ViewsTestCase( }) url = reverse('un_flag_abuse_for_comment', kwargs={ 'comment_id': '518d4237b023791dca00000d', - 'course_id': six.text_type(self.course_id) + 'course_id': str(self.course_id) }) response = self.client.post(url) assert mock_request.called call_list = [ ( - ('get', '{prefix}/comments/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/comments/518d4237b023791dca00000d'), { 'data': None, 'params': {'request_id': ANY}, @@ -1014,7 +1010,7 @@ class ViewsTestCase( } ), ( - ('put', '{prefix}/comments/518d4237b023791dca00000d/abuse_unflag'.format(prefix=CS_PREFIX)), + ('put', f'{CS_PREFIX}/comments/518d4237b023791dca00000d/abuse_unflag'), { 'data': {'user_id': '1'}, 'params': {'request_id': ANY}, @@ -1023,7 +1019,7 @@ class ViewsTestCase( } ), ( - ('get', '{prefix}/comments/518d4237b023791dca00000d'.format(prefix=CS_PREFIX)), + ('get', f'{CS_PREFIX}/comments/518d4237b023791dca00000d'), { 'data': None, 'params': {'request_id': ANY}, @@ -1050,7 +1046,7 @@ class ViewsTestCase( response = self.client.post( reverse( view_name, - kwargs={item_id: 'dummy', 'course_id': six.text_type(self.course_id)} + kwargs={item_id: 'dummy', 'course_id': str(self.course_id)} ) ) assert response.status_code == 200 @@ -1062,7 +1058,7 @@ class ViewsTestCase( response = self.client.post( reverse( 'endorse_comment', - kwargs={'comment_id': 'dummy', 'course_id': six.text_type(self.course_id)} + kwargs={'comment_id': 'dummy', 'course_id': str(self.course_id)} ) ) assert response.status_code == 200 @@ -1075,12 +1071,12 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(ViewPermissionsTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(ViewPermissionsTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) @@ -1095,13 +1091,13 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(ViewPermissionsTestCase, self).setUp() + super().setUp() def test_pin_thread_as_student(self, mock_request): self._set_mock_request_data(mock_request, {}) self.client.login(username=self.student.username, password=self.password) response = self.client.post( - reverse("pin_thread", kwargs={"course_id": six.text_type(self.course.id), "thread_id": "dummy"}) + reverse("pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) assert response.status_code == 401 @@ -1109,7 +1105,7 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor self._set_mock_request_data(mock_request, {}) self.client.login(username=self.moderator.username, password=self.password) response = self.client.post( - reverse("pin_thread", kwargs={"course_id": six.text_type(self.course.id), "thread_id": "dummy"}) + reverse("pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) assert response.status_code == 200 @@ -1117,7 +1113,7 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor self._set_mock_request_data(mock_request, {}) self.client.login(username=self.student.username, password=self.password) response = self.client.post( - reverse("un_pin_thread", kwargs={"course_id": six.text_type(self.course.id), "thread_id": "dummy"}) + reverse("un_pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) assert response.status_code == 401 @@ -1125,7 +1121,7 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor self._set_mock_request_data(mock_request, {}) self.client.login(username=self.moderator.username, password=self.password) response = self.client.post( - reverse("un_pin_thread", kwargs={"course_id": six.text_type(self.course.id), "thread_id": "dummy"}) + reverse("un_pin_thread", kwargs={"course_id": str(self.course.id), "thread_id": "dummy"}) ) assert response.status_code == 200 @@ -1148,7 +1144,7 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor ) self.client.login(username=self.moderator.username, password=self.password) response = self.client.post( - reverse("endorse_comment", kwargs={"course_id": six.text_type(self.course.id), "comment_id": "dummy"}) + reverse("endorse_comment", kwargs={"course_id": str(self.course.id), "comment_id": "dummy"}) ) assert response.status_code == 200 @@ -1160,7 +1156,7 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor ) self.client.login(username=self.student.username, password=self.password) response = self.client.post( - reverse("endorse_comment", kwargs={"course_id": six.text_type(self.course.id), "comment_id": "dummy"}) + reverse("endorse_comment", kwargs={"course_id": str(self.course.id), "comment_id": "dummy"}) ) assert response.status_code == 401 @@ -1172,7 +1168,7 @@ class ViewPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStor ) self.client.login(username=self.student.username, password=self.password) response = self.client.post( - reverse("endorse_comment", kwargs={"course_id": six.text_type(self.course.id), "comment_id": "dummy"}) + reverse("endorse_comment", kwargs={"course_id": str(self.course.id), "comment_id": "dummy"}) ) assert response.status_code == 200 @@ -1186,12 +1182,12 @@ class CreateThreadUnicodeTestCase( @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(CreateThreadUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(CreateThreadUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) cls.student = UserFactory.create() @@ -1208,7 +1204,7 @@ class CreateThreadUnicodeTestCase( request.view_name = "create_thread" response = views.create_thread( # The commentable ID contains a username, the Unicode char below ensures it works fine - request, course_id=six.text_type(self.course.id), commentable_id=u"non_tÃ¥em_dummy_id" + request, course_id=str(self.course.id), commentable_id="non_tÃ¥em_dummy_id" ) assert response.status_code == 200 @@ -1228,12 +1224,12 @@ class UpdateThreadUnicodeTestCase( @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(UpdateThreadUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(UpdateThreadUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) cls.student = UserFactory.create() @@ -1252,7 +1248,7 @@ class UpdateThreadUnicodeTestCase( request = RequestFactory().post("dummy_url", {"body": text, "title": text, "thread_type": "question", "commentable_id": "test_commentable"}) request.user = self.student request.view_name = "update_thread" - response = views.update_thread(request, course_id=six.text_type(self.course.id), thread_id="dummy_thread_id") + response = views.update_thread(request, course_id=str(self.course.id), thread_id="dummy_thread_id") assert response.status_code == 200 assert mock_request.called @@ -1273,12 +1269,12 @@ class CreateCommentUnicodeTestCase( @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(CreateCommentUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(CreateCommentUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) cls.student = UserFactory.create() @@ -1299,7 +1295,7 @@ class CreateCommentUnicodeTestCase( request.user = self.student request.view_name = "create_comment" response = views.create_comment( - request, course_id=six.text_type(self.course.id), thread_id="dummy_thread_id" + request, course_id=str(self.course.id), thread_id="dummy_thread_id" ) assert response.status_code == 200 @@ -1320,12 +1316,12 @@ class UpdateCommentUnicodeTestCase( @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(UpdateCommentUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(UpdateCommentUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) cls.student = UserFactory.create() @@ -1340,7 +1336,7 @@ class UpdateCommentUnicodeTestCase( request = RequestFactory().post("dummy_url", {"body": text}) request.user = self.student request.view_name = "update_comment" - response = views.update_comment(request, course_id=six.text_type(self.course.id), comment_id="dummy_comment_id") + response = views.update_comment(request, course_id=str(self.course.id), comment_id="dummy_comment_id") assert response.status_code == 200 assert mock_request.called @@ -1360,12 +1356,12 @@ class CreateSubCommentUnicodeTestCase( @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(CreateSubCommentUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(CreateSubCommentUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) cls.student = UserFactory.create() @@ -1388,7 +1384,7 @@ class CreateSubCommentUnicodeTestCase( Thread.commentable_id = "test_commentable" try: response = views.create_sub_comment( - request, course_id=six.text_type(self.course.id), comment_id="dummy_comment_id" + request, course_id=str(self.course.id), comment_id="dummy_comment_id" ) assert response.status_code == 200 @@ -1441,7 +1437,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(TeamsPermissionsTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): teams_config_data = { 'topics': [{'id': "topic_id", 'name': 'Solar Power', 'description': 'Solar power is hot'}] } @@ -1449,7 +1445,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto @classmethod def setUpTestData(cls): - super(TeamsPermissionsTestCase, cls).setUpTestData() + super().setUpTestData() cls.course = CourseFactory.create() cls.password = "test password" seed_permissions_roles(cls.course.id) @@ -1491,7 +1487,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto # Create a team cls.team_commentable_id = "team_discussion_id" cls.team = CourseTeamFactory.create( - name=u'The Only Team', + name='The Only Team', course_id=cls.course.id, topic_id='topic_id', discussion_topic_id=cls.team_commentable_id @@ -1510,7 +1506,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(TeamsPermissionsTestCase, self).setUp() + super().setUp() def _setup_mock(self, user, mock_request, data): user = getattr(self, user) @@ -1555,14 +1551,14 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto "closed": False, "commentable_id": commentable_id, "context": "standalone", "username": thread_author.username, - "course_id": six.text_type(self.course.id) + "course_id": str(self.course.id) } ) response = self.client.post( reverse( "update_thread", kwargs={ - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "thread_id": "dummy" } ), @@ -1599,14 +1595,14 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto "commentable_id": commentable_id, "user_id": str(comment_author.id), "username": comment_author.username, - "course_id": six.text_type(self.course.id) + "course_id": str(self.course.id) }) response = self.client.post( reverse( "delete_comment", kwargs={ - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "comment_id": "dummy" } ), @@ -1627,7 +1623,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto reverse( "create_comment", kwargs={ - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "thread_id": "dummy" } ), @@ -1650,7 +1646,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto reverse( "create_sub_comment", kwargs={ - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "comment_id": "dummy_comment" } ), @@ -1674,7 +1670,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto response = self.client.post( reverse( action, - kwargs={"course_id": six.text_type(self.course.id), "comment_id": "dummy_comment"} + kwargs={"course_id": str(self.course.id), "comment_id": "dummy_comment"} ) ) assert response.status_code == status_code @@ -1696,7 +1692,7 @@ class TeamsPermissionsTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleSto response = self.client.post( reverse( action, - kwargs={"course_id": six.text_type(self.course.id), "thread_id": "dummy_thread"} + kwargs={"course_id": str(self.course.id), "thread_id": "dummy_thread"} ) ) assert response.status_code == status_code @@ -1714,12 +1710,12 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(ForumEventTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(ForumEventTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) @@ -1742,7 +1738,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque request = RequestFactory().post("dummy_url", {"body": "Test comment", 'auto_subscribe': True}) request.user = self.student request.view_name = "create_comment" - views.create_comment(request, course_id=six.text_type(self.course.id), thread_id='test_thread_id') + views.create_comment(request, course_id=str(self.course.id), thread_id='test_thread_id') event_name, event = mock_emit.call_args[0] assert event_name == 'edx.forum.response.created' @@ -1769,7 +1765,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque request = RequestFactory().post("dummy_url", {"body": "Another comment"}) request.user = self.student request.view_name = "create_sub_comment" - views.create_sub_comment(request, course_id=six.text_type(self.course.id), comment_id="dummy_comment_id") + views.create_sub_comment(request, course_id=str(self.course.id), comment_id="dummy_comment_id") event_name, event = mock_emit.call_args[0] assert event_name == 'edx.forum.comment.created' @@ -1818,7 +1814,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque request.user = user request.view_name = view_name - getattr(views, view_name)(request, course_id=six.text_type(self.course.id), **view_kwargs) + getattr(views, view_name)(request, course_id=str(self.course.id), **view_kwargs) name, event = mock_emit.call_args[0] assert name == event_name @@ -1845,7 +1841,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque request.user = self.student request.view_name = view_name view_function = getattr(views, view_name) - kwargs = dict(course_id=six.text_type(self.course.id)) + kwargs = dict(course_id=str(self.course.id)) kwargs[obj_id_name] = obj_id_name if not undo: kwargs.update(value='up') @@ -1853,7 +1849,7 @@ class ForumEventTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockReque assert mock_emit.called event_name, event = mock_emit.call_args[0] - assert event_name == 'edx.forum.{}.voted'.format(obj_type) + assert event_name == f'edx.forum.{obj_type}.voted' assert event['target_username'] == 'gumprecht' assert event['undo_vote'] == undo assert event['vote_value'] == 'up' @@ -1864,12 +1860,12 @@ class UsersEndpointTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockRe @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(UsersEndpointTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(UsersEndpointTestCase, cls).setUpTestData() + super().setUpTestData() seed_permissions_roles(cls.course.id) @@ -1892,7 +1888,7 @@ class UsersEndpointTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, MockRe request = getattr(RequestFactory(), method)("dummy_url", kwargs) request.user = self.student request.view_name = "users" - return views.users(request, course_id=text_type(course_id)) + return views.users(request, course_id=str(course_id)) @patch('openedx.core.djangoapps.django_comment_common.comment_client.utils.requests.request', autospec=True) def test_finds_exact_match(self, mock_request): @@ -2050,7 +2046,7 @@ class ForumThreadViewedEventTransformerTestCase(ForumsEnableMixin, UrlResetMixin @mock.patch.dict("common.djangoapps.student.models.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(ForumThreadViewedEventTransformerTestCase, self).setUp() + super().setUp() self.courses_by_store = { ModuleStoreEnum.Type.mongo: CourseFactory.create( org='TestX', @@ -2198,7 +2194,7 @@ class ForumThreadViewedEventTransformerTestCase(ForumsEnableMixin, UrlResetMixin topic_id=commentable_id, thread_id=thread_id, ) - expected_path = '/courses/{0}/discussion/forum/{1}/threads/{2}'.format( + expected_path = '/courses/{}/discussion/forum/{}/threads/{}'.format( course.id, commentable_id, thread_id ) assert event_trans['event'].get('url').endswith(expected_path) @@ -2221,7 +2217,7 @@ class ForumThreadViewedEventTransformerTestCase(ForumsEnableMixin, UrlResetMixin topic_id=self.category.discussion_id, ) assert event_trans_2['event'].get('category_id') == self.category.discussion_id - full_category_name = u'{0} / {1}'.format(self.category.discussion_category, self.category.discussion_target) + full_category_name = f'{self.category.discussion_category} / {self.category.discussion_target}' assert event_trans_2['event'].get('category_name') == full_category_name def test_roles(self): diff --git a/lms/djangoapps/discussion/django_comment_client/base/views.py b/lms/djangoapps/discussion/django_comment_client/base/views.py index 5644d55cba9..3293dd6a4db 100644 --- a/lms/djangoapps/discussion/django_comment_client/base/views.py +++ b/lms/djangoapps/discussion/django_comment_client/base/views.py @@ -1,6 +1,4 @@ """Views for discussion forums.""" - - import functools import json import logging @@ -18,10 +16,10 @@ from django.views.decorators import csrf from django.views.decorators.clickjacking import xframe_options_exempt from django.views.decorators.http import require_GET, require_POST from opaque_keys.edx.keys import CourseKey -from six import text_type import lms.djangoapps.discussion.django_comment_client.settings as cc_settings import openedx.core.djangoapps.django_comment_common.comment_client as cc +from common.djangoapps.util.file import store_uploaded_file from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.courses import get_course_by_id, get_course_overview_with_access, get_course_with_access from lms.djangoapps.courseware.exceptions import CourseAccessRedirect @@ -57,7 +55,6 @@ from openedx.core.djangoapps.django_comment_common.signals import ( thread_voted ) from openedx.core.djangoapps.django_comment_common.utils import ThreadContext -from common.djangoapps.util.file import store_uploaded_file log = logging.getLogger(__name__) @@ -237,7 +234,7 @@ def create_thread(request, course_id, commentable_id): Given a course and commentable ID, create the thread """ - log.debug(u"Creating new thread in %r, id %r", course_id, commentable_id) + log.debug("Creating new thread in %r, id %r", course_id, commentable_id) course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key) post = request.POST @@ -262,7 +259,7 @@ def create_thread(request, course_id, commentable_id): 'anonymous': anonymous, 'anonymous_to_peers': anonymous_to_peers, 'commentable_id': commentable_id, - 'course_id': text_type(course_key), + 'course_id': str(course_key), 'user_id': user.id, 'thread_type': post["thread_type"], 'body': post["body"], @@ -380,7 +377,7 @@ def _create_comment(request, course_key, thread_id=None, parent_id=None): anonymous=anonymous, anonymous_to_peers=anonymous_to_peers, user_id=user.id, - course_id=text_type(course_key), + course_id=str(course_key), thread_id=thread_id, parent_id=parent_id, body=post["body"] @@ -771,10 +768,10 @@ def upload(request, course_id): # ajax upload file to a question or answer # l ) except exceptions.PermissionDenied as err: - error = six.text_type(err) + error = str(err) except Exception as err: # pylint: disable=broad-except print(err) - logging.critical(six.text_type(err)) + logging.critical(str(err)) error = _('Error uploading file. Please contact the site administrator. Thank you.') if error == '': diff --git a/lms/djangoapps/discussion/django_comment_client/middleware.py b/lms/djangoapps/discussion/django_comment_client/middleware.py index 7785bb7e8f5..b3133f710b1 100644 --- a/lms/djangoapps/discussion/django_comment_client/middleware.py +++ b/lms/djangoapps/discussion/django_comment_client/middleware.py @@ -3,7 +3,6 @@ import json import logging from django.utils.deprecation import MiddlewareMixin -from six import text_type from lms.djangoapps.discussion.django_comment_client.utils import JsonError from openedx.core.djangoapps.django_comment_common.comment_client import CommentClientRequestError @@ -23,7 +22,7 @@ class AjaxExceptionMiddleware(MiddlewareMixin): """ if isinstance(exception, CommentClientRequestError) and request.is_ajax(): try: - return JsonError(json.loads(text_type(exception)), exception.status_code) + return JsonError(json.loads(str(exception)), exception.status_code) except ValueError: - return JsonError(text_type(exception), exception.status_code) + return JsonError(str(exception), exception.status_code) return None diff --git a/lms/djangoapps/discussion/django_comment_client/permissions.py b/lms/djangoapps/discussion/django_comment_client/permissions.py index 10adf740cb0..a91fc0927f1 100644 --- a/lms/djangoapps/discussion/django_comment_client/permissions.py +++ b/lms/djangoapps/discussion/django_comment_client/permissions.py @@ -5,7 +5,6 @@ Module for checking permissions with the comment_client backend import logging -import six from edx_django_utils.cache import DEFAULT_REQUEST_CACHE from opaque_keys.edx.keys import CourseKey @@ -104,7 +103,7 @@ def _check_condition(user, condition, content): try: commentable_id = content['commentable_id'] request_cache_dict = DEFAULT_REQUEST_CACHE.data - cache_key = u"django_comment_client.check_team_member.{}.{}".format(user.id, commentable_id) + cache_key = f"django_comment_client.check_team_member.{user.id}.{commentable_id}" if cache_key in request_cache_dict: return request_cache_dict[cache_key] team = get_team(commentable_id) @@ -138,7 +137,7 @@ def _check_conditions_permissions(user, permissions, course_id, content, user_gr """ def test(user, per, operator="or"): - if isinstance(per, six.string_types): + if isinstance(per, str): if per in CONDITIONS: return _check_condition(user, per, content) if 'group_' in per: diff --git a/lms/djangoapps/discussion/django_comment_client/tests/factories.py b/lms/djangoapps/discussion/django_comment_client/tests/factories.py index 6330b81d4b1..d78ca5f445b 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/factories.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/factories.py @@ -5,7 +5,7 @@ from openedx.core.djangoapps.django_comment_common.models import Permission, Rol class RoleFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing-class-docstring - class Meta(object): + class Meta: model = Role name = 'Student' @@ -13,7 +13,7 @@ class RoleFactory(DjangoModelFactory): # lint-amnesty, pylint: disable=missing- class PermissionFactory(DjangoModelFactory): - class Meta(object): + class Meta: model = Permission name = 'create_comment' diff --git a/lms/djangoapps/discussion/django_comment_client/tests/group_id.py b/lms/djangoapps/discussion/django_comment_client/tests/group_id.py index 3ec2598a250..6acf974d0aa 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/group_id.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/group_id.py @@ -11,7 +11,7 @@ from openedx.core.djangoapps.django_comment_common.models import CourseDiscussio from openedx.core.djangoapps.django_comment_common.utils import set_course_discussion_settings -class GroupIdAssertionMixin(object): +class GroupIdAssertionMixin: def _data_or_params_cs_request(self, mock_request): """ Returns the data or params dict that `mock_request` was called with. diff --git a/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/mock_cs_server.py b/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/mock_cs_server.py index 9cbfd854749..bcc5da168d5 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/mock_cs_server.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/mock_cs_server.py @@ -30,7 +30,7 @@ class MockCommentServiceRequestHandler(BaseHTTPRequestHandler): # Log the request # pylint: disable=logging-format-interpolation logger.debug( - u"Comment Service received POST request {0} to path {1}" + "Comment Service received POST request {} to path {}" .format(json.dumps(post_dict), self.path) ) @@ -38,7 +38,7 @@ class MockCommentServiceRequestHandler(BaseHTTPRequestHandler): if 'X-Edx-Api-Key' in self.headers: response = self.server._response_str # Log the response - logger.debug(u"Comment Service: sending response %s", json.dumps(response)) + logger.debug("Comment Service: sending response %s", json.dumps(response)) # Send a response back to the client self.send_response(200) @@ -68,7 +68,7 @@ class MockCommentServiceRequestHandler(BaseHTTPRequestHandler): # Log the request # pylint: disable=logging-format-interpolation logger.debug( - u"Comment Service received PUT request {0} to path {1}" + "Comment Service received PUT request {} to path {}" .format(json.dumps(post_dict), self.path) ) @@ -76,7 +76,7 @@ class MockCommentServiceRequestHandler(BaseHTTPRequestHandler): if 'X-Edx-Api-Key' in self.headers: response = self.server._response_str # Log the response - logger.debug(u"Comment Service: sending response %s", json.dumps(response)) + logger.debug("Comment Service: sending response %s", json.dumps(response)) # Send a response back to the client self.send_response(200) diff --git a/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/test_mock_cs_server.py b/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/test_mock_cs_server.py index 6fb577f4b89..b25bea9b029 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/test_mock_cs_server.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/mock_cs_server/test_mock_cs_server.py @@ -15,7 +15,7 @@ class MockCommentServiceServerTest(unittest.TestCase): ''' def setUp(self): - super(MockCommentServiceServerTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # This is a test of the test setup, # so it does not need to run as part of the unit test suite @@ -44,8 +44,8 @@ class MockCommentServiceServerTest(unittest.TestCase): of how you would create a new user """ # Send a request - values = {'username': u'user100', - 'external_id': '4', 'email': u'user100@edx.org'} + values = {'username': 'user100', + 'external_id': '4', 'email': 'user100@edx.org'} data = json.dumps(values) headers = {'Content-Type': 'application/json', 'Content-Length': len(data), 'X-Edx-Api-Key': 'TEST_API_KEY'} req = six.moves.urllib.request.Request(self.server_url + '/api/v1/users/4', data, headers) # lint-amnesty, pylint: disable=undefined-variable diff --git a/lms/djangoapps/discussion/django_comment_client/tests/test_middleware.py b/lms/djangoapps/discussion/django_comment_client/tests/test_middleware.py index aa83d66bd89..d16bae5d7a7 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/test_middleware.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/test_middleware.py @@ -3,7 +3,6 @@ import json import django.http from django.test import TestCase -from six import text_type import lms.djangoapps.discussion.django_comment_client.middleware as middleware import openedx.core.djangoapps.django_comment_common.comment_client as comment_client @@ -12,7 +11,7 @@ import openedx.core.djangoapps.django_comment_common.comment_client as comment_c class AjaxExceptionTestCase(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring def setUp(self): - super(AjaxExceptionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.a = middleware.AjaxExceptionMiddleware() self.request1 = django.http.HttpRequest() self.request0 = django.http.HttpRequest() @@ -26,12 +25,12 @@ class AjaxExceptionTestCase(TestCase): # lint-amnesty, pylint: disable=missing- response1 = self.a.process_exception(self.request1, self.exception1) assert isinstance(response1, middleware.JsonError) assert self.exception1.status_code == response1.status_code - assert {'errors': json.loads(text_type(self.exception1))} == json.loads(response1.content.decode('utf-8')) + assert {'errors': json.loads(str(self.exception1))} == json.loads(response1.content.decode('utf-8')) response2 = self.a.process_exception(self.request1, self.exception2) assert isinstance(response2, middleware.JsonError) assert self.exception2.status_code == response2.status_code - assert {'errors': [text_type(self.exception2)]} == json.loads(response2.content.decode('utf-8')) + assert {'errors': [str(self.exception2)]} == json.loads(response2.content.decode('utf-8')) assert self.a.process_exception(self.request1, self.exception0) is None assert self.a.process_exception(self.request0, self.exception1) is None diff --git a/lms/djangoapps/discussion/django_comment_client/tests/test_models.py b/lms/djangoapps/discussion/django_comment_client/tests/test_models.py index dba7476bd1a..b5d063b39b7 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/test_models.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/test_models.py @@ -18,7 +18,7 @@ class RoleClassTestCase(ModuleStoreTestCase): MODULESTORE = TEST_DATA_MIXED_MODULESTORE def setUp(self): - super(RoleClassTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # For course ID, syntax edx/classname/classdate is important # because xmodel.course_module.id_to_location looks for a string to split @@ -58,7 +58,7 @@ class PermissionClassTestCase(TestCase): """ def setUp(self): - super(PermissionClassTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.permission = models.Permission.objects.get_or_create(name="test")[0] def test_unicode(self): diff --git a/lms/djangoapps/discussion/django_comment_client/tests/test_utils.py b/lms/djangoapps/discussion/django_comment_client/tests/test_utils.py index 1c6566b54eb..cd99ed9efc1 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/test_utils.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/test_utils.py @@ -1,26 +1,25 @@ # pylint: skip-file -# -*- coding: utf-8 -*- import datetime import json import sys +from unittest import mock +from unittest.mock import Mock, patch import ddt -import mock import pytest -import six from django.test import RequestFactory, TestCase from django.urls import reverse from edx_django_utils.cache import RequestCache -from mock import Mock, patch from opaque_keys.edx.keys import CourseKey from pytz import UTC -from six import text_type import lms.djangoapps.discussion.django_comment_client.utils as utils from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.roles import CourseStaffRole +from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory from lms.djangoapps.courseware.tabs import get_course_tab_list from lms.djangoapps.courseware.tests.factories import InstructorFactory from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY @@ -47,8 +46,6 @@ from openedx.core.djangoapps.django_comment_common.utils import ( set_course_discussion_settings ) from openedx.core.djangoapps.util.testing import ContentGroupTestCase -from common.djangoapps.student.roles import CourseStaffRole -from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import TEST_DATA_MIXED_MODULESTORE, ModuleStoreTestCase @@ -81,7 +78,7 @@ class AccessUtilsTestCase(ModuleStoreTestCase): CREATE_USER = False def setUp(self): - super(AccessUtilsTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create() self.course_id = self.course.id @@ -105,7 +102,7 @@ class AccessUtilsTestCase(ModuleStoreTestCase): def test_get_role_ids(self): ret = utils.get_role_ids(self.course_id) - expected = {u'Moderator': [3], u'Community TA': [4, 5]} + expected = {'Moderator': [3], 'Community TA': [4, 5]} assert ret == expected def test_has_discussion_privileges(self): @@ -134,7 +131,7 @@ class CoursewareContextTestCase(ModuleStoreTestCase): comment client service integration """ def setUp(self): - super(CoursewareContextTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create(org="TestX", number="101", display_name="Test Course") self.discussion1 = ItemFactory.create( parent_location=self.course.location, @@ -170,7 +167,7 @@ class CoursewareContextTestCase(ModuleStoreTestCase): def assertThreadCorrect(thread, discussion, expected_title): # pylint: disable=invalid-name """Asserts that the given thread has the expected set of properties""" assert set(thread.keys()) == set(['commentable_id', 'courseware_url', 'courseware_title']) - assert thread.get('courseware_url') == reverse('jump_to', kwargs={'course_id': text_type(self.course.id), 'location': text_type(discussion.location)}) + assert thread.get('courseware_url') == reverse('jump_to', kwargs={'course_id': str(self.course.id), 'location': str(discussion.location)}) assert thread.get('courseware_title') == expected_title assertThreadCorrect(threads[0], self.discussion1, "Chapter / Discussion 1") @@ -228,7 +225,7 @@ class CachedDiscussionIdMapTestCase(ModuleStoreTestCase): ENABLED_SIGNALS = ['course_published'] def setUp(self): - super(CachedDiscussionIdMapTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create(org='TestX', number='101', display_name='Test Course') self.discussion = ItemFactory.create( @@ -340,7 +337,7 @@ class CachedDiscussionIdMapTestCase(ModuleStoreTestCase): assert not utils.discussion_category_id_access(self.course, user, 'private_discussion_id') -class CategoryMapTestMixin(object): +class CategoryMapTestMixin: """ Provides functionality for classes that test `get_discussion_category_map`. @@ -361,7 +358,7 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): comment client service integration """ def setUp(self): - super(CategoryMapTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create( org="TestX", number="101", display_name="Test Course", @@ -382,7 +379,7 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): return ItemFactory.create( parent_location=self.course.location, category="discussion", - discussion_id="discussion{}".format(self.discussion_num), + discussion_id=f"discussion{self.discussion_num}", discussion_category=discussion_category, discussion_target=discussion_target, **kwargs @@ -676,7 +673,7 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): def test_start_date_filter(self): now = datetime.datetime.now() self.create_discussion("Chapter 1", "Discussion 1", start=now) - self.create_discussion("Chapter 1", u"Discussion 2 обÑуждение", start=self.later) + self.create_discussion("Chapter 1", "Discussion 2 обÑуждение", start=self.later) self.create_discussion("Chapter 2", "Discussion", start=now) self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion", start=self.later) self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion", start=self.later) @@ -1003,11 +1000,8 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): "Topic B": {"id": "Topic_B"}, "Topic C": {"id": "Topic_C"} } - six.assertCountEqual( - self, - utils.get_discussion_categories_ids(self.course, self.user), - ["Topic_A", "Topic_B", "Topic_C"] - ) + assert len(utils.get_discussion_categories_ids(self.course, self.user)) ==\ + len(["Topic_A", "Topic_B", "Topic_C"]) def test_ids_inline(self): self.create_discussion("Chapter 1", "Discussion 1") @@ -1016,11 +1010,8 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion") self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion") self.create_discussion("Chapter 3 / Section 1", "Discussion") - six.assertCountEqual( - self, - utils.get_discussion_categories_ids(self.course, self.user), - ["discussion1", "discussion2", "discussion3", "discussion4", "discussion5", "discussion6"] - ) + assert len(utils.get_discussion_categories_ids(self.course, self.user)) ==\ + len(["discussion1", "discussion2", "discussion3", "discussion4", "discussion5", "discussion6"]) def test_ids_mixed(self): self.course.discussion_topics = { @@ -1031,11 +1022,8 @@ class CategoryMapTestCase(CategoryMapTestMixin, ModuleStoreTestCase): self.create_discussion("Chapter 1", "Discussion 1") self.create_discussion("Chapter 2", "Discussion") self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion") - six.assertCountEqual( - self, - utils.get_discussion_categories_ids(self.course, self.user), - ["Topic_A", "Topic_B", "Topic_C", "discussion1", "discussion2", "discussion3"] - ) + assert len(utils.get_discussion_categories_ids(self.course, self.user)) ==\ + len(["Topic_A", "Topic_B", "Topic_C", "discussion1", "discussion2", "discussion3"]) class ContentGroupCategoryMapTestCase(CategoryMapTestMixin, ContentGroupTestCase): @@ -1212,7 +1200,7 @@ class DiscussionTabTestCase(ModuleStoreTestCase): """ Test visibility of the discussion tab. """ def setUp(self): - super(DiscussionTabTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create() self.enrolled_user = UserFactory.create() self.staff_user = AdminFactory.create() @@ -1252,7 +1240,7 @@ class IsCommentableDividedTestCase(ModuleStoreTestCase): """ Make sure that course is reloaded every time--clear out the modulestore. """ - super(IsCommentableDividedTestCase, self).setUp() + super().setUp() self.toy_course_key = ToyCourseFactory.create().id def test_is_commentable_divided(self): @@ -1385,7 +1373,7 @@ class GroupIdForUserTestCase(ModuleStoreTestCase): """ Test the get_group_id_for_user method. """ def setUp(self): - super(GroupIdForUserTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create() CourseModeFactory.create(course_id=self.course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory.create(course_id=self.course.id, mode_slug=CourseMode.VERIFIED) @@ -1425,7 +1413,7 @@ class CourseDiscussionDivisionEnabledTestCase(ModuleStoreTestCase): """ Test the course_discussion_division_enabled and available_division_schemes methods. """ def setUp(self): - super(CourseDiscussionDivisionEnabledTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create() CourseModeFactory.create(course_id=self.course.id, mode_slug=CourseMode.AUDIT) self.test_cohort = CohortFactory( @@ -1471,7 +1459,7 @@ class GroupNameTestCase(ModuleStoreTestCase): """ Test the get_group_name and get_group_names_by_id methods. """ def setUp(self): - super(GroupNameTestCase, self).setUp() + super().setUp() self.course = CourseFactory.create() CourseModeFactory.create(course_id=self.course.id, mode_slug=CourseMode.AUDIT) CourseModeFactory.create(course_id=self.course.id, mode_slug=CourseMode.VERIFIED) @@ -1585,7 +1573,7 @@ class GroupModeratorPermissionsTestCase(ModuleStoreTestCase): return True if condition == 'is_open' or condition == 'is_team_member_if_applicable' else False def setUp(self): - super(GroupModeratorPermissionsTestCase, self).setUp() + super().setUp() # Create course, seed permissions roles, and create team self.course = CourseFactory.create() diff --git a/lms/djangoapps/discussion/django_comment_client/tests/unicode.py b/lms/djangoapps/discussion/django_comment_client/tests/unicode.py index f8086d3ecf8..a95ab3b530e 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/unicode.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/unicode.py @@ -1,23 +1,23 @@ # lint-amnesty, pylint: disable=missing-module-docstring -class UnicodeTestMixin(object): # lint-amnesty, pylint: disable=missing-class-docstring +class UnicodeTestMixin: # lint-amnesty, pylint: disable=missing-class-docstring def test_ascii(self): - self._test_unicode_data(u"This post contains ASCII.") + self._test_unicode_data("This post contains ASCII.") def test_latin_1(self): - self._test_unicode_data(u"ThÃs pøst çòñtáins Lätin-1 tæxt") + self._test_unicode_data("ThÃs pøst çòñtáins Lätin-1 tæxt") def test_CJK(self): - self._test_unicode_data(u"イんノ丂 ï½±o丂イ co刀イムノ刀丂 cフズ") + self._test_unicode_data("イんノ丂 ï½±o丂イ co刀イムノ刀丂 cフズ") def test_non_BMP(self): - self._test_unicode_data(u"ð•‹ð•™ð•šð•¤ ð•¡ð• ð•¤ð•¥ ð•”ð• ð•Ÿð•¥ð•’ð•šð•Ÿð•¤ ð•”ð•™ð•’ð•£ð•’ð•”ð•¥ð•–ð•£ð•¤ ð• ð•¦ð•¥ð•¤ð•šð••ð•– ð•¥ð•™ð•– ð”¹ð•„â„™") + self._test_unicode_data("ð•‹ð•™ð•šð•¤ ð•¡ð• ð•¤ð•¥ ð•”ð• ð•Ÿð•¥ð•’ð•šð•Ÿð•¤ ð•”ð•™ð•’ð•£ð•’ð•”ð•¥ð•–ð•£ð•¤ ð• ð•¦ð•¥ð•¤ð•šð••ð•– ð•¥ð•™ð•– ð”¹ð•„â„™") def test_special_chars(self): self._test_unicode_data( - u"\" This , post > contains < delimiter ] and [ other } special { characters ; that & may ' break things" + "\" This , post > contains < delimiter ] and [ other } special { characters ; that & may ' break things" ) def test_string_interp(self): - self._test_unicode_data(u"This post contains %s string interpolation #{syntax}") + self._test_unicode_data("This post contains %s string interpolation #{syntax}") diff --git a/lms/djangoapps/discussion/django_comment_client/tests/utils.py b/lms/djangoapps/discussion/django_comment_client/tests/utils.py index 52d32e541b7..357f57217bd 100644 --- a/lms/djangoapps/discussion/django_comment_client/tests/utils.py +++ b/lms/djangoapps/discussion/django_comment_client/tests/utils.py @@ -3,8 +3,10 @@ Utilities for tests within the django_comment_client module. """ -from mock import patch +from unittest.mock import patch +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from common.djangoapps.util.testing import UrlResetMixin from openedx.core.djangoapps.course_groups.tests.helpers import CohortFactory from openedx.core.djangoapps.django_comment_common.models import ForumsConfig, Role from openedx.core.djangoapps.django_comment_common.utils import ( @@ -13,20 +15,18 @@ from openedx.core.djangoapps.django_comment_common.utils import ( set_course_discussion_settings ) from openedx.core.lib.teams_config import TeamsConfig -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from common.djangoapps.util.testing import UrlResetMixin from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory -class ForumsEnableMixin(object): +class ForumsEnableMixin: """ Ensures that the forums are enabled for a given test class. """ def setUp(self): - super(ForumsEnableMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() config = ForumsConfig.current() config.enabled = True @@ -40,7 +40,7 @@ class CohortedTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCa @classmethod @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUpClass(cls): - super(CohortedTestCase, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create( cohort_config={ "cohorted": True, @@ -61,7 +61,7 @@ class CohortedTestCase(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCa @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(CohortedTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() seed_permissions_roles(self.course.id) self.student = UserFactory.create() @@ -115,8 +115,8 @@ def config_course_discussions( division_scheme=CourseDiscussionSettings.COHORT, ) - course.discussion_topics = dict((name, {"sort_key": "A", "id": to_id(name)}) - for name in discussion_topics) + course.discussion_topics = {name: {"sort_key": "A", "id": to_id(name)} + for name in discussion_topics} try: # Not implemented for XMLModulestore, which is used by test_cohorts. modulestore().update_item(course, ModuleStoreEnum.UserID.test) diff --git a/lms/djangoapps/discussion/django_comment_client/utils.py b/lms/djangoapps/discussion/django_comment_client/utils.py index c58b1c387ec..6d8fae21c63 100644 --- a/lms/djangoapps/discussion/django_comment_client/utils.py +++ b/lms/djangoapps/discussion/django_comment_client/utils.py @@ -6,18 +6,17 @@ import logging from collections import defaultdict from datetime import datetime -import six from django.conf import settings from django.contrib.auth.models import User from django.db import connection from django.http import HttpResponse from django.urls import reverse from django.utils.deprecation import MiddlewareMixin -from opaque_keys.edx.keys import CourseKey, i4xEncoder, UsageKey +from opaque_keys.edx.keys import CourseKey, UsageKey, i4xEncoder from pytz import UTC -from six import text_type -from six.moves import map +from common.djangoapps.student.models import get_user_by_username_or_email +from common.djangoapps.student.roles import GlobalStaff from lms.djangoapps.courseware import courses from lms.djangoapps.courseware.access import has_access from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY @@ -37,8 +36,6 @@ from openedx.core.djangoapps.django_comment_common.models import ( ) from openedx.core.djangoapps.django_comment_common.utils import get_course_discussion_settings from openedx.core.lib.cache_utils import request_cached -from common.djangoapps.student.models import get_user_by_username_or_email -from common.djangoapps.student.roles import GlobalStaff from xmodule.modulestore.django import modulestore from xmodule.partitions.partitions import ENROLLMENT_TRACK_PARTITION_ID from xmodule.partitions.partitions_service import PartitionService @@ -57,7 +54,7 @@ def strip_none(dic): """ Returns a dictionary stripped of any keys having values of None """ - return dict([(k, v) for k, v in six.iteritems(dic) if v is not None]) + return {k: v for k, v in dic.items() if v is not None} def strip_blank(dic): @@ -69,7 +66,7 @@ def strip_blank(dic): Determines if the provided value contains no information """ return isinstance(v, str) and len(v.strip()) == 0 - return dict([(k, v) for k, v in six.iteritems(dic) if not _is_blank(v)]) + return {k: v for k, v in dic.items() if not _is_blank(v)} # TODO should we be checking if d1 and d2 have the same keys with different values? @@ -79,7 +76,7 @@ def get_role_ids(course_id): Returns a dictionary having role names as keys and a list of users as values """ roles = Role.objects.filter(course_id=course_id).exclude(name=FORUM_ROLE_STUDENT) - return dict([(role.name, list(role.users.values_list('id', flat=True))) for role in roles]) + return {role.name: list(role.users.values_list('id', flat=True)) for role in roles} def has_discussion_privileges(user, course_id): @@ -129,7 +126,7 @@ def has_required_keys(xblock): for key in ('discussion_id', 'discussion_category', 'discussion_target'): if getattr(xblock, key, None) is None: log.debug( - u"Required key '%s' not in discussion %s, leaving out of category map", + "Required key '%s' not in discussion %s, leaving out of category map", key, xblock.location ) @@ -281,7 +278,7 @@ def _filter_unstarted_categories(category_map, course): filtered_map["entries"][child][key] = unfiltered_map["entries"][child][key] else: log.debug( - u"Filtering out:%s with start_date: %s", child, unfiltered_map["entries"][child]["start_date"] + "Filtering out:%s with start_date: %s", child, unfiltered_map["entries"][child]["start_date"] ) else: if course.self_paced or unfiltered_map["subcategories"][child]["start_date"] < now: @@ -425,7 +422,7 @@ def get_discussion_category_map(course, user, divided_only_if_explicit=False, ex # If we've already seen this title, append an incrementing number to disambiguate # the category from other categores sharing the same title in the course discussion UI. dupe_counters[title] += 1 - title = u"{title} ({counter})".format(title=title, counter=dupe_counters[title]) + title = "{title} ({counter})".format(title=title, counter=dupe_counters[title]) node[level]["entries"][title] = {"id": entry["id"], "sort_key": entry["sort_key"], "start_date": entry["start_date"], @@ -496,8 +493,7 @@ class JsonResponse(HttpResponse): Object constructor, converts data (if provided) to JSON """ content = json.dumps(data, cls=i4xEncoder) - super(JsonResponse, self).__init__(content, - content_type='application/json; charset=utf-8') + super().__init__(content, content_type='application/json; charset=utf-8') class JsonError(HttpResponse): @@ -508,11 +504,10 @@ class JsonError(HttpResponse): """ Object constructor, returns an error response containing the provided exception messages """ - if isinstance(error_messages, six.string_types): + if isinstance(error_messages, str): error_messages = [error_messages] content = json.dumps({'errors': error_messages}, indent=2, ensure_ascii=False) - super(JsonError, self).__init__(content, - content_type='application/json; charset=utf-8', status=status) + super().__init__(content, content_type='application/json; charset=utf-8', status=status) class HtmlResponse(HttpResponse): @@ -523,7 +518,7 @@ class HtmlResponse(HttpResponse): """ Object constructor, brokers provided HTML to caller """ - super(HtmlResponse, self).__init__(html, content_type='text/plain') + super().__init__(html, content_type='text/plain') class ViewNameMiddleware(MiddlewareMixin): @@ -562,7 +557,7 @@ class QueryCountDebugMiddleware(MiddlewareMixin): query_time = query.get('duration', 0) / 1000 total_time += float(query_time) - log.info(u'%s queries run, total %s seconds', len(connection.queries), total_time) + log.info('%s queries run, total %s seconds', len(connection.queries), total_time) return response @@ -687,7 +682,7 @@ def get_metadata_for_threads(course_id, threads, user, user_info): def permalink(content): if isinstance(content['course_id'], CourseKey): - course_id = text_type(content['course_id']) + course_id = str(content['course_id']) else: course_id = content['course_id'] if content['type'] == 'thread': @@ -702,10 +697,10 @@ def extend_content(content): if content.get('user_id'): try: user = User.objects.get(pk=content['user_id']) - roles = dict(('name', role.name.lower()) for role in user.roles.filter(course_id=content['course_id'])) + roles = {'name': role.name.lower() for role in user.roles.filter(course_id=content['course_id'])} except User.DoesNotExist: log.error( - u'User ID %s in comment content %s but not in our DB.', + 'User ID %s in comment content %s but not in our DB.', content.get('user_id'), content.get('id') ) @@ -735,10 +730,10 @@ def add_courseware_context(content_list, course, user, id_map=None): for content in content_list: commentable_id = content['commentable_id'] if commentable_id in id_map: - location = text_type(id_map[commentable_id]["location"]) + location = str(id_map[commentable_id]["location"]) title = id_map[commentable_id]["title"] - url = reverse('jump_to', kwargs={"course_id": text_type(course.id), + url = reverse('jump_to', kwargs={"course_id": str(course.id), "location": location}) content.update({"courseware_url": url, "courseware_title": title}) @@ -787,7 +782,7 @@ def prepare_content(content, course_key, is_staff=False, discussion_division_ena endorser = User.objects.get(pk=endorsement["user_id"]) except User.DoesNotExist: log.error( - u"User ID %s in endorsement for comment %s but not in our DB.", + "User ID %s in endorsement for comment %s but not in our DB.", content.get('user_id'), content.get('id') ) @@ -946,7 +941,7 @@ def is_commentable_divided(course_key, commentable_id, course_discussion_setting # inline discussions are divided by default ans = True - log.debug(u"is_commentable_divided(%s, %s) = {%s}", course_key, commentable_id, ans) + log.debug("is_commentable_divided(%s, %s) = {%s}", course_key, commentable_id, ans) return ans diff --git a/lms/djangoapps/discussion/management/commands/assign_roles_for_course.py b/lms/djangoapps/discussion/management/commands/assign_roles_for_course.py index 49e39277973..921c01122b8 100644 --- a/lms/djangoapps/discussion/management/commands/assign_roles_for_course.py +++ b/lms/djangoapps/discussion/management/commands/assign_roles_for_course.py @@ -8,8 +8,8 @@ Enrollments. from django.core.management.base import BaseCommand -from openedx.core.djangoapps.django_comment_common.models import assign_default_role_on_enrollment from common.djangoapps.student.models import CourseEnrollment +from openedx.core.djangoapps.django_comment_common.models import assign_default_role_on_enrollment class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docstring @@ -26,5 +26,5 @@ class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docst for i, enrollment in enumerate(CourseEnrollment.objects.filter(course_id=course_id, is_active=1), start=1): assign_default_role_on_enrollment(None, enrollment) if i % 1000 == 0: - print('{0}...'.format(i), end=' ') + print(f'{i}...', end=' ') print() diff --git a/lms/djangoapps/discussion/management/commands/create_roles_for_existing.py b/lms/djangoapps/discussion/management/commands/create_roles_for_existing.py index d33dc641ace..f71016e8f4f 100644 --- a/lms/djangoapps/discussion/management/commands/create_roles_for_existing.py +++ b/lms/djangoapps/discussion/management/commands/create_roles_for_existing.py @@ -8,8 +8,8 @@ Enrollments. from django.core.management.base import BaseCommand -from openedx.core.djangoapps.django_comment_common.models import assign_default_role_on_enrollment from common.djangoapps.student.models import CourseEnrollment +from openedx.core.djangoapps.django_comment_common.models import assign_default_role_on_enrollment class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docstring @@ -20,5 +20,5 @@ class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docst for i, enrollment in enumerate(CourseEnrollment.objects.filter(is_active=1), start=1): assign_default_role_on_enrollment(None, enrollment) if i % 1000 == 0: - print('{0}...'.format(i), end=' ') + print(f'{i}...', end=' ') print() diff --git a/lms/djangoapps/discussion/management/commands/get_discussion_link.py b/lms/djangoapps/discussion/management/commands/get_discussion_link.py index 8c2d624a00f..3cd19286362 100644 --- a/lms/djangoapps/discussion/management/commands/get_discussion_link.py +++ b/lms/djangoapps/discussion/management/commands/get_discussion_link.py @@ -19,7 +19,7 @@ class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docst course = get_course(course_key) if not course: - raise CommandError(u'Invalid course id: {}'.format(course_id)) + raise CommandError(f'Invalid course id: {course_id}') if course.discussion_link: self.stdout.write(course.discussion_link) diff --git a/lms/djangoapps/discussion/management/commands/reload_forum_users.py b/lms/djangoapps/discussion/management/commands/reload_forum_users.py index 28bc59c566e..196d2e2084a 100644 --- a/lms/djangoapps/discussion/management/commands/reload_forum_users.py +++ b/lms/djangoapps/discussion/management/commands/reload_forum_users.py @@ -24,7 +24,7 @@ class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docst cc_user = cc.User.from_django_user(user) cc_user.save() except Exception as err: # lint-amnesty, pylint: disable=broad-except - print(u'update user info to discussion failed for user with id: {}, error={}'.format(user, str(err))) + print('update user info to discussion failed for user with id: {}, error={}'.format(user, str(err))) def handle(self, *args, **options): if len(options['usernames']) >= 1: diff --git a/lms/djangoapps/discussion/management/commands/show_permissions.py b/lms/djangoapps/discussion/management/commands/show_permissions.py index a570191400d..3581a7b6a2f 100644 --- a/lms/djangoapps/discussion/management/commands/show_permissions.py +++ b/lms/djangoapps/discussion/management/commands/show_permissions.py @@ -20,16 +20,16 @@ class Command(BaseCommand): # lint-amnesty, pylint: disable=missing-class-docst else: user = User.objects.get(username=email_or_username) except User.DoesNotExist: - print(u'User {} does not exist. '.format(email_or_username)) + print(f'User {email_or_username} does not exist. ') print('Available users: ') print(User.objects.all()) return roles = user.roles.all() - print(u'{} has %d roles:'.format(user, len(roles))) + print('{} has %d roles:'.format(user, len(roles))) for role in roles: - print(u'\t{}'.format(role)) + print(f'\t{role}') for role in roles: - print(u'{} has permissions: '.format(role)) + print(f'{role} has permissions: ') print(role.permissions.all()) diff --git a/lms/djangoapps/discussion/notification_prefs/tests.py b/lms/djangoapps/discussion/notification_prefs/tests.py index 3521abc8c27..0da81f04ccc 100644 --- a/lms/djangoapps/discussion/notification_prefs/tests.py +++ b/lms/djangoapps/discussion/notification_prefs/tests.py @@ -1,9 +1,6 @@ # pylint: disable=consider-iterating-dictionary, missing-module-docstring - - import json -import six from django.contrib.auth.models import AnonymousUser from django.core.exceptions import PermissionDenied from django.http import Http404 @@ -13,6 +10,8 @@ from django.test.utils import override_settings from django.urls import reverse from mock import patch +from common.djangoapps.student.tests.factories import UserFactory +from common.djangoapps.util.testing import UrlResetMixin from lms.djangoapps.discussion.notification_prefs import NOTIFICATION_PREF_KEY from lms.djangoapps.discussion.notification_prefs.views import ( UsernameCipher, @@ -22,8 +21,6 @@ from lms.djangoapps.discussion.notification_prefs.views import ( set_subscription ) from openedx.core.djangoapps.user_api.models import UserPreference -from common.djangoapps.student.tests.factories import UserFactory -from common.djangoapps.util.testing import UrlResetMixin @override_settings(SECRET_KEY="test secret key") @@ -32,7 +29,7 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase): # lint-amnesty, pylint @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(NotificationPrefViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create(username="testuser") # Tokens are intentionally hard-coded instead of computed to help us # avoid breaking existing links. @@ -45,7 +42,7 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase): # lint-amnesty, pylint UserFactory.create(username="thisusernameissoveryverylong"): "AAAAAAAAAAAAAAAAAAAAAPECbYqPI7_W4mRF8LbTaHuHt3tNXPggZ1Bke-zDyEiZ", # Non-ASCII username - UserFactory.create(username=u"\u4e2d\u56fd"): + UserFactory.create(username="\u4e2d\u56fd"): "AAAAAAAAAAAAAAAAAAAAAMjfGAhZKIZsI3L-Z7nflTA=" } self.request_factory = RequestFactory() @@ -63,7 +60,7 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase): # lint-amnesty, pylint # now coerce username to utf-8 encoded str, since we test with non-ascii unicdoe above and # the unittest framework has hard time coercing to unicode. # decrypt also can't take a unicode input, so coerce its input to str - assert six.binary_type(user.username.encode('utf-8')) == UsernameCipher().decrypt(str(pref.value)) + assert bytes(user.username.encode('utf-8')) == UsernameCipher().decrypt(str(pref.value)) def assertNotPrefExists(self, user): """Ensure that the user does not have a persisted preference""" @@ -189,7 +186,7 @@ class NotificationPrefViewTest(UrlResetMixin, TestCase): # lint-amnesty, pylint def test_unsubscribe_invalid_token(self): def test_invalid_token(token, message): request = self.request_factory.get("dummy") - self.assertRaisesRegex(Http404, "^{}$".format(message), set_subscription, request, token, False) + self.assertRaisesRegex(Http404, f"^{message}$", set_subscription, request, token, False) # Invalid base64 encoding test_invalid_token("ZOMG INVALID BASE64 CHARS!!!", "base64url") diff --git a/lms/djangoapps/discussion/notification_prefs/views.py b/lms/djangoapps/discussion/notification_prefs/views.py index 6dbf279da0c..470f9a821ad 100644 --- a/lms/djangoapps/discussion/notification_prefs/views.py +++ b/lms/djangoapps/discussion/notification_prefs/views.py @@ -1,14 +1,13 @@ """ Views to support notification preferences. """ - - import json import os from base64 import urlsafe_b64decode, urlsafe_b64encode from binascii import Error from hashlib import sha256 +import six from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers.algorithms import AES @@ -19,8 +18,6 @@ from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imp from django.core.exceptions import PermissionDenied from django.http import Http404, HttpResponse from django.views.decorators.http import require_GET, require_POST -import six -from six import text_type from common.djangoapps.edxmako.shortcuts import render_to_response from lms.djangoapps.discussion.notification_prefs import NOTIFICATION_PREF_KEY @@ -34,7 +31,7 @@ class UsernameDecryptionException(Exception): pass -class UsernameCipher(object): +class UsernameCipher: """ A transformation of a username to/from an opaque token @@ -191,7 +188,7 @@ def set_subscription(request, token, subscribe): except UnicodeDecodeError: raise Http404("base64url") # lint-amnesty, pylint: disable=raise-missing-from except UsernameDecryptionException as exn: - raise Http404(text_type(exn)) # lint-amnesty, pylint: disable=raise-missing-from + raise Http404(str(exn)) # lint-amnesty, pylint: disable=raise-missing-from except User.DoesNotExist: raise Http404("username") # lint-amnesty, pylint: disable=raise-missing-from diff --git a/lms/djangoapps/discussion/plugins.py b/lms/djangoapps/discussion/plugins.py index b279827c24a..915ed31e3f0 100644 --- a/lms/djangoapps/discussion/plugins.py +++ b/lms/djangoapps/discussion/plugins.py @@ -29,7 +29,7 @@ class DiscussionTab(TabFragmentViewMixin, EnrolledTab): @classmethod def is_enabled(cls, course, user=None): - if not super(DiscussionTab, cls).is_enabled(course, user): + if not super().is_enabled(course, user): return False # Disable the regular discussion tab if LTI-based external Discussion forum is enabled if DiscussionLtiCourseTab.is_enabled(course, user): diff --git a/lms/djangoapps/discussion/rest_api/api.py b/lms/djangoapps/discussion/rest_api/api.py index b9475a1194e..f56e895569c 100644 --- a/lms/djangoapps/discussion/rest_api/api.py +++ b/lms/djangoapps/discussion/rest_api/api.py @@ -7,7 +7,6 @@ import itertools from collections import defaultdict from enum import Enum -import six from django.core.exceptions import ValidationError from django.http import Http404 from django.urls import reverse @@ -64,11 +63,12 @@ from openedx.core.djangoapps.django_comment_common.signals import ( ) from openedx.core.djangoapps.django_comment_common.utils import get_course_discussion_settings from openedx.core.djangoapps.user_api.accounts.api import get_account_settings -from openedx.core.djangoapps.user_api.accounts.views import AccountViewSet # lint-amnesty, pylint: disable=unused-import +from openedx.core.djangoapps.user_api.accounts.views import \ + AccountViewSet # lint-amnesty, pylint: disable=unused-import from openedx.core.lib.exceptions import CourseNotFoundError, DiscussionNotFoundError, PageNotFoundError -class DiscussionTopic(object): +class DiscussionTopic: """ Class for discussion topic structure """ @@ -177,7 +177,7 @@ def get_thread_list_url(request, course_key, topic_id_list=None, following=False """ path = reverse("thread-list") query_list = ( - [("course_id", six.text_type(course_key))] + + [("course_id", str(course_key))] + [("topic_id", topic_id) for topic_id in topic_id_list or []] + ([("following", following)] if following else []) ) @@ -228,7 +228,7 @@ def get_course(request, course_key): course = _get_course(course_key, request.user) return { - "id": six.text_type(course_key), + "id": str(course_key), "blackouts": [ { "start": _format_datetime(blackout["start"]), @@ -369,7 +369,7 @@ def get_course_topics(request, course_key, topic_ids=None): not_found_topic_ids = topic_ids - (existing_courseware_topic_ids | existing_non_courseware_topic_ids) if not_found_topic_ids: raise DiscussionNotFoundError( - u"Discussion not found for '{}'.".format(", ".join(str(id) for id in not_found_topic_ids)) + "Discussion not found for '{}'.".format(", ".join(str(id) for id in not_found_topic_ids)) ) return { @@ -576,18 +576,18 @@ def get_thread_list( if order_by not in cc_map: raise ValidationError({ "order_by": - [u"Invalid value. '{}' must be 'last_activity_at', 'comment_count', or 'vote_count'".format(order_by)] + [f"Invalid value. '{order_by}' must be 'last_activity_at', 'comment_count', or 'vote_count'"] }) if order_direction != "desc": raise ValidationError({ - "order_direction": [u"Invalid value. '{}' must be 'desc'".format(order_direction)] + "order_direction": [f"Invalid value. '{order_direction}' must be 'desc'"] }) course = _get_course(course_key, request.user) context = get_context(course, request) query_params = { - "user_id": six.text_type(request.user.id), + "user_id": str(request.user.id), "group_id": ( None if context["is_requester_privileged"] else get_group_id_for_user(request.user, get_course_discussion_settings(course.id)) @@ -603,13 +603,13 @@ def get_thread_list( query_params[view] = "true" else: ValidationError({ - "view": [u"Invalid value. '{}' must be 'unread' or 'unanswered'".format(view)] + "view": [f"Invalid value. '{view}' must be 'unread' or 'unanswered'"] }) if following: paginated_results = context["cc_requester"].subscribed_threads(query_params) else: - query_params["course_id"] = six.text_type(course.id) + query_params["course_id"] = str(course.id) query_params["commentable_ids"] = ",".join(topic_id_list) if topic_id_list else None query_params["text"] = text_search paginated_results = Thread.search(query_params) @@ -1046,7 +1046,7 @@ def get_thread(request, thread_id, requested_fields=None): thread_id, retrieve_kwargs={ "with_responses": True, - "user_id": six.text_type(request.user.id), + "user_id": str(request.user.id), } ) return _serialize_discussion_entities(request, context, [cc_thread], requested_fields, DiscussionEntity.thread)[0] diff --git a/lms/djangoapps/discussion/rest_api/forms.py b/lms/djangoapps/discussion/rest_api/forms.py index 8449ddf9a92..9b1f0fcc415 100644 --- a/lms/djangoapps/discussion/rest_api/forms.py +++ b/lms/djangoapps/discussion/rest_api/forms.py @@ -11,7 +11,6 @@ from django.forms import BooleanField, CharField, ChoiceField, Form, IntegerFiel from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from opaque_keys.edx.locator import CourseLocator -from six import text_type from lms.djangoapps.courseware.courses import get_course_with_access from openedx.core.djangoapps.django_comment_common.models import ( @@ -75,7 +74,7 @@ class ThreadListGetForm(_PaginationForm): try: return CourseLocator.from_string(value) except InvalidKeyError: - raise ValidationError(u"'{}' is not a valid course id".format(value)) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError(f"'{value}' is not a valid course id") # lint-amnesty, pylint: disable=raise-missing-from def clean_following(self): """Validate following""" @@ -86,13 +85,13 @@ class ThreadListGetForm(_PaginationForm): return value def clean(self): - cleaned_data = super(ThreadListGetForm, self).clean() # lint-amnesty, pylint: disable=super-with-arguments + cleaned_data = super().clean() exclusive_params_count = sum( 1 for param in self.EXCLUSIVE_PARAMS if cleaned_data.get(param) ) if exclusive_params_count > 1: raise ValidationError( - u"The following query parameters are mutually exclusive: {}".format( + "The following query parameters are mutually exclusive: {}".format( ", ".join(self.EXCLUSIVE_PARAMS) ) ) @@ -143,7 +142,7 @@ class CourseDiscussionSettingsForm(Form): def __init__(self, *args, **kwargs): self.request_user = kwargs.pop('request_user') - super(CourseDiscussionSettingsForm, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) def clean_course_id(self): """Validate the 'course_id' value""" @@ -154,7 +153,7 @@ class CourseDiscussionSettingsForm(Form): self.cleaned_data['course_key'] = course_key return course_id except InvalidKeyError: - raise ValidationError(u"'{}' is not a valid course key".format(text_type(course_id))) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError("'{}' is not a valid course key".format(str(course_id))) # lint-amnesty, pylint: disable=raise-missing-from class CourseDiscussionRolesForm(CourseDiscussionSettingsForm): @@ -168,7 +167,7 @@ class CourseDiscussionRolesForm(CourseDiscussionSettingsForm): ) rolename = ChoiceField( choices=ROLE_CHOICES, - error_messages={u"invalid_choice": u"Role '%(value)s' does not exist"} + error_messages={"invalid_choice": "Role '%(value)s' does not exist"} ) def clean_rolename(self): @@ -179,7 +178,7 @@ class CourseDiscussionRolesForm(CourseDiscussionSettingsForm): try: role = Role.objects.get(name=rolename, course_id=course_id) except Role.DoesNotExist: - raise ValidationError(u"Role '{}' does not exist".format(rolename)) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError(f"Role '{rolename}' does not exist") # lint-amnesty, pylint: disable=raise-missing-from self.cleaned_data['role'] = role return rolename diff --git a/lms/djangoapps/discussion/rest_api/pagination.py b/lms/djangoapps/discussion/rest_api/pagination.py index 9c66d15f298..244d9b96a12 100644 --- a/lms/djangoapps/discussion/rest_api/pagination.py +++ b/lms/djangoapps/discussion/rest_api/pagination.py @@ -7,7 +7,7 @@ from edx_rest_framework_extensions.paginators import NamespacedPageNumberPaginat from rest_framework.utils.urls import replace_query_param -class _Page(object): +class _Page: """ Implements just enough of the django.core.paginator.Page interface to allow PaginationSerializer to work. @@ -51,7 +51,7 @@ class DiscussionAPIPagination(NamespacedPageNumberPagination): self.base_url = request.build_absolute_uri() self.count = result_count - super(DiscussionAPIPagination, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments + super().__init__() def get_result_count(self): """ diff --git a/lms/djangoapps/discussion/rest_api/serializers.py b/lms/djangoapps/discussion/rest_api/serializers.py index 3f6012b549c..05bc75a64f7 100644 --- a/lms/djangoapps/discussion/rest_api/serializers.py +++ b/lms/djangoapps/discussion/rest_api/serializers.py @@ -9,6 +9,7 @@ from django.urls import reverse from rest_framework import serializers from six.moves.urllib.parse import urlencode, urlunparse +from common.djangoapps.student.models import get_user_by_username_or_email from lms.djangoapps.discussion.django_comment_client.utils import ( course_discussion_division_enabled, get_group_id_for_user, @@ -34,7 +35,6 @@ from openedx.core.djangoapps.django_comment_common.models import ( Role ) from openedx.core.djangoapps.django_comment_common.utils import get_course_discussion_settings -from common.djangoapps.student.models import get_user_by_username_or_email def get_context(course, request, thread=None): @@ -103,10 +103,10 @@ class _ContentSerializer(serializers.Serializer): non_updatable_fields = set() def __init__(self, *args, **kwargs): - super(_ContentSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) for field in self.non_updatable_fields: - setattr(self, "validate_{}".format(field), self._validate_non_updatable) + setattr(self, f"validate_{field}", self._validate_non_updatable) def _validate_non_updatable(self, value): """Ensure that a field is not edited in an update operation.""" @@ -223,7 +223,7 @@ class ThreadSerializer(_ContentSerializer): non_updatable_fields = NON_UPDATABLE_THREAD_FIELDS def __init__(self, *args, **kwargs): - super(ThreadSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) # Compensate for the fact that some threads in the comments service do # not have the pinned field set if self.instance and self.instance.get("pinned") is None: @@ -329,7 +329,7 @@ class CommentSerializer(_ContentSerializer): def __init__(self, *args, **kwargs): remove_fields = kwargs.pop('remove_fields', None) - super(CommentSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) if remove_fields: # for multiple fields in a list @@ -379,7 +379,7 @@ class CommentSerializer(_ContentSerializer): def to_representation(self, data): # pylint: disable=arguments-differ - data = super(CommentSerializer, self).to_representation(data) # lint-amnesty, pylint: disable=super-with-arguments + data = super().to_representation(data) # Django Rest Framework v3 no longer includes None values # in the representation. To maintain the previous behavior, @@ -478,7 +478,7 @@ class DiscussionSettingsSerializer(serializers.Serializer): def __init__(self, *args, **kwargs): self.course = kwargs.pop('course') self.discussion_settings = kwargs.pop('discussion_settings') - super(DiscussionSettingsSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) def validate(self, attrs): """ @@ -532,7 +532,7 @@ class DiscussionRolesSerializer(serializers.Serializer): user_id = serializers.CharField() def __init__(self, *args, **kwargs): - super(DiscussionRolesSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) self.user = None def validate_user_id(self, user_id): # lint-amnesty, pylint: disable=missing-function-docstring @@ -540,7 +540,7 @@ class DiscussionRolesSerializer(serializers.Serializer): self.user = get_user_by_username_or_email(user_id) return user_id except DjangoUser.DoesNotExist: - raise ValidationError(u"'{}' is not a valid student identifier".format(user_id)) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError(f"'{user_id}' is not a valid student identifier") # lint-amnesty, pylint: disable=raise-missing-from def validate(self, attrs): """Validate the data at an object level.""" @@ -574,7 +574,7 @@ class DiscussionRolesMemberSerializer(serializers.Serializer): group_name = serializers.SerializerMethodField() def __init__(self, *args, **kwargs): - super(DiscussionRolesMemberSerializer, self).__init__(*args, **kwargs) # lint-amnesty, pylint: disable=super-with-arguments + super().__init__(*args, **kwargs) self.course_discussion_settings = self.context['course_discussion_settings'] def get_group_name(self, instance): diff --git a/lms/djangoapps/discussion/rest_api/tests/test_api.py b/lms/djangoapps/discussion/rest_api/tests/test_api.py index 92655445a47..be4dbf762a5 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_api.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_api.py @@ -5,19 +5,20 @@ Tests for Discussion API internal interface import itertools from datetime import datetime, timedelta -import pytest +from unittest import mock + import ddt import httpretty -import mock -import six +import pytest from django.core.exceptions import ValidationError from django.test.client import RequestFactory from opaque_keys.edx.locator import CourseLocator from pytz import UTC from rest_framework.exceptions import PermissionDenied -from six.moves import range from six.moves.urllib.parse import parse_qs, urlencode, urlparse, urlunparse +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from common.djangoapps.util.testing import UrlResetMixin from common.test.utils import MockSignalHandlerMixin, disable_signal from lms.djangoapps.courseware.tests.factories import BetaTesterFactory, StaffFactory from lms.djangoapps.discussion.django_comment_client.tests.utils import ForumsEnableMixin @@ -57,8 +58,6 @@ from openedx.core.djangoapps.django_comment_common.models import ( Role ) from openedx.core.lib.exceptions import CourseNotFoundError, PageNotFoundError -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from common.djangoapps.util.testing import UrlResetMixin from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase @@ -141,12 +140,12 @@ class GetCourseTest(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase) @classmethod def setUpClass(cls): - super(GetCourseTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create(org="x", course="y", run="z") @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(GetCourseTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.user = UserFactory.create() CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) self.request = RequestFactory().get("/dummy") @@ -168,7 +167,7 @@ class GetCourseTest(ForumsEnableMixin, UrlResetMixin, SharedModuleStoreTestCase) def test_basic(self): assert get_course(self.request, self.course.id) == { - 'id': six.text_type(self.course.id), + 'id': str(self.course.id), 'blackouts': [], 'thread_list_url': 'http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz', 'following_thread_list_url': @@ -186,7 +185,7 @@ class GetCourseTestBlackouts(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCa @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(GetCourseTestBlackouts, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create(org="x", course="y", run="z") self.user = UserFactory.create() CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) @@ -223,7 +222,7 @@ class GetCourseTopicsTest(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) """Test for get_course_topics""" @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(GetCourseTopicsTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.maxDiff = None # pylint: disable=invalid-name self.partition = UserPartition( 0, @@ -266,7 +265,7 @@ class GetCourseTopicsTest(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) """ path = "http://testserver/api/discussion/v1/threads/" topic_ids_to_query = [("topic_id", topic_id) for topic_id in topic_id_list] - query_list = [("course_id", six.text_type(self.course.id))] + topic_ids_to_query + query_list = [("course_id", str(self.course.id))] + topic_ids_to_query return urlunparse(("", "", path, "", urlencode(query_list), "")) def get_course_topics(self): @@ -592,12 +591,12 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix @classmethod def setUpClass(cls): - super(GetThreadListTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(GetThreadListTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -662,8 +661,8 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix self.get_thread_list([], topic_id_list=["topic_x", "topic_meow"]) assert urlparse(httpretty.last_request().path).path == '/api/v1/threads' # lint-amnesty, pylint: disable=no-member self.assert_last_query_params({ - "user_id": [six.text_type(self.user.id)], - "course_id": [six.text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["1"], @@ -673,8 +672,8 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix def test_basic_query_params(self): self.get_thread_list([], page=6, page_size=14) self.assert_last_query_params({ - "user_id": [six.text_type(self.user.id)], - "course_id": [six.text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["6"], "per_page": ["14"], @@ -686,7 +685,7 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix source_threads = [ make_minimal_cs_thread({ "id": "test_thread_id_0", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "topic_x", "username": self.author.username, "user_id": str(self.author.id), @@ -702,7 +701,7 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix }), make_minimal_cs_thread({ "id": "test_thread_id_1", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "topic_y", "group_id": self.cohort.id, "username": self.author.username, @@ -828,8 +827,8 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix text_search='test search string' ).data == expected_result self.assert_last_query_params({ - "user_id": [six.text_type(self.user.id)], - "course_id": [six.text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["10"], @@ -853,10 +852,10 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix assert result == expected_result assert urlparse( httpretty.last_request().path # lint-amnesty, pylint: disable=no-member - ).path == '/api/v1/users/{}/subscribed_threads'.format(self.user.id) + ).path == f"/api/v1/users/{self.user.id}/subscribed_threads" self.assert_last_query_params({ - "user_id": [six.text_type(self.user.id)], - "course_id": [six.text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["11"], @@ -880,8 +879,8 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix assert result == expected_result assert urlparse(httpretty.last_request().path).path == '/api/v1/threads' # lint-amnesty, pylint: disable=no-member self.assert_last_query_params({ - "user_id": [six.text_type(self.user.id)], - "course_id": [six.text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["11"], @@ -918,8 +917,8 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix assert result == expected_result assert urlparse(httpretty.last_request().path).path == '/api/v1/threads' # lint-amnesty, pylint: disable=no-member self.assert_last_query_params({ - "user_id": [six.text_type(self.user.id)], - "course_id": [six.text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": [cc_query], "page": ["1"], "per_page": ["11"], @@ -946,8 +945,8 @@ class GetThreadListTest(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetMix assert result == expected_result assert urlparse(httpretty.last_request().path).path == '/api/v1/threads' # lint-amnesty, pylint: disable=no-member self.assert_last_query_params({ - "user_id": [six.text_type(self.user.id)], - "course_id": [six.text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["11"], @@ -976,12 +975,12 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu @classmethod def setUpClass(cls): - super(GetCommentListTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(GetCommentListTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -1000,7 +999,7 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu already in overrides. """ overrides = overrides.copy() if overrides else {} - overrides.setdefault("course_id", six.text_type(self.course.id)) + overrides.setdefault("course_id", str(self.course.id)) return make_minimal_cs_thread(overrides) def get_comment_list(self, thread, endorsed=None, page=1, page_size=1): @@ -1031,7 +1030,7 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu with pytest.raises(DiscussionDisabledError): self.get_comment_list( self.make_minimal_cs_thread( - overrides={"course_id": six.text_type(disabled_course.id)} + overrides={"course_id": str(disabled_course.id)} ) ) @@ -1067,7 +1066,7 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu cohort = CohortFactory.create(course_id=cohort_course.id, users=[self.user]) _assign_role_to_user(user=self.user, course_id=cohort_course.id, role=role_name) thread = self.make_minimal_cs_thread({ - "course_id": six.text_type(cohort_course.id), + "course_id": str(cohort_course.id), "commentable_id": "test_topic", "group_id": ( None if thread_group_state == "no_group" else @@ -1319,7 +1318,7 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu thread = self.make_minimal_cs_thread({ "thread_type": "question", "endorsed_responses": [make_minimal_cs_comment({ - "id": "comment_{}".format(i), + "id": f"comment_{i}", "username": self.user.username }) for i in range(10)] }) @@ -1331,12 +1330,12 @@ class GetCommentListTest(ForumsEnableMixin, CommentsServiceMockMixin, SharedModu """ actual = self.get_comment_list(thread, endorsed=True, page=page, page_size=page_size).data result_ids = [result["id"] for result in actual["results"]] - assert result_ids == ['comment_{}'.format(i) for i in range(expected_start, expected_stop)] + assert result_ids == [f"comment_{i}" for i in range(expected_start, expected_stop)] assert actual['pagination']['next'] == ( - 'http://testserver/test_path?page={}'.format(expected_next) if expected_next else None + f"http://testserver/test_path?page={expected_next}" if expected_next else None ) assert actual['pagination']['previous'] == ( - 'http://testserver/test_path?page={}'.format(expected_prev) if expected_prev else None + f"http://testserver/test_path?page={expected_prev}" if expected_prev else None ) # Only page @@ -1437,7 +1436,7 @@ class CreateThreadTest( @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(CreateThreadTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() httpretty.reset() httpretty.enable() @@ -1449,7 +1448,7 @@ class CreateThreadTest( self.request.user = self.user CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id) self.minimal_data = { - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "topic_id": "test_topic", "type": "discussion", "title": "Test Title", @@ -1468,13 +1467,13 @@ class CreateThreadTest( actual = create_thread(self.request, self.minimal_data) expected = self.expected_thread_data({ "id": "test_id", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_id", "read": True, }) assert actual == expected assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], 'title': ['Test Title'], @@ -1532,7 +1531,7 @@ class CreateThreadTest( expected = self.expected_thread_data({ "author_label": "Staff", "id": "test_id", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "comment_list_url": "http://testserver/api/discussion/v1/comments/?thread_id=test_id", "read": True, }) @@ -1540,7 +1539,7 @@ class CreateThreadTest( self.assertEqual( httpretty.last_request().parsed_body, # lint-amnesty, pylint: disable=no-member { - "course_id": [six.text_type(self.course.id)], + "course_id": [str(self.course.id)], "commentable_id": ["test_topic"], "thread_type": ["discussion"], "title": ["Test Title"], @@ -1639,7 +1638,7 @@ class CreateThreadTest( _assign_role_to_user(user=self.user, course_id=cohort_course.id, role=role_name) self.register_post_thread_response({"username": self.user.username}) data = self.minimal_data.copy() - data["course_id"] = six.text_type(cohort_course.id) + data["course_id"] = str(cohort_course.id) if data_group_state == "group_is_none": data["group_id"] = None elif data_group_state == "group_is_set": @@ -1663,7 +1662,7 @@ class CreateThreadTest( assert 'group_id' not in actual_post_data except ValidationError as ex: if not expected_error: - self.fail(u"Unexpected validation error: {}".format(ex)) + self.fail(f"Unexpected validation error: {ex}") def test_following(self): self.register_post_thread_response({"id": "test_id", "username": self.user.username}) @@ -1673,7 +1672,7 @@ class CreateThreadTest( result = create_thread(self.request, data) assert result['following'] is True cs_request = httpretty.last_request() - assert urlparse(cs_request.path).path == '/api/v1/users/{}/subscriptions'.format(self.user.id) # lint-amnesty, pylint: disable=no-member + assert urlparse(cs_request.path).path == f"/api/v1/users/{self.user.id}/subscriptions" # lint-amnesty, pylint: disable=no-member assert cs_request.method == 'POST' assert cs_request.parsed_body == {'source_type': ['thread'], 'source_id': ['test_id']} # lint-amnesty, pylint: disable=no-member @@ -1723,7 +1722,7 @@ class CreateThreadTest( def test_discussions_disabled(self): disabled_course = _discussion_disabled_course_for(self.user) - self.minimal_data["course_id"] = six.text_type(disabled_course.id) + self.minimal_data["course_id"] = str(disabled_course.id) with pytest.raises(DiscussionDisabledError): create_thread(self.request, self.minimal_data) @@ -1746,10 +1745,14 @@ class CreateCommentTest( MockSignalHandlerMixin ): """Tests for create_comment""" + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(CreateCommentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.course = CourseFactory.create() @@ -1763,7 +1766,7 @@ class CreateCommentTest( self.register_get_thread_response( make_minimal_cs_thread({ "id": "test_thread", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "test_topic", }) ) @@ -1815,12 +1818,12 @@ class CreateCommentTest( } assert actual == expected expected_url = ( - "/api/v1/comments/{}".format(parent_id) if parent_id else + f"/api/v1/comments/{parent_id}" if parent_id else "/api/v1/threads/test_thread/comments" ) assert urlparse(httpretty.last_request().path).path == expected_url # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)] } @@ -1905,7 +1908,7 @@ class CreateCommentTest( self.assertEqual( httpretty.last_request().parsed_body, # lint-amnesty, pylint: disable=no-member { - "course_id": [six.text_type(self.course.id)], + "course_id": [str(self.course.id)], "body": ["Test body"], "user_id": [str(self.user.id)] } @@ -1960,7 +1963,7 @@ class CreateCommentTest( self.register_get_thread_response( make_minimal_cs_thread({ "id": "test_thread", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "thread_type": thread_type, "user_id": str(self.user.id) if is_thread_author else str(self.user.id + 1), }) @@ -2031,7 +2034,7 @@ class CreateCommentTest( self.register_get_thread_response( make_minimal_cs_thread({ "id": "test_thread", - "course_id": six.text_type(disabled_course.id), + "course_id": str(disabled_course.id), "commentable_id": "test_topic", }) ) @@ -2055,7 +2058,7 @@ class CreateCommentTest( cohort_course, cohort = _create_course_and_cohort_with_user_role(course_is_cohorted, self.user, role_name) self.register_get_thread_response(make_minimal_cs_thread({ "id": "cohort_thread", - "course_id": six.text_type(cohort_course.id), + "course_id": str(cohort_course.id), "group_id": ( None if thread_group_state == "no_group" else cohort.id if thread_group_state == "match_group" else @@ -2097,12 +2100,12 @@ class UpdateThreadTest( """Tests for update_thread""" @classmethod def setUpClass(cls): - super(UpdateThreadTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(UpdateThreadTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -2122,7 +2125,7 @@ class UpdateThreadTest( """ cs_data = make_minimal_cs_thread({ "id": "test_thread", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "original_topic", "username": self.user.username, "user_id": str(self.user.id), @@ -2156,7 +2159,7 @@ class UpdateThreadTest( 'title': 'Original Title' }) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['original_topic'], 'thread_type': ['discussion'], 'title': ['Original Title'], @@ -2187,7 +2190,7 @@ class UpdateThreadTest( def test_discussions_disabled(self): disabled_course = _discussion_disabled_course_for(self.user) - self.register_thread(overrides={"course_id": six.text_type(disabled_course.id)}) + self.register_thread(overrides={"course_id": str(disabled_course.id)}) with pytest.raises(DiscussionDisabledError): update_thread(self.request, "test_thread", {}) @@ -2207,7 +2210,7 @@ class UpdateThreadTest( def test_group_access(self, role_name, course_is_cohorted, thread_group_state): cohort_course, cohort = _create_course_and_cohort_with_user_role(course_is_cohorted, self.user, role_name) self.register_thread({ - "course_id": six.text_type(cohort_course.id), + "course_id": str(cohort_course.id), "group_id": ( None if thread_group_state == "no_group" else cohort.id if thread_group_state == "match_group" else @@ -2264,7 +2267,7 @@ class UpdateThreadTest( result = update_thread(self.request, "test_thread", data) assert result['following'] == new_following last_request_path = urlparse(httpretty.last_request().path).path # lint-amnesty, pylint: disable=no-member - subscription_url = "/api/v1/users/{}/subscriptions".format(self.user.id) + subscription_url = f"/api/v1/users/{self.user.id}/subscriptions" if old_following == new_following: assert last_request_path != subscription_url else: @@ -2450,12 +2453,12 @@ class UpdateCommentTest( @classmethod def setUpClass(cls): - super(UpdateCommentTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(UpdateCommentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() @@ -2479,7 +2482,7 @@ class UpdateCommentTest( cs_thread_data = make_minimal_cs_thread({ "id": "test_thread", - "course_id": six.text_type(course.id) + "course_id": str(course.id) }) cs_thread_data.update(thread_overrides or {}) self.register_get_thread_response(cs_thread_data) @@ -2533,7 +2536,7 @@ class UpdateCommentTest( assert actual == expected assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member 'body': ['Edited body'], - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], 'anonymous': ['False'], 'anonymous_to_peers': ['False'], @@ -2581,7 +2584,7 @@ class UpdateCommentTest( {"thread_id": "test_thread"}, thread_overrides={ "id": "test_thread", - "course_id": six.text_type(cohort_course.id), + "course_id": str(cohort_course.id), "group_id": ( None if thread_group_state == "no_group" else cohort.id if thread_group_state == "match_group" else @@ -2827,12 +2830,12 @@ class DeleteThreadTest( """Tests for delete_thread""" @classmethod def setUpClass(cls): - super(DeleteThreadTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(DeleteThreadTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -2852,7 +2855,7 @@ class DeleteThreadTest( """ cs_data = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "user_id": str(self.user.id), }) cs_data.update(overrides or {}) @@ -2863,7 +2866,7 @@ class DeleteThreadTest( self.register_thread() with self.assert_signal_sent(api, 'thread_deleted', sender=None, user=self.user, exclude_args=('post',)): assert delete_thread(self.request, self.thread_id) is None - assert urlparse(httpretty.last_request().path).path == '/api/v1/threads/{}'.format(self.thread_id) # lint-amnesty, pylint: disable=no-member + assert urlparse(httpretty.last_request().path).path == f"/api/v1/threads/{self.thread_id}" # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().method == 'DELETE' def test_thread_id_not_found(self): @@ -2884,7 +2887,7 @@ class DeleteThreadTest( def test_discussions_disabled(self): disabled_course = _discussion_disabled_course_for(self.user) - self.register_thread(overrides={"course_id": six.text_type(disabled_course.id)}) + self.register_thread(overrides={"course_id": str(disabled_course.id)}) with pytest.raises(DiscussionDisabledError): delete_thread(self.request, self.thread_id) @@ -2928,7 +2931,7 @@ class DeleteThreadTest( """ cohort_course, cohort = _create_course_and_cohort_with_user_role(course_is_cohorted, self.user, role_name) self.register_thread({ - "course_id": six.text_type(cohort_course.id), + "course_id": str(cohort_course.id), "group_id": ( None if thread_group_state == "no_group" else cohort.id if thread_group_state == "match_group" else @@ -2960,12 +2963,12 @@ class DeleteCommentTest( """Tests for delete_comment""" @classmethod def setUpClass(cls): - super(DeleteCommentTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(DeleteCommentTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -2986,7 +2989,7 @@ class DeleteCommentTest( """ cs_thread_data = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": six.text_type(self.course.id) + "course_id": str(self.course.id) }) cs_thread_data.update(thread_overrides or {}) self.register_get_thread_response(cs_thread_data) @@ -3005,7 +3008,7 @@ class DeleteCommentTest( self.register_comment_and_thread() with self.assert_signal_sent(api, 'comment_deleted', sender=None, user=self.user, exclude_args=('post',)): assert delete_comment(self.request, self.comment_id) is None - assert urlparse(httpretty.last_request().path).path == '/api/v1/comments/{}'.format(self.comment_id) # lint-amnesty, pylint: disable=no-member + assert urlparse(httpretty.last_request().path).path == f"/api/v1/comments/{self.comment_id}" # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().method == 'DELETE' def test_comment_id_not_found(self): @@ -3029,8 +3032,8 @@ class DeleteCommentTest( def test_discussions_disabled(self): disabled_course = _discussion_disabled_course_for(self.user) self.register_comment_and_thread( - thread_overrides={"course_id": six.text_type(disabled_course.id)}, - overrides={"course_id": six.text_type(disabled_course.id)} + thread_overrides={"course_id": str(disabled_course.id)}, + overrides={"course_id": str(disabled_course.id)} ) with pytest.raises(DiscussionDisabledError): delete_comment(self.request, self.comment_id) @@ -3079,7 +3082,7 @@ class DeleteCommentTest( self.register_comment_and_thread( overrides={"thread_id": "test_thread"}, thread_overrides={ - "course_id": six.text_type(cohort_course.id), + "course_id": str(cohort_course.id), "group_id": ( None if thread_group_state == "no_group" else cohort.id if thread_group_state == "match_group" else @@ -3110,12 +3113,12 @@ class RetrieveThreadTest( """Tests for get_thread""" @classmethod def setUpClass(cls): - super(RetrieveThreadTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(RetrieveThreadTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -3135,7 +3138,7 @@ class RetrieveThreadTest( """ cs_data = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "test_topic", "username": self.user.username, "user_id": str(self.user.id), @@ -3202,7 +3205,7 @@ class RetrieveThreadTest( """ cohort_course, cohort = _create_course_and_cohort_with_user_role(course_is_cohorted, self.user, role_name) self.register_thread({ - "course_id": six.text_type(cohort_course.id), + "course_id": str(cohort_course.id), "group_id": ( None if thread_group_state == "no_group" else cohort.id if thread_group_state == "match_group" else diff --git a/lms/djangoapps/discussion/rest_api/tests/test_forms.py b/lms/djangoapps/discussion/rest_api/tests/test_forms.py index d792767c4f6..0443a19c3cb 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_forms.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_forms.py @@ -15,7 +15,7 @@ from lms.djangoapps.discussion.rest_api.forms import CommentListGetForm, ThreadL from openedx.core.djangoapps.util.test_forms import FormTestMixin -class PaginationTestMixin(object): +class PaginationTestMixin: """A mixin for testing forms with pagination fields""" def test_missing_page(self): @@ -45,7 +45,7 @@ class ThreadListGetFormTest(FormTestMixin, PaginationTestMixin, TestCase): FORM_CLASS = ThreadListGetForm def setUp(self): - super(ThreadListGetFormTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.form_data = QueryDict( urlencode( { @@ -159,7 +159,7 @@ class CommentListGetFormTest(FormTestMixin, PaginationTestMixin, TestCase): FORM_CLASS = CommentListGetForm def setUp(self): - super(CommentListGetFormTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.form_data = { "thread_id": "deadbeef", "endorsed": "False", diff --git a/lms/djangoapps/discussion/rest_api/tests/test_render.py b/lms/djangoapps/discussion/rest_api/tests/test_render.py index 9394727e218..e5fe26a3dd5 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_render.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_render.py @@ -12,7 +12,7 @@ from lms.djangoapps.discussion.rest_api.render import render_body def _add_p_tags(raw_body): """Return raw_body surrounded by p tags""" - return "<p>{raw_body}</p>".format(raw_body=raw_body) + return f"<p>{raw_body}</p>" @ddt.ddt @@ -29,8 +29,8 @@ class RenderBodyTest(TestCase): ) @ddt.unpack def test_markdown_inline(self, delimiter, tag): - assert render_body(u'{delimiter}some text{delimiter}'.format(delimiter=delimiter)) == \ - u'<p><{tag}>some text</{tag}></p>'.format(tag=tag) + assert render_body('{delimiter}some text{delimiter}'.format(delimiter=delimiter)) == \ + '<p><{tag}>some text</{tag}></p>'.format(tag=tag) @ddt.data( "b", "blockquote", "code", "del", "dd", "dl", "dt", "em", "h1", "h2", "h3", "i", "kbd", @@ -44,14 +44,14 @@ class RenderBodyTest(TestCase): @ddt.data("br", "hr") def test_selfclosing_tag(self, tag): - raw_body = "<{tag}>".format(tag=tag) + raw_body = f"<{tag}>" is_inline_tag = tag == "br" rendered_body = _add_p_tags(raw_body) if is_inline_tag else raw_body assert render_body(raw_body) == rendered_body @ddt.data("http", "https", "ftp") def test_allowed_a_tag(self, protocol): - raw_body = '<a href="{protocol}://foo" title="bar">baz</a>'.format(protocol=protocol) + raw_body = f'<a href="{protocol}://foo" title="bar">baz</a>' assert render_body(raw_body) == _add_p_tags(raw_body) def test_disallowed_a_tag(self): @@ -75,7 +75,7 @@ class RenderBodyTest(TestCase): @ddt.data("p", "br", "li", "hr") # img is tested above def test_allowed_unpaired_tags(self, tag): - raw_body = "foo<{tag}>bar".format(tag=tag) + raw_body = f"foo<{tag}>bar" assert render_body(raw_body) == _add_p_tags(raw_body) def test_unpaired_start_tag(self): diff --git a/lms/djangoapps/discussion/rest_api/tests/test_serializers.py b/lms/djangoapps/discussion/rest_api/tests/test_serializers.py index b833d1dbed1..6e1d3e71655 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_serializers.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_serializers.py @@ -4,14 +4,15 @@ Tests for Discussion API serializers import itertools +from unittest import mock import ddt import httpretty -import mock -import six from django.test.client import RequestFactory from six.moves.urllib.parse import urlparse +from common.djangoapps.student.tests.factories import UserFactory +from common.djangoapps.util.testing import UrlResetMixin from lms.djangoapps.discussion.django_comment_client.tests.utils import ForumsEnableMixin from lms.djangoapps.discussion.rest_api.serializers import CommentSerializer, ThreadSerializer, get_context from lms.djangoapps.discussion.rest_api.tests.utils import ( @@ -29,8 +30,6 @@ from openedx.core.djangoapps.django_comment_common.models import ( FORUM_ROLE_STUDENT, Role ) -from common.djangoapps.student.tests.factories import UserFactory -from common.djangoapps.util.testing import UrlResetMixin from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase @@ -45,12 +44,12 @@ class SerializerTestMixin(ForumsEnableMixin, CommentsServiceMockMixin, UrlResetM @classmethod @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUpClass(cls): - super(SerializerTestMixin, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(SerializerTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -149,7 +148,7 @@ class ThreadSerializerSerializationTest(SerializerTestMixin, SharedModuleStoreTe Create a thread with the given overrides, plus some useful test data. """ merged_overrides = { - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "user_id": str(self.author.id), "username": self.author.username, "read": True, @@ -169,7 +168,7 @@ class ThreadSerializerSerializationTest(SerializerTestMixin, SharedModuleStoreTe def test_basic(self): thread = make_minimal_cs_thread({ "id": "test_thread", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "test_topic", "user_id": str(self.author.id), "username": self.author.username, @@ -246,7 +245,7 @@ class ThreadSerializerSerializationTest(SerializerTestMixin, SharedModuleStoreTe class CommentSerializerTest(SerializerTestMixin, SharedModuleStoreTestCase): """Tests for CommentSerializer.""" def setUp(self): - super(CommentSerializerTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.endorser = UserFactory.create() self.endorsed_at = "2015-05-18T12:34:56Z" @@ -412,12 +411,12 @@ class ThreadSerializerDeserializationTest( @classmethod @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUpClass(cls): - super(ThreadSerializerDeserializationTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(ThreadSerializerDeserializationTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -427,7 +426,7 @@ class ThreadSerializerDeserializationTest( self.request = RequestFactory().get("/dummy") self.request.user = self.user self.minimal_data = { - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "topic_id": "test_topic", "type": "discussion", "title": "Test Title", @@ -435,7 +434,7 @@ class ThreadSerializerDeserializationTest( } self.existing_thread = Thread(**make_minimal_cs_thread({ "id": "existing_thread", - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "original_topic", "thread_type": "discussion", "title": "Original Title", @@ -468,7 +467,7 @@ class ThreadSerializerDeserializationTest( assert urlparse(httpretty.last_request().path).path ==\ '/api/v1/test_topic/threads' # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], 'title': ['Test Title'], @@ -483,7 +482,7 @@ class ThreadSerializerDeserializationTest( data["group_id"] = 42 self.save_and_reserialize(data) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], 'title': ['Test Title'], @@ -524,7 +523,7 @@ class ThreadSerializerDeserializationTest( self.register_put_thread_response(self.existing_thread.attributes) self.save_and_reserialize({}, self.existing_thread) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['original_topic'], 'thread_type': ['discussion'], 'title': ['Original Title'], @@ -549,7 +548,7 @@ class ThreadSerializerDeserializationTest( } saved = self.save_and_reserialize(data, self.existing_thread) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['edited_topic'], 'thread_type': ['question'], 'title': ['Edited Title'], @@ -593,11 +592,11 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc """Tests for ThreadSerializer deserialization.""" @classmethod def setUpClass(cls): - super(CommentSerializerDeserializationTest, cls).setUpClass() + super().setUpClass() cls.course = CourseFactory.create() def setUp(self): - super(CommentSerializerDeserializationTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -616,7 +615,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc "body": "Original body", "user_id": str(self.user.id), "username": self.user.username, - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), })) def save_and_reserialize(self, data, instance=None): @@ -627,7 +626,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc context = get_context( self.course, self.request, - make_minimal_cs_thread({"course_id": six.text_type(self.course.id)}) + make_minimal_cs_thread({"course_id": str(self.course.id)}) ) serializer = CommentSerializer( instance, @@ -652,12 +651,12 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc ) saved = self.save_and_reserialize(data) expected_url = ( - "/api/v1/comments/{}".format(parent_id) if parent_id else + f"/api/v1/comments/{parent_id}" if parent_id else "/api/v1/threads/test_thread/comments" ) assert urlparse(httpretty.last_request().path).path == expected_url # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)] } @@ -676,7 +675,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc ) self.save_and_reserialize(data) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)], 'endorsed': ['True'] @@ -754,7 +753,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc data["endorsed"] = True saved = self.save_and_reserialize(data) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)], 'endorsed': ['True'] @@ -769,7 +768,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc self.save_and_reserialize({}, instance=self.existing_comment) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member 'body': ['Original body'], - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], 'anonymous': ['False'], 'anonymous_to_peers': ['False'], @@ -787,7 +786,7 @@ class CommentSerializerDeserializationTest(ForumsEnableMixin, CommentsServiceMoc saved = self.save_and_reserialize(data, instance=self.existing_comment) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member 'body': ['Edited body'], - 'course_id': [six.text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], 'anonymous': ['False'], 'anonymous_to_peers': ['False'], diff --git a/lms/djangoapps/discussion/rest_api/tests/test_views.py b/lms/djangoapps/discussion/rest_api/tests/test_views.py index 54aed38e996..704a9b5ad91 100644 --- a/lms/djangoapps/discussion/rest_api/tests/test_views.py +++ b/lms/djangoapps/discussion/rest_api/tests/test_views.py @@ -5,22 +5,23 @@ Tests for Discussion API views import json from datetime import datetime +from unittest import mock import ddt import httpretty -import mock from django.urls import reverse from opaque_keys.edx.keys import CourseKey from pytz import UTC from rest_framework.parsers import JSONParser from rest_framework.test import APIClient, APITestCase -from six import text_type -from six.moves import range from six.moves.urllib.parse import urlparse -from common.test.utils import disable_signal from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.models import get_retired_username_by_username +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, SuperuserFactory, UserFactory +from common.djangoapps.util.testing import PatchMediaTypeMixin, UrlResetMixin +from common.test.utils import disable_signal from lms.djangoapps.discussion.django_comment_client.tests.utils import ( ForumsEnableMixin, config_course_discussions, @@ -38,12 +39,9 @@ from openedx.core.djangoapps.course_groups.tests.helpers import config_course_co from openedx.core.djangoapps.django_comment_common.models import CourseDiscussionSettings, Role from openedx.core.djangoapps.django_comment_common.utils import seed_permissions_roles from openedx.core.djangoapps.oauth_dispatch.jwt import create_jwt_for_user -from openedx.core.djangoapps.oauth_dispatch.tests.factories import ApplicationFactory, AccessTokenFactory +from openedx.core.djangoapps.oauth_dispatch.tests.factories import AccessTokenFactory, ApplicationFactory from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_image_storage from openedx.core.djangoapps.user_api.models import RetirementState, UserRetirementStatus -from common.djangoapps.student.models import get_retired_username_by_username -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, SuperuserFactory, UserFactory -from common.djangoapps.util.testing import PatchMediaTypeMixin, UrlResetMixin from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase @@ -61,7 +59,7 @@ class DiscussionAPIViewTestMixin(ForumsEnableMixin, CommentsServiceMockMixin, Ur @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(DiscussionAPIViewTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.maxDiff = None # pylint: disable=invalid-name self.course = CourseFactory.create( org="x", @@ -92,7 +90,7 @@ class DiscussionAPIViewTestMixin(ForumsEnableMixin, CommentsServiceMockMixin, Ur """ cs_thread = make_minimal_cs_thread({ "id": "test_thread", - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "test_topic", "username": self.user.username, "user_id": str(self.user.id), @@ -110,7 +108,7 @@ class DiscussionAPIViewTestMixin(ForumsEnableMixin, CommentsServiceMockMixin, Ur """ cs_comment = make_minimal_cs_comment({ "id": "test_comment", - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "thread_id": "test_thread", "username": self.user.username, "user_id": str(self.user.id), @@ -139,8 +137,8 @@ class DiscussionAPIViewTestMixin(ForumsEnableMixin, CommentsServiceMockMixin, Ur class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for CourseView""" def setUp(self): - super(CourseViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments - self.url = reverse("discussion_course", kwargs={"course_id": text_type(self.course.id)}) + super().setUp() + self.url = reverse("discussion_course", kwargs={"course_id": str(self.course.id)}) def test_404(self): response = self.client.get( @@ -158,7 +156,7 @@ class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): response, 200, { - "id": text_type(self.course.id), + "id": str(self.course.id), "blackouts": [], "thread_list_url": "http://testserver/api/discussion/v1/threads/?course_id=x%2Fy%2Fz", "following_thread_list_url": ( @@ -174,7 +172,7 @@ class CourseViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): class RetireViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for CourseView""" def setUp(self): - super(RetireViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() RetirementState.objects.create(state_name='PENDING', state_execution_order=1) self.retire_forums_state = RetirementState.objects.create(state_name='RETIRE_FORUMS', state_execution_order=11) @@ -248,7 +246,7 @@ class RetireViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): class ReplaceUsernamesViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for ReplaceUsernamesView""" def setUp(self): - super(ReplaceUsernamesViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.client_user = UserFactory() self.client_user.username = "test_replace_username_service_worker" self.new_username = "test_username_replacement" @@ -261,7 +259,7 @@ class ReplaceUsernamesViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): assert response.status_code == expected_status if expected_content: - assert text_type(response.content) == expected_content + assert str(response.content) == expected_content def build_jwt_headers(self, user): """ @@ -342,8 +340,8 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): Tests for CourseTopicsView """ def setUp(self): - super(CourseTopicsViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments - self.url = reverse("course_topics", kwargs={"course_id": text_type(self.course.id)}) + super().setUp() + self.url = reverse("course_topics", kwargs={"course_id": str(self.course.id)}) def create_course(self, modules_count, module_store, topics): """ @@ -358,15 +356,15 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): discussion_topics=topics ) CourseEnrollmentFactory.create(user=self.user, course_id=course.id) - course_url = reverse("course_topics", kwargs={"course_id": text_type(course.id)}) + course_url = reverse("course_topics", kwargs={"course_id": str(course.id)}) # add some discussion xblocks for i in range(modules_count): ItemFactory.create( parent_location=course.location, category='discussion', - discussion_id='id_module_{}'.format(i), - discussion_category='Category {}'.format(i), - discussion_target='Discussion {}'.format(i), + discussion_id=f'id_module_{i}', + discussion_category=f'Category {i}', + discussion_target=f'Discussion {i}', publish_item=False, ) return course_url @@ -433,7 +431,7 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """ topic_id = "courseware-topic-id" self.make_discussion_xblock(topic_id, "test_category", "test_target") - url = "{}?topic_id=invalid_topic_id".format(self.url) + url = f"{self.url}?topic_id=invalid_topic_id" response = self.client.get(url) self.assert_response_correct( response, @@ -449,7 +447,7 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): topic_id_2 = "topic_id_2" self.make_discussion_xblock(topic_id_1, "test_category_1", "test_target_1") self.make_discussion_xblock(topic_id_2, "test_category_2", "test_target_2") - url = "{}?topic_id=topic_id_1,topic_id_2".format(self.url) + url = f"{self.url}?topic_id=topic_id_1,topic_id_2" response = self.client.get(url) self.assert_response_correct( response, @@ -495,7 +493,7 @@ class CourseTopicsViewTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, ProfileImageTestMixin): """Tests for ThreadViewSet list""" def setUp(self): - super(ThreadViewSetListTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.author = UserFactory.create() self.url = reverse("thread-list") @@ -505,7 +503,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro """ thread = make_minimal_cs_thread({ "id": "test_thread", - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "test_topic", "user_id": str(self.user.id), "username": self.user.username, @@ -530,7 +528,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro ) def test_404(self): - response = self.client.get(self.url, {"course_id": text_type("non/existent/course")}) + response = self.client.get(self.url, {"course_id": "non/existent/course"}) self.assert_response_correct( response, 404, @@ -553,7 +551,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro "editable_fields": ["abuse_flagged", "following", "read", "voted"], })] self.register_get_threads_response(source_threads, page=1, num_pages=2) - response = self.client.get(self.url, {"course_id": text_type(self.course.id), "following": ""}) + response = self.client.get(self.url, {"course_id": str(self.course.id), "following": ""}) expected_response = make_paginated_api_response( results=expected_threads, count=1, @@ -568,8 +566,8 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro expected_response ) self.assert_last_query_params({ - "user_id": [text_type(self.user.id)], - "course_id": [text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["10"], @@ -583,13 +581,13 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro self.client.get( self.url, { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "view": query, } ) self.assert_last_query_params({ - "user_id": [text_type(self.user.id)], - "course_id": [text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["10"], @@ -601,7 +599,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro self.register_get_threads_response([], page=1, num_pages=1) response = self.client.get( self.url, - {"course_id": text_type(self.course.id), "page": "18", "page_size": "4"} + {"course_id": str(self.course.id), "page": "18", "page_size": "4"} ) self.assert_response_correct( response, @@ -609,8 +607,8 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro {"developer_message": "Page not found (No results on this page)."} ) self.assert_last_query_params({ - "user_id": [text_type(self.user.id)], - "course_id": [text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["18"], "per_page": ["4"], @@ -621,7 +619,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro self.register_get_threads_search_response([], None, num_pages=0) response = self.client.get( self.url, - {"course_id": text_type(self.course.id), "text_search": "test search string"} + {"course_id": str(self.course.id), "text_search": "test search string"} ) expected_response = make_paginated_api_response( @@ -634,8 +632,8 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro expected_response ) self.assert_last_query_params({ - "user_id": [text_type(self.user.id)], - "course_id": [text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["10"], @@ -649,7 +647,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro response = self.client.get( self.url, { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "following": following, } ) @@ -665,14 +663,14 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro ) assert urlparse( httpretty.last_request().path # lint-amnesty, pylint: disable=no-member - ).path == '/api/v1/users/{}/subscribed_threads'.format(self.user.id) + ).path == f"/api/v1/users/{self.user.id}/subscribed_threads" @ddt.data(False, "false", "0") def test_following_false(self, following): response = self.client.get( self.url, { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "following": following, } ) @@ -688,7 +686,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro response = self.client.get( self.url, { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "following": "invalid-boolean", } ) @@ -720,13 +718,13 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro self.client.get( self.url, { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "order_by": http_query, } ) self.assert_last_query_params({ - "user_id": [text_type(self.user.id)], - "course_id": [text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "page": ["1"], "per_page": ["10"], "sort_key": [cc_query], @@ -743,13 +741,13 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro self.client.get( self.url, { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "order_direction": "desc", } ) self.assert_last_query_params({ - "user_id": [text_type(self.user.id)], - "course_id": [text_type(self.course.id)], + "user_id": [str(self.user.id)], + "course_id": [str(self.course.id)], "sort_key": ["activity"], "page": ["1"], "per_page": ["10"], @@ -762,7 +760,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro self.register_get_user_response(self.user) self.register_get_threads_search_response([], None, num_pages=0) response = self.client.get(self.url, { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "text_search": "test search string", "topic_id": "topic1, topic2", }) @@ -795,7 +793,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro response = self.client.get( self.url, - {"course_id": text_type(self.course.id), "requested_fields": "profile_image"}, + {"course_id": str(self.course.id), "requested_fields": "profile_image"}, ) assert response.status_code == 200 response_threads = json.loads(response.content.decode('utf-8'))['results'] @@ -820,7 +818,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro response = self.client.get( self.url, - {"course_id": text_type(self.course.id), "requested_fields": "profile_image"}, + {"course_id": str(self.course.id), "requested_fields": "profile_image"}, ) assert response.status_code == 200 response_thread = json.loads(response.content.decode('utf-8'))['results'][0] @@ -834,7 +832,7 @@ class ThreadViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pro class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for ThreadViewSet create""" def setUp(self): - super(ThreadViewSetCreateTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("thread-list") def test_basic(self): @@ -846,7 +844,7 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): }) self.register_post_thread_response(cs_thread) request_data = { - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "topic_id": "test_topic", "type": "discussion", "title": "Test Title", @@ -861,7 +859,7 @@ class ThreadViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): response_data = json.loads(response.content.decode('utf-8')) assert response_data == self.expected_thread_data({'read': True}) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], 'title': ['Test Title'], @@ -897,7 +895,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest """Tests for ThreadViewSet partial_update""" def setUp(self): self.unsupported_media_type = JSONParser.media_type - super(ThreadViewSetPartialUpdateTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"}) def test_basic(self): @@ -923,7 +921,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest 'response_count': 2 }) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'commentable_id': ['test_topic'], 'thread_type': ['discussion'], 'title': ['Test Title'], @@ -1030,7 +1028,7 @@ class ThreadViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTest class ThreadViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for ThreadViewSet delete""" def setUp(self): - super(ThreadViewSetDeleteTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"}) self.thread_id = "test_thread" @@ -1038,7 +1036,7 @@ class ThreadViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): self.register_get_user_response(self.user) cs_thread = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "username": self.user.username, "user_id": str(self.user.id), }) @@ -1047,7 +1045,7 @@ class ThreadViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): response = self.client.delete(self.url) assert response.status_code == 204 assert response.content == b'' - assert urlparse(httpretty.last_request().path).path == '/api/v1/threads/{}'.format(self.thread_id) # lint-amnesty, pylint: disable=no-member + assert urlparse(httpretty.last_request().path).path == f"/api/v1/threads/{self.thread_id}" # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().method == 'DELETE' def test_delete_nonexistent_thread(self): @@ -1062,7 +1060,7 @@ class ThreadViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, ProfileImageTestMixin): """Tests for CommentViewSet list""" def setUp(self): - super(CommentViewSetListTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.author = UserFactory.create() self.url = reverse("comment-list") self.thread_id = "test_thread" @@ -1092,7 +1090,7 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pr already in overrides. """ overrides = overrides.copy() if overrides else {} - overrides.setdefault("course_id", text_type(self.course.id)) + overrides.setdefault("course_id", str(self.course.id)) return make_minimal_cs_thread(overrides) def expected_response_comment(self, overrides=None): @@ -1155,7 +1153,7 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pr })] self.register_get_thread_response({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "thread_type": "discussion", "children": source_comments, "resp_total": 100, @@ -1192,7 +1190,7 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pr self.register_get_user_response(self.user) self.register_get_thread_response(make_minimal_cs_thread({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "thread_type": "discussion", "resp_total": 10, })) @@ -1301,7 +1299,7 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pr }) thread = self.make_minimal_cs_thread({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "thread_type": "discussion", "children": [response_1, response_2], "resp_total": 2, @@ -1336,7 +1334,7 @@ class CommentViewSetListTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, Pr source_comments = [self.create_source_comment()] self.register_get_thread_response({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "thread_type": "discussion", "children": source_comments, "resp_total": 100, @@ -1437,7 +1435,7 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for ThreadViewSet delete""" def setUp(self): - super(CommentViewSetDeleteTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"}) self.comment_id = "test_comment" @@ -1445,7 +1443,7 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): self.register_get_user_response(self.user) cs_thread = make_minimal_cs_thread({ "id": "test_thread", - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), }) self.register_get_thread_response(cs_thread) cs_comment = make_minimal_cs_comment({ @@ -1460,7 +1458,7 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): response = self.client.delete(self.url) assert response.status_code == 204 assert response.content == b'' - assert urlparse(httpretty.last_request().path).path == '/api/v1/comments/{}'.format(self.comment_id) # lint-amnesty, pylint: disable=no-member + assert urlparse(httpretty.last_request().path).path == f"/api/v1/comments/{self.comment_id}" # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().method == 'DELETE' def test_delete_nonexistent_comment(self): @@ -1475,7 +1473,7 @@ class CommentViewSetDeleteTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): """Tests for CommentViewSet create""" def setUp(self): - super(CommentViewSetCreateTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("comment-list") def test_basic(self): @@ -1517,7 +1515,7 @@ class CommentViewSetCreateTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase): assert response_data == expected_response_data assert urlparse(httpretty.last_request().path).path == '/api/v1/threads/test_thread/comments' # lint-amnesty, pylint: disable=no-member assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member - 'course_id': [text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'body': ['Test body'], 'user_id': [str(self.user.id)] } @@ -1558,7 +1556,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes """Tests for CommentViewSet partial_update""" def setUp(self): self.unsupported_media_type = JSONParser.media_type - super(CommentViewSetPartialUpdateTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() httpretty.reset() httpretty.enable() self.addCleanup(httpretty.reset) @@ -1610,7 +1608,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes }) assert httpretty.last_request().parsed_body == { # lint-amnesty, pylint: disable=no-member 'body': ['Edited body'], - 'course_id': [text_type(self.course.id)], + 'course_id': [str(self.course.id)], 'user_id': [str(self.user.id)], 'anonymous': ['False'], 'anonymous_to_peers': ['False'], @@ -1666,7 +1664,7 @@ class CommentViewSetPartialUpdateTest(DiscussionAPIViewTestMixin, ModuleStoreTes class ThreadViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, ProfileImageTestMixin): """Tests for ThreadViewSet Retrieve""" def setUp(self): - super(ThreadViewSetRetrieveTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("thread-detail", kwargs={"thread_id": "test_thread"}) self.thread_id = "test_thread" @@ -1674,7 +1672,7 @@ class ThreadViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, self.register_get_user_response(self.user) cs_thread = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "commentable_id": "test_topic", "username": self.user.username, "user_id": str(self.user.id), @@ -1699,7 +1697,7 @@ class ThreadViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, self.register_get_user_response(self.user) cs_thread = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "username": self.user.username, "user_id": str(self.user.id), }) @@ -1717,7 +1715,7 @@ class ThreadViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase, ProfileImageTestMixin): """Tests for CommentViewSet Retrieve""" def setUp(self): - super(CommentViewSetRetrieveTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.url = reverse("comment-detail", kwargs={"comment_id": "test_comment"}) self.thread_id = "test_thread" self.comment_id = "test_comment" @@ -1729,7 +1727,7 @@ class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase return make_minimal_cs_comment({ "id": comment_id, "parent_id": parent_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "thread_id": self.thread_id, "thread_type": "discussion", "username": self.user.username, @@ -1746,7 +1744,7 @@ class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase cs_comment = self.make_comment_data(self.comment_id, None, [cs_comment_child]) cs_thread = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "children": [cs_comment], }) self.register_get_thread_response(cs_thread) @@ -1794,7 +1792,7 @@ class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase cs_comment = self.make_comment_data(self.comment_id, None, [cs_comment_child]) cs_thread = make_minimal_cs_thread({ "id": self.thread_id, - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "children": [cs_comment], }) self.register_get_thread_response(cs_thread) @@ -1818,7 +1816,7 @@ class CommentViewSetRetrieveTest(DiscussionAPIViewTestMixin, ModuleStoreTestCase cs_comment = self.make_comment_data(self.comment_id, None, [cs_comment_child]) cs_thread = make_minimal_cs_thread({ 'id': self.thread_id, - 'course_id': text_type(self.course.id), + 'course_id': str(self.course.id), 'children': [cs_comment], }) self.register_get_thread_response(cs_thread) @@ -1842,7 +1840,7 @@ class CourseDiscussionSettingsAPIViewTest(APITestCase, UrlResetMixin, ModuleStor """ @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(CourseDiscussionSettingsAPIViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create( org="x", course="y", @@ -1850,7 +1848,7 @@ class CourseDiscussionSettingsAPIViewTest(APITestCase, UrlResetMixin, ModuleStor start=datetime.now(UTC), discussion_topics={"Test Topic": {"id": "test_topic"}} ) - self.path = reverse('discussion_course_settings', kwargs={'course_id': text_type(self.course.id)}) + self.path = reverse('discussion_course_settings', kwargs={'course_id': str(self.course.id)}) self.password = 'edx' self.user = UserFactory(username='staff', password=self.password, is_staff=True) @@ -1894,12 +1892,12 @@ class CourseDiscussionSettingsAPIViewTest(APITestCase, UrlResetMixin, ModuleStor def _get_expected_response(self): """Return the default expected response before any changes to the discussion settings.""" return { - u'always_divide_inline_discussions': False, - u'divided_inline_discussions': [], - u'divided_course_wide_discussions': [], - u'id': 1, - u'division_scheme': u'cohort', - u'available_division_schemes': [u'cohort'] + 'always_divide_inline_discussions': False, + 'divided_inline_discussions': [], + 'divided_course_wide_discussions': [], + 'id': 1, + 'division_scheme': 'cohort', + 'available_division_schemes': ['cohort'] } def patch_request(self, data, headers=None): @@ -2085,7 +2083,7 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe """ @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(CourseDiscussionRolesAPIViewTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create( org="x", course="y", @@ -2100,7 +2098,7 @@ class CourseDiscussionRolesAPIViewTest(APITestCase, UrlResetMixin, ModuleStoreTe @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def path(self, course_id=None, role=None): """Return the URL path to the endpoint based on the provided arguments.""" - course_id = text_type(self.course.id) if course_id is None else course_id + course_id = str(self.course.id) if course_id is None else course_id role = 'Moderator' if role is None else role return reverse( 'discussion_course_roles', diff --git a/lms/djangoapps/discussion/rest_api/tests/utils.py b/lms/djangoapps/discussion/rest_api/tests/utils.py index 4535bf1281a..45c145139f9 100644 --- a/lms/djangoapps/discussion/rest_api/tests/utils.py +++ b/lms/djangoapps/discussion/rest_api/tests/utils.py @@ -10,7 +10,6 @@ from contextlib import closing from datetime import datetime import httpretty -import six from PIL import Image from pytz import UTC @@ -68,7 +67,7 @@ def _get_comment_callback(comment_data, thread_id, parent_id): return callback -class CommentsServiceMockMixin(object): +class CommentsServiceMockMixin: """Mixin with utility methods for mocking the comments service""" def register_get_threads_response(self, threads, page, num_pages): """Register a mock response for GET on the CS thread list endpoint""" @@ -128,7 +127,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.GET, - "http://localhost:4567/api/v1/threads/{id}".format(id=thread_id), + f"http://localhost:4567/api/v1/threads/{thread_id}", body="", status=status_code ) @@ -152,9 +151,9 @@ class CommentsServiceMockMixin(object): specified. """ if parent_id: - url = "http://localhost:4567/api/v1/comments/{}".format(parent_id) + url = f"http://localhost:4567/api/v1/comments/{parent_id}" else: - url = "http://localhost:4567/api/v1/threads/{}/comments".format(thread_id) + url = f"http://localhost:4567/api/v1/threads/{thread_id}/comments" assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( @@ -185,7 +184,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.GET, - "http://localhost:4567/api/v1/comments/{id}".format(id=comment_id), + f"http://localhost:4567/api/v1/comments/{comment_id}", body="", status=status_code ) @@ -208,7 +207,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.GET, - "http://localhost:4567/api/v1/users/{id}".format(id=user.id), + f"http://localhost:4567/api/v1/users/{user.id}", body=json.dumps({ "id": str(user.id), "subscribed_thread_ids": subscribed_thread_ids or [], @@ -222,7 +221,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.POST, - "http://localhost:4567/api/v1/users/{id}/retire".format(id=user.id), + f"http://localhost:4567/api/v1/users/{user.id}/retire", body=body, status=status ) @@ -231,7 +230,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.POST, - "http://localhost:4567/api/v1/users/{id}/replace_username".format(id=user.id), + f"http://localhost:4567/api/v1/users/{user.id}/replace_username", body=body, status=status ) @@ -241,7 +240,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.GET, - "http://localhost:4567/api/v1/users/{}/subscribed_threads".format(user.id), + f"http://localhost:4567/api/v1/users/{user.id}/subscribed_threads", body=json.dumps({ "collection": threads, "page": page, @@ -260,7 +259,7 @@ class CommentsServiceMockMixin(object): for method in [httpretty.POST, httpretty.DELETE]: httpretty.register_uri( method, - "http://localhost:4567/api/v1/users/{id}/subscriptions".format(id=user.id), + f"http://localhost:4567/api/v1/users/{user.id}/subscriptions", body=json.dumps({}), # body is unused status=200 ) @@ -274,7 +273,7 @@ class CommentsServiceMockMixin(object): for method in [httpretty.PUT, httpretty.DELETE]: httpretty.register_uri( method, - "http://localhost:4567/api/v1/threads/{}/votes".format(thread_id), + f"http://localhost:4567/api/v1/threads/{thread_id}/votes", body=json.dumps({}), # body is unused status=200 ) @@ -288,7 +287,7 @@ class CommentsServiceMockMixin(object): for method in [httpretty.PUT, httpretty.DELETE]: httpretty.register_uri( method, - "http://localhost:4567/api/v1/comments/{}/votes".format(comment_id), + f"http://localhost:4567/api/v1/comments/{comment_id}/votes", body=json.dumps({}), # body is unused status=200 ) @@ -315,7 +314,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.POST, - "http://localhost:4567/api/v1/users/{id}/read".format(id=user.id), + f"http://localhost:4567/api/v1/users/{user.id}/read", params={'source_type': content_type, 'source_id': content_id}, body=json.dumps({}), # body is unused status=200 @@ -336,7 +335,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.DELETE, - "http://localhost:4567/api/v1/threads/{id}".format(id=thread_id), + f"http://localhost:4567/api/v1/threads/{thread_id}", body=json.dumps({}), # body is unused status=200 ) @@ -348,7 +347,7 @@ class CommentsServiceMockMixin(object): assert httpretty.is_enabled(), 'httpretty must be enabled to mock calls.' httpretty.register_uri( httpretty.DELETE, - "http://localhost:4567/api/v1/comments/{id}".format(id=comment_id), + f"http://localhost:4567/api/v1/comments/{comment_id}", body=json.dumps({}), # body is unused status=200 ) @@ -392,7 +391,7 @@ class CommentsServiceMockMixin(object): "voted": False, "vote_count": 0, "editable_fields": ["abuse_flagged", "following", "raw_body", "read", "title", "topic_id", "type", "voted"], - "course_id": six.text_type(self.course.id), + "course_id": str(self.course.id), "topic_id": "test_topic", "group_id": None, "group_name": None, @@ -494,7 +493,7 @@ def make_paginated_api_response(results=None, count=0, num_pages=0, next_link=No } -class ProfileImageTestMixin(object): +class ProfileImageTestMixin: """ Mixin with utility methods for user profile image """ diff --git a/lms/djangoapps/discussion/rest_api/urls.py b/lms/djangoapps/discussion/rest_api/urls.py index c05e4c5cc1c..ea9f6895a23 100644 --- a/lms/djangoapps/discussion/rest_api/urls.py +++ b/lms/djangoapps/discussion/rest_api/urls.py @@ -39,14 +39,14 @@ urlpatterns = [ name="discussion_course_roles", ), url( - r"^v1/courses/{}".format(settings.COURSE_ID_PATTERN), + fr"^v1/courses/{settings.COURSE_ID_PATTERN}", CourseView.as_view(), name="discussion_course" ), url(r"^v1/accounts/retire_forum", RetireUserView.as_view(), name="retire_discussion_user"), url(r"^v1/accounts/replace_username", ReplaceUsernamesView.as_view(), name="replace_discussion_username"), url( - r"^v1/course_topics/{}".format(settings.COURSE_ID_PATTERN), + fr"^v1/course_topics/{settings.COURSE_ID_PATTERN}", CourseTopicsView.as_view(), name="course_topics" ), diff --git a/lms/djangoapps/discussion/rest_api/views.py b/lms/djangoapps/discussion/rest_api/views.py index 2ee70818e57..bff900e58d2 100644 --- a/lms/djangoapps/discussion/rest_api/views.py +++ b/lms/djangoapps/discussion/rest_api/views.py @@ -17,10 +17,8 @@ from rest_framework.parsers import JSONParser from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.viewsets import ViewSet -from six import text_type -from lms.djangoapps.discussion.views import get_divided_discussions -from lms.djangoapps.instructor.access import update_forum_role +from common.djangoapps.util.json_request import JsonResponse from lms.djangoapps.discussion.django_comment_client.utils import available_division_schemes from lms.djangoapps.discussion.rest_api.api import ( create_comment, @@ -48,6 +46,8 @@ from lms.djangoapps.discussion.rest_api.serializers import ( DiscussionRolesSerializer, DiscussionSettingsSerializer ) +from lms.djangoapps.discussion.views import get_divided_discussions +from lms.djangoapps.instructor.access import update_forum_role from openedx.core.djangoapps.django_comment_common import comment_client from openedx.core.djangoapps.django_comment_common.models import Role from openedx.core.djangoapps.django_comment_common.utils import ( @@ -57,10 +57,8 @@ from openedx.core.djangoapps.django_comment_common.utils import ( from openedx.core.djangoapps.user_api.accounts.permissions import CanReplaceUsername, CanRetireUser from openedx.core.djangoapps.user_api.models import UserRetirementStatus from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser - from openedx.core.lib.api.parsers import MergePatchParser from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin, view_auth_classes -from common.djangoapps.util.json_request import JsonResponse from xmodule.modulestore.django import modulestore log = logging.getLogger(__name__) @@ -594,7 +592,7 @@ class RetireUserView(APIView): return Response(status=status.HTTP_404_NOT_FOUND) raise except Exception as exc: # pylint: disable=broad-except - return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR) + return Response(str(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR) return Response(status=status.HTTP_204_NO_CONTENT) @@ -661,7 +659,7 @@ class ReplaceUsernamesView(APIView): cc_user.replace_username(new_username) except User.DoesNotExist: log.warning( - u"Unable to change username from %s to %s in forums because %s doesn't exist in LMS DB.", + "Unable to change username from %s to %s in forums because %s doesn't exist in LMS DB.", current_username, new_username, new_username, @@ -670,14 +668,14 @@ class ReplaceUsernamesView(APIView): except comment_client.CommentClientRequestError as exc: if exc.status_code == 404: log.info( - u"Unable to change username from %s to %s in forums because user doesn't exist in forums", + "Unable to change username from %s to %s in forums because user doesn't exist in forums", current_username, new_username, ) return True else: log.exception( - u"Unable to change username from %s to %s in forums because forums API call failed with: %s.", + "Unable to change username from %s to %s in forums because forums API call failed with: %s.", current_username, new_username, exc, @@ -685,7 +683,7 @@ class ReplaceUsernamesView(APIView): return False log.info( - u"Successfully changed username from %s to %s in forums.", + "Successfully changed username from %s to %s in forums.", current_username, new_username, ) @@ -824,7 +822,7 @@ class CourseDiscussionSettingsAPIView(DeveloperErrorViewMixin, APIView): try: discussion_settings = set_course_discussion_settings(course_key, **settings_to_change) except ValueError as e: - raise ValidationError(text_type(e)) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError(str(e)) # lint-amnesty, pylint: disable=raise-missing-from return Response(status=status.HTTP_204_NO_CONTENT) @@ -937,7 +935,7 @@ class CourseDiscussionRolesAPIView(DeveloperErrorViewMixin, APIView): try: update_forum_role(course_id, user, rolename, action) except Role.DoesNotExist: - raise ValidationError(u"Role '{}' does not exist".format(rolename)) # lint-amnesty, pylint: disable=raise-missing-from + raise ValidationError(f"Role '{rolename}' does not exist") # lint-amnesty, pylint: disable=raise-missing-from role = form.cleaned_data['role'] data = {'course_id': course_id, 'users': role.users.all()} diff --git a/lms/djangoapps/discussion/signals/handlers.py b/lms/djangoapps/discussion/signals/handlers.py index b3519bbd6c1..3b99f7b6372 100644 --- a/lms/djangoapps/discussion/signals/handlers.py +++ b/lms/djangoapps/discussion/signals/handlers.py @@ -5,7 +5,6 @@ Signal handlers related to discussions. import logging -import six from django.conf import settings from django.dispatch import receiver from opaque_keys.edx.locator import LibraryLocator @@ -33,7 +32,7 @@ def update_discussions_on_course_publish(sender, course_key, **kwargs): # pylin return context = { - 'course_id': six.text_type(course_key), + 'course_id': str(course_key), } tasks.update_discussions_map.apply_async( args=[context], @@ -45,16 +44,16 @@ def update_discussions_on_course_publish(sender, course_key, **kwargs): # pylin def send_discussion_email_notification(sender, user, post, **kwargs): # lint-amnesty, pylint: disable=missing-function-docstring, unused-argument current_site = get_current_site() if current_site is None: - log.info(u'Discussion: No current site, not sending notification about post: %s.', post.id) + log.info('Discussion: No current site, not sending notification about post: %s.', post.id) return try: if not current_site.configuration.get_value(ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY, False): - log_message = u'Discussion: notifications not enabled for site: %s. Not sending message about post: %s.' + log_message = 'Discussion: notifications not enabled for site: %s. Not sending message about post: %s.' log.info(log_message, current_site, post.id) return except SiteConfiguration.DoesNotExist: - log_message = u'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.' + log_message = 'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.' log.info(log_message, current_site, post.id) return @@ -64,7 +63,7 @@ def send_discussion_email_notification(sender, user, post, **kwargs): # lint-am def send_message(comment, site): # lint-amnesty, pylint: disable=missing-function-docstring thread = comment.thread context = { - 'course_id': six.text_type(thread.course_id), + 'course_id': str(thread.course_id), 'comment_id': comment.id, 'comment_body': comment.body, 'comment_author_id': comment.user_id, diff --git a/lms/djangoapps/discussion/tasks.py b/lms/djangoapps/discussion/tasks.py index ba6e08e31da..4f5d7314451 100644 --- a/lms/djangoapps/discussion/tasks.py +++ b/lms/djangoapps/discussion/tasks.py @@ -6,7 +6,6 @@ pertaining to new discussion forum comments. import logging -import six from celery import shared_task from celery_utils.logged_task import LoggedTask from django.conf import settings # lint-amnesty, pylint: disable=unused-import @@ -21,6 +20,7 @@ from opaque_keys.edx.keys import CourseKey from six.moves.urllib.parse import urljoin import openedx.core.djangoapps.django_comment_common.comment_client as cc +from common.djangoapps.track import segment from lms.djangoapps.discussion.django_comment_client.utils import ( get_accessible_discussion_xblocks_by_course_id, permalink @@ -30,7 +30,6 @@ from openedx.core.djangoapps.ace_common.template_context import get_base_templat from openedx.core.djangoapps.content.course_overviews.models import CourseOverview from openedx.core.djangoapps.django_comment_common.models import DiscussionsIdMapping from openedx.core.lib.celery.task_utils import emulate_http_request -from common.djangoapps.track import segment log = logging.getLogger(__name__) @@ -51,7 +50,7 @@ def update_discussions_map(context): course_key = CourseKey.from_string(context['course_id']) discussion_blocks = get_accessible_discussion_xblocks_by_course_id(course_key, include_all=True) discussions_id_map = { - discussion_block.discussion_id: six.text_type(discussion_block.location) + discussion_block.discussion_id: str(discussion_block.location) for discussion_block in discussion_blocks } DiscussionsIdMapping.update_mapping(course_key, discussions_id_map) @@ -76,7 +75,7 @@ def send_ace_message(context): # lint-amnesty, pylint: disable=missing-function _get_course_language(context['course_id']), message_context ) - log.info(u'Sending forum comment email notification with context %s', message_context) + log.info('Sending forum comment email notification with context %s', message_context) ace.send(message) _track_notification_sent(message, context) @@ -89,10 +88,10 @@ def _track_notification_sent(message, context): 'app_label': 'discussion', 'name': 'responsenotification', # This is 'Campaign' in GA 'language': message.language, - 'uuid': six.text_type(message.uuid), - 'send_uuid': six.text_type(message.send_uuid), + 'uuid': str(message.uuid), + 'send_uuid': str(message.send_uuid), 'thread_id': context['thread_id'], - 'course_id': six.text_type(context['course_id']), + 'course_id': str(context['course_id']), 'thread_created_at': date.deserialize(context['thread_created_at']), 'nonInteraction': 1, } diff --git a/lms/djangoapps/discussion/templates/discussion/discussion_board_js.template b/lms/djangoapps/discussion/templates/discussion/discussion_board_js.template index b23082c49de..9ceccee1140 100644 --- a/lms/djangoapps/discussion/templates/discussion/discussion_board_js.template +++ b/lms/djangoapps/discussion/templates/discussion/discussion_board_js.template @@ -1,7 +1,6 @@ ## mako <%! -import six from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string %> @@ -48,7 +47,7 @@ from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_str $(function() { require(['discussion/js/discussion_board_factory'], function (DiscussionBoardFactory) { DiscussionBoardFactory({ - courseId: '${six.text_type(course.id) | n, js_escaped_string}', + courseId: '${str(course.id) | n, js_escaped_string}', $el: $(".discussion-board"), rootUrl: '${root_url | n, js_escaped_string}', userInfo: ${user_info | n, dump_js_escaped_json}, diff --git a/lms/djangoapps/discussion/templates/discussion/discussion_profile_page.html b/lms/djangoapps/discussion/templates/discussion/discussion_profile_page.html index aade0ac41d3..07f74aed277 100644 --- a/lms/djangoapps/discussion/templates/discussion/discussion_profile_page.html +++ b/lms/djangoapps/discussion/templates/discussion/discussion_profile_page.html @@ -6,7 +6,6 @@ <%! import json -import six from django.utils.translation import ugettext as _, ungettext from django.template.defaultfilters import escapejs @@ -21,7 +20,7 @@ from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_str <%static:require_module module_name="discussion/js/discussion_profile_page_factory" class_name="DiscussionProfilePageFactory"> profile_page_context = { 'courseSettings': ${course_settings | n, dump_js_escaped_json}, - 'courseId': '${six.text_type(course.id) | n, js_escaped_string}', + 'courseId': '${str(course.id) | n, js_escaped_string}', 'courseName': '${course.display_name_with_default | n, js_escaped_string}', 'contentInfo': ${annotated_content_info | n, dump_js_escaped_json}, 'userInfo': ${user_info | n, dump_js_escaped_json}, diff --git a/lms/djangoapps/discussion/tests/test_signals.py b/lms/djangoapps/discussion/tests/test_signals.py index 887d3c273c6..8213eb8b9cc 100644 --- a/lms/djangoapps/discussion/tests/test_signals.py +++ b/lms/djangoapps/discussion/tests/test_signals.py @@ -1,8 +1,6 @@ """ Tests the forum notification signals. """ - - import mock from django.test import TestCase from edx_django_utils.cache import RequestCache diff --git a/lms/djangoapps/discussion/tests/test_tasks.py b/lms/djangoapps/discussion/tests/test_tasks.py index e6f2d934a08..7d54d177ad7 100644 --- a/lms/djangoapps/discussion/tests/test_tasks.py +++ b/lms/djangoapps/discussion/tests/test_tasks.py @@ -6,10 +6,9 @@ Tests the execution of forum notification tasks. import json import math from datetime import datetime, timedelta +from unittest import mock import ddt -import mock -import six from django.contrib.sites.models import Site from edx_ace.channel import ChannelType, get_channel_for_message from edx_ace.recipient import Recipient @@ -17,6 +16,7 @@ from edx_ace.renderers import EmailRenderer from edx_ace.utils import date import openedx.core.djangoapps.django_comment_common.comment_client as cc +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from lms.djangoapps.discussion.signals.handlers import ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY from lms.djangoapps.discussion.tasks import _should_send_message, _track_notification_sent from openedx.core.djangoapps.ace_common.template_context import get_base_template_context @@ -25,7 +25,6 @@ from openedx.core.djangoapps.django_comment_common.models import ForumsConfig from openedx.core.djangoapps.django_comment_common.signals import comment_created from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory from openedx.core.lib.celery.task_utils import emulate_http_request -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase NOW = datetime.utcnow() @@ -72,7 +71,7 @@ class TaskTestCase(ModuleStoreTestCase): # lint-amnesty, pylint: disable=missin @classmethod @mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUpClass(cls): - super(TaskTestCase, cls).setUpClass() + super().setUpClass() cls.discussion_id = 'dummy_discussion_id' cls.course = CourseOverviewFactory.create(language='fr') @@ -109,7 +108,7 @@ class TaskTestCase(ModuleStoreTestCase): # lint-amnesty, pylint: disable=missin def create_thread_and_comments(cls): # lint-amnesty, pylint: disable=missing-function-docstring cls.thread = { 'id': cls.discussion_id, - 'course_id': six.text_type(cls.course.id), + 'course_id': str(cls.course.id), 'created_at': date.serialize(TWO_HOURS_AGO), 'title': 'thread-title', 'user_id': cls.thread_author.id, @@ -147,7 +146,7 @@ class TaskTestCase(ModuleStoreTestCase): # lint-amnesty, pylint: disable=missin cls.comment['child_count'] = 1 cls.thread2 = { 'id': cls.discussion_id, - 'course_id': six.text_type(cls.course.id), + 'course_id': str(cls.course.id), 'created_at': date.serialize(TWO_HOURS_AGO), 'title': 'thread-title', 'user_id': cls.thread_author.id, @@ -156,7 +155,7 @@ class TaskTestCase(ModuleStoreTestCase): # lint-amnesty, pylint: disable=missin } def setUp(self): - super(TaskTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.request_patcher = mock.patch('requests.request') self.mock_request = self.request_patcher.start() @@ -168,7 +167,7 @@ class TaskTestCase(ModuleStoreTestCase): # lint-amnesty, pylint: disable=missin self.mock_permalink = self.permalink_patcher.start() def tearDown(self): - super(TaskTestCase, self).tearDown() # lint-amnesty, pylint: disable=super-with-arguments + super().tearDown() self.request_patcher.stop() self.ace_send_patcher.stop() self.permalink_patcher.stop() diff --git a/lms/djangoapps/discussion/tests/test_views.py b/lms/djangoapps/discussion/tests/test_views.py index 9b948b13e54..ae8e1b43cd8 100644 --- a/lms/djangoapps/discussion/tests/test_views.py +++ b/lms/djangoapps/discussion/tests/test_views.py @@ -6,22 +6,22 @@ Tests the forum notification views. import json import logging from datetime import datetime +from unittest.mock import ANY, Mock, call, patch import ddt import pytest -import six from django.http import Http404 from django.test.client import Client, RequestFactory from django.test.utils import override_settings from django.urls import reverse from django.utils import translation from edx_django_utils.cache import RequestCache -from mock import ANY, Mock, call, patch -from six import text_type -from six.moves import range from common.djangoapps.course_modes.models import CourseMode from common.djangoapps.course_modes.tests.factories import CourseModeFactory +from common.djangoapps.student.roles import CourseStaffRole, UserBasedRole +from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory +from common.djangoapps.util.testing import EventTestMixin, UrlResetMixin from lms.djangoapps.courseware.exceptions import CourseAccessRedirect from lms.djangoapps.discussion import views from lms.djangoapps.discussion.django_comment_client.constants import TYPE_ENTRY, TYPE_SUBCATEGORY @@ -56,9 +56,6 @@ from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES from openedx.core.lib.teams_config import TeamsConfig from openedx.features.content_type_gating.models import ContentTypeGatingConfig from openedx.features.enterprise_support.tests.mixins.enterprise import EnterpriseTestConsentRequired -from common.djangoapps.student.roles import CourseStaffRole, UserBasedRole -from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory -from common.djangoapps.util.testing import EventTestMixin, UrlResetMixin from xmodule.modulestore import ModuleStoreEnum from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ( @@ -81,7 +78,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase): # lint-amnest # Patching the ENABLE_DISCUSSION_SERVICE value affects the contents of urls.py, # so we need to call super.setUp() which reloads urls.py (because # of the UrlResetMixin) - super(ViewsExceptionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() # create a course self.course = CourseFactory.create(org='MITx', course='999', @@ -121,7 +118,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase): # lint-amnest mock_from_django_user.return_value = Mock() url = reverse('user_profile', - kwargs={'course_id': text_type(self.course.id), 'user_id': '12345'}) # There is no user 12345 + kwargs={'course_id': str(self.course.id), 'user_id': '12345'}) # There is no user 12345 response = self.client.get(url) assert response.status_code == 404 @@ -138,7 +135,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase): # lint-amnest mock_from_django_user.return_value = Mock() url = reverse('followed_threads', - kwargs={'course_id': text_type(self.course.id), 'user_id': '12345'}) # There is no user 12345 + kwargs={'course_id': str(self.course.id), 'user_id': '12345'}) # There is no user 12345 response = self.client.get(url) assert response.status_code == 404 @@ -176,7 +173,7 @@ def make_mock_thread_data( # lint-amnesty, pylint: disable=missing-function-doc thread_data['is_commentable_divided'] = is_commentable_divided if num_children is not None: thread_data["children"] = [{ - "id": "dummy_comment_id_{}".format(i), + "id": f"dummy_comment_id_{i}", "type": "comment", "body": text, } for i in range(num_children)] @@ -283,7 +280,7 @@ def make_mock_request_impl( # lint-amnesty, pylint: disable=missing-function-do return mock_request_impl -class StringEndsWithMatcher(object): # lint-amnesty, pylint: disable=missing-class-docstring +class StringEndsWithMatcher: # lint-amnesty, pylint: disable=missing-class-docstring,eq-without-hash def __init__(self, suffix): self.suffix = suffix @@ -291,14 +288,14 @@ class StringEndsWithMatcher(object): # lint-amnesty, pylint: disable=missing-cl return other.endswith(self.suffix) -class PartialDictMatcher(object): # lint-amnesty, pylint: disable=missing-class-docstring +class PartialDictMatcher: # lint-amnesty, pylint: disable=missing-class-docstring,eq-without-hash def __init__(self, expected_values): self.expected_values = expected_values def __eq__(self, other): return all([ key in other and other[key] == value - for key, value in six.iteritems(self.expected_values) + for key, value in self.expected_values.items() ]) @@ -308,7 +305,7 @@ class SingleThreadTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amne CREATE_USER = False def setUp(self): - super(SingleThreadTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}}) self.student = UserFactory.create() @@ -326,7 +323,7 @@ class SingleThreadTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amne request.user = self.student response = views.single_thread( request, - text_type(self.course.id), + str(self.course.id), "dummy_discussion_id", "test_thread_id" ) @@ -365,7 +362,7 @@ class SingleThreadTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amne request.user = self.student response = views.single_thread( request, - text_type(self.course.id), + str(self.course.id), "dummy_discussion_id", "test_thread_id" ) @@ -398,7 +395,7 @@ class SingleThreadTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amne request = RequestFactory().post("dummy_url") response = views.single_thread( request, - text_type(self.course.id), + str(self.course.id), "dummy_discussion_id", "dummy_thread_id" ) @@ -413,7 +410,7 @@ class SingleThreadTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amne Http404, views.single_thread, request, - text_type(self.course.id), + str(self.course.id), "test_discussion_id", "test_thread_id" ) @@ -436,7 +433,7 @@ class SingleThreadTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amne mocked.return_value = True response = self.client.get( reverse('single_thread', kwargs={ - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'discussion_id': discussion_topic_id, 'thread_id': thread_id, }) @@ -464,7 +461,7 @@ class AllowPlusOrMinusOneInt(int): # pylint: disable=eq-without-hash return other in self.values def __repr__(self): - return "({} +/- 1)".format(self.value) + return f"({self.value} +/- 1)" @ddt.ddt @@ -532,7 +529,7 @@ class SingleThreadQueryCountTestCase(ForumsEnableMixin, ModuleStoreTestCase): with patch.dict("django.conf.settings.FEATURES", dict(ENABLE_ENTERPRISE_INTEGRATION=enterprise_enabled)): response = views.single_thread( request, - text_type(course.id), + str(course.id), "dummy_discussion_id", test_thread_id ) @@ -577,7 +574,7 @@ class SingleCohortedThreadTestCase(CohortedTestCase): # lint-amnesty, pylint: d request.user = self.student response = views.single_thread( request, - text_type(self.course.id), + str(self.course.id), "cohorted_topic", mock_thread_id ) @@ -601,7 +598,7 @@ class SingleCohortedThreadTestCase(CohortedTestCase): # lint-amnesty, pylint: d self.client.login(username=self.student.username, password='test') response = self.client.get( reverse('single_thread', kwargs={ - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'discussion_id': "cohorted_topic", 'thread_id': mock_thread_id, }) @@ -635,7 +632,7 @@ class SingleThreadAccessTestCase(CohortedTestCase): # lint-amnesty, pylint: dis request.user = user return views.single_thread( request, - text_type(self.course.id), + str(self.course.id), commentable_id, thread_id ) @@ -735,7 +732,7 @@ class SingleThreadGroupIdTestCase(CohortedTestCase, GroupIdAssertionMixin): # l self.client.login(username=user.username, password='test') return self.client.get( - reverse('single_thread', args=[six.text_type(self.course.id), commentable_id, "dummy_thread_id"]), + reverse('single_thread', args=[str(self.course.id), commentable_id, "dummy_thread_id"]), data=request_data, **headers ) @@ -774,7 +771,7 @@ class ForumFormDiscussionContentGroupTestCase(ForumsEnableMixin, ContentGroupTes @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(ForumFormDiscussionContentGroupTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.thread_list = [ {"thread_id": "test_general_thread_id"}, {"thread_id": "test_global_group_thread_id", "commentable_id": self.global_module.discussion_id}, @@ -800,7 +797,7 @@ class ForumFormDiscussionContentGroupTestCase(ForumsEnableMixin, ContentGroupTes ) self.client.login(username=user.username, password='test') return self.client.get( - reverse("forum_form_discussion", args=[six.text_type(self.course.id)]), + reverse("forum_form_discussion", args=[str(self.course.id)]), HTTP_X_REQUESTED_WITH="XMLHttpRequest" ) @@ -854,7 +851,7 @@ class SingleThreadContentGroupTestCase(ForumsEnableMixin, UrlResetMixin, Content @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(SingleThreadContentGroupTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() def assert_can_access(self, user, discussion_id, thread_id, should_have_access): """ @@ -865,7 +862,7 @@ class SingleThreadContentGroupTestCase(ForumsEnableMixin, UrlResetMixin, Content def call_single_thread(): self.client.login(username=user.username, password='test') return self.client.get( - reverse('single_thread', args=[six.text_type(self.course.id), discussion_id, thread_id]) + reverse('single_thread', args=[str(self.course.id), discussion_id, thread_id]) ) if should_have_access: @@ -963,7 +960,7 @@ class SingleThreadContentGroupTestCase(ForumsEnableMixin, UrlResetMixin, Content class InlineDiscussionContextTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amnesty, pylint: disable=missing-class-docstring def setUp(self): - super(InlineDiscussionContextTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() CourseEnrollmentFactory(user=self.user, course_id=self.course.id) self.discussion_topic_id = "dummy_topic" @@ -989,7 +986,7 @@ class InlineDiscussionContextTestCase(ForumsEnableMixin, ModuleStoreTestCase): response = views.inline_discussion( request, - six.text_type(self.course.id), + str(self.course.id), self.discussion_topic_id, ) @@ -1012,7 +1009,7 @@ class InlineDiscussionContextTestCase(ForumsEnableMixin, ModuleStoreTestCase): mocked.return_value = True response = views.inline_discussion( request, - six.text_type(self.course.id), + str(self.course.id), self.discussion_topic_id, ) assert response.status_code == 403 @@ -1028,7 +1025,7 @@ class InlineDiscussionGroupIdTestCase( # lint-amnesty, pylint: disable=missing- cs_endpoint = "/threads" def setUp(self): - super(InlineDiscussionGroupIdTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.cohorted_commentable_id = 'cohorted_topic' def call_view(self, mock_request, commentable_id, user, group_id, pass_group_id=True): @@ -1054,7 +1051,7 @@ class InlineDiscussionGroupIdTestCase( # lint-amnesty, pylint: disable=missing- request.user = user return views.inline_discussion( request, - text_type(self.course.id), + str(self.course.id), commentable_id ) @@ -1089,7 +1086,7 @@ class ForumFormDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupIdT self.client.login(username=user.username, password='test') return self.client.get( - reverse("forum_form_discussion", args=[six.text_type(self.course.id)]), + reverse("forum_form_discussion", args=[str(self.course.id)]), data=request_data, **headers ) @@ -1141,7 +1138,7 @@ class UserProfileDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGroupI self.client.login(username=requesting_user.username, password='test') return self.client.get( - reverse('user_profile', args=[six.text_type(self.course.id), profiled_user.id]), + reverse('user_profile', args=[str(self.course.id), profiled_user.id]), data=request_data, **headers ) @@ -1295,7 +1292,7 @@ class FollowedThreadsDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGr request.user = user return views.followed_threads( request, - text_type(self.course.id), + str(self.course.id), user.id ) @@ -1315,7 +1312,7 @@ class FollowedThreadsDiscussionGroupIdTestCase(CohortedTestCase, CohortedTopicGr class InlineDiscussionTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint-amnesty, pylint: disable=missing-class-docstring def setUp(self): - super(InlineDiscussionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create( org="TestX", @@ -1351,7 +1348,7 @@ class InlineDiscussionTestCase(ForumsEnableMixin, ModuleStoreTestCase): # lint- course=self.course, text="dummy content", commentable_id=self.discussion1.discussion_id ) return views.inline_discussion( - request, text_type(self.course.id), self.discussion1.discussion_id + request, str(self.course.id), self.discussion1.discussion_id ) def test_context(self, mock_request): @@ -1376,7 +1373,7 @@ class UserProfileTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(UserProfileTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.student = UserFactory.create() @@ -1392,7 +1389,7 @@ class UserProfileTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) response = self.client.get( reverse('user_profile', kwargs={ - 'course_id': six.text_type(self.course.id), + 'course_id': str(self.course.id), 'user_id': self.profiled_user.id, }), data=params, @@ -1400,10 +1397,10 @@ class UserProfileTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) ) mock_request.assert_any_call( "get", - StringEndsWithMatcher('/users/{}/active_threads'.format(self.profiled_user.id)), + StringEndsWithMatcher(f'/users/{self.profiled_user.id}/active_threads'), data=None, params=PartialDictMatcher({ - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "page": params.get("page", 1), "per_page": views.THREADS_PER_PAGE }), @@ -1421,13 +1418,10 @@ class UserProfileTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) self.assertRegex(html, r'data-num-pages="1"') self.assertRegex(html, r'<span class="discussion-count">1</span> discussion started') self.assertRegex(html, r'<span class="discussion-count">2</span> comments') - self.assertRegex(html, u''id': '{}''.format(self.TEST_THREAD_ID)) - self.assertRegex(html, u''title': '{}''.format(self.TEST_THREAD_TEXT)) - self.assertRegex(html, u''body': '{}''.format(self.TEST_THREAD_TEXT)) - if six.PY2: - self.assertRegex(html, u''username': u'{}''.format(self.student.username)) - else: - self.assertRegex(html, u''username': '{}''.format(self.student.username)) + self.assertRegex(html, f''id': '{self.TEST_THREAD_ID}'') + self.assertRegex(html, f''title': '{self.TEST_THREAD_TEXT}'') + self.assertRegex(html, f''body': '{self.TEST_THREAD_TEXT}'') + self.assertRegex(html, f''username': '{self.student.username}'') def check_ajax(self, mock_request, **params): # lint-amnesty, pylint: disable=missing-function-docstring response = self.get_response(mock_request, params, HTTP_X_REQUESTED_WITH="XMLHttpRequest") @@ -1459,7 +1453,7 @@ class UserProfileTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) with pytest.raises(Http404): views.user_profile( request, - text_type(self.course.id), + str(self.course.id), unenrolled_user.id ) @@ -1469,7 +1463,7 @@ class UserProfileTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) with pytest.raises(Http404): views.user_profile( request, - text_type(self.course.id), + str(self.course.id), -999 ) @@ -1491,7 +1485,7 @@ class UserProfileTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTestCase) request.user = self.student response = views.user_profile( request, - text_type(self.course.id), + str(self.course.id), self.profiled_user.id ) assert response.status_code == 405 @@ -1504,13 +1498,13 @@ class CommentsServiceRequestHeadersTestCase(ForumsEnableMixin, UrlResetMixin, Mo @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(CommentsServiceRequestHeadersTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() username = "foo" password = "bar" # Invoke UrlResetMixin - super(CommentsServiceRequestHeadersTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create(discussion_topics={'dummy discussion': {'id': 'dummy_discussion_id'}}) self.student = UserFactory.create(username=username, password=password) CourseEnrollmentFactory.create(user=self.student, course_id=self.course.id) @@ -1540,7 +1534,7 @@ class CommentsServiceRequestHeadersTestCase(ForumsEnableMixin, UrlResetMixin, Mo reverse( "single_thread", kwargs={ - "course_id": text_type(self.course.id), + "course_id": str(self.course.id), "discussion_id": "dummy_discussion_id", "thread_id": thread_id, } @@ -1556,7 +1550,7 @@ class CommentsServiceRequestHeadersTestCase(ForumsEnableMixin, UrlResetMixin, Mo self.client.get( reverse( "forum_form_discussion", - kwargs={"course_id": text_type(self.course.id)} + kwargs={"course_id": str(self.course.id)} ), ) self.assert_all_calls_have_header(mock_request, "X-Edx-Api-Key", "test_api_key") @@ -1567,12 +1561,12 @@ class InlineDiscussionUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCa @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(InlineDiscussionUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(InlineDiscussionUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() cls.student = UserFactory.create() CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id) @@ -1584,7 +1578,7 @@ class InlineDiscussionUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCa request.user = self.student response = views.inline_discussion( - request, text_type(self.course.id), self.course.discussion_topics['General']['id'] + request, str(self.course.id), self.course.discussion_topics['General']['id'] ) assert response.status_code == 200 response_data = json.loads(response.content.decode('utf-8')) @@ -1597,12 +1591,12 @@ class ForumFormDiscussionUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTes @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(ForumFormDiscussionUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(ForumFormDiscussionUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() cls.student = UserFactory.create() CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id) @@ -1614,7 +1608,7 @@ class ForumFormDiscussionUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTes request.user = self.student request.META["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" # so request.is_ajax() == True - response = views.forum_form_discussion(request, text_type(self.course.id)) + response = views.forum_form_discussion(request, str(self.course.id)) assert response.status_code == 200 response_data = json.loads(response.content.decode('utf-8')) assert response_data['discussion_data'][0]['title'] == text @@ -1627,7 +1621,7 @@ class ForumDiscussionXSSTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTe @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(ForumDiscussionXSSTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() username = "foo" password = "bar" @@ -1645,11 +1639,11 @@ class ForumDiscussionXSSTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTe """ mock_user.return_value.to_dict.return_value = {} mock_req.return_value.status_code = 200 - reverse_url = "%s%s" % (reverse( + reverse_url = "{}{}".format(reverse( "forum_form_discussion", - kwargs={"course_id": six.text_type(self.course.id)}), '/forum_form_discussion') + kwargs={"course_id": str(self.course.id)}), '/forum_form_discussion') # Test that malicious code does not appear in html - url = "%s?%s=%s" % (reverse_url, 'sort_key', malicious_code) + url = "{}?{}={}".format(reverse_url, 'sort_key', malicious_code) resp = self.client.get(url) self.assertNotContains(resp, malicious_code) @@ -1669,9 +1663,9 @@ class ForumDiscussionXSSTestCase(ForumsEnableMixin, UrlResetMixin, ModuleStoreTe mock_request.side_effect = make_mock_request_impl(course=self.course, text='dummy') url = reverse('user_profile', - kwargs={'course_id': six.text_type(self.course.id), 'user_id': str(self.student.id)}) + kwargs={'course_id': str(self.course.id), 'user_id': str(self.student.id)}) # Test that malicious code does not appear in html - url_string = "%s?%s=%s" % (url, 'page', malicious_code) + url_string = "{}?{}={}".format(url, 'page', malicious_code) resp = self.client.get(url_string) self.assertNotContains(resp, malicious_code) @@ -1681,12 +1675,12 @@ class ForumDiscussionSearchUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreT @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(ForumDiscussionSearchUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(ForumDiscussionSearchUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() cls.student = UserFactory.create() CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id) @@ -1702,7 +1696,7 @@ class ForumDiscussionSearchUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreT request.user = self.student request.META["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" # so request.is_ajax() == True - response = views.forum_form_discussion(request, text_type(self.course.id)) + response = views.forum_form_discussion(request, str(self.course.id)) assert response.status_code == 200 response_data = json.loads(response.content.decode('utf-8')) assert response_data['discussion_data'][0]['title'] == text @@ -1714,12 +1708,12 @@ class SingleThreadUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(SingleThreadUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create(discussion_topics={'dummy_discussion_id': {'id': 'dummy_discussion_id'}}) @classmethod def setUpTestData(cls): - super(SingleThreadUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() cls.student = UserFactory.create() CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id) @@ -1732,7 +1726,7 @@ class SingleThreadUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, request.user = self.student request.META["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" # so request.is_ajax() == True - response = views.single_thread(request, text_type(self.course.id), "dummy_discussion_id", thread_id) + response = views.single_thread(request, str(self.course.id), "dummy_discussion_id", thread_id) assert response.status_code == 200 response_data = json.loads(response.content.decode('utf-8')) assert response_data['content']['title'] == text @@ -1744,12 +1738,12 @@ class UserProfileUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, U @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(UserProfileUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(UserProfileUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() cls.student = UserFactory.create() CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id) @@ -1761,7 +1755,7 @@ class UserProfileUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCase, U request.user = self.student request.META["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" # so request.is_ajax() == True - response = views.user_profile(request, text_type(self.course.id), str(self.student.id)) + response = views.user_profile(request, str(self.course.id), str(self.student.id)) assert response.status_code == 200 response_data = json.loads(response.content.decode('utf-8')) assert response_data['discussion_data'][0]['title'] == text @@ -1773,12 +1767,12 @@ class FollowedThreadsUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCas @classmethod def setUpClass(cls): # pylint: disable=super-method-not-called - with super(FollowedThreadsUnicodeTestCase, cls).setUpClassAndTestData(): + with super().setUpClassAndTestData(): cls.course = CourseFactory.create() @classmethod def setUpTestData(cls): - super(FollowedThreadsUnicodeTestCase, cls).setUpTestData() + super().setUpTestData() cls.student = UserFactory.create() CourseEnrollmentFactory(user=cls.student, course_id=cls.course.id) @@ -1790,7 +1784,7 @@ class FollowedThreadsUnicodeTestCase(ForumsEnableMixin, SharedModuleStoreTestCas request.user = self.student request.META["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" # so request.is_ajax() == True - response = views.followed_threads(request, text_type(self.course.id), str(self.student.id)) + response = views.followed_threads(request, str(self.course.id), str(self.student.id)) assert response.status_code == 200 response_data = json.loads(response.content.decode('utf-8')) assert response_data['discussion_data'][0]['title'] == text @@ -1805,7 +1799,7 @@ class EnrollmentTestCase(ForumsEnableMixin, ModuleStoreTestCase): @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): - super(EnrollmentTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() self.course = CourseFactory.create() self.student = UserFactory.create() @@ -1816,7 +1810,7 @@ class EnrollmentTestCase(ForumsEnableMixin, ModuleStoreTestCase): request = RequestFactory().get('dummy_url') request.user = self.student with pytest.raises(CourseAccessRedirect): - views.forum_form_discussion(request, course_id=text_type(self.course.id)) # pylint: disable=no-value-for-parameter, unexpected-keyword-arg + views.forum_form_discussion(request, course_id=str(self.course.id)) # pylint: disable=no-value-for-parameter, unexpected-keyword-arg @patch('requests.request', autospec=True) @@ -1829,7 +1823,7 @@ class EnterpriseConsentTestCase(EnterpriseTestConsentRequired, ForumsEnableMixin @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): # Invoke UrlResetMixin setUp - super(EnterpriseConsentTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments + super().setUp() username = "foo" password = "bar" @@ -1851,7 +1845,7 @@ class EnterpriseConsentTestCase(EnterpriseTestConsentRequired, ForumsEnableMixin mock_enterprise_customer_for_request.return_value = None thread_id = 'dummy' - course_id = six.text_type(self.course.id) + course_id = str(self.course.id) mock_request.side_effect = make_mock_request_impl(course=self.course, text='dummy', thread_id=thread_id) for url in ( @@ -1909,7 +1903,7 @@ class CourseDiscussionTopicsTestCase(DividedDiscussionsTestCase): """ Verify that we cannot access divide_discussion_topics if we're a non-staff user. """ - self._verify_non_staff_cannot_access(views.discussion_topics, "GET", [six.text_type(self.course.id)]) + self._verify_non_staff_cannot_access(views.discussion_topics, "GET", [str(self.course.id)]) def test_get_discussion_topics(self): """ @@ -1965,12 +1959,12 @@ class CourseDiscussionsHandlerTestCase(DividedDiscussionsTestCase): Returns the static response dict. """ return { - u'always_divide_inline_discussions': False, - u'divided_inline_discussions': [], - u'divided_course_wide_discussions': [], - u'id': 1, - u'division_scheme': u'cohort', - u'available_division_schemes': [u'cohort'] + 'always_divide_inline_discussions': False, + 'divided_inline_discussions': [], + 'divided_course_wide_discussions': [], + 'id': 1, + 'division_scheme': 'cohort', + 'available_division_schemes': ['cohort'] } def test_non_staff(self): @@ -1978,10 +1972,10 @@ class CourseDiscussionsHandlerTestCase(DividedDiscussionsTestCase): Verify that we cannot access course_discussions_settings_handler if we're a non-staff user. """ self._verify_non_staff_cannot_access( - course_discussions_settings_handler, "GET", [six.text_type(self.course.id)] + course_discussions_settings_handler, "GET", [str(self.course.id)] ) self._verify_non_staff_cannot_access( - course_discussions_settings_handler, "PATCH", [six.text_type(self.course.id)] + course_discussions_settings_handler, "PATCH", [str(self.course.id)] ) def test_update_always_divide_inline_discussion_settings(self): @@ -2161,7 +2155,7 @@ class ThreadViewedEventTestCase(EventTestMixin, ForumsEnableMixin, UrlResetMixin @patch.dict("django.conf.settings.FEATURES", {"ENABLE_DISCUSSION_SERVICE": True}) def setUp(self): # pylint: disable=arguments-differ - super(ThreadViewedEventTestCase, self).setUp('eventtracking.tracker') # lint-amnesty, pylint: disable=super-with-arguments + super().setUp('eventtracking.tracker') self.course = CourseFactory.create( teams_configuration=TeamsConfig({ @@ -2206,8 +2200,8 @@ class ThreadViewedEventTestCase(EventTestMixin, ForumsEnableMixin, UrlResetMixin thread_id=self.DUMMY_THREAD_ID, commentable_id=self.category.discussion_id, ) - url = '/courses/{0}/discussion/forum/{1}/threads/{2}'.format( - six.text_type(self.course.id), + url = '/courses/{}/discussion/forum/{}/threads/{}'.format( + str(self.course.id), self.category.discussion_id, self.DUMMY_THREAD_ID ) diff --git a/lms/djangoapps/discussion/views.py b/lms/djangoapps/discussion/views.py index 2fbedfb3e5b..472b9b997e2 100644 --- a/lms/djangoapps/discussion/views.py +++ b/lms/djangoapps/discussion/views.py @@ -6,7 +6,6 @@ Views handling read (GET) requests for the Discussion tab and inline discussions import logging from functools import wraps -import six from django.conf import settings from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user @@ -28,6 +27,8 @@ from web_fragments.fragment import Fragment import lms.djangoapps.discussion.django_comment_client.utils as utils import openedx.core.djangoapps.django_comment_common.comment_client as cc +from common.djangoapps.student.models import CourseEnrollment +from common.djangoapps.util.json_request import JsonResponse, expect_json from lms.djangoapps.courseware.access import has_access from lms.djangoapps.courseware.courses import get_course_with_access from lms.djangoapps.courseware.views.views import CourseTabView @@ -57,8 +58,6 @@ from openedx.core.djangoapps.django_comment_common.utils import ( ) from openedx.core.djangoapps.plugin_api.views import EdxFragmentView from openedx.features.course_duration_limits.access import generate_course_expired_fragment -from common.djangoapps.student.models import CourseEnrollment -from common.djangoapps.util.json_request import JsonResponse, expect_json from xmodule.modulestore.django import modulestore log = logging.getLogger("edx.discussions") @@ -84,7 +83,7 @@ def make_course_settings(course, user, include_category_map=True): 'allow_anonymous': course.allow_anonymous, 'allow_anonymous_to_peers': course.allow_anonymous_to_peers, 'groups': [ - {"id": str(group_id), "name": group_name} for group_id, group_name in six.iteritems(group_names_by_id) + {"id": str(group_id), "name": group_name} for group_id, group_name in group_names_by_id.items() ] } if include_category_map: @@ -115,7 +114,7 @@ def get_threads(request, course, user_info, discussion_id=None, per_page=THREADS 'per_page': per_page, 'sort_key': 'activity', 'text': '', - 'course_id': six.text_type(course.id), + 'course_id': str(course.id), 'user_id': request.user.id, 'context': ThreadContext.COURSE, 'group_id': get_group_id_for_comments_service(request, course.id, discussion_id), # may raise ValueError @@ -290,7 +289,7 @@ def forum_form_discussion(request, course_key): 'corrected_text': query_params['corrected_text'], }) else: - course_id = six.text_type(course.id) + course_id = str(course.id) tab_view = CourseTabView() return tab_view.get(request, course_id, 'discussion') @@ -344,7 +343,7 @@ def single_thread(request, course_key, discussion_id, thread_id): 'annotated_content_info': annotated_content_info, }) else: - course_id = six.text_type(course.id) + course_id = str(course.id) tab_view = CourseTabView() return tab_view.get(request, course_id, 'discussion', discussion_id=discussion_id, thread_id=thread_id) @@ -475,7 +474,7 @@ def _create_discussion_board_context(request, base_context, thread=None): if "pinned" not in thread: thread["pinned"] = False thread_pages = 1 - root_url = reverse('forum_form_discussion', args=[six.text_type(course.id)]) + root_url = reverse('forum_form_discussion', args=[str(course.id)]) else: threads, query_params = get_threads(request, course, user_info) # This might process a search query thread_pages = query_params['num_pages'] @@ -608,7 +607,7 @@ def user_profile(request, course_key, user_id): # 'user_profile' page context['load_mathjax'] = False - return tab_view.get(request, six.text_type(course_key), 'discussion', profile_page_context=context) + return tab_view.get(request, str(course_key), 'discussion', profile_page_context=context) except User.DoesNotExist: raise Http404 # lint-amnesty, pylint: disable=raise-missing-from except ValueError: @@ -768,7 +767,7 @@ class DiscussionBoardFragmentView(EdxFragmentView): return fragment except TeamDiscussionHiddenFromUserException: log.warning( - u'User with id={user_id} tried to view private discussion with id={discussion_id}'.format( + 'User with id={user_id} tried to view private discussion with id={discussion_id}'.format( user_id=request.user.id, discussion_id=discussion_id ) @@ -938,7 +937,7 @@ def course_discussions_settings_handler(request, course_key_string): ) if not settings_to_change: - return JsonResponse({"error": six.text_type("Bad Request")}, 400) + return JsonResponse({"error": "Bad Request"}, 400) try: if settings_to_change: @@ -946,7 +945,7 @@ def course_discussions_settings_handler(request, course_key_string): except ValueError as err: # Note: error message not translated because it is not exposed to the user (UI prevents this state). - return JsonResponse({"error": six.text_type(err)}, 400) + return JsonResponse({"error": str(err)}, 400) divided_course_wide_discussions, divided_inline_discussions = get_divided_discussions( course, discussion_settings -- GitLab