diff --git a/contrib/internal/prepare-dev.py b/contrib/internal/prepare-dev.py
index 8770ba95135d09369089e4775ebfdefcac5fe5a1..4b55ef596f030d0526c384f3b9e39f7019302b85 100755
--- a/contrib/internal/prepare-dev.py
+++ b/contrib/internal/prepare-dev.py
@@ -216,7 +216,7 @@ def install_media(site):
     for package_type, package_type_desc in package_types:
         packages = packager.packages[package_type]
 
-        for package_name, package in sorted(six.iteritems(packages),
+        for package_name, package in sorted(packages.items(),
                                             key=lambda pair: pair[0]):
             console.progress_step(
                 'Compiling %s bundle %s' % (package_type_desc,
diff --git a/contrib/internal/webapi-lint.py b/contrib/internal/webapi-lint.py
index 16297b52ae1765657602cc1d9d3ad49cedd43428..1492f67cce8c494f9cd438df3cf4603ced15ecf6 100755
--- a/contrib/internal/webapi-lint.py
+++ b/contrib/internal/webapi-lint.py
@@ -196,7 +196,7 @@ class ResourceLinter(Linter):
                 A string indicating where this list of fields lives,
                 for use in error messages.
         """
-        for field_name, field_info in six.iteritems(fields):
+        for field_name, field_info in fields.items():
             try:
                 field_type = field_info['type']
             except KeyError:
diff --git a/reviewboard/accounts/backends/standard.py b/reviewboard/accounts/backends/standard.py
index 98070901f3e145ee3283c6039baaa55b82f18c42..b56b33a2bdacd7d5a80571806a7f2e38cc485b1a 100644
--- a/reviewboard/accounts/backends/standard.py
+++ b/reviewboard/accounts/backends/standard.py
@@ -8,7 +8,6 @@ from django.conf import settings
 from django.contrib.auth import hashers
 from django.contrib.auth.backends import ModelBackend
 from django.contrib.auth.models import User
-from django.utils import six
 from django.utils.translation import ugettext_lazy as _
 from djblets.db.query import get_object_or_none
 
@@ -149,11 +148,11 @@ class StandardAuthBackend(BaseAuthBackend, ModelBackend):
                     site_perms = site_profile.permissions or {}
 
                     if site_perms:
-                        perm_cache = set([
+                        perm_cache = {
                             key
-                            for key, value in six.iteritems(site_perms)
+                            for key, value in site_perms.items()
                             if value
-                        ])
+                        }
                 except LocalSiteProfile.DoesNotExist:
                     pass
 
diff --git a/reviewboard/admin/forms/auth_settings.py b/reviewboard/admin/forms/auth_settings.py
index f970e88a3d598f9e4a60f474d49b2be03e1e9ac6..eb792870b52b0a6b185a53f6f368b8cebd902037 100644
--- a/reviewboard/admin/forms/auth_settings.py
+++ b/reviewboard/admin/forms/auth_settings.py
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
 import logging
 
 from django import forms
-from django.utils import six
 from django.utils.translation import ugettext_lazy as _
 from djblets.siteconfig.forms import SiteSettingsForm
 
@@ -181,7 +180,7 @@ class AuthenticationSettingsForm(SiteSettingsForm):
             if auth_backend in self.auth_backend_forms:
                 self.auth_backend_forms[auth_backend].full_clean()
         else:
-            for form in six.itervalues(self.auth_backend_forms):
+            for form in self.auth_backend_forms.values():
                 form.full_clean()
 
     class Meta:
diff --git a/reviewboard/admin/forms/general_settings.py b/reviewboard/admin/forms/general_settings.py
index f40d7cb5c5b333be4d774e433a40080fa253585d..51305ef67df1470fdc1228ea6cfd106fe23698bf 100644
--- a/reviewboard/admin/forms/general_settings.py
+++ b/reviewboard/admin/forms/general_settings.py
@@ -8,7 +8,6 @@ from django import forms
 from django.conf import settings
 from django.contrib.sites.models import Site
 from django.core.exceptions import ValidationError
-from django.utils import six
 from django.utils.module_loading import import_string
 from django.utils.six.moves.urllib.parse import urlparse
 from django.utils.translation import (ugettext,
@@ -307,7 +306,7 @@ class GeneralSettingsForm(SiteSettingsForm):
         """
         self.cache_backend_forms = {
             backend_id: backend_info['form_cls'](data=data, files=files)
-            for backend_id, backend_info in six.iteritems(self._cache_backends)
+            for backend_id, backend_info in self._cache_backends.items()
             if backend_info.get('available', True)
         }
 
@@ -339,7 +338,7 @@ class GeneralSettingsForm(SiteSettingsForm):
         cache_backend_path = cache_backend['BACKEND']
         cache_type = 'custom'
 
-        for _cache_type, backend_info in six.iteritems(self._cache_backends):
+        for _cache_type, backend_info in self._cache_backends.items():
             if (cache_backend_path == backend_info['backend_cls_path'] or
                 cache_backend_path in backend_info.get(
                     'legacy_backend_cls_paths', [])):
@@ -348,7 +347,7 @@ class GeneralSettingsForm(SiteSettingsForm):
 
         cache_type_choices = [
             (backend_id, backend_info['name'])
-            for backend_id, backend_info in six.iteritems(self._cache_backends)
+            for backend_id, backend_info in self._cache_backends.items()
             if backend_info.get('available', True)
         ]
 
diff --git a/reviewboard/admin/management/sites.py b/reviewboard/admin/management/sites.py
index 49226af26e4aa7ed252157f3011634891b2a9aa8..23ad4fc815af3235e8e951dc09ee0e08213bd93c 100644
--- a/reviewboard/admin/management/sites.py
+++ b/reviewboard/admin/management/sites.py
@@ -70,7 +70,7 @@ auth_backend_map = {
 def migrate_settings(siteconfig):
     """Migrate any settings we want in the database from the settings file."""
     # Convert everything in the table.
-    for siteconfig_key, setting_data in six.iteritems(migration_table):
+    for siteconfig_key, setting_data in migration_table.items():
         if isinstance(setting_data, dict):
             setting_key = setting_data['key']
             serialize_func = setting_data.get('serialize_func', None)
diff --git a/reviewboard/admin/security_checks.py b/reviewboard/admin/security_checks.py
index 59ce537b1b5f2bb951e4826e5e3352026230765a..9a67c802d8c6cee63c24439616889339583a95a6 100644
--- a/reviewboard/admin/security_checks.py
+++ b/reviewboard/admin/security_checks.py
@@ -8,7 +8,6 @@ from collections import OrderedDict
 from django.conf import settings
 from django.core.files.base import ContentFile
 from django.core.files.storage import FileSystemStorage
-from django.utils import six
 from django.utils.six.moves.urllib.error import HTTPError
 from django.utils.six.moves.urllib.request import urlopen
 from django.utils.translation import ngettext
@@ -415,7 +414,7 @@ class SecurityCheckRunner(object):
         all_test_results = []
         checks = get_security_checks()
 
-        for name, cls in six.iteritems(checks):
+        for name, cls in checks.items():
             check = cls()
 
             check.setUp()
diff --git a/reviewboard/avatars/services.py b/reviewboard/avatars/services.py
index 28a37df843234b96864539ea0b32a44f2617ca6f..a674801b773d2d55130e8d2324310fee12d2ac4a 100644
--- a/reviewboard/avatars/services.py
+++ b/reviewboard/avatars/services.py
@@ -2,7 +2,6 @@
 
 from __future__ import unicode_literals
 
-from django.utils import six
 from django.utils.six.moves.urllib.parse import urlparse
 from djblets.avatars.services import \
     FileUploadService as DjbletsFileUploadService
@@ -38,7 +37,7 @@ class FileUploadService(DjbletsFileUploadService):
 
         return {
             resolution: self._ensure_absolute(url)
-            for resolution, url in six.iteritems(urls)
+            for resolution, url in urls.items()
         }
 
     def _ensure_absolute(self, url):
diff --git a/reviewboard/avatars/templatetags/avatars.py b/reviewboard/avatars/templatetags/avatars.py
index f4a4958eeb72e3e2acca65400cd8cb5dff957c49..f076024a99578efc8198a4ec6b0dff30e51d00f0 100644
--- a/reviewboard/avatars/templatetags/avatars.py
+++ b/reviewboard/avatars/templatetags/avatars.py
@@ -4,7 +4,6 @@ import json
 import logging
 
 from django import template
-from django.utils import six
 from django.utils.html import mark_safe
 
 from reviewboard.avatars import avatar_services
@@ -134,13 +133,8 @@ def avatar_urls(context, user, size, service_id=None):
                       user)
         urls = {}
     else:
-        urls = {
-            resolution: url
-            for resolution, url in six.iteritems(
-                service.get_avatar_urls(request=context['request'],
-                                        user=user,
-                                        size=size)
-            )
-        }
+        urls = service.get_avatar_urls(request=context['request'],
+                                       user=user,
+                                       size=size)
 
     return mark_safe(json.dumps(urls, sort_keys=True))
diff --git a/reviewboard/cmdline/rbsite.py b/reviewboard/cmdline/rbsite.py
index 1637eb81dd00be8d0edd0199a71e64e8f6579bb7..2b6d0d6c0b8e2ce7e04dd6407b4d282900a347f5 100755
--- a/reviewboard/cmdline/rbsite.py
+++ b/reviewboard/cmdline/rbsite.py
@@ -2518,19 +2518,19 @@ class ManageCommand(Command):
 
         indent_len = initial_indent_len + max(
             len(command_name)
-            for topic_commands in six.itervalues(common_commands)
-            for command_name in six.iterkeys(topic_commands)
+            for topic_commands in common_commands.values()
+            for command_name in topic_commands.keys()
         )
 
         initial_indent = ' ' * initial_indent_len
         subsequent_indent = '    %s' % (' ' * indent_len)
         wrap_width = get_console().term_width - (2 * initial_indent_len)
 
-        for topic, topic_commands in sorted(six.iteritems(common_commands),
+        for topic, topic_commands in sorted(common_commands.items(),
                                             key=lambda pair: pair[0]):
             commands_help.append('%s%s:' % (initial_indent, topic))
 
-            for name, help_text in sorted(six.iteritems(topic_commands),
+            for name, help_text in sorted(topic_commands.items(),
                                           key=lambda pair: pair[0]):
                 commands_help.append(textwrap.fill(
                     help_text,
diff --git a/reviewboard/cmdline/tests/test_rbsite.py b/reviewboard/cmdline/tests/test_rbsite.py
index 3c1a126ec55829708dba22825df67be11ae825f1..e52e00e8ab308eadeb2aca74b1f74d7f52be6dd6 100644
--- a/reviewboard/cmdline/tests/test_rbsite.py
+++ b/reviewboard/cmdline/tests/test_rbsite.py
@@ -1002,7 +1002,7 @@ class SiteTests(kgb.SpyAgency, BaseRBSiteTestCase):
         class SettingsLocal(object):
             pass
 
-        for key, value in six.iteritems(stored_settings):
+        for key, value in stored_settings.items():
             setattr(SettingsLocal, key, value)
 
         site = Site(install_dir=self.sitedir2,
@@ -1063,7 +1063,7 @@ class SiteTests(kgb.SpyAgency, BaseRBSiteTestCase):
         class SettingsLocal(object):
             pass
 
-        for key, value in six.iteritems(stored_settings):
+        for key, value in stored_settings.items():
             setattr(SettingsLocal, key, value)
 
         site = Site(install_dir=self.sitedir2,
diff --git a/reviewboard/datagrids/sidebar.py b/reviewboard/datagrids/sidebar.py
index 8cc8ab9a20d97e9879f7b1a49ef7332635bc70e2..da0c57a2080dbafd3c10158ca951734d244dd4b6 100644
--- a/reviewboard/datagrids/sidebar.py
+++ b/reviewboard/datagrids/sidebar.py
@@ -2,7 +2,6 @@
 
 from __future__ import unicode_literals
 
-from django.utils import six
 from django.utils.six.moves.urllib.parse import urlencode
 from djblets.util.compat.django.template.loader import render_to_string
 
@@ -135,7 +134,7 @@ class BaseSidebarItem(object):
             return False
 
         if self.view_args:
-            for key, value in six.iteritems(self.view_args):
+            for key, value in self.view_args.items():
                 if request.GET.get(key) != value:
                     return False
 
diff --git a/reviewboard/diffviewer/diffutils.py b/reviewboard/diffviewer/diffutils.py
index 049f53dda8c3b60aa39af799118d788d173bb068..50efb92bcdb10c48213a4a78495f0e5a36a78e05 100644
--- a/reviewboard/diffviewer/diffutils.py
+++ b/reviewboard/diffviewer/diffutils.py
@@ -2040,7 +2040,7 @@ def get_total_line_counts(files_qs):
     }
 
     for filediff in files_qs:
-        for key, value in six.iteritems(filediff.get_line_counts()):
+        for key, value in filediff.get_line_counts().items():
             if value is not None:
                 if counts[key] is None:
                     counts[key] = value
diff --git a/reviewboard/diffviewer/models/diffset.py b/reviewboard/diffviewer/models/diffset.py
index ead7e83adf809fc7d05fa46b1b571edbe01717cc..3551e28c89142fe89db60f0a8f04a62bc0b74818 100644
--- a/reviewboard/diffviewer/models/diffset.py
+++ b/reviewboard/diffviewer/models/diffset.py
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
 
 from django.core.exceptions import ValidationError
 from django.db import models
-from django.utils import six, timezone
+from django.utils import timezone
 from django.utils.encoding import python_2_unicode_compatible
 from django.utils.translation import ugettext, ugettext_lazy as _
 from djblets.db.fields import JSONField, RelationCounterField
@@ -115,7 +115,7 @@ class DiffSet(models.Model):
 
             missing_commit_ids = set()
 
-            for commit_id, info in six.iteritems(validation_info):
+            for commit_id, info in validation_info.items():
                 if (commit_id not in commits or
                     commits[commit_id].parent_id != info['parent_id']):
                     missing_commit_ids.add(commit_id)
@@ -127,7 +127,7 @@ class DiffSet(models.Model):
                     % ', '.join(missing_commit_ids),
                     code='validation_info')
 
-            for commit_id, commit in six.iteritems(commits):
+            for commit_id, commit in commits.items():
                 if (commit_id not in validation_info or
                     validation_info[commit_id]['parent_id'] !=
                         commit.parent_id):
diff --git a/reviewboard/diffviewer/models/filediff.py b/reviewboard/diffviewer/models/filediff.py
index 5cd9c2ce6648233b45ac71dd869135196561bc88..232bcb86d2bd60042e01d92f21b91918d6683f3f 100644
--- a/reviewboard/diffviewer/models/filediff.py
+++ b/reviewboard/diffviewer/models/filediff.py
@@ -7,7 +7,6 @@ from itertools import chain
 
 from django.db import models
 from django.db.models import Q
-from django.utils import six
 from django.utils.six.moves import range
 from django.utils.encoding import python_2_unicode_compatible
 from django.utils.translation import ugettext_lazy as _
@@ -612,8 +611,8 @@ class FileDiff(models.Model):
                     by_detail = by_dest_file[current.source_file]
                     prev_set = (
                         filediff
-                        for by_commit in six.itervalues(by_detail)
-                        for filediff in six.itervalues(by_commit)
+                        for by_commit in by_detail.values()
+                        for filediff in by_commit.values()
                         if filediff.deleted
                     )
                 except KeyError:
@@ -623,8 +622,7 @@ class FileDiff(models.Model):
                 # FileDiff.
                 try:
                     by_detail = by_dest_file[current.source_file]
-                    prev_set = six.itervalues(
-                        by_detail[current.source_revision])
+                    prev_set = by_detail[current.source_revision].values()
                 except KeyError:
                     # There is no previous FileDiff created by the commit series.
                     break
diff --git a/reviewboard/diffviewer/opcode_generator.py b/reviewboard/diffviewer/opcode_generator.py
index e5d8031999d0e831584cb5d88751b1a29897033c..92dd81746ae8b5356d666752668fa0e5ca5a97be 100644
--- a/reviewboard/diffviewer/opcode_generator.py
+++ b/reviewboard/diffviewer/opcode_generator.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import os
 import re
 
-from django.utils import six
 from django.utils.six.moves import range
 
 from reviewboard.diffviewer.processors import (filter_interdiff_opcodes,
@@ -588,7 +587,7 @@ class DiffOpcodeGenerator(object):
         # problem.
         r_move_range = None
 
-        for iter_move_range in six.itervalues(r_move_ranges):
+        for iter_move_range in r_move_ranges.values():
             if not r_move_range:
                 r_move_range = iter_move_range
             else:
diff --git a/reviewboard/diffviewer/parser.py b/reviewboard/diffviewer/parser.py
index e046022f6604990688ed1cf7f240286872b13133..0711dee5eee995ffebd88e34f3346c4ca11198b4 100644
--- a/reviewboard/diffviewer/parser.py
+++ b/reviewboard/diffviewer/parser.py
@@ -505,7 +505,7 @@ class ParsedDiffFile(object):
         """
         self._warn_old_usage_deprecation()
 
-        for key, value in six.iteritems(items):
+        for key, value in items.items():
             self._deprecated_info[key] = value
             setattr(self, key, value)
 
diff --git a/reviewboard/diffviewer/tests/test_commit_utils.py b/reviewboard/diffviewer/tests/test_commit_utils.py
index 42c33567571b6f531d9a75618f5fe80c4759e84a..2a1cd1c1a607d63c46de5685f80d3ef3bb332435 100644
--- a/reviewboard/diffviewer/tests/test_commit_utils.py
+++ b/reviewboard/diffviewer/tests/test_commit_utils.py
@@ -2,7 +2,6 @@
 
 from __future__ import unicode_literals
 
-from django.utils import six
 from kgb import SpyAgency
 
 from reviewboard.diffviewer.commit_utils import (CommitHistoryDiffEntry,
@@ -732,10 +731,7 @@ class GetBaseAndTipCommitsTests(TestCase):
             base, tip = get_base_and_tip_commits(
                 base_commit_id=1,
                 tip_commit_id=5,
-                commits=[
-                    commit
-                    for commit in six.itervalues(self.commits)
-                ])
+                commits=list(self.commits.values()))
 
         self.assertEqual(self.commits[1], base)
         self.assertEqual(self.commits[5], tip)
@@ -758,10 +754,7 @@ class GetBaseAndTipCommitsTests(TestCase):
         base, tip = get_base_and_tip_commits(
             base_commit_id=7,
             tip_commit_id=5000,
-            commits=[
-                commit
-                for commit in six.itervalues(self.commits)
-            ])
+            commits=list(self.commits.values()))
 
         self.assertIsNone(base)
         self.assertIsNone(tip)
diff --git a/reviewboard/diffviewer/tests/test_filediff.py b/reviewboard/diffviewer/tests/test_filediff.py
index d29fd1adbf2214cd4e59e1d8435b9fda6e9a4336..90c6a8c6bd57485a6417e7c6878078da485389f4 100644
--- a/reviewboard/diffviewer/tests/test_filediff.py
+++ b/reviewboard/diffviewer/tests/test_filediff.py
@@ -4,8 +4,6 @@ from __future__ import unicode_literals
 
 from itertools import chain
 
-from django.utils import six
-
 from reviewboard.diffviewer.models import DiffSet, FileDiff
 from reviewboard.diffviewer.tests.test_diffutils import \
     BaseFileDiffAncestorTests
@@ -364,7 +362,7 @@ class FileDiffAncestorTests(BaseFileDiffAncestorTests):
 
         by_details = self.get_filediffs_by_details()
 
-        for filediff, ancestors in six.iteritems(all_ancestors):
+        for filediff, ancestors in all_ancestors.items():
             rest_ids, minimal_ids = paths[(
                 filediff.commit_id,
                 filediff.source_file,
diff --git a/reviewboard/hostingsvcs/forms.py b/reviewboard/hostingsvcs/forms.py
index 74c5c1e38f23ec9dcfde7d40041f45fd870a662f..25439bdabbd7fa52f168c76f22cd2800d9b11612 100644
--- a/reviewboard/hostingsvcs/forms.py
+++ b/reviewboard/hostingsvcs/forms.py
@@ -3,7 +3,6 @@ from __future__ import unicode_literals
 import logging
 
 from django import forms
-from django.utils import six
 from django.utils.encoding import force_text
 from django.utils.translation import ugettext_lazy as _, ugettext
 
@@ -568,6 +567,6 @@ class HostingServiceForm(_HostingServiceSubFormMixin,
         if repository is None:
             repository = self.repository
 
-        for key, value in six.iteritems(self.cleaned_data):
+        for key, value in self.cleaned_data.items():
             key = self.add_prefix(force_text(key))
             repository.extra_data[key] = value
diff --git a/reviewboard/hostingsvcs/service.py b/reviewboard/hostingsvcs/service.py
index f0cafd565f263b056e6aa5479d0b4cd01a7bfb64..5a9148603a383ca6a4b7203266d9d81e33dc3a66 100644
--- a/reviewboard/hostingsvcs/service.py
+++ b/reviewboard/hostingsvcs/service.py
@@ -148,7 +148,7 @@ class HostingServiceHTTPRequest(object):
         self.headers = {}
 
         if headers:
-            for key, value in six.iteritems(headers):
+            for key, value in headers.items():
                 self.add_header(key, value)
 
         if query:
@@ -159,7 +159,7 @@ class HostingServiceHTTPRequest(object):
             parsed_url[4] = urlencode(
                 OrderedDict(
                     pair
-                    for pair in sorted(six.iteritems(new_query),
+                    for pair in sorted(new_query.items(),
                                        key=lambda pair: pair[0])
                 ),
                 doseq=True)
@@ -399,7 +399,7 @@ class HostingServiceHTTPResponse(object):
 
         new_headers = {}
 
-        for key, value in six.iteritems(headers):
+        for key, value in headers.items():
             if not isinstance(key, str) or not isinstance(value, str):
                 _log_and_raise(
                     request,
@@ -1018,7 +1018,7 @@ class HostingServiceClient(object):
 
             auth_headers = credentials.get('headers') or {}
 
-            for header, value in six.iteritems(auth_headers):
+            for header, value in auth_headers.items():
                 request.add_header(header, value)
 
         return request
@@ -1333,7 +1333,7 @@ class HostingServiceClient(object):
         content_parts = []
 
         if fields:
-            for key, value in sorted(six.iteritems(fields),
+            for key, value in sorted(fields.items(),
                                      key=lambda pair: pair[0]):
                 if isinstance(key, six.text_type):
                     key = key.encode('utf-8')
@@ -1354,7 +1354,7 @@ class HostingServiceClient(object):
                 )
 
         if files:
-            for key, data in sorted(six.iteritems(files),
+            for key, data in sorted(files.items(),
                                     key=lambda pair: pair[0]['filename']):
                 filename = data['filename']
                 content = data['content']
@@ -1952,7 +1952,7 @@ class HostingService(object):
 
         assert tool_name in fields
 
-        for field, value in six.iteritems(fields[tool_name]):
+        for field, value in fields[tool_name].items():
             try:
                 results[field] = value % new_vars
             except KeyError as e:
diff --git a/reviewboard/hostingsvcs/testing/testcases.py b/reviewboard/hostingsvcs/testing/testcases.py
index d29229638e94499553398f372b6798fd4c195366..36a12609f3d14464373d64287f0e5459b331716c 100644
--- a/reviewboard/hostingsvcs/testing/testcases.py
+++ b/reviewboard/hostingsvcs/testing/testcases.py
@@ -175,7 +175,7 @@ class HttpTestContext(object):
             raise failureException('HTTP call %s: headers: %r != %r'
                                    % (index, call.kwargs['headers'], body))
 
-        for key, value in six.iteritems(kwargs):
+        for key, value in kwargs.items():
             if call.kwargs[key] != value:
                 raise failureException('HTTP call %s: %s: %r != %r'
                                        % (index, key, call.kwargs[key], value))
@@ -398,7 +398,7 @@ class HostingServiceTestCase(SpyAgency, TestCase):
                })
         """
         # Validate the paths to make sure payloads are in the right format.
-        for path, path_info in six.iteritems(paths):
+        for path, path_info in paths.items():
             payload = path_info.get('payload')
 
             if payload is not None and not isinstance(payload, bytes):
diff --git a/reviewboard/hostingsvcs/tests/test_codebasehq.py b/reviewboard/hostingsvcs/tests/test_codebasehq.py
index c1ac9b936453f7145f3335e33c098aa6b1b8d76b..f3d885bab83512c24f3c2549cf06515a98957903 100644
--- a/reviewboard/hostingsvcs/tests/test_codebasehq.py
+++ b/reviewboard/hostingsvcs/tests/test_codebasehq.py
@@ -2,8 +2,6 @@
 
 from __future__ import unicode_literals
 
-from django.utils import six
-
 from reviewboard.hostingsvcs.errors import RepositoryError
 from reviewboard.hostingsvcs.testing import HostingServiceTestCase
 from reviewboard.scmtools.crypto_utils import (decrypt_password,
@@ -137,7 +135,7 @@ class CodebaseHQTests(HostingServiceTestCase):
                 'Accept': 'application/xml',
             })
 
-        self.assertEqual(set(six.iterkeys(hosting_account.data)),
+        self.assertEqual(set(hosting_account.data.keys()),
                          {'api_key', 'domain', 'password'})
         self.assertEqual(decrypt_password(hosting_account.data['api_key']),
                          'abc123')
diff --git a/reviewboard/notifications/email/message.py b/reviewboard/notifications/email/message.py
index 477ba4ff5dd4da53410d87b604e6f0bb40dd43be..0d5129ea0a2d6f227a92c36422b56b764719c861 100644
--- a/reviewboard/notifications/email/message.py
+++ b/reviewboard/notifications/email/message.py
@@ -7,7 +7,6 @@ import logging
 from django.conf import settings
 from django.contrib.auth.models import User
 from django.core.urlresolvers import reverse
-from django.utils import six
 from django.utils.datastructures import MultiValueDict
 from djblets.mail.message import EmailMessage as DjbletsEmailMessage
 from djblets.siteconfig.models import SiteConfiguration
@@ -189,7 +188,7 @@ def prepare_base_review_request_mail(user, review_request, subject,
         if not isinstance(extra_headers, MultiValueDict):
             extra_headers = MultiValueDict(
                 (key, [value])
-                for key, value in six.iteritems(extra_headers)
+                for key, value in extra_headers.items()
             )
 
         headers.update(extra_headers)
diff --git a/reviewboard/notifications/tests/test_email_backend.py b/reviewboard/notifications/tests/test_email_backend.py
index 73bd2eb5e801a737559d860bf40c232e998b2e4b..912170949e1be1bdc7be11416ceeb9fbf3c3c6ec 100644
--- a/reviewboard/notifications/tests/test_email_backend.py
+++ b/reviewboard/notifications/tests/test_email_backend.py
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
 from smtplib import SMTP, SMTPDataError
 
 import kgb
-from django.utils import six
 from djblets.mail.message import EmailMessage
 
 from reviewboard.notifications.email.backend import EmailBackend
@@ -86,7 +85,7 @@ class EmailBackendTests(kgb.SpyAgency, TestCase):
 
     def test_is_ses_with_ses(self):
         """Testing EmailBackend.is_ses with Amazon SES SMTP hostname"""
-        for host in six.iterkeys(self.SES_HOSTS):
+        for host in self.SES_HOSTS.keys():
             backend = EmailBackend(host=host)
             self.assertTrue(backend.is_ses,
                             msg='EmailBackend.is_ses failed for %s' % host)
@@ -98,7 +97,7 @@ class EmailBackendTests(kgb.SpyAgency, TestCase):
 
     def test_ses_message_id_domain(self):
         """Testing EmailBackend.ses_message_id_domain"""
-        for mail_host, mail_info in six.iteritems(self.SES_HOSTS):
+        for mail_host, mail_info in self.SES_HOSTS.items():
             backend = EmailBackend(host=mail_host)
             self.assertEqual(backend.ses_message_id_domain,
                              mail_info['msgid_domain'])
@@ -114,7 +113,7 @@ class EmailBackendTests(kgb.SpyAgency, TestCase):
 
         # We're going to run this test for every region, to ensure that
         # there aren't any issues with the differences between regions.
-        for mail_host, mail_info in six.iteritems(self.SES_HOSTS):
+        for mail_host, mail_info in self.SES_HOSTS.items():
             backend = EmailBackend(host=mail_host)
             self.assertTrue(backend.is_ses)
 
diff --git a/reviewboard/notifications/tests/test_email_sending.py b/reviewboard/notifications/tests/test_email_sending.py
index 1a4584de28e9ddba2ec47661d12c1191b064f67b..92ba51e43220bfb38af69c2c2180551a14750a81 100644
--- a/reviewboard/notifications/tests/test_email_sending.py
+++ b/reviewboard/notifications/tests/test_email_sending.py
@@ -9,7 +9,6 @@ from django.contrib.auth.models import User
 from django.core import mail
 from django.core.urlresolvers import clear_url_caches, reverse
 from django.test.utils import override_settings
-from django.utils import six
 from django.utils.datastructures import MultiValueDict
 from django.utils.six.moves import range
 from djblets.mail.testing import DmarcDnsTestsMixin
@@ -92,7 +91,7 @@ class EmailTestHelper(object):
             siteconfig = SiteConfiguration.objects.get_current()
             needs_reload = False
 
-            for key, value in six.iteritems(self.email_siteconfig_settings):
+            for key, value in self.email_siteconfig_settings.items():
                 old_value = siteconfig.get(key)
 
                 if old_value != value:
@@ -115,7 +114,7 @@ class EmailTestHelper(object):
             siteconfig = SiteConfiguration.objects.get_current()
             needs_reload = False
 
-            for key, value in six.iteritems(self._old_email_settings):
+            for key, value in self._old_email_settings.items():
                 self._old_email_settings[key] = siteconfig.get(key)
                 siteconfig.set(key, value)
 
diff --git a/reviewboard/notifications/tests/test_webhooks.py b/reviewboard/notifications/tests/test_webhooks.py
index cad84980944d88946ac42300c5808bf373c4b0d9..c4e725bc4702c3fd65867b162068e8b071befb60 100644
--- a/reviewboard/notifications/tests/test_webhooks.py
+++ b/reviewboard/notifications/tests/test_webhooks.py
@@ -1107,7 +1107,7 @@ class WebHookSignalDispatchTests(SpyAgency, TestCase):
                            six.text_type, OrderedDict))
 
         if type(payload) in (dict, OrderedDict):
-            for key, value in six.iteritems(payload):
+            for key, value in payload.items():
                 if key is not None:
                     self.assertIn(type(key), (bool, int, float, long,
                                               six.text_type))
diff --git a/reviewboard/notifications/webhooks.py b/reviewboard/notifications/webhooks.py
index ca8850e4c502b5b529b4daa50546a6c79d4d9497..1d19c857ece533192d7e4c5ae6c653d3954457d7 100644
--- a/reviewboard/notifications/webhooks.py
+++ b/reviewboard/notifications/webhooks.py
@@ -256,7 +256,7 @@ def normalize_webhook_payload(payload, request, use_string_keys=False):
         elif isinstance(value, dict):
             return OrderedDict(
                 (_normalize_key(dict_key), _normalize_value(dict_value))
-                for dict_key, dict_value in six.iteritems(value)
+                for dict_key, dict_value in value.items()
             )
         elif isinstance(value, (list, tuple)):
             return [
@@ -416,7 +416,7 @@ def dispatch_webhook_event(request, webhook_targets, event, payload):
             if six.PY2:
                 headers = {
                     force_str(key): force_str(value)
-                    for key, value in six.iteritems(headers)
+                    for key, value in headers.items()
                 }
 
             urlopen(Request(url, body, headers))
diff --git a/reviewboard/reviews/builtin_fields.py b/reviewboard/reviews/builtin_fields.py
index d6e02045cee17e3ef2ebb00987ccd80f473fd728..a1beecd6d2e17cba018b4d018ff5e92fed96d48d 100644
--- a/reviewboard/reviews/builtin_fields.py
+++ b/reviewboard/reviews/builtin_fields.py
@@ -225,7 +225,7 @@ class BaseCaptionsField(ReviewRequestPageDataMixin, BaseReviewRequestField):
 
         s = ['<table class="caption-changed">']
 
-        for id_str, caption in six.iteritems(info):
+        for id_str, caption in info.items():
             obj = obj_map[int(id_str)]
 
             s.append(format_html(
@@ -265,7 +265,7 @@ class BaseCaptionsField(ReviewRequestPageDataMixin, BaseReviewRequestField):
                 'new': data[six.text_type(obj.pk)]['new'][0],
                 self.caption_object_field: obj,
             }
-            for obj in self.model.objects.filter(pk__in=six.iterkeys(data))
+            for obj in self.model.objects.filter(pk__in=data.keys())
         ]
 
 
@@ -499,10 +499,10 @@ class OwnerField(BuiltinFieldMixin, BaseEditableField):
         """
         entry = super(OwnerField, self).serialize_change_entry(changedesc)
 
-        return dict(
-            (key, value[0])
-            for key, value in six.iteritems(entry)
-        )
+        return {
+            key: value[0]
+            for key, value in entry.items()
+        }
 
 
 class RepositoryField(BuiltinFieldMixin, BaseReviewRequestField):
diff --git a/reviewboard/reviews/context.py b/reviewboard/reviews/context.py
index b9df81750dd877ec0b08ccc235761f2f1602333b..6ae0d9c954d096a099445f08e97e787a11d4d92a 100644
--- a/reviewboard/reviews/context.py
+++ b/reviewboard/reviews/context.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 from functools import cmp_to_key
 
-from django.utils import six
 from django.utils.translation import ugettext as _
 from django.template.defaultfilters import truncatechars
 from djblets.siteconfig.models import SiteConfiguration
@@ -80,7 +79,7 @@ def comment_counts(user, all_comments, filediff, interfilediff=None):
 
     comments_array = []
 
-    for key, value in six.iteritems(comment_dict):
+    for key, value in comment_dict.items():
         comments_array.append({
             'linenum': key[0],
             'num_lines': key[1],
diff --git a/reviewboard/reviews/detail.py b/reviewboard/reviews/detail.py
index 659856b254fdfe1f665920de379701302b4cdf37..f8f39ace87dd0ed2ede64dcffee93dc58375b40a 100644
--- a/reviewboard/reviews/detail.py
+++ b/reviewboard/reviews/detail.py
@@ -389,10 +389,10 @@ class ReviewRequestPageData(object):
                 review._status_update_cache = None
 
         # Link up all the review body replies.
-        for reply_id, replies in six.iteritems(self.body_top_replies):
+        for reply_id, replies in self.body_top_replies.items():
             self.reviews_by_id[reply_id]._body_top_replies = reversed(replies)
 
-        for reply_id, replies in six.iteritems(self.body_bottom_replies):
+        for reply_id, replies in self.body_bottom_replies.items():
             self.reviews_by_id[reply_id]._body_bottom_replies = \
                 reversed(replies)
 
@@ -428,7 +428,7 @@ class ReviewRequestPageData(object):
                 screenshot._comments = []
 
         if self.reviews:
-            review_ids = list(six.iterkeys(self.reviews_by_id))
+            review_ids = list(self.reviews_by_id.keys())
 
             for model, review_field_name, key, ordering in (
                 (GeneralComment,
diff --git a/reviewboard/reviews/models/review_request.py b/reviewboard/reviews/models/review_request.py
index 94d71210a448d706af02df01ec45cc200c736f4d..bde3e6d966ce05c3358d7c66631087ea8ee9281f 100644
--- a/reviewboard/reviews/models/review_request.py
+++ b/reviewboard/reviews/models/review_request.py
@@ -86,7 +86,7 @@ def fetch_issue_counts(review_request, extra_query=None):
         }
 
         for issue_fields in issue_statuses:
-            for key, comments in six.iteritems(comment_fields):
+            for key, comments in comment_fields.items():
                 issue_opened = issue_fields[key + '__issue_opened']
                 comment_pk = issue_fields[key + '__pk']
 
diff --git a/reviewboard/reviews/views.py b/reviewboard/reviews/views.py
index 968f2a2b3d7d2000893de981e4d377c7611000bf..9ddcf560b495e811e19473b1905f88fa67fac7ba 100644
--- a/reviewboard/reviews/views.py
+++ b/reviewboard/reviews/views.py
@@ -860,7 +860,7 @@ class ReviewRequestUpdatesView(ReviewRequestViewMixin, ETagViewMixin,
         if self.entry_ids:
             entry_classes = []
 
-            for entry_type in six.iterkeys(self.entry_ids):
+            for entry_type in self.entry_ids.keys():
                 entry_cls = entry_registry.get_entry(entry_type)
 
                 if entry_cls:
diff --git a/reviewboard/scmtools/core.py b/reviewboard/scmtools/core.py
index ed36879d80bdd79d2b4c78976a68bb43cb1d5ac6..3d5cce28f1efd3d6042fb2eb724f59c06aed2f2c 100644
--- a/reviewboard/scmtools/core.py
+++ b/reviewboard/scmtools/core.py
@@ -1216,7 +1216,7 @@ class SCMTool(object):
         """
         new_env = {
             force_str(key): force_str(value)
-            for key, value in six.iteritems(env)
+            for key, value in env.items()
         }
 
         if local_site_name:
diff --git a/reviewboard/scmtools/forms.py b/reviewboard/scmtools/forms.py
index 6775dd803def9700bb0897328e4d161af5776cb7..bed72a51c2bdb764948a0d8ed9fe8dcee7ea6bd6 100644
--- a/reviewboard/scmtools/forms.py
+++ b/reviewboard/scmtools/forms.py
@@ -155,10 +155,10 @@ class BaseRepositorySubForm(forms.Form):
             help_texts = getattr(meta, 'help_texts', {})
             labels = getattr(meta, 'labels', {})
 
-            for field_name, help_text in six.iteritems(help_texts):
+            for field_name, help_text in help_texts.items():
                 self.fields[field_name].help_text = help_text
 
-            for field_name, label in six.iteritems(labels):
+            for field_name, label in labels.items():
                 self.fields[field_name].label = label
 
     def get_initial_data(self):
@@ -183,7 +183,7 @@ class BaseRepositorySubForm(forms.Form):
         :py:meth:`get_initial_data`. Subclasses can override this to set
         other fields or state as needed.
         """
-        for key, value in six.iteritems(self.get_initial_data()):
+        for key, value in self.get_initial_data().items():
             self.fields[key].initial = value
 
     def save(self):
@@ -229,7 +229,7 @@ class BaseRepositorySubForm(forms.Form):
         model_fields = set(model_fields or [])
 
         if field_names is None:
-            field_names = six.iterkeys(self.fields)
+            field_names = self.fields.keys()
 
         if norm_key_func is None:
             norm_key_func = self.add_prefix
@@ -316,7 +316,7 @@ class SCMToolSubFormMixin(object):
 
         super(SCMToolSubFormMixin, self).__init__(**kwargs)
 
-        for name, help_text in six.iteritems(scmtool_cls.field_help_text):
+        for name, help_text in scmtool_cls.field_help_text.items():
             if name in self.fields:
                 self.fields[name].help_text = help_text
 
@@ -351,7 +351,7 @@ class SCMToolSubFormMixin(object):
         repository = self.repository
         assert repository is not None
 
-        for key, value in six.iteritems(self.cleaned_data):
+        for key, value in self.cleaned_data.items():
             if key in self._MODEL_FIELDS:
                 setattr(repository, key, value)
             elif key in self._PREFIXLESS_KEYS:
@@ -930,7 +930,7 @@ class RepositoryForm(LocalSiteAwareModelFormMixin, forms.ModelForm):
                 logging.exception('Error loading hosting service %s: %s',
                                   hosting_service_id, e)
 
-        for class_name, cls in six.iteritems(FAKE_HOSTING_SERVICES):
+        for class_name, cls in FAKE_HOSTING_SERVICES.items():
             if class_name not in hosting_services:
                 service_info = self._get_hosting_service_info(cls)
                 service_info['fake'] = True
@@ -992,7 +992,7 @@ class RepositoryForm(LocalSiteAwareModelFormMixin, forms.ModelForm):
 
         # Create placeholders for any SCMTools we want to list that aren't
         # currently installed.
-        for scmtool_id, name in six.iteritems(FAKE_SCMTOOLS):
+        for scmtool_id, name in FAKE_SCMTOOLS.items():
             if scmtool_id not in available_scmtools:
                 scmtool_choices.append((scmtool_id, name))
                 self.scmtool_info[scmtool_id] = {
@@ -1108,16 +1108,16 @@ class RepositoryForm(LocalSiteAwareModelFormMixin, forms.ModelForm):
 
         if with_auth_forms:
             subform_lists += [
-                six.itervalues(self.scmtool_auth_forms),
-                six.itervalues(self.hosting_auth_forms),
+                self.scmtool_auth_forms.values(),
+                self.hosting_auth_forms.values(),
             ]
 
-        subform_lists.append(six.itervalues(self.scmtool_repository_forms))
+        subform_lists.append(self.scmtool_repository_forms.values())
         subform_lists += [
-            six.itervalues(plan_forms)
+            plan_forms.values()
             for plan_forms in chain(
-                six.itervalues(self.hosting_repository_forms),
-                six.itervalues(self.hosting_bug_tracker_forms))
+                self.hosting_repository_forms.values(),
+                self.hosting_bug_tracker_forms.values())
         ]
 
         subforms = chain.from_iterable(subform_lists)
@@ -1701,7 +1701,7 @@ class RepositoryForm(LocalSiteAwareModelFormMixin, forms.ModelForm):
             }, **{
                 # Strip the prefix from each bit of cleaned data in the form.
                 key.replace(form.prefix, ''): value
-                for key, value in six.iteritems(form.cleaned_data)
+                for key, value in form.cleaned_data.items()
             })
 
             try:
@@ -1720,7 +1720,7 @@ class RepositoryForm(LocalSiteAwareModelFormMixin, forms.ModelForm):
 
         # Save the required values for all native fields, so that we can
         # restore them we've changed the values and processed forms.
-        for field in six.itervalues(self.fields):
+        for field in self.fields.values():
             required_values[field] = field.required
 
         if self.data:
@@ -1815,7 +1815,7 @@ class RepositoryForm(LocalSiteAwareModelFormMixin, forms.ModelForm):
         # Undo the required settings above. Now that we're done with them
         # for validation, we want to fix the display so that users don't
         # see the required states change.
-        for field, required in six.iteritems(required_values):
+        for field, required in required_values.items():
             field.required = required
 
     def clean(self):
@@ -2144,7 +2144,7 @@ class RepositoryForm(LocalSiteAwareModelFormMixin, forms.ModelForm):
         extra_data_prefixes_to_remove = tuple(extra_data_prefixes_to_remove)
 
         if extra_data_prefixes_to_remove:
-            for key in list(six.iterkeys(extra_data)):
+            for key in list(extra_data.keys()):
                 if key.startswith(extra_data_prefixes_to_remove):
                     del extra_data[key]
 
diff --git a/reviewboard/scmtools/svn/__init__.py b/reviewboard/scmtools/svn/__init__.py
index 43785d914fc96855393cd1c6ee8a1ba8587e3d7f..1d8a574830cf3486358eb73a0c87e0649962e0ea 100644
--- a/reviewboard/scmtools/svn/__init__.py
+++ b/reviewboard/scmtools/svn/__init__.py
@@ -189,7 +189,7 @@ class SVNTool(SCMTool):
 
                 results += [
                     self._create_branch_from_dirent(name, dirents[name])
-                    for name in sorted(six.iterkeys(dirents))
+                    for name in sorted(dirents.keys())
                 ]
             except Exception as e:
                 raise self.normalize_error(e)
@@ -198,7 +198,7 @@ class SVNTool(SCMTool):
         # catch-all for repositories which do not use the standard layout, and
         # for those that do, will include any additional top-level directories
         # that people may have.
-        for name in sorted(six.iterkeys(root_dirents)):
+        for name in sorted(root_dirents.keys()):
             if name not in ('trunk', 'branches'):
                 results.append(self._create_branch_from_dirent(
                     name, root_dirents[name], default))
diff --git a/reviewboard/scmtools/svn/subvertpy.py b/reviewboard/scmtools/svn/subvertpy.py
index 7dec677889b85f93933a5ec5eda22f6c404a6a45..650ccf540ca8242096917271996fe84b4335f72c 100644
--- a/reviewboard/scmtools/svn/subvertpy.py
+++ b/reviewboard/scmtools/svn/subvertpy.py
@@ -394,7 +394,7 @@ class Client(base.Client):
 
         dirents = self.client.list(norm_path, None, depth)
 
-        for name, dirent in six.iteritems(dirents):
+        for name, dirent in dirents.items():
             if name:
                 result[six.text_type(name)] = {
                     'path': '%s/%s' % (path.strip('/'), name),
diff --git a/reviewboard/scmtools/tests/test_repository_form.py b/reviewboard/scmtools/tests/test_repository_form.py
index b8157c648db35183c732a8ad9bfacaf9e99a6bc2..4486151f204bb46d04e4ff8d120944a84a6e830d 100644
--- a/reviewboard/scmtools/tests/test_repository_form.py
+++ b/reviewboard/scmtools/tests/test_repository_form.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 from django.contrib.auth.models import User
 from django.http import QueryDict
-from django.utils import six
 from kgb import SpyAgency
 
 from reviewboard.hostingsvcs.models import HostingServiceAccount
@@ -787,7 +786,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
     def test_plain_repository_with_prefixed_standard_fields(self):
@@ -822,7 +821,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
         new_repository = form.save()
@@ -884,7 +883,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
         self.assertSpyCalledWith(PerforceTool.check_repository,
@@ -911,7 +910,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
     def test_plain_repository_with_unverified_ssl_cert(self):
@@ -1065,7 +1064,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
         self.assertSpyCalledWith(TestService.check_repository,
@@ -1105,7 +1104,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
     def test_with_hosting_service_new_account_repo_errors(self):
@@ -1135,7 +1134,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
     def test_with_hosting_service_new_account_2fa_code_required(self):
@@ -1166,7 +1165,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
     def test_with_hosting_service_new_account_2fa_code_provided(self):
@@ -1195,7 +1194,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
     def test_with_hosting_service_new_account_missing_fields(self):
@@ -1227,7 +1226,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
     def test_with_hosting_service_self_hosted_and_new_account(self):
@@ -1273,7 +1272,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
 
         # Make sure none of the other auth forms are unhappy. That would be
         # an indicator that we're doing form processing and validation wrong.
-        for auth_form in six.itervalues(form.hosting_auth_forms):
+        for auth_form in form.hosting_auth_forms.values():
             self.assertEqual(auth_form.errors, {})
 
         self.assertSpyCalledWith(SelfHostedTestService.check_repository,
@@ -2374,7 +2373,7 @@ class RepositoryFormTests(SpyAgency, TestCase):
             post_data = QueryDict(mutable=True)
             post_data.update(dict({
                 name: field.initial
-                for name, field in six.iteritems(RepositoryForm.base_fields)
+                for name, field in RepositoryForm.base_fields.items()
             }, **data))
             post_data._mutable = False
         else:
diff --git a/reviewboard/search/forms.py b/reviewboard/search/forms.py
index 1d0d2f52b9926c9dbd1951d6349c8bd4621124e5..b0b07955e60325790956587a11ce0994115a5d99 100644
--- a/reviewboard/search/forms.py
+++ b/reviewboard/search/forms.py
@@ -6,7 +6,6 @@ from collections import OrderedDict
 
 from django import forms
 from django.contrib.auth.models import User
-from django.utils import six
 from django.utils.translation import ugettext_lazy as _
 from haystack.forms import ModelSearchForm
 from haystack.inputs import Raw
@@ -48,7 +47,7 @@ class RBSearchForm(ModelSearchForm):
     model_filter = forms.MultipleChoiceField(
         choices=(
             (filter_id, filter_type['name'])
-            for filter_id, filter_type in six.iteritems(FILTER_TYPES)
+            for filter_id, filter_type in FILTER_TYPES.items()
         ),
         required=False,
     )
diff --git a/reviewboard/search/search_backends/base.py b/reviewboard/search/search_backends/base.py
index 6b1ebc325e8b4948fb36c62bb0ff21ff168d8104..aec7c4fd56bb93061a78a5df058c02325ee40fc5 100644
--- a/reviewboard/search/search_backends/base.py
+++ b/reviewboard/search/search_backends/base.py
@@ -4,7 +4,6 @@ from __future__ import unicode_literals
 
 from django import forms
 from django.core.exceptions import ValidationError
-from django.utils import six
 from django.utils.translation import ugettext as _
 from djblets.siteconfig.models import SiteConfiguration
 from haystack.utils.loading import load_backend
@@ -73,7 +72,7 @@ class SearchBackend(object):
 
         configuration = {
             key: engine_settings.get(key, self.default_settings[key])
-            for key in six.iterkeys(self.default_settings)
+            for key in self.default_settings.keys()
         }
         configuration['ENGINE'] = self.haystack_backend_name
 
@@ -98,7 +97,7 @@ class SearchBackend(object):
 
         engine_settings.update({
             key: value[key]
-            for key in six.iterkeys(self.default_settings)
+            for key in self.default_settings.keys()
             if key in value
         })
 
@@ -118,7 +117,7 @@ class SearchBackend(object):
         """
         return {
             config_key: form_data.get(field_name)
-            for field_name, config_key in six.iteritems(self.form_field_map)
+            for field_name, config_key in self.form_field_map.items()
         }
 
     def get_form_data(self):
@@ -132,7 +131,7 @@ class SearchBackend(object):
 
         return {
             field_name: configuration[config_key]
-            for field_name, config_key in six.iteritems(self.form_field_map)
+            for field_name, config_key in self.form_field_map.items()
         }
 
     def load_haystack_engine(self, **kwargs):
diff --git a/reviewboard/search/signal_processor.py b/reviewboard/search/signal_processor.py
index 498bdfdddae4e2a3d6c167146087892d1f793138..0aa6e8b8aeb0ffb52bb7305a0bf0ca2a64861c93 100644
--- a/reviewboard/search/signal_processor.py
+++ b/reviewboard/search/signal_processor.py
@@ -9,7 +9,6 @@ from functools import partial
 from django.contrib.auth.models import User
 from django.core.exceptions import ObjectDoesNotExist
 from django.db.models.signals import post_delete, post_save, m2m_changed
-from django.utils import six
 from djblets.siteconfig.models import SiteConfiguration
 from haystack.signals import BaseSignalProcessor
 
@@ -96,7 +95,7 @@ class SignalProcessor(BaseSignalProcessor):
             for cls, handler in m2m_changed_signals:
                 self._handlers[(cls, m2m_changed)] = handler
 
-            for (cls, signal), handler in six.iteritems(self._handlers):
+            for (cls, signal), handler in self._handlers.items():
                 signal.connect(handler, sender=cls)
 
             self.is_setup = True
@@ -104,7 +103,7 @@ class SignalProcessor(BaseSignalProcessor):
     def teardown(self):
         """Unregister all signal handlers for this processor."""
         if self.is_setup:
-            for (cls, signal), handler in six.iteritems(self._handlers):
+            for (cls, signal), handler in self._handlers.items():
                 signal.disconnect(handler, sender=cls)
 
             self.is_setup = False
diff --git a/reviewboard/search/views.py b/reviewboard/search/views.py
index 1bd291dbf82ff215d2edd086cb79b746bb9709d0..260073102a98bf9e7ae9047906da28fac9269ed7 100644
--- a/reviewboard/search/views.py
+++ b/reviewboard/search/views.py
@@ -7,7 +7,6 @@ from collections import OrderedDict
 from django.contrib.auth.models import User
 from django.http import HttpResponseRedirect
 from django.shortcuts import render
-from django.utils import six
 from django.utils.six.moves import range
 from haystack.generic_views import SearchView
 from haystack.query import SearchQuerySet
@@ -146,7 +145,7 @@ class RBSearchView(CheckLoginRequiredViewMixin,
             'filter_types': OrderedDict(
                 (filter_id, dict(active=(filter_id in active_filters),
                                  **filter_type))
-                for filter_id, filter_type in six.iteritems(form.FILTER_TYPES)
+                for filter_id, filter_type in form.FILTER_TYPES.items()
             ),
             'hits_returned': len(object_list),
             'last_page_num': paginator.num_pages - 1,
@@ -178,7 +177,7 @@ class RBSearchView(CheckLoginRequiredViewMixin,
         if avatar_services.avatars_enabled:
             show_users = any(
                 filter_type['active'] and User in filter_type['models']
-                for filter_type in six.itervalues(context['filter_types'])
+                for filter_type in context['filter_types'].values()
             )
 
         if show_users:
diff --git a/reviewboard/site/mixins.py b/reviewboard/site/mixins.py
index 8af86732aff80050b77216d5bb99a913c60cdfe5..d337e964c37c1bb7ad870fa2da9b17a7054b0af0 100644
--- a/reviewboard/site/mixins.py
+++ b/reviewboard/site/mixins.py
@@ -7,7 +7,6 @@ import logging
 import django
 from django.contrib.auth.models import User
 from django.db import models
-from django.utils import six
 from django.utils.decorators import method_decorator
 from django.utils.translation import ugettext as _
 from djblets.db.query import get_object_or_none
@@ -183,7 +182,7 @@ class LocalSiteAwareModelFormMixin(object):
         self._queryset_fields = []
         self._patched_local_sites = False
 
-        for field_name, field in six.iteritems(self.fields):
+        for field_name, field in self.fields.items():
             if isinstance(field.widget, RelatedObjectWidget):
                 self._related_obj_fields.append(field)
             elif isinstance(field, ConditionsField):
@@ -290,7 +289,7 @@ class LocalSiteAwareModelFormMixin(object):
         finally:
             # Restore the values so that the original options are available
             # if the form is shown again (due to errors).
-            for obj, (attr, value) in six.iteritems(old_values):
+            for obj, (attr, value) in old_values.items():
                 setattr(obj, attr, value)
 
     def _clean_fields(self):
diff --git a/reviewboard/tests.py b/reviewboard/tests.py
index 9fb37b6682e7aadcfb92f47d0780a48c1035e36d..a666a7c97ce9e676fc0959d454db893e3cbfa6ad 100644
--- a/reviewboard/tests.py
+++ b/reviewboard/tests.py
@@ -4,7 +4,6 @@ from __future__ import unicode_literals
 
 import os
 
-from django.utils import six
 from djblets.staticbundles import (
     PIPELINE_JAVASCRIPT as DJBLETS_PIPELINE_JAVASCRIPT,
     PIPELINE_STYLESHEETS as DJBLETS_PIPELINE_STYLESHEETS)
@@ -28,7 +27,7 @@ class StaticBundlesTests(TestCase):
         """
         missing = set()
 
-        for name, group in six.iteritems(groups):
+        for name, group in groups.items():
             if name in exclude:
                 continue
 
diff --git a/reviewboard/webapi/base.py b/reviewboard/webapi/base.py
index 10b908a228d03a30a126f870059b481d99ea17e7..f28016985f5d5a5217227f5b5b10d07f06ad0e84 100644
--- a/reviewboard/webapi/base.py
+++ b/reviewboard/webapi/base.py
@@ -506,7 +506,7 @@ class WebAPIResource(RBResourceMixin, DjbletsWebAPIResource):
         # Support setting individual keys to simple values. This is the older
         # method of setting JSON data, and is no longer recommended for new
         # clients.
-        for key, value in six.iteritems(fields):
+        for key, value in fields.items():
             if key.startswith('extra_data.'):
                 key = key[EXTRA_DATA_LEN:]
 
@@ -593,7 +593,7 @@ class WebAPIResource(RBResourceMixin, DjbletsWebAPIResource):
         """
         query_str = '&'.join([
             '%s=%s' % (urllib_quote(key), urllib_quote(value))
-            for key, value in six.iteritems(request.GET)
+            for key, value in request.GET.items()
             if key not in SPECIAL_PARAMS
         ])
 
@@ -624,7 +624,7 @@ class WebAPIResource(RBResourceMixin, DjbletsWebAPIResource):
         """
         clone = copy.copy(extra_data)
 
-        for field_name, value in six.iteritems(extra_data):
+        for field_name, value in extra_data.items():
             if parent_path:
                 path = parent_path + (field_name,)
             else:
diff --git a/reviewboard/webapi/mixins.py b/reviewboard/webapi/mixins.py
index fb3bfa779cdb91694a561b3961f8e64efbf9eff9..e1416677ca4720f5360ef0eb7116cea4c309e029 100644
--- a/reviewboard/webapi/mixins.py
+++ b/reviewboard/webapi/mixins.py
@@ -78,7 +78,7 @@ class MarkdownFieldsMixin(object):
             for extra_text_type in self._get_extra_text_types(obj, **kwargs)
         )
 
-        for field, field_info in six.iteritems(self.fields):
+        for field, field_info in self.fields.items():
             if not field_info.get('supports_text_types'):
                 continue
 
@@ -101,7 +101,7 @@ class MarkdownFieldsMixin(object):
                 obj.extra_data = {}
 
             # Work on a copy of extra_data, in case we change it.
-            for field, value in six.iteritems(obj.extra_data.copy()):
+            for field, value in obj.extra_data.copy().items():
                 if not self.get_extra_data_field_supports_markdown(obj, field):
                     continue
 
@@ -111,9 +111,10 @@ class MarkdownFieldsMixin(object):
                 # with the extra text types that should be included in the
                 # payload.
                 if not all_text_types_extra_data:
-                    all_text_types_extra_data = dict(
-                        (k, {}) for k in six.iterkeys(extra_text_type_fields)
-                    )
+                    all_text_types_extra_data = {
+                        _key: {}
+                        for _key in extra_text_type_fields.keys()
+                    }
 
                 # Note that we assume all custom fields are in Markdown by
                 # default. This is to preserve compatibility with older
@@ -123,10 +124,10 @@ class MarkdownFieldsMixin(object):
                     obj, extra_data, all_text_types_extra_data, field,
                     force_text_type, self._extra_data_rich_text_getter)
 
-            for key, values in six.iteritems(all_text_types_extra_data):
+            for key, values in all_text_types_extra_data.items():
                 extra_text_type_fields[key]['extra_data'] = values
 
-        for key, values in six.iteritems(extra_text_type_fields):
+        for key, values in extra_text_type_fields.items():
             data[key + '_text_fields'] = values
 
         return data
diff --git a/reviewboard/webapi/resources/base_comment.py b/reviewboard/webapi/resources/base_comment.py
index 0241a3a6b1d34fd4ca13f6204b75016ac8ca1f83..74f250604769c27cc7e5d07408020870e63733e3 100644
--- a/reviewboard/webapi/resources/base_comment.py
+++ b/reviewboard/webapi/resources/base_comment.py
@@ -43,7 +43,7 @@ class BaseCommentResource(MarkdownFieldsMixin, WebAPIResource):
         },
         'issue_status': {
             'type': ChoiceFieldType,
-            'choices': tuple(six.iterkeys(BaseComment.ISSUE_STRING_TO_STATUS)),
+            'choices': tuple(BaseComment.ISSUE_STRING_TO_STATUS.keys()),
             'description': 'The status of an issue.',
         },
         'public': {
@@ -150,7 +150,7 @@ class BaseCommentResource(MarkdownFieldsMixin, WebAPIResource):
         },
         'issue_status': {
             'type': ChoiceFieldType,
-            'choices': tuple(six.iterkeys(BaseComment.ISSUE_STRING_TO_STATUS)),
+            'choices': tuple(BaseComment.ISSUE_STRING_TO_STATUS.keys()),
             'description': 'The status of an open issue.',
             'added_in': '2.0',
         },
diff --git a/reviewboard/webapi/resources/change.py b/reviewboard/webapi/resources/change.py
index f8b0b3402c66c365e34dc22fbb6b8a7ccee569af..18dddd5800cdfde388cee3c34b7ea75a2af07daa 100644
--- a/reviewboard/webapi/resources/change.py
+++ b/reviewboard/webapi/resources/change.py
@@ -1,6 +1,5 @@
 from __future__ import unicode_literals
 
-from django.utils import six
 from djblets.util.decorators import augment_method_from
 from djblets.webapi.fields import (ChoiceFieldType,
                                    DateTimeFieldType,
@@ -104,7 +103,7 @@ class ChangeResource(MarkdownFieldsMixin, WebAPIResource):
         review_request = obj.review_request.get()
         fields_changed = {}
 
-        for field_name, data in six.iteritems(obj.fields_changed):
+        for field_name, data in obj.fields_changed.items():
             field_cls = get_review_request_field(field_name)
 
             if field_cls:
diff --git a/reviewboard/webapi/resources/hosting_service.py b/reviewboard/webapi/resources/hosting_service.py
index 0e0236ac926ed67c618145db2f4caf3aab503f9a..6a5f3cb222b4334d362d5975bd99d8a26a74036e 100644
--- a/reviewboard/webapi/resources/hosting_service.py
+++ b/reviewboard/webapi/resources/hosting_service.py
@@ -2,7 +2,6 @@ from __future__ import unicode_literals
 
 import inspect
 
-from django.utils import six
 from djblets.db.query import LocalDataQuerySet
 from djblets.util.decorators import augment_method_from
 from djblets.webapi.fields import (BooleanFieldType,
@@ -152,8 +151,8 @@ class HostingServiceResource(WebAPIResource):
                         'required': field.required,
                         'help_text': field.help_text,
                     }
-                    for field_name, field in six.iteritems(
-                        info.get('form', default_form).base_fields)
+                    for field_name, field in
+                        info.get('form', default_form).base_fields.items()
                 },
             }
             for plan_id, info in plans
diff --git a/reviewboard/webapi/resources/oauth_app.py b/reviewboard/webapi/resources/oauth_app.py
index e9a6c8f71d36034df80d04d74512b16570fbba4f..05112d3b9413a56c9d0822e88d06446bd66b22e1 100644
--- a/reviewboard/webapi/resources/oauth_app.py
+++ b/reviewboard/webapi/resources/oauth_app.py
@@ -7,7 +7,6 @@ from itertools import chain
 
 from django.contrib.auth.models import User
 from django.db.models.query import Q
-from django.utils import six
 from django.utils.six.moves import filter
 from django.utils.translation import ugettext_lazy as _
 from djblets.util.decorators import augment_method_from
@@ -394,9 +393,9 @@ class OAuthApplicationResource(UpdateFormMixin, WebAPIResource):
     @webapi_login_required
     @webapi_response_errors(INVALID_FORM_DATA)
     @webapi_request_fields(
-        optional=dict(chain(six.iteritems(CREATE_REQUIRED_FIELDS),
-                            six.iteritems(CREATE_OPTIONAL_FIELDS),
-                            six.iteritems(UPDATE_OPTIONAL_FIELDS))),
+        optional=dict(chain(CREATE_REQUIRED_FIELDS.items(),
+                            CREATE_OPTIONAL_FIELDS.items(),
+                            UPDATE_OPTIONAL_FIELDS.items())),
         allow_unknown=True,
     )
     def update(self, request, parsed_request_fields, extra_fields,
diff --git a/reviewboard/webapi/resources/review_request_draft.py b/reviewboard/webapi/resources/review_request_draft.py
index b0bdaea0493f2488cf95a037c183d96636a73977..2e3a689cb41c45572e5a0c8a2e418198f9b9445b 100644
--- a/reviewboard/webapi/resources/review_request_draft.py
+++ b/reviewboard/webapi/resources/review_request_draft.py
@@ -699,7 +699,7 @@ class ReviewRequestDraftResource(MarkdownFieldsMixin, WebAPIResource):
             # relation values, which we want to set only after the object
             # is saved. Start by setting any field values, and store the
             # M2M values for after.
-            for key, value in six.iteritems(new_values):
+            for key, value in new_values.items():
                 field = obj._meta.get_field(key)
 
                 if isinstance(field, ManyToManyField):
@@ -718,7 +718,7 @@ class ReviewRequestDraftResource(MarkdownFieldsMixin, WebAPIResource):
             # Each entry will have zero or more values. We'll be
             # setting to the list of values, which will fully replace
             # the stored entries in the database.
-            for key, values in six.iteritems(new_m2m_values):
+            for key, values in new_m2m_values.items():
                 setattr(obj, key, values)
 
         # Next, check if the draft is set to be published.
diff --git a/reviewboard/webapi/server_info.py b/reviewboard/webapi/server_info.py
index 081e6d4c9946945b8ff863c6f940dfe19e184262..000085cbb67e39c6889bf2093c1fd3f0937f9d5e 100644
--- a/reviewboard/webapi/server_info.py
+++ b/reviewboard/webapi/server_info.py
@@ -6,7 +6,6 @@ import logging
 from copy import deepcopy
 
 from django.conf import settings
-from django.utils import six
 
 from reviewboard import get_version_string, get_package_version, is_release
 from reviewboard.admin.server import get_server_url
@@ -132,8 +131,8 @@ def get_feature_gated_capabilities(request=None):
         * The capability name (:py:class:`unicode`).
         * Whether or not the capability is enabled (:py:class:`bool`).
     """
-    for category, caps in six.iteritems(_feature_gated_capabilities):
-        for cap, required_feature in six.iteritems(caps):
+    for category, caps in _feature_gated_capabilities.items():
+        for cap, required_feature in caps.items():
             if required_feature.is_enabled(request=request):
                 yield category, cap, True
 
diff --git a/reviewboard/webapi/tests/mixins.py b/reviewboard/webapi/tests/mixins.py
index 42f1594c7633d104a92b7e2eec3e6321603667ca..767df06e294f31c81bcb033aa05e6b60d9d968e3 100644
--- a/reviewboard/webapi/tests/mixins.py
+++ b/reviewboard/webapi/tests/mixins.py
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 from datetime import timedelta
 
 from django.contrib.auth.models import User
-from django.utils import six, timezone
+from django.utils import timezone
 from django.utils.six.moves import range
 from djblets.features.testing import override_feature_checks
 from djblets.testing.decorators import add_fixtures
@@ -165,7 +165,7 @@ class BasicTestsMixin(object):
                                   % self.__class__.__name__)
 
     def _close_file_handles(self, post_data):
-        for value in six.itervalues(post_data):
+        for value in post_data.values():
             if hasattr(value, 'close'):
                 value.close()
 
diff --git a/reviewboard/webapi/tests/test_change.py b/reviewboard/webapi/tests/test_change.py
index ab8fcb602c9cf31469d2cff92c3d91fa760d2090..1802becc97e1b7d2557dc52dfcedfb51eb0c2eeb 100644
--- a/reviewboard/webapi/tests/test_change.py
+++ b/reviewboard/webapi/tests/test_change.py
@@ -168,7 +168,7 @@ class ResourceItemTests(ReviewRequestChildItemMixin, BaseWebAPITestCase):
     def test_get(self):
         """Testing the GET review-requests/<id>/changes/<id>/ API"""
         def write_fields(obj, index):
-            for field, data in six.iteritems(test_data):
+            for field, data in test_data.items():
                 value = data[index]
 
                 if isinstance(value, list) and field not in model_fields:
@@ -238,7 +238,7 @@ class ResourceItemTests(ReviewRequestChildItemMixin, BaseWebAPITestCase):
         change = r.changedescs.get()
         self.assertEqual(change.text, changedesc_text)
 
-        for field, data in six.iteritems(test_data):
+        for field, data in test_data.items():
             old, new, removed, added = data
             field_data = change.fields_changed[field]
 
@@ -295,7 +295,7 @@ class ResourceItemTests(ReviewRequestChildItemMixin, BaseWebAPITestCase):
 
         fields_changed = rsp['change']['fields_changed']
 
-        for field, data in six.iteritems(test_data):
+        for field, data in test_data.items():
             old, new, removed, added = data
 
             self.assertIn(field, fields_changed)
diff --git a/reviewboard/webapi/tests/test_hosting_service.py b/reviewboard/webapi/tests/test_hosting_service.py
index 8c814099fcc073e6015ae8a9cbfd654687b996a2..c342d697f9ec8bb099eb436581bb14bf05861db0 100644
--- a/reviewboard/webapi/tests/test_hosting_service.py
+++ b/reviewboard/webapi/tests/test_hosting_service.py
@@ -1,7 +1,5 @@
 from __future__ import unicode_literals
 
-from django.utils import six
-
 from reviewboard.hostingsvcs.service import (get_hosting_services,
                                              get_hosting_service)
 from reviewboard.webapi.resources import resources
@@ -28,7 +26,7 @@ def _compare_item(self, item_rsp, hosting_service):
                      hosting_service.supported_scmtools)
 
     plans_rsp = item_rsp['plans']
-    plan_keys = set(six.iterkeys(plans_rsp))
+    plan_keys = set(plans_rsp.keys())
 
     if plan_keys == {''}:
         self.assertIsNone(hosting_service.plans)
