Skip to content

Commit eae9403

Browse files
developer0hyeclaude
andcommitted
fix(analyzer): register KrPassportRecognizer and align its default language
KrPassportRecognizer was the only Korean recognizer absent from default_recognizers.yaml, for two reasons that also kept it out of the predefined registry. RecognizerListLoader.get instantiates every predefined recognizer with a name keyword argument, taken from the YAML entry (or from name when class_name supplies the class). KrPassportRecognizer.__init__ did not accept it, so listing the recognizer in default_recognizers.yaml made the registry raise TypeError on load. Adding the argument is what makes the entry possible. Its default supported_language was kr, while every other Korean recognizer defaults to ko, the ISO 639-1 code. #1742 migrated the Korean recognizers from kr to ko; #1814 added this one afterwards and reintroduced kr, so an AnalyzerEngine running ko silently skipped it. The default is now ko. This only affects direct instantiation: when an entry omits supported_languages the loader passes the registry's language explicitly, so the class default never applies on the YAML path. Registers the recognizer with enabled: false and country_code: kr, matching its siblings, and covers all three points with tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e069216 commit eae9403

3 files changed

Lines changed: 74 additions & 8 deletions

File tree

presidio-analyzer/presidio_analyzer/conf/default_recognizers.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,14 @@ recognizers:
311311
enabled: false
312312
country_code: kr
313313

314+
- name: KrPassportRecognizer
315+
supported_languages:
316+
- ko
317+
- kr
318+
type: predefined
319+
enabled: false
320+
country_code: kr
321+
314322
- name: SeOrganisationsnummerRecognizer
315323
supported_languages:
316324
- sv

presidio-analyzer/presidio_analyzer/predefined_recognizers/country_specific/korea/kr_passport_recognizer.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,9 @@ def __init__(
4848
self,
4949
patterns: Optional[List[Pattern]] = None,
5050
context: Optional[List[str]] = None,
51-
supported_language: str = "kr",
51+
supported_language: str = "ko",
5252
supported_entity: str = "KR_PASSPORT",
53+
name: Optional[str] = None,
5354
):
5455
patterns = patterns if patterns else self.PATTERNS
5556
context = context if context else self.CONTEXT
@@ -58,4 +59,5 @@ def __init__(
5859
patterns=patterns,
5960
context=context,
6061
supported_language=supported_language,
62+
name=name,
6163
)

presidio-analyzer/tests/test_kr_passport_recognizer.py

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1+
import copy
2+
import tempfile
3+
from pathlib import Path
4+
5+
import presidio_analyzer
16
import pytest
7+
import yaml
8+
from presidio_analyzer.predefined_recognizers.country_specific.korea.kr_passport_recognizer import (
9+
KrPassportRecognizer,
10+
)
11+
from presidio_analyzer.recognizer_registry import RecognizerRegistryProvider
212

313
from tests import assert_result_within_score_range
4-
from presidio_analyzer.predefined_recognizers.country_specific.korea.kr_passport_recognizer import KrPassportRecognizer
14+
515

616
@pytest.fixture(scope="module")
717
def recognizer():
@@ -25,18 +35,18 @@ def entities():
2535
("My passport number is M123A4567", 1, ((22, 31),), ((0.1, 0.1),)),
2636
("Korean passport: M456B7890", 1, ((17, 26),), ((0.1, 0.1),)),
2737
("여권번호는 M789C1234입니다", 1, ((6, 15),), ((0.1, 0.1),)),
28-
38+
2939
# Valid previous format passports (M + 8 digits)
3040
("M12345678", 1, ((0, 9),), ((0.05, 0.05),)),
3141
("m87654321", 1, ((0, 9),), ((0.05, 0.05),)),
3242
("d11223344", 1, ((0, 9),), ((0.05, 0.05),)),
3343
("s99887766", 1, ((0, 9),), ((0.05, 0.05),)),
3444
("My old passport M12345678", 1, ((16, 25),), ((0.05, 0.05),)),
3545
("대한민국 여권 S87654321", 1, ((8, 17),), ((0.05, 0.05),)),
36-
46+
3747
# Multiple passport numbers
3848
("M123A4567 and M456B7890", 2, ((0, 9), (14, 23)), ((0.1, 0.1), (0.1, 0.1))),
39-
49+
4050
# Invalid formats - should not match
4151
("A123B4567", 0, (), ()), # Wrong first letter
4252
("M12A4567", 0, (), ()), # Too few digits before letter
@@ -69,7 +79,7 @@ def test_when_all_passports_then_succeed(
6979
assert len(results) == expected_len
7080
for res, (st_pos, fn_pos), (st_score, fn_score) in zip(
7181
results, expected_positions, expected_score_ranges
72-
):
82+
):
7383
print(f"res: {res}, st_pos: {st_pos}, fn_pos: {fn_pos}, st_score: {st_score}, fn_score: {fn_score}")
7484
if fn_score == "max":
7585
fn_score = max_score
@@ -104,7 +114,53 @@ def test_when_no_passport_then_no_results(recognizer, entities):
104114
"M123456789", # Too long for old format
105115
"123A4567", # Missing M prefix
106116
]
107-
117+
108118
for text in invalid_texts:
109119
results = recognizer.analyze(text, entities)
110-
assert len(results) == 0, f"Expected no results for text: {text}"
120+
assert len(results) == 0, f"Expected no results for text: {text}"
121+
122+
123+
def test_default_supported_language_is_ko():
124+
"""Default language must be ``ko``, like the other Korean recognizers.
125+
126+
It was previously ``kr``, which registered the recognizer under a language
127+
code that an AnalyzerEngine running ``ko`` never queried.
128+
"""
129+
assert KrPassportRecognizer().supported_language == "ko"
130+
131+
132+
def test_accepts_name_kwarg():
133+
"""Constructor must accept the ``name`` kwarg the YAML loader passes.
134+
135+
Without it, loading the recognizer from a registry YAML raises
136+
``TypeError``, which is why it could not be listed there before.
137+
"""
138+
recognizer = KrPassportRecognizer(name="CustomKrPassport")
139+
assert recognizer.name == "CustomKrPassport"
140+
141+
142+
@pytest.mark.parametrize("language", ["ko", "kr"])
143+
def test_loads_from_default_recognizers_yaml(language):
144+
"""Recognizer is registered in the default YAML and loads once enabled."""
145+
conf = (
146+
Path(presidio_analyzer.__file__).parent
147+
/ "conf"
148+
/ "default_recognizers.yaml"
149+
)
150+
recognizers = yaml.safe_load(conf.read_text())["recognizers"]
151+
entries = [r for r in recognizers if r.get("name") == "KrPassportRecognizer"]
152+
assert len(entries) == 1, "KrPassportRecognizer missing from YAML"
153+
entry = entries[0]
154+
assert entry["country_code"] == "kr"
155+
assert language in entry["supported_languages"]
156+
157+
entry = copy.deepcopy(entry)
158+
entry["enabled"] = True
159+
tmp = Path(tempfile.mkdtemp()) / "conf.yaml"
160+
tmp.write_text(
161+
yaml.safe_dump({"supported_languages": [language], "recognizers": [entry]})
162+
)
163+
provider = RecognizerRegistryProvider(conf_file=str(tmp))
164+
registry = provider.create_recognizer_registry()
165+
entities = {e for rec in registry.recognizers for e in rec.supported_entities}
166+
assert "KR_PASSPORT" in entities

0 commit comments

Comments
 (0)