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

35 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:53 +0000

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 astroid.brain.helpers import register_module_extender 

8from astroid.builder import extract_node, parse 

9from astroid.const import PY39_PLUS 

10from astroid.context import InferenceContext 

11from astroid.exceptions import AttributeInferenceError 

12from astroid.manager import AstroidManager 

13from astroid.nodes.scoped_nodes import ClassDef 

14 

15 

16def _collections_transform(): 

17 return parse( 

18 """ 

19 class defaultdict(dict): 

20 default_factory = None 

21 def __missing__(self, key): pass 

22 def __getitem__(self, key): return default_factory 

23 

24 """ 

25 + _deque_mock() 

26 + _ordered_dict_mock() 

27 ) 

28 

29 

30def _deque_mock(): 

31 base_deque_class = """ 

32 class deque(object): 

33 maxlen = 0 

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

35 self.iterable = iterable or [] 

36 def append(self, x): pass 

37 def appendleft(self, x): pass 

38 def clear(self): pass 

39 def count(self, x): return 0 

40 def extend(self, iterable): pass 

41 def extendleft(self, iterable): pass 

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

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

44 def remove(self, value): pass 

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

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

47 def __iter__(self): return self 

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

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

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

51 def __delitem__(self, index): pass 

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

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

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

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

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

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

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

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

60 def __add__(self, other): pass 

61 def __iadd__(self, other): pass 

62 def __mul__(self, other): pass 

63 def __imul__(self, other): pass 

64 def __rmul__(self, other): pass""" 

65 if PY39_PLUS: 

66 base_deque_class += """ 

67 @classmethod 

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

69 return base_deque_class 

70 

71 

72def _ordered_dict_mock(): 

73 base_ordered_dict_class = """ 

74 class OrderedDict(dict): 

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

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

77 if PY39_PLUS: 

78 base_ordered_dict_class += """ 

79 @classmethod 

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

81 return base_ordered_dict_class 

82 

83 

84register_module_extender(AstroidManager(), "collections", _collections_transform) 

85 

86 

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

88 """ 

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

90 that supports subscripting. 

91 

92 :param node: ClassDef node 

93 """ 

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

95 "collections" 

96 ): 

97 try: 

98 node.getattr("__class_getitem__") 

99 return True 

100 except AttributeInferenceError: 

101 pass 

102 return False 

103 

104 

105CLASS_GET_ITEM_TEMPLATE = """ 

106@classmethod 

107def __class_getitem__(cls, item): 

108 return cls 

109""" 

110 

111 

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

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

114 # put an easy inference tip 

115 func_to_add = extract_node(CLASS_GET_ITEM_TEMPLATE) 

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

117 

118 

119if PY39_PLUS: 

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

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

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

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

124 AstroidManager().register_transform( 

125 ClassDef, easy_class_getitem_inference, _looks_like_subscriptable 

126 )