diff --git a/lms/djangoapps/dashboard/git_import.py b/lms/djangoapps/dashboard/git_import.py
index 279fb72a98e92c2fbf710ee982d072d0924b345c..4a7d46ce973f08f2b3c14bd95a626bda05ffe5b2 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 dfd28543804a97a351f75a1012cb7e8315d286ff..331079a00bf04df7b0af9e8c52c31dbea6029685 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 baddfdb1c3ce11ffe1ad076adddee5e264e97faa..65bb015620ee45c2da0e2e5ea81312f0c1483508 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 cd3d2de20cbdedd4c5495fd3bf00656d81d2da47..9196f5ecea58ffea16f5667b17f89d62b2bc389f 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 3c498bc5933478f58af620564a0e5f04ec3de952..656d45b6032991c9454cec20f19488f07dddf02d 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 2b80beaf670e876e3feb863cbf1b211629b8bc4b..a179debfa951f3c18a0927139a7fe98b8fef40e3 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 56b1e7b6b5f4f142226f178db4d8197d4330a7dc..3c92c9258a8dfc22d4aa7fad40fbe397d94899b3 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 7bf403fd72b0826a9def50a1b787a38984844296..8d43c67385cd7e2270997d7516af49f277855af8 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 033c0af98b77fa28517c6bd847d9c784276970b2..775ad9d03e73d4b6c3a8f79c37b060bb69489299 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 efea25403c4ed2af74750b194cf8043963d456dc..1341a1392a10319674db0e6631260bfb9cd3198b 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 f1cd61297ff1accd2c6a328eab588e5e1404940b..e8ab0838aab8cf2c9f47db82376728374e95c6a2 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 5644d55cba90e8cf714bf6f31cc88fd2a93e8cd1..3293dd6a4db718ad94a3441201e320acaeb1c4c8 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 7785bb7e8f59a602a544920cc4d59d4cd7441c61..b3133f710b15977b8dbec9540ef345199687c494 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 10adf740cb07785dc85dbd6521c7eefe5f875d55..a91fc0927f1f59ca4ffe580968fa8bc3a34b6be8 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 6330b81d4b1ede34f40b9cc1e0824b7512e881ff..d78ca5f445bfe61f7985cae407c7b3cd80b33d53 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 3ec2598a250be1f82fcde45c6baeed8896d5567e..6acf974d0aaa6e2c0561cd2cf02a1eda919dd315 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 9cbfd854749dfa137d5695f63d310dc595e85012..bcc5da168d5217caf607098f5303050690230d68 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 6fb577f4b89f673c97b2023f452ea0d796653d8d..b25bea9b0297c8bac6351547e0cc3581e092b52b 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 aa83d66bd89c88be5228363f49a9e8b68f63d8ab..d16bae5d7a7263d27b93c1f24dc81d992dcf57c6 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 dba7476bd1ac41abb08d72946990d8da42a83f5d..b5d063b39b71768d23c50ec91eee6a60c28ec353 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 1c6566b54eb6f2d8a0c476c7487f6a7a56b17d14..cd99ed9efc14e0198b99408233c9b02e4fa126e4 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 f8086d3ecf86cd47eb7acc500e33f0d016bd8dc6..a95ab3b530eade56885a50dc2603282770019c74 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 52d32e541b7379486f35b72060e802bb74c47ba9..357f57217bda16dacc8d83f68e8f2a979b48142a 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 c58b1c387ec427f7f4208bbd1165190c1be5273d..6d8fae21c63605864c074b9668046ba88b8778b1 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 49e39277973c125f028b116c8584d74b4c1efca7..921c01122b80d6e56e78898f48d6cbd730a32845 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 d33dc641acedc78cbe6eccd501c94221358eb628..f71016e8f4f652bd02e3c9822c374573d6ee503c 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 8c2d624a00f27b8e75fed96c4422425c1c1e6161..3cd19286362c4c195ef75b708b6884da48fd8297 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 28bc59c566ebc82ae612b664256a6c6ed32511a1..196d2e2084accc39a73f348e5315527aa174441e 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 a570191400db3e2057cf75f766f62f6a76c636ea..3581a7b6a2f82f834008632445ff91c6ca85c43b 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 3521abc8c27e885f58ad160c113c29bb2209b921..0da81f04cccbad0849e7dbf1fc6ed0ab503dbd15 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 6dbf279da0cb4084182e1826113c165a8662b588..470f9a821ad0fd008f9e9918430a5569c9ae5e32 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 b279827c24a026be027df171c2f670f169137c1c..915ed31e3f0c3a18249b4ff917ce36fdd32e0336 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 b9475a1194eda7dc512873c68649ca482f25db4b..f56e895569c700104728105b3efa1f7616ad34bb 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 8449ddf9a92fa24d4da6e5ecce5e362f31a173f7..9b1f0fcc41592fd212427134ea583d30b7050c86 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 9c66d15f29862f0579ae72319ec8150fc0d6cb29..244d9b96a12060f9438120bf55da8fccfa069296 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 3f6012b549ca74e56fc5c756cfae9001d1ecc2c4..05bc75a64f76691f5610005fc97828aaece011a4 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 92655445a47d96710e988c08bfde3b7563a21a3c..be4dbf762a5e4be943bad6f47c8f18768477284b 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 d792767c4f6a44b9c13b2b632e7836b47ccfec22..0443a19c3cb299f21aea777bd2ecfa28cc63ab0b 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 9394727e2188f9f4e2f5dce03bf48cf2138a583e..e5fe26a3dd5dbcd3f407812e68c96253563e8b6c 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 b833d1dbed16f310caa5d9f9cc0cd964cf87ea61..6e1d3e716553e353133d259b4b40fb200f8fabea 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 54aed38e99683458822e1ffc1e08575fda8de8a8..704a9b5ad9193689cf0e01ee6e4d94bc7fb3f936 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 4535bf1281a7a6fd6c2571926aa1daddcab2a2bb..45c145139f9ae5ee5a7f5eb0f642731128e39b30 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 c05e4c5cc1c202d5de2b4b1c9086632bdd056eed..ea9f6895a235b9692b46e9194d12098cbcf38b3b 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 2ee70818e57fb51ab48f3ed7dc80b5df28a2da6b..bff900e58d2ca2b9e86ed319903c5a5f8745941d 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 b3519bbd6c1a8da449f3943641d3ff2ac368aebe..3b99f7b6372fdc050eb88ca8e63c9147c7246b7a 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 ba6e08e31dafeb292a670359928c8845637253b2..4f5d731445148978ffea00929da3236fc1b7c927 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 b23082c49dec267dfc0c967a8c9b4f32b81ff92e..9ceccee1140fb40bdeca77fe6b3f2a2c3961ee10 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 aade0ac41d3cb15dc7deca25b5ef6582cbc2abdc..07f74aed277d4091d7822a25332e6c96bd5f3d4b 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 887d3c273c63c7e24380fb20b86e24455077b05c..8213eb8b9cca00d663ccb2463408e101669d4712 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 e6f2d934a082df74ab2e4aec138a5de7ff0006b3..7d54d177ad724c1847d22df29bab3eb3b0a2aadb 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 9b948b13e546d17eb103ed58b61f876b5603b35f..ae8e1b43cd8e6897c48dd93573475cc9605dbfd7 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'&#39;id&#39;: &#39;{}&#39;'.format(self.TEST_THREAD_ID))
-        self.assertRegex(html, u'&#39;title&#39;: &#39;{}&#39;'.format(self.TEST_THREAD_TEXT))
-        self.assertRegex(html, u'&#39;body&#39;: &#39;{}&#39;'.format(self.TEST_THREAD_TEXT))
-        if six.PY2:
-            self.assertRegex(html, u'&#39;username&#39;: u&#39;{}&#39;'.format(self.student.username))
-        else:
-            self.assertRegex(html, u'&#39;username&#39;: &#39;{}&#39;'.format(self.student.username))
+        self.assertRegex(html, f'&#39;id&#39;: &#39;{self.TEST_THREAD_ID}&#39;')
+        self.assertRegex(html, f'&#39;title&#39;: &#39;{self.TEST_THREAD_TEXT}&#39;')
+        self.assertRegex(html, f'&#39;body&#39;: &#39;{self.TEST_THREAD_TEXT}&#39;')
+        self.assertRegex(html, f'&#39;username&#39;: &#39;{self.student.username}&#39;')
 
     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 2fbedfb3e5bba9da3e044054eba88a715e9dcaed..472b9b997e2499c6cc458a32459cd76fb4c015b9 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