From 8ad52c0640f38beb68ea5608a2e51121ed193d05 Mon Sep 17 00:00:00 2001 From: Nick Blumberg Date: Wed, 1 Jul 2026 17:46:48 -0700 Subject: [PATCH 1/2] Reverse best place type selection logic --- server/services/datacommons.py | 18 +++++++++++++----- server/tests/migration_verification_test.py | 8 ++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/server/services/datacommons.py b/server/services/datacommons.py index 9f46d70e57..676ab678bb 100644 --- a/server/services/datacommons.py +++ b/server/services/datacommons.py @@ -17,6 +17,7 @@ import collections import json import logging +import math from typing import Dict, List from flask import current_app @@ -456,18 +457,25 @@ def _get_all_values(resp, dcid, prop, key='dcid'): def _get_best_type(types_list): - """Selects the best type from a list of types based on PLACE_TYPE_RANK.""" + """Selects the best type most specific place type from a list of types. + + Prioritizes types with a lower non-zero rank in PLACE_TYPE_RANK (e.g. City + over State over Place), prioritizes standard names over 'AdministrativeArea' + names, and puts unrecognized types last. + """ if not types_list: return '' - # Sort types by rank (highest rank first) + # Prefer known types over unknown types. + # Within known types, prefer smaller rank (more specific, e.g. City (30) < State (80) < Place (150)) # If ranks are tied, prefer types that don't start with 'AdministrativeArea' def sort_key(t): - rank = PLACE_TYPE_RANK.get(t, 0) + raw_rank = PLACE_TYPE_RANK.get(t, 0) + rank = raw_rank if raw_rank > 0 else math.inf is_admin = 1 if t.startswith('AdministrativeArea') else 0 - return (rank, -is_admin) + return (rank, is_admin) - return sorted(types_list, key=sort_key, reverse=True)[0] + return sorted(types_list, key=sort_key, reverse=False)[0] def get_place_info(dcids: List[str]) -> Dict: diff --git a/server/tests/migration_verification_test.py b/server/tests/migration_verification_test.py index c67c37d3f3..6d83065f74 100644 --- a/server/tests/migration_verification_test.py +++ b/server/tests/migration_verification_test.py @@ -46,6 +46,10 @@ def side_effect(url, data, api_key=None, log_extreme_calls=False): "typeOf": { "nodes": [{ "dcid": "Country" + }, { + "dcid": "Place" + }, { + "dcid": "SomeCustomType" }] } } @@ -55,6 +59,10 @@ def side_effect(url, data, api_key=None, log_extreme_calls=False): "typeOf": { "nodes": [{ "dcid": "State" + }, { + "dcid": "Place" + }, { + "dcid": "SomeOtherCustomType" }] } } From 7e3163d0c07af08791c7a9b8de46a9cd1d939cc5 Mon Sep 17 00:00:00 2001 From: Nick Blumberg Date: Wed, 1 Jul 2026 19:40:21 -0700 Subject: [PATCH 2/2] Simplify type selection in _get_best_type using min() and update docstring --- server/services/datacommons.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/services/datacommons.py b/server/services/datacommons.py index 676ab678bb..0b4a45860b 100644 --- a/server/services/datacommons.py +++ b/server/services/datacommons.py @@ -457,7 +457,7 @@ def _get_all_values(resp, dcid, prop, key='dcid'): def _get_best_type(types_list): - """Selects the best type most specific place type from a list of types. + """Selects the most specific place type from a list of types. Prioritizes types with a lower non-zero rank in PLACE_TYPE_RANK (e.g. City over State over Place), prioritizes standard names over 'AdministrativeArea' @@ -475,7 +475,7 @@ def sort_key(t): is_admin = 1 if t.startswith('AdministrativeArea') else 0 return (rank, is_admin) - return sorted(types_list, key=sort_key, reverse=False)[0] + return min(types_list, key=sort_key) def get_place_info(dcids: List[str]) -> Dict: