Coverage for presidio_analyzer / predefined_recognizers / country_specific / italy / it_vat_code.py: 100%

28 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-03-29 09:03 +0000

1from typing import List, Optional, Tuple 

2 

3from presidio_analyzer import EntityRecognizer, Pattern, PatternRecognizer 

4 

5 

6class ItVatCodeRecognizer(PatternRecognizer): 

7 """ 

8 Recognizes Italian VAT code using regex and checksum. 

9 

10 For more information about italian VAT code: 

11 https://en.wikipedia.org/wiki/VAT_identification_number#:~:text=%5B2%5D)-,Italy,-Partita%20IVA 

12 

13 :param patterns: List of patterns to be used by this recognizer 

14 :param context: List of context words to increase confidence in detection 

15 :param supported_language: Language this recognizer supports 

16 :param supported_entity: The entity this recognizer can detect 

17 :param replacement_pairs: List of tuples with potential replacement values 

18 for different strings to be used during pattern matching. 

19 This can allow a greater variety in input, for example by removing dashes or spaces. 

20 """ 

21 

22 # Class variables 

23 PATTERNS = [ 

24 Pattern( 

25 "IT Vat code (piva)", 

26 r"\b([0-9][ _]?){11}\b", 

27 0.1, 

28 ) 

29 ] 

30 

31 CONTEXT = ["piva", "partita iva", "pi"] 

32 

33 def __init__( 

34 self, 

35 patterns: Optional[List[Pattern]] = None, 

36 context: Optional[List[str]] = None, 

37 supported_language: str = "it", 

38 supported_entity: str = "IT_VAT_CODE", 

39 replacement_pairs: Optional[List[Tuple[str, str]]] = None, 

40 name: Optional[str] = None, 

41 version: str = "0.0.1", 

42 ): 

43 self.replacement_pairs = ( 

44 replacement_pairs 

45 if replacement_pairs 

46 else [("-", ""), (" ", ""), ("_", "")] 

47 ) 

48 patterns = patterns if patterns else self.PATTERNS 

49 context = context if context else self.CONTEXT 

50 super().__init__( 

51 supported_entity=supported_entity, 

52 patterns=patterns, 

53 context=context, 

54 supported_language=supported_language, 

55 name=name, 

56 version=version, 

57 ) 

58 

59 def validate_result(self, pattern_text: str) -> bool: 

60 """ 

61 Validate the pattern logic e.g., by running checksum on a detected pattern. 

62 

63 :param pattern_text: the text to validated. 

64 Only the part in text that was detected by the regex engine 

65 :return: A bool indicating whether the validation was successful. 

66 """ 

67 

68 # Pre-processing before validation checks 

69 text = EntityRecognizer.sanitize_value(pattern_text, self.replacement_pairs) 

70 

71 # Edge-case that passes the checksum even though it is not a 

72 # valid italian vat code. 

73 if text == "00000000000": 

74 return False 

75 

76 x = 0 

77 y = 0 

78 

79 for i in range(0, 5): 

80 x += int(text[2 * i]) 

81 tmp_y = int(text[2 * i + 1]) * 2 

82 if tmp_y > 9: 

83 tmp_y = tmp_y - 9 

84 y += tmp_y 

85 

86 t = (x + y) % 10 

87 c = (10 - t) % 10 

88 

89 if c == int(text[10]): 

90 result = True 

91 else: 

92 result = False 

93 

94 return result