From 3b80b108771a79544d56f2c7d1f401d3180512e0 Mon Sep 17 00:00:00 2001
From: Tanner Prestegard <tanner.prestegard@ligo.org>
Date: Thu, 18 Jul 2019 10:36:34 -0500
Subject: [PATCH] python 3 compatibility: dict usage

Remove usage of .keys(), .has_key(), and .iteritems(), and
account for the fact that .values() produces an iterator in Python 3.
---
 docs/user_docs/source/rest.rst                      |  2 +-
 gracedb/api/exceptions.py                           |  3 ++-
 gracedb/api/v1/events/views.py                      | 13 +++++++------
 gracedb/api/v1/fields.py                            |  4 ++--
 gracedb/api/v1/main/tests/test_views.py             |  2 +-
 gracedb/api/v1/superevents/filters.py               |  2 +-
 .../api/v1/superevents/tests/test_serializers.py    | 12 ++++++------
 gracedb/core/forms.py                               |  4 ++--
 gracedb/core/middleware/proxy.py                    |  2 +-
 gracedb/events/buildVOEvent.py                      |  2 +-
 .../migrations/0011_add_O2VirgoTest_search.py       |  2 +-
 gracedb/events/models.py                            |  4 ++--
 gracedb/events/serialize.py                         |  6 +++---
 gracedb/events/tests/test_perms.py                  |  2 +-
 gracedb/events/view_logic.py                        | 10 +++++-----
 .../migrations/0005_update_emfollow_accounts.py     |  4 ++--
 .../ligoauth/migrations/0019_update_idq_certs.py    |  4 ++--
 gracedb/ligoauth/tests/test_backends.py             |  4 ++--
 .../0016_create_access_and_superevent_groups.py     |  2 +-
 gracedb/migrations/auth/0017_assign_permissions.py  |  4 ++--
 .../guardian/0003_update_emfollow_accounts.py       |  4 ++--
 gracedb/search/constants.py                         |  2 +-
 gracedb/search/query/events.py                      |  4 ++--
 gracedb/search/query/superevents.py                 |  2 +-
 gracedb/search/tests/test_access.py                 | 12 ++++++------
 gracedb/superevents/utils.py                        |  6 +++---
 26 files changed, 60 insertions(+), 58 deletions(-)

diff --git a/docs/user_docs/source/rest.rst b/docs/user_docs/source/rest.rst
index 149588fe3..3f4157fec 100644
--- a/docs/user_docs/source/rest.rst
+++ b/docs/user_docs/source/rest.rst
@@ -81,7 +81,7 @@ If you have reason to believe that your request may be throttled, you can wrap i
         except HTTPError as e:
             try:
                 rdict = json.loads(e.message)
-                if 'retry-after' in rdict.keys():
+                if 'retry-after' in rdict:
                     time.sleep(int(rdict['retry-after']))
                     continue
                 else:
diff --git a/gracedb/api/exceptions.py b/gracedb/api/exceptions.py
index 07c86d032..2716683b8 100644
--- a/gracedb/api/exceptions.py
+++ b/gracedb/api/exceptions.py
@@ -13,7 +13,8 @@ def gracedb_exception_handler(exc, context):
 
     if hasattr(exc, 'detail') and hasattr(exc.detail, 'values'):
         # Combine values into one list
-        exc_out = [item for sublist in exc.detail.values() for item in sublist]
+        exc_out = [item for sublist in list(exc.detail.values())
+                   for item in sublist]
 
         # For only one exception, just print it rather than the list
         if len(exc_out) == 1:
diff --git a/gracedb/api/v1/events/views.py b/gracedb/api/v1/events/views.py
index f2fab2b52..58fc41311 100644
--- a/gracedb/api/v1/events/views.py
+++ b/gracedb/api/v1/events/views.py
@@ -246,7 +246,8 @@ class CoincAccess(Exception):
         return repr(self.detail)
 
 def assembleLigoLw(data):
-    if 'events' in data.keys():
+    # data is a dict
+    if 'events' in data:
         eventDictList = data['events']
     else:
         # There is only one event.
@@ -272,7 +273,7 @@ class LigoLwRenderer(BaseRenderer):
         # XXX If there was an error, we will return the error message
         # in plain text, effectively ignoring the accepts header. 
         # Somewhat irregular?
-        if 'error' in data.keys():
+        if 'error' in data:
             return data['error']
         
         xmldoc = assembleLigoLw(data)
@@ -286,12 +287,12 @@ class TSVRenderer(BaseRenderer):
     format = 'tsv'
 
     def render(self, data, media_type=None, renderer_context=None):
-        if 'error' in data.keys():
+        if 'error' in data:
             return data['error']
 
         accessFun = {
             "labels" : lambda e: \
-                ",".join(e['labels'].keys()),
+                ",".join(list(e['labels'])),
             "dataurl" : lambda e: e['links']['files'],
         }
         def defaultAccess(e,a):
@@ -957,7 +958,7 @@ class EventLogList(InheritPermissionsAPIView):
         rv = eventLogToDict(logentry, request=request)
         response = Response(rv, status=status.HTTP_201_CREATED)
         response['Location'] = rv['self']
-        #if 'tagWarning' in tw_dict.keys():
+        #if 'tagWarning' in tw_dict:
         #    response['tagWarning'] = tw_dict['tagWarning']
 
         # Issue alert.
@@ -1064,7 +1065,7 @@ class EMObservationList(InheritPermissionsAPIView):
         # XXX Note the following hack.
         # If this JSON information is requested for skymapViewer, use a different
         # representation for backwards compatibility.
-        if 'skymapViewer' in request.query_params.keys():
+        if 'skymapViewer' in request.query_params:
             emo = [ skymapViewerEMObservationToDict(emo, request)
                     for emo in emo_set.iterator() ]
 
diff --git a/gracedb/api/v1/fields.py b/gracedb/api/v1/fields.py
index ebc3ec316..7fc167bc5 100644
--- a/gracedb/api/v1/fields.py
+++ b/gracedb/api/v1/fields.py
@@ -125,8 +125,8 @@ class GenericField(fields.Field):
                 err_msg = self.get_does_not_exist_error(data)
             else:
                 err_msg = '{model} with {lf}={data} does not exist'.format(
-                    model=self.model.__name__, lf=model_dict.keys()[0],
-                    data=model_dict.values()[0]
+                    model=self.model.__name__, lf=list(model_dict)[0],
+                    data=list(model_dict.values())[0]
                 )
             raise exceptions.ValidationError(err_msg)
 
diff --git a/gracedb/api/v1/main/tests/test_views.py b/gracedb/api/v1/main/tests/test_views.py
index 74d8c9810..728d34526 100644
--- a/gracedb/api/v1/main/tests/test_views.py
+++ b/gracedb/api/v1/main/tests/test_views.py
@@ -46,5 +46,5 @@ class TestUserInfoView(GraceDbApiTestBase):
         self.assertEqual(response.status_code, 200)
 
         # Test information
-        self.assertEqual(response.data.keys(), ['username'])
+        self.assertEqual(list(response.data), ['username'])
         self.assertEqual(response.data['username'], 'AnonymousUser')
diff --git a/gracedb/api/v1/superevents/filters.py b/gracedb/api/v1/superevents/filters.py
index cb6a15306..8ff62a004 100644
--- a/gracedb/api/v1/superevents/filters.py
+++ b/gracedb/api/v1/superevents/filters.py
@@ -58,7 +58,7 @@ class SupereventOrderingFilter(filters.OrderingFilter):
         for f in fields:
             prefix = '-' if f.startswith('-') else ''
             f_s = f.lstrip('-')
-            if f_s in self.field_map.keys():
+            if f_s in self.field_map:
                 mapped_fields = self.field_map[f_s]
                 if not isinstance(mapped_fields, list):
                     mapped_fields = [mapped_fields]
diff --git a/gracedb/api/v1/superevents/tests/test_serializers.py b/gracedb/api/v1/superevents/tests/test_serializers.py
index 809d3ea24..939bf64e0 100644
--- a/gracedb/api/v1/superevents/tests/test_serializers.py
+++ b/gracedb/api/v1/superevents/tests/test_serializers.py
@@ -45,12 +45,12 @@ class TestSupereventSerializerViaWeb(SupereventSetup, GraceDbApiTestBase):
         response = self.request_as_user(url, "GET", self.internal_user)
         self.assertEqual(response.status_code, 200)
         # Check data on page
-        response_keys = response.json().keys()
+        response_keys = list(response.json())
         response_links = response.json()['links']
         self.assertIn('preferred_event', response_keys)
         self.assertIn('gw_events', response_keys)
         self.assertIn('em_events', response_keys)
-        self.assertIn('events', response_links.keys())
+        self.assertIn('events', response_links)
 
     def test_lvem_user_get_superevent_detail(self):
         """LV-EM user sees events link and all event graceids"""
@@ -61,12 +61,12 @@ class TestSupereventSerializerViaWeb(SupereventSetup, GraceDbApiTestBase):
         response = self.request_as_user(url, "GET", self.lvem_user)
         self.assertEqual(response.status_code, 200)
         # Check data on page
-        response_keys = response.json().keys()
+        response_keys = list(response.json())
         response_links = response.json()['links']
         self.assertIn('preferred_event', response_keys)
         self.assertIn('gw_events', response_keys)
         self.assertIn('em_events', response_keys)
-        self.assertIn('events', response_links.keys())
+        self.assertIn('events', response_links)
 
     def test_public_user_get_superevent_detail(self):
         """Public user does not see events link or all event graceids"""
@@ -77,9 +77,9 @@ class TestSupereventSerializerViaWeb(SupereventSetup, GraceDbApiTestBase):
         response = self.request_as_user(url, "GET")
         self.assertEqual(response.status_code, 200)
         # Check data on page
-        response_keys = response.json().keys()
+        response_keys = list(response.json())
         response_links = response.json()['links']
         self.assertNotIn('preferred_event', response_keys)
         self.assertNotIn('gw_events', response_keys)
         self.assertNotIn('em_events', response_keys)
-        self.assertNotIn('events', response_links.keys())
+        self.assertNotIn('events', response_links)
diff --git a/gracedb/core/forms.py b/gracedb/core/forms.py
index 45a5e8462..4e49be5bd 100644
--- a/gracedb/core/forms.py
+++ b/gracedb/core/forms.py
@@ -37,8 +37,8 @@ class ModelFormUpdateMixin(forms.ModelForm):
 
         # Insert instance data for missing fields only
         instance_data = self.get_instance_data()
-        for key in self.fields.keys():
-            if not self.data.has_key(key) and instance_data[key]:
+        for key in self.fields:
+            if not key in self.data and instance_data[key]:
                 self.data[key] = instance_data[key]
 
 
diff --git a/gracedb/core/middleware/proxy.py b/gracedb/core/middleware/proxy.py
index 0f989656a..93c05a066 100644
--- a/gracedb/core/middleware/proxy.py
+++ b/gracedb/core/middleware/proxy.py
@@ -11,7 +11,7 @@ class XForwardedForMiddleware(object):
 
     def __call__(self, request):
         # Process request -----------------------------------------------------
-        if request.META.has_key('HTTP_X_FORWARDED_FOR'):
+        if 'HTTP_X_FORWARDED_FOR' in request.META:
             request.META['REMOTE_ADDR'] = \
                 request.META['HTTP_X_FORWARDED_FOR'].split(",")[0].strip()
 
diff --git a/gracedb/events/buildVOEvent.py b/gracedb/events/buildVOEvent.py
index 1ef4f27e3..67b159665 100644
--- a/gracedb/events/buildVOEvent.py
+++ b/gracedb/events/buildVOEvent.py
@@ -59,7 +59,7 @@ def buildVOEvent(event, voevent, request=None):
     if not event.gpstime:
         raise VOEventBuilderException("Cannot build a VOEvent because event has no gpstime.")
 
-    if not voevent.voevent_type in VOEVENT_TYPE_DICT.keys():
+    if not voevent.voevent_type in VOEVENT_TYPE_DICT:
         raise VOEventBuilderException("voevent_type must be preliminary, initial, update, or retraction")
 
     # Let's convert that voevent_type to something nicer looking
diff --git a/gracedb/events/migrations/0011_add_O2VirgoTest_search.py b/gracedb/events/migrations/0011_add_O2VirgoTest_search.py
index 8c625f349..3bb7f6cb3 100644
--- a/gracedb/events/migrations/0011_add_O2VirgoTest_search.py
+++ b/gracedb/events/migrations/0011_add_O2VirgoTest_search.py
@@ -18,7 +18,7 @@ def add_search(apps, schema_editor):
     # Create search
     new_search, created = Search.objects.get_or_create(name=SEARCH['name'])
     if created:
-        for key in SEARCH.keys():
+        for key in SEARCH:
             setattr(new_search, key, SEARCH[key])
         new_search.save()
 
diff --git a/gracedb/events/models.py b/gracedb/events/models.py
index 65e4af1c3..d1f4fa4a5 100644
--- a/gracedb/events/models.py
+++ b/gracedb/events/models.py
@@ -833,8 +833,8 @@ class SingleInspiral(models.Model):
             return cls._field_names
         except AttributeError: pass
         model_field_names = set([ x.name for x in cls._meta.get_fields(include_parents=False) ])
-        ligolw_field_names = set(
-                glue.ligolw.lsctables.SnglInspiralTable.validcolumns.keys())
+        ligolw_field_names = set(list(
+                glue.ligolw.lsctables.SnglInspiralTable.validcolumns))
         cls._field_names = model_field_names.intersection(ligolw_field_names)
         return cls._field_names
 
diff --git a/gracedb/events/serialize.py b/gracedb/events/serialize.py
index 9551517ce..1a40f7cae 100644
--- a/gracedb/events/serialize.py
+++ b/gracedb/events/serialize.py
@@ -39,7 +39,7 @@ H1_detlist = ['H1']
 L1_detlist = ['L1']
 V1_detlist = ['V1']
 
-#this is the subset of SnglInspiralTable.validcolumn.keys() that
+#this is the subset of keys in SnglInspiralTable.validcolumn that
 #are assigned from MBTA coinc triggers
 MBTA_set_keys = ['ifo', 'search', 'end_time', 'end_time_ns', 'mass1', 'mass2',\
                'mchirp', 'mtotal', 'eta', 'snr', 'eff_distance', 'event_id',\
@@ -166,7 +166,7 @@ def populate_omega_tables(datafile, set_keys = Omega_set_keys):
   row.confidence = -log(float(omega_data['probGlitch']))
   cid = lsctables.CoincTable.get_next_id()
   row.coinc_event_id = cid
-  for key in mb_table.validcolumns.keys():
+  for key in mb_table.validcolumns:
       if key not in set_keys:
         setattr(row,key,None)
   mb_table.append(row)
@@ -215,7 +215,7 @@ def populate_cwb_tables(datafile, set_keys=CWB_set_keys):
   row.start_time_ns = st.nanoseconds
   cid = lsctables.CoincTable.get_next_id()
   row.coinc_event_id = cid
-  for key in mb_table.validcolumns.keys():
+  for key in mb_table.validcolumns:
       if key not in set_keys:
         setattr(row,key,None)
   mb_table.append(row)
diff --git a/gracedb/events/tests/test_perms.py b/gracedb/events/tests/test_perms.py
index 61e22e16b..72d14684e 100644
--- a/gracedb/events/tests/test_perms.py
+++ b/gracedb/events/tests/test_perms.py
@@ -50,7 +50,7 @@ def extra_args(user):
     # Need to handle reverse proxy case where headers are used
     # instead of Apache environment variables.
     if settings.USE_X_FORWARDED_HOST:
-        for k in AUTH_DICT.keys():
+        for k in AUTH_DICT:
             AUTH_DICT['HTTP_' + k.upper()] = AUTH_DICT.pop(k)
 
     return AUTH_DICT
diff --git a/gracedb/events/view_logic.py b/gracedb/events/view_logic.py
index 2bfe74d73..8e54e94a4 100644
--- a/gracedb/events/view_logic.py
+++ b/gracedb/events/view_logic.py
@@ -299,28 +299,28 @@ def get_performance_info():
         # Localize so we can compare with aware datetimes
         dt = SERVER_TZ.localize(dt)
         if dt > dt_min:
-            if method not in totals_by_method.keys():
+            if method not in totals_by_method:
                 totals_by_method[method] = 1
                 totals_by_status[method] = {status: 1}
             else:
                 totals_by_method[method] += 1
-                if status not in totals_by_status[method].keys():
+                if status not in totals_by_status[method]:
                     totals_by_status[method][status] = 1
                 else:
                     totals_by_status[method][status] += 1
 
     # Calculate summary information:
     summaries = {}
-    for method in totals_by_method.keys():
+    for method in totals_by_method:
         summaries[method] = {'gt_500': 0, 'btw_300_500': 0}
-        for key in totals_by_status[method].keys():
+        for key in totals_by_status[method]:
             if key >= 500:
                 summaries[method]['gt_500'] += totals_by_status[method][key]
             elif key >= 300:
                 summaries[method]['btw_300_500'] += totals_by_status[method][key]
         # Normalize
         if totals_by_method[method] > 0:
-            for key in summaries[method].keys():
+            for key in summaries[method]:
                 summaries[method][key] = float(summaries[method][key])/totals_by_method[method]
 
     context = {
diff --git a/gracedb/ligoauth/migrations/0005_update_emfollow_accounts.py b/gracedb/ligoauth/migrations/0005_update_emfollow_accounts.py
index f88071fce..ce155144e 100644
--- a/gracedb/ligoauth/migrations/0005_update_emfollow_accounts.py
+++ b/gracedb/ligoauth/migrations/0005_update_emfollow_accounts.py
@@ -49,7 +49,7 @@ def deactivate_old_and_add_new_accounts(apps, schema_editor):
     Group = apps.get_model('auth', 'Group')
 
     # Mark old users as inactive and delete their certificates
-    for username in OLD_ACCOUNTS.keys():
+    for username in OLD_ACCOUNTS:
         user = LocalUser.objects.get(username=username)
         for subject in OLD_ACCOUNTS[username]['certs']:
             cert = user.x509cert_set.get(subject=subject)
@@ -73,7 +73,7 @@ def activate_old_and_remove_new_accounts(apps, schema_editor):
     X509Cert = apps.get_model('ligoauth', 'X509Cert')
 
     # Activate old accounts and add their X509 certificates
-    for username in OLD_ACCOUNTS.keys():
+    for username in OLD_ACCOUNTS:
         user = LocalUser.objects.get(username=username)
         for subject in OLD_ACCOUNTS[username]['certs']:
             cert = user.x509cert_set.create(subject=subject)
diff --git a/gracedb/ligoauth/migrations/0019_update_idq_certs.py b/gracedb/ligoauth/migrations/0019_update_idq_certs.py
index 66a636670..0bb25d3e2 100644
--- a/gracedb/ligoauth/migrations/0019_update_idq_certs.py
+++ b/gracedb/ligoauth/migrations/0019_update_idq_certs.py
@@ -19,7 +19,7 @@ ACCOUNTS = {
 def update_certs(apps, schema_editor):
     User = apps.get_model('auth', 'User')
 
-    for user, certs in ACCOUNTS.iteritems():
+    for user, certs in ACCOUNTS.items():
         # Get user
         user = User.objects.get(username=user)
 
@@ -35,7 +35,7 @@ def revert_certs(apps, schema_editor):
     User = apps.get_model('auth', 'User')
     X509Cert = apps.get_model('ligoauth', 'X509Cert')
 
-    for user, certs in ACCOUNTS.iteritems():
+    for user, certs in ACCOUNTS.items():
         # Get user
         user = User.objects.get(username=user)
 
diff --git a/gracedb/ligoauth/tests/test_backends.py b/gracedb/ligoauth/tests/test_backends.py
index 7a485526a..8505ee8b2 100644
--- a/gracedb/ligoauth/tests/test_backends.py
+++ b/gracedb/ligoauth/tests/test_backends.py
@@ -48,7 +48,7 @@ class TestShibbolethRemoteUserBackend(GraceDbTestBase):
         # Set up request and headers
         request = self.factory.get(self.url)
         for k,v in user_data.items():
-            if settings.SHIB_ATTRIBUTE_MAP.has_key(k):
+            if k in settings.SHIB_ATTRIBUTE_MAP:
                 request.META[settings.SHIB_ATTRIBUTE_MAP[k]] = v
 
         # Pass data to backend
@@ -71,7 +71,7 @@ class TestShibbolethRemoteUserBackend(GraceDbTestBase):
         # Set up request and headers
         request = self.factory.get(self.url)
         for k,v in new_user_data.items():
-            if settings.SHIB_ATTRIBUTE_MAP.has_key(k):
+            if k in settings.SHIB_ATTRIBUTE_MAP:
                 request.META[settings.SHIB_ATTRIBUTE_MAP[k]] = v
 
         # Get initial user data
diff --git a/gracedb/migrations/auth/0016_create_access_and_superevent_groups.py b/gracedb/migrations/auth/0016_create_access_and_superevent_groups.py
index 461952d76..03eae3970 100644
--- a/gracedb/migrations/auth/0016_create_access_and_superevent_groups.py
+++ b/gracedb/migrations/auth/0016_create_access_and_superevent_groups.py
@@ -17,7 +17,7 @@ def add_groups(apps, schema_editor):
     Group = apps.get_model('auth', 'Group')
     User = apps.get_model('auth', 'User')
 
-    for group_name, usernames in GROUPS.iteritems():
+    for group_name, usernames in GROUPS.items():
         g, _ = Group.objects.get_or_create(name=group_name)
         users = User.objects.filter(username__in=usernames)
         g.user_set.add(*users)
diff --git a/gracedb/migrations/auth/0017_assign_permissions.py b/gracedb/migrations/auth/0017_assign_permissions.py
index 3aa26471c..2c8fd59c8 100644
--- a/gracedb/migrations/auth/0017_assign_permissions.py
+++ b/gracedb/migrations/auth/0017_assign_permissions.py
@@ -76,7 +76,7 @@ def add_perms(apps, schema_editor):
     Permission = apps.get_model('auth', 'Permission')
 
     # Add superevent permissions to groups
-    for codename, group_names in SUPEREVENT_PERMS.iteritems():
+    for codename, group_names in SUPEREVENT_PERMS.items():
         p = Permission.objects.get(codename=codename,
             content_type__app_label='superevents')
         groups = Group.objects.filter(name__in=group_names)
@@ -88,7 +88,7 @@ def remove_perms(apps, schema_editor):
     Permission = apps.get_model('auth', 'Permission')
 
     # Add permissions to groups
-    for codename, group_names in SUPEREVENT_PERMS.iteritems():
+    for codename, group_names in SUPEREVENT_PERMS.items():
         p = Permission.objects.get(codename=codename,
             content_type__app_label='superevents')
         groups = Group.objects.filter(name__in=group_names)
diff --git a/gracedb/migrations/guardian/0003_update_emfollow_accounts.py b/gracedb/migrations/guardian/0003_update_emfollow_accounts.py
index 3f799dbfb..68315728c 100644
--- a/gracedb/migrations/guardian/0003_update_emfollow_accounts.py
+++ b/gracedb/migrations/guardian/0003_update_emfollow_accounts.py
@@ -26,7 +26,7 @@ def update_perms(apps, schema_editor):
     ctype = ContentType.objects.get_for_model(Pipeline)
 
     # Remove UOPs from old accounts which allow pipeline population
-    for username, pipelines in OLD_ACCOUNTS.iteritems():
+    for username, pipelines in OLD_ACCOUNTS.items():
         user = LocalUser.objects.get(username=username)
         for pipeline_name in pipelines:
             pipeline = Pipeline.objects.get(name=pipeline_name)
@@ -53,7 +53,7 @@ def revert_perms(apps, schema_editor):
     ctype = ContentType.objects.get_for_model(Pipeline)
 
     # Re-add UOPs to old accounts which allow pipeline population
-    for username, pipelines in OLD_ACCOUNTS.iteritems():
+    for username, pipelines in OLD_ACCOUNTS.items():
         user = LocalUser.objects.get(username=username)
         for pipeline_name in pipelines:
             pipeline = Pipeline.objects.get(name=pipeline_name)
diff --git a/gracedb/search/constants.py b/gracedb/search/constants.py
index 8f5582588..5e0c74c96 100644
--- a/gracedb/search/constants.py
+++ b/gracedb/search/constants.py
@@ -11,7 +11,7 @@ EXPR_OPERATORS = {
     ">": "__gt",
     ">=": "__gte",
 }
-ExpressionOperator = Or(map(Literal, EXPR_OPERATORS.keys()))
+ExpressionOperator = Or(map(Literal, list(EXPR_OPERATORS)))
 ExpressionOperator.setParseAction(lambda toks: EXPR_OPERATORS[toks[0]])
 
 
diff --git a/gracedb/search/query/events.py b/gracedb/search/query/events.py
index 10c5e5b50..6644bb4ca 100644
--- a/gracedb/search/query/events.py
+++ b/gracedb/search/query/events.py
@@ -41,7 +41,7 @@ gpsQ = Optional(Suppress(Keyword("gpstime:"))) + (gpstime^gpstimeRange)
 gpsQ = gpsQ.setParseAction(maybeRange("gpstime"))
 
 # run ids
-runid = Or(map(CaselessLiteral, RUN_MAP.keys())).setName("run id")
+runid = Or(map(CaselessLiteral, list(RUN_MAP))).setName("run id")
 #runidList = OneOrMore(runid).setName("run id list")
 runQ = (Optional(Suppress(Keyword("runid:"))) + runid)
 runQ = runQ.setParseAction(lambda toks: ("gpstime", Q(gpstime__range=
@@ -335,4 +335,4 @@ def parseQuery(s):
     if "id" in d and "hid" in d:
         d["id"] = d["id"] | d["hid"]
         del d["hid"]
-    return reduce(Q.__and__, d.values(), Q())
+    return reduce(Q.__and__, list(d.values()), Q())
diff --git a/gracedb/search/query/superevents.py b/gracedb/search/query/superevents.py
index 2ccaffc3a..d2440ef7e 100644
--- a/gracedb/search/query/superevents.py
+++ b/gracedb/search/query/superevents.py
@@ -96,7 +96,7 @@ parameter_dicts = {
     'runid': {
         'keyword': 'runid',
         'keywordOptional': True,
-        'value': Or(map(CaselessLiteral, RUN_MAP.keys())).setName("run id"),
+        'value': Or(map(CaselessLiteral, list(RUN_MAP))).setName("run id"),
         'doRange': False,
         'parseAction': lambda toks: ("t_0", Q(t_0__range=RUN_MAP[toks[0]])),
     },
diff --git a/gracedb/search/tests/test_access.py b/gracedb/search/tests/test_access.py
index 94625c3bb..25de155a6 100644
--- a/gracedb/search/tests/test_access.py
+++ b/gracedb/search/tests/test_access.py
@@ -182,7 +182,7 @@ class TestEventLatest(EventCreateMixin, GraceDbTestBase):
         # Response status
         self.assertEqual(response.status_code, 200) 
         # Make sure all events are shown
-        self.assertIn('events', response.context.keys())
+        self.assertIn('events', response.context)
         for e in Event.objects.all():
             self.assertIn(e, response.context['events'])
 
@@ -193,7 +193,7 @@ class TestEventLatest(EventCreateMixin, GraceDbTestBase):
         # Response status
         self.assertEqual(response.status_code, 200) 
         # Make sure only exposed events are shown
-        self.assertIn('events', response.context.keys())
+        self.assertIn('events', response.context)
         self.assertIn(self.lvem_event, response.context['events'])
         self.assertEqual(len(response.context['events']), 1)
 
@@ -206,7 +206,7 @@ class TestEventLatest(EventCreateMixin, GraceDbTestBase):
         # Response status
         self.assertEqual(response.status_code, 200) 
         # Make sure only exposed events are shown
-        self.assertIn('events', response.context.keys())
+        self.assertIn('events', response.context)
         self.assertEqual(len(response.context['events']), 0)
 
 
@@ -232,7 +232,7 @@ class TestSupereventLatest(SupereventSetup, GraceDbTestBase):
         # Response status
         self.assertEqual(response.status_code, 200) 
         # Make sure all superevents are shown
-        self.assertIn('superevents', response.context.keys())
+        self.assertIn('superevents', response.context)
         for s in Superevent.objects.all():
             self.assertIn(s, response.context['superevents'])
 
@@ -243,7 +243,7 @@ class TestSupereventLatest(SupereventSetup, GraceDbTestBase):
         # Response status
         self.assertEqual(response.status_code, 200) 
         # Make sure only exposed superevents are shown
-        self.assertIn('superevents', response.context.keys())
+        self.assertIn('superevents', response.context)
         self.assertIn(self.lvem_superevent, response.context['superevents'])
         self.assertIn(self.public_superevent, response.context['superevents'])
         self.assertEqual(len(response.context['superevents']), 2)
@@ -254,6 +254,6 @@ class TestSupereventLatest(SupereventSetup, GraceDbTestBase):
         # Response status
         self.assertEqual(response.status_code, 200) 
         # Make sure only exposed superevents are shown
-        self.assertIn('superevents', response.context.keys())
+        self.assertIn('superevents', response.context)
         self.assertIn(self.public_superevent, response.context['superevents'])
         self.assertEqual(len(response.context['superevents']), 1)
diff --git a/gracedb/superevents/utils.py b/gracedb/superevents/utils.py
index 6422150ce..57a73d836 100644
--- a/gracedb/superevents/utils.py
+++ b/gracedb/superevents/utils.py
@@ -133,7 +133,7 @@ def update_superevent(superevent, updater, add_log_message=True,
     new_params = {k: v for k,v in kwargs.items() if k in param_names}
 
     # Get old parameters
-    old_params = {k: getattr(superevent, k) for k in new_params.keys()}
+    old_params = {k: getattr(superevent, k) for k in new_params}
 
     # Update superevent object
     for k,v in new_params.items():
@@ -145,7 +145,7 @@ def update_superevent(superevent, updater, add_log_message=True,
     superevent_alert_kwargs = {}
     if add_log_message:
         updates = ["{name}: {old} -> {new}".format(name=k, old=old_params[k],
-            new=new_params[k]) for k in new_params.keys()
+            new=new_params[k]) for k in new_params
             if old_params[k] != new_params[k]]
         update_comment = "Updated superevent parameters: {0}".format(
             ", ".join(updates))
@@ -153,7 +153,7 @@ def update_superevent(superevent, updater, add_log_message=True,
             issue_alert=False)
 
         # If preferred event changed, do a few things
-        if new_params.has_key('preferred_event') and \
+        if 'preferred_event' in new_params and \
             (old_params['preferred_event'] != new_params['preferred_event']):
             # Write log for old preferred event
             old_msg = ("Removed as preferred event for superevent: "
-- 
GitLab