Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/icalendar/caselessdict.py: 69%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

77 statements  

1from __future__ import annotations 

2 

3from collections import OrderedDict 

4from typing import TYPE_CHECKING, Any, TypeVar 

5 

6from icalendar.parser_tools import to_unicode 

7 

8if TYPE_CHECKING: 

9 from collections.abc import Iterable, Mapping 

10 

11try: 

12 from typing import Self 

13except ImportError: 

14 from typing_extensions import Self 

15 

16KT = TypeVar("KT") 

17VT = TypeVar("VT") 

18 

19 

20def canonsort_keys( 

21 keys: Iterable[KT], canonical_order: Iterable[KT] | None = None 

22) -> list[KT]: 

23 """Sorts leading keys according to canonical_order. Keys not specified in 

24 canonical_order will appear alphabetically at the end. 

25 """ 

26 canonical_map = {k: i for i, k in enumerate(canonical_order or [])} 

27 head = [k for k in keys if k in canonical_map] 

28 tail = [k for k in keys if k not in canonical_map] 

29 return sorted(head, key=lambda k: canonical_map[k]) + sorted(tail) 

30 

31 

32def canonsort_items( 

33 dict1: Mapping[KT, VT], canonical_order: Iterable[KT] | None = None 

34) -> list[tuple[KT, VT]]: 

35 """Returns a list of items from dict1, sorted by canonical_order.""" 

36 return [(k, dict1[k]) for k in canonsort_keys(dict1.keys(), canonical_order)] 

37 

38 

39class CaselessDict(OrderedDict): 

40 """A dictionary that isn't case sensitive, and only uses strings as keys. 

41 Values retain their case. 

42 """ 

43 

44 def __init__(self, *args: Any, **kwargs: Any) -> None: 

45 """Set keys to upper for initial dict.""" 

46 super().__init__(*args, **kwargs) 

47 for key, value in self.items(): 

48 key_upper = to_unicode(key).upper() 

49 if key != key_upper: 

50 super().__delitem__(key) 

51 self[key_upper] = value 

52 

53 __hash__ = None 

54 

55 def __getitem__(self, key: Any) -> Any: 

56 key = to_unicode(key) 

57 return super().__getitem__(key.upper()) 

58 

59 def __setitem__(self, key: Any, value: Any) -> None: 

60 key = to_unicode(key) 

61 super().__setitem__(key.upper(), value) 

62 

63 def __delitem__(self, key: Any) -> None: 

64 key = to_unicode(key) 

65 super().__delitem__(key.upper()) 

66 

67 def __contains__(self, key: Any) -> bool: 

68 key = to_unicode(key) 

69 return super().__contains__(key.upper()) 

70 

71 def get(self, key: Any, default: Any = None) -> Any: 

72 key = to_unicode(key) 

73 return super().get(key.upper(), default) 

74 

75 def setdefault(self, key: Any, value: Any = None) -> Any: 

76 key = to_unicode(key) 

77 return super().setdefault(key.upper(), value) 

78 

79 def pop(self, key: Any, default: Any = None) -> Any: 

80 key = to_unicode(key) 

81 return super().pop(key.upper(), default) 

82 

83 def popitem(self) -> tuple[Any, Any]: 

84 return super().popitem() 

85 

86 def has_key(self, key: Any) -> bool: 

87 key = to_unicode(key) 

88 return super().__contains__(key.upper()) 

89 

90 def update(self, *args: Any, **kwargs: Any) -> None: 

91 # Multiple keys where key1.upper() == key2.upper() will be lost. 

92 mappings = list(args) + [kwargs] 

93 for mapping in mappings: 

94 if hasattr(mapping, "items"): 

95 mapping = iter(mapping.items()) # noqa: PLW2901 

96 for key, value in mapping: 

97 self[key] = value 

98 

99 def copy(self) -> Self: 

100 return type(self)(super().copy()) 

101 

102 def __repr__(self) -> str: 

103 return f"{type(self).__name__}({dict(self)})" 

104 

105 def __eq__(self, other: object) -> bool: 

106 if not isinstance(other, dict): 

107 return NotImplemented 

108 return self is other or dict(self.items()) == dict(other.items()) 

109 

110 def __ne__(self, other: object) -> bool: 

111 return not self == other 

112 

113 # A list of keys that must appear first in sorted_keys and sorted_items; 

114 # must be uppercase. 

115 canonical_order = None 

116 

117 def sorted_keys(self) -> list[str]: 

118 """Sorts keys according to the canonical_order for the derived class. 

119 Keys not specified in canonical_order will appear at the end. 

120 """ 

121 return canonsort_keys(self.keys(), self.canonical_order) 

122 

123 def sorted_items(self) -> list[tuple[Any, Any]]: 

124 """Sorts items according to the canonical_order for the derived class. 

125 Items not specified in canonical_order will appear at the end. 

126 """ 

127 return canonsort_items(self, self.canonical_order) 

128 

129 

130__all__ = ["CaselessDict", "canonsort_items", "canonsort_keys"]