Source code for compass.plugin.utilities

"""COMPASS plugin utilities"""

from warnings import warn

from compass.exceptions import COMPASSPluginConfigurationError
from compass.warn import COMPASSPluginConfigurationWarning


_ORDINANCE_WEBSITE_KEYWORDS = {
    "planning",
    "plan",
    "government",
    "zoning",
    "land",
    "municipal",
    "department",
}


[docs] def normalize_website_keywords(raw): """Normalize website keyword tiers or legacy score mappings Parameters ---------- raw : dict or list The raw website keywords, either as a dictionary of scores or a list of keyword tiers. Returns ------- dict A normalized dictionary of website keywords with scores. """ if isinstance(raw, dict): keywords = _augment_website_keywords(raw) elif isinstance(raw, list): keywords = _keyword_weights_from_tiers(raw) else: msg = ( "Website keywords must be a dictionary of scores or a list of " "keyword tiers." ) raise COMPASSPluginConfigurationError(msg) _warn_if_ordinance_website_keywords_are_missing(keywords) return keywords
def _keyword_weights_from_tiers(tiers): """Compute flat keyword scores from ordered keyword tiers""" if not tiers: msg = "Website keywords must contain at least one keyword tier." raise COMPASSPluginConfigurationError(msg) expanded_tiers = [] known_keywords = set() for tier_ind, tier in enumerate(tiers, start=1): expanded = _expand_website_keyword_tier(tier, tier_ind) collisions = known_keywords.intersection(expanded) if collisions: msg = ( "Website keyword tiers must not contain duplicate keywords " f"or URL variants: {sorted(collisions)}." ) raise COMPASSPluginConfigurationError(msg) known_keywords.update(expanded) expanded_tiers.append(expanded) keywords = {} weight = 1 for tier in reversed(expanded_tiers): keywords.update(dict.fromkeys(tier, weight)) weight *= len(tier) + 1 return keywords def _expand_website_keyword_tier(tier, tier_ind): """Expand and validate one website keyword tier""" if isinstance(tier, str): tier = [tier] if not isinstance(tier, list) or not tier: msg = ( f"Website keyword tier {tier_ind} must be a non-empty list " "or string." ) raise COMPASSPluginConfigurationError(msg) expanded = {} for keyword in tier: if not isinstance(keyword, str) or not keyword.strip(): msg = ( f"Website keyword tier {tier_ind} must contain " "non-empty strings." ) raise COMPASSPluginConfigurationError(msg) variants = _augment_website_keywords({keyword: None}) collisions = set(expanded).intersection(variants) if collisions: msg = ( "Website keyword tiers must not contain duplicate keywords " f"or URL variants: {sorted(collisions)}." ) raise COMPASSPluginConfigurationError(msg) expanded.update(variants) return expanded def _warn_if_ordinance_website_keywords_are_missing(keywords): """Warn when ordinance-oriented crawl keywords are absent""" missing = _ORDINANCE_WEBSITE_KEYWORDS - set(keywords) if not missing: return msg = ( "Website keywords are missing ordinance-oriented terms: " f"{sorted(missing)}. These keywords help push link prioritization " "toward ordinance documents. Add the missing keywords to silence " "this warning. If they are intentionally excluded, set their scores " "to 0 in a flat score mapping so they have no influence." ) warn(msg, COMPASSPluginConfigurationWarning) def _augment_website_keywords(keywords): """Add URL-encoded variants for multi-word keywords""" augmented = dict(keywords) for keyword, score in list(augmented.items()): if not isinstance(keyword, str): continue if " " not in keyword: continue encoded = keyword.replace(" ", "%20") if encoded not in augmented: augmented[encoded] = score plus_encoded = keyword.replace(" ", "+") if plus_encoded not in augmented: augmented[plus_encoded] = score return augmented