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

74 statements  

1from __future__ import annotations 

2 

3from icalendar.parser_tools import to_unicode 

4 

5from collections import OrderedDict 

6 

7from typing import Any, Optional, Iterable, Mapping, TypeVar 

8 

9try: 

10 from typing import Self 

11except ImportError: 

12 from typing_extensions import Self 

13 

14KT = TypeVar("KT") 

15VT = TypeVar("VT") 

16 

17def canonsort_keys(keys: Iterable[KT], canonical_order: Optional[Iterable[KT]] = None) -> list[KT]: 

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

19 canonical_order will appear alphabetically at the end. 

20 """ 

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

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

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

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

25 

26 

27def canonsort_items(dict1: Mapping[KT, VT], canonical_order: Optional[Iterable[KT]] = None) -> list[tuple[KT, VT]]: 

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

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

30 

31 

32class CaselessDict(OrderedDict): 

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

34 Values retain their case. 

35 """ 

36 

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

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

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

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

41 key_upper = to_unicode(key).upper() 

42 if key != key_upper: 

43 super().__delitem__(key) 

44 self[key_upper] = value 

45 

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

47 key = to_unicode(key) 

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

49 

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

51 key = to_unicode(key) 

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

53 

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

55 key = to_unicode(key) 

56 super().__delitem__(key.upper()) 

57 

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

59 key = to_unicode(key) 

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

61 

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

63 key = to_unicode(key) 

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

65 

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

67 key = to_unicode(key) 

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

69 

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

71 key = to_unicode(key) 

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

73 

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

75 return super().popitem() 

76 

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

78 key = to_unicode(key) 

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

80 

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

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

83 mappings = list(args) + [kwargs] 

84 for mapping in mappings: 

85 if hasattr(mapping, "items"): 

86 mapping = iter(mapping.items()) 

87 for key, value in mapping: 

88 self[key] = value 

89 

90 def copy(self) -> Self: 

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

92 

93 def __repr__(self) -> str: 

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

95 

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

97 if not isinstance(other, dict): 

98 return NotImplemented 

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

100 

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

102 return not self == other 

103 

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

105 # must be uppercase. 

106 canonical_order = None 

107 

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

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

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

111 """ 

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

113 

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

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

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

117 """ 

118 return canonsort_items(self, self.canonical_order) 

119 

120 

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