Skip to content

load_predefined_recognizers(countries=[...]) can't load country recognizers that ship enabled: false, so countries=["in"] loads none #2467

Open

Description

@abhishek-pandey7

Describe the bug

RecognizerRegistry.load_predefined_recognizers(countries=[...]) can only narrow the recognizers that conf/default_recognizers.yaml already enables. Country-specific recognizers ship with enabled: false, so naming a country does not load them. For 13 countries every recognizer is disabled (au, ca, de, fi, in, kr, ng, ph, se, sg, th, tr, za), and for those countries=[...] loads no country recognizer at all, with no warning.

The docs example says otherwise. docs/analyzer/filtering_by_country.md says countries=["us", "uk"] gives "US- and UK-specific recognizers (US SSN, UK NHS, UK NINO, …)", but UkNinoRecognizer is enabled: false and is not loaded.

To Reproduce

presidio-analyzer from main at 5f5a42e (2.2.366), Python 3.12:

from presidio_analyzer import RecognizerRegistry


def country_recognizers(countries):
    registry = RecognizerRegistry()
    registry.load_predefined_recognizers(languages=["en"], countries=countries)
    return sorted(
        (r.country_code(), r.name) for r in registry.recognizers if r.country_code() is not None
    )


for countries in (["in"], ["us", "uk"], ["au"]):
    found = country_recognizers(countries)
    print(f"countries={countries!r}: {len(found)} country-specific recognizer(s)")
    for code, name in found:
        print(f"    {code}  {name}")
countries=['in']: 0 country-specific recognizer(s)
countries=['us', 'uk']: 7 country-specific recognizer(s)
    uk  NhsRecognizer
    us  MedicalLicenseRecognizer
    us  UsBankRecognizer
    us  UsItinRecognizer
    us  UsLicenseRecognizer
    us  UsPassportRecognizer
    us  UsSsnRecognizer
countries=['au']: 0 country-specific recognizer(s)

Expected behavior

In #2000, which added the filter, the agreed rule was "calling with a country code returns all recognizers with this country value + all recognizers with None". I expected countries=["in"] to load the six India recognizers (InAadhaarRecognizer, InPanRecognizer, …) and countries=["us", "uk"] to include UkNinoRecognizer, as in the docs example.

Additional context

RecognizerListLoader.get skips disabled entries while building the instances (recognizers_loader_utils.py:412 and :439) and applies the country filter to what is left (:466). A country that is named can't bring back a recognizer that was dropped earlier.

The filter was probably more useful when it was added. Since then, CONTRIBUTING has required new country-specific recognizers to ship enabled: false, so each new country makes the gap bigger.

I see two ways to fix it, and I'd like to know which you prefer before I open a PR:

  1. Naming a country enables it. When countries is passed to load_predefined_recognizers, load the named countries' predefined recognizers even if they ship enabled: false. This matches the docs and the rule from feat(analyzer): add optional country filter to load_predefined_recogn… #2000. It changes behavior: anyone already passing countries=["us"] would also get the 9 US recognizers that are disabled today (UsMbiRecognizer, UsNpiRecognizer, AbaRoutingRecognizer, …), which can add false positives. A user's own YAML with an explicit enabled: false should keep winning. Only the shipped defaults would be overridden.
  2. The filter stays narrow-only. Fix the docs example and the docstring to say the filter only narrows what is enabled. Log a warning when a requested country ends up with no recognizers, and point to enabling them in a registry YAML. No change in detection.

I found this while checking which of the existing India recognizers I could use instead of the custom Aadhaar and PAN recognizers in a project that redacts Indian records. I'm happy to send the PR once you pick a direction.

Activity

  1. MaiAditya commented on Nov 12, 2026

    @MaiAditya

    I'd like to pick this up. Option 1 matches docs/analyzer/filtering_by_country.md and the rule from #2000 (a country code returns that country's recognizers plus the locale-agnostic ones), so that's what I have ready:

    • load_predefined_recognizers(countries=[...]) enables the requested countries' predefined recognizers that ship with enabled: false; other countries stay excluded and countries=None is unchanged.
    • It only applies to the shipped default config, so an enabled: false in a user's own YAML still wins.
    • Tests for ["in"] and ["us", "uk"], plus a short note in the filtering docs.

    One side effect to confirm: countries=["us"] would then also load the US recognizers that are disabled by default (e.g. UsMbiRecognizer, UsNpiRecognizer, AbaRoutingRecognizer), which can add false positives. If you'd rather keep the filter narrow-only (option 2), I can do the docs fix and a warning instead. Shall I open the PR?

  2. abhishek-pandey7 commented on Nov 12, 2026

    @abhishek-pandey7
    Author

    Thanks @MaiAditya ! As I mentioned in the issue, I was planning to send the PR for this once a direction is picked, so I'd like to keep it if that's OK. @omri374 , do you prefer option 1 or option 2? I can have a PR up within a few days of your answer.

  3. MaiAditya commented on Nov 12, 2026

    @MaiAditya

    Of course, go ahead. I missed that you'd planned to send it. Happy to review the PR if that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions