Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/astroid/brain/brain_collections.py: 58%

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

38 statements  

1# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html 

2# For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE 

3# Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt 

4 

5from __future__ import annotations 

6 

7from typing import TYPE_CHECKING 

8 

9from astroid.brain.helpers import register_module_extender 

10from astroid.builder import AstroidBuilder, extract_node, parse 

11from astroid.const import PY313_PLUS 

12from astroid.context import InferenceContext 

13from astroid.exceptions import AttributeInferenceError 

14from astroid.manager import AstroidManager 

15from astroid.nodes.scoped_nodes import ClassDef 

16 

17if TYPE_CHECKING: 

18 from astroid import nodes 

19 

20 

21def _collections_transform(): 

22 return parse( 

23 """ 

24 class defaultdict(dict): 

25 default_factory = None 

26 def __missing__(self, key): pass 

27 def __getitem__(self, key): return default_factory 

28 

29 """ 

30 + _deque_mock() 

31 + _ordered_dict_mock() 

32 ) 

33 

34 

35def _collections_abc_313_transform() -> nodes.Module: 

36 """See https://github.com/python/cpython/pull/124735""" 

37 return AstroidBuilder(AstroidManager()).string_build( 

38 "from _collections_abc import *" 

39 ) 

40 

41 

42def _deque_mock(): 

43 base_deque_class = """ 

44 class deque(object): 

45 maxlen = 0 

46 def __init__(self, iterable=None, maxlen=None): 

47 self.iterable = iterable or [] 

48 def append(self, x): pass 

49 def appendleft(self, x): pass 

50 def clear(self): pass 

51 def count(self, x): return 0 

52 def extend(self, iterable): pass 

53 def extendleft(self, iterable): pass 

54 def pop(self): return self.iterable[0] 

55 def popleft(self): return self.iterable[0] 

56 def remove(self, value): pass 

57 def reverse(self): return reversed(self.iterable) 

58 def rotate(self, n=1): return self 

59 def __iter__(self): return self 

60 def __reversed__(self): return self.iterable[::-1] 

61 def __getitem__(self, index): return self.iterable[index] 

62 def __setitem__(self, index, value): pass 

63 def __delitem__(self, index): pass 

64 def __bool__(self): return bool(self.iterable) 

65 def __nonzero__(self): return bool(self.iterable) 

66 def __contains__(self, o): return o in self.iterable 

67 def __len__(self): return len(self.iterable) 

68 def __copy__(self): return deque(self.iterable) 

69 def copy(self): return deque(self.iterable) 

70 def index(self, x, start=0, end=0): return 0 

71 def insert(self, i, x): pass 

72 def __add__(self, other): pass 

73 def __iadd__(self, other): pass 

74 def __mul__(self, other): pass 

75 def __imul__(self, other): pass 

76 def __rmul__(self, other): pass 

77 @classmethod 

78 def __class_getitem__(self, item): return cls""" 

79 return base_deque_class 

80 

81 

82def _ordered_dict_mock(): 

83 base_ordered_dict_class = """ 

84 class OrderedDict(dict): 

85 def __reversed__(self): return self[::-1] 

86 def move_to_end(self, key, last=False): pass 

87 @classmethod 

88 def __class_getitem__(cls, item): return cls""" 

89 return base_ordered_dict_class 

90 

91 

92def _looks_like_subscriptable(node: ClassDef) -> bool: 

93 """ 

94 Returns True if the node corresponds to a ClassDef of the Collections.abc module 

95 that supports subscripting. 

96 

97 :param node: ClassDef node 

98 """ 

99 if node.qname().startswith("_collections") or node.qname().startswith( 

100 "collections" 

101 ): 

102 try: 

103 node.getattr("__class_getitem__") 

104 return True 

105 except AttributeInferenceError: 

106 pass 

107 return False 

108 

109 

110CLASS_GET_ITEM_TEMPLATE = """ 

111@classmethod 

112def __class_getitem__(cls, item): 

113 return cls 

114""" 

115 

116 

117def easy_class_getitem_inference(node, context: InferenceContext | None = None): 

118 # Here __class_getitem__ exists but is quite a mess to infer thus 

119 # put an easy inference tip 

120 func_to_add = extract_node(CLASS_GET_ITEM_TEMPLATE) 

121 node.locals["__class_getitem__"] = [func_to_add] 

122 

123 

124def register(manager: AstroidManager) -> None: 

125 register_module_extender(manager, "collections", _collections_transform) 

126 

127 # Starting with Python39 some objects of the collection module are subscriptable 

128 # thanks to the __class_getitem__ method but the way it is implemented in 

129 # _collection_abc makes it difficult to infer. (We would have to handle AssignName inference in the 

130 # getitem method of the ClassDef class) Instead we put here a mock of the __class_getitem__ method 

131 manager.register_transform( 

132 ClassDef, easy_class_getitem_inference, _looks_like_subscriptable 

133 ) 

134 

135 if PY313_PLUS: 

136 register_module_extender( 

137 manager, "collections.abc", _collections_abc_313_transform 

138 )