Coverage for jsonschema_diff/core/tools/compare.py: 95%
20 statements
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-25 07:00 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-25 07:00 +0000
1from __future__ import annotations
3from types import NoneType
4from typing import TYPE_CHECKING, Any, TypeAlias, cast
6if TYPE_CHECKING: # prevents import cycle
7 from .. import Compare
10COMPARE_RULES_TYPE: TypeAlias = dict[
11 type | tuple[type, type] | str | tuple[str, type, type] | tuple[str, type],
12 type["Compare"],
13]
14"""Mapping *search pattern* → *Compare* subclass."""
17class CompareRules:
18 """Pick an appropriate comparator class according to rule precedence."""
20 # ------------------------------------------------------------------ #
21 # Public helpers
22 # ------------------------------------------------------------------ #
24 @staticmethod
25 def get_comparator_from_values(
26 rules: COMPARE_RULES_TYPE,
27 default: type["Compare"],
28 key: str,
29 old: Any,
30 new: Any,
31 ) -> type["Compare"]:
32 """Wrapper that resolves comparator from **values**."""
33 return CompareRules.get_comparator(rules, default, key, type(old), type(new))
35 @staticmethod
36 def get_comparator(
37 rules: COMPARE_RULES_TYPE,
38 default: type["Compare"],
39 key: str,
40 old: type,
41 new: type,
42 ) -> type["Compare"]:
43 """
44 Resolve a comparator class according to the following lookup order:
46 1. ``(key, old_type, new_type)``
47 2. ``key``
48 3. ``(old_type, new_type)``
49 4. ``old_type`` or ``new_type`` (if one of them is ``NoneType``)
50 5. *default*
52 Parameters
53 ----------
54 rules : dict
55 Precedence map.
56 default : Compare subclass
57 Fallback comparator.
58 key : str
59 Field name.
60 old, new : type
61 Types being compared.
62 """
63 for search in [
64 ((key, old, new)),
65 (key),
66 ((old, new)),
67 ]:
68 tuple_types = rules.get(cast(Any, search), None)
69 if tuple_types is not None:
70 return tuple_types
71 else:
72 if old is NoneType:
73 return rules.get(new, default)
74 elif old is not NoneType or old is new:
75 return rules.get(old, default)
76 else:
77 return default