Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/libcst/metadata/base_provider.py: 48%

46 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:43 +0000

1# Copyright (c) Meta Platforms, Inc. and affiliates. 

2# 

3# This source code is licensed under the MIT license found in the 

4# LICENSE file in the root directory of this source tree. 

5 

6from pathlib import Path 

7from types import MappingProxyType 

8from typing import ( 

9 Callable, 

10 Generic, 

11 List, 

12 Mapping, 

13 MutableMapping, 

14 Optional, 

15 Type, 

16 TYPE_CHECKING, 

17 TypeVar, 

18 Union, 

19) 

20 

21from libcst._batched_visitor import BatchableCSTVisitor 

22from libcst._metadata_dependent import ( 

23 _T as _MetadataT, 

24 _UNDEFINED_DEFAULT, 

25 LazyValue, 

26 MetadataDependent, 

27) 

28from libcst._visitors import CSTVisitor 

29 

30if TYPE_CHECKING: 

31 from libcst._nodes.base import CSTNode 

32 from libcst._nodes.module import _ModuleSelfT as _ModuleT, Module 

33 from libcst.metadata.wrapper import MetadataWrapper 

34 

35 

36ProviderT = Type["BaseMetadataProvider[object]"] 

37# BaseMetadataProvider[int] would be a subtype of BaseMetadataProvider[object], so the 

38# typevar is covariant. 

39_ProvidedMetadataT = TypeVar("_ProvidedMetadataT", covariant=True) 

40MaybeLazyMetadataT = Union[LazyValue[_ProvidedMetadataT], _ProvidedMetadataT] 

41 

42 

43# We can't use an ABCMeta here, because of metaclass conflicts 

44class BaseMetadataProvider(MetadataDependent, Generic[_ProvidedMetadataT]): 

45 """ 

46 The low-level base class for all metadata providers. This class should be 

47 extended for metadata providers that are not visitor-based. 

48 

49 This class is generic. A subclass of ``BaseMetadataProvider[T]`` will 

50 provider metadata of type ``T``. 

51 """ 

52 

53 #: Cache of metadata computed by this provider 

54 # 

55 # N.B. This has some typing variance problems. See `set_metadata` for an 

56 # explanation. 

57 _computed: MutableMapping["CSTNode", MaybeLazyMetadataT] 

58 

59 #: Implement gen_cache to indicate the metadata provider depends on cache from external 

60 #: system. This function will be called by :class:`~libcst.metadata.FullRepoManager` 

61 #: to compute required cache object per file path. 

62 gen_cache: Optional[Callable[[Path, List[str], int], Mapping[str, object]]] = None 

63 

64 def __init__(self, cache: object = None) -> None: 

65 super().__init__() 

66 self._computed: MutableMapping["CSTNode", MaybeLazyMetadataT] = {} 

67 if self.gen_cache and cache is None: 

68 # The metadata provider implementation is responsible to store and use cache. 

69 raise Exception( 

70 f"Cache is required for initializing {self.__class__.__name__}." 

71 ) 

72 self.cache = cache 

73 

74 def _gen( 

75 self, wrapper: "MetadataWrapper" 

76 ) -> Mapping["CSTNode", MaybeLazyMetadataT]: 

77 """ 

78 Resolves and returns metadata mapping for the module in ``wrapper``. 

79 

80 This method is used by the metadata resolver and should not be called 

81 directly. 

82 """ 

83 

84 self._computed = {} 

85 # Resolve metadata dependencies for this provider 

86 with self.resolve(wrapper): 

87 self._gen_impl(wrapper.module) 

88 

89 # Copy into a mapping proxy to ensure immutability 

90 return MappingProxyType(dict(self._computed)) 

91 

92 def _gen_impl(self, module: "Module") -> None: 

93 """ 

94 Override this method with a metadata computation implementation. 

95 """ 

96 ... 

97 

98 def set_metadata(self, node: "CSTNode", value: MaybeLazyMetadataT) -> None: 

99 """ 

100 Record a metadata value ``value`` for ``node``. 

101 """ 

102 self._computed[node] = value 

103 

104 def get_metadata( 

105 self, 

106 key: Type["BaseMetadataProvider[_MetadataT]"], 

107 node: "CSTNode", 

108 default: Union[ 

109 MaybeLazyMetadataT, Type[_UNDEFINED_DEFAULT] 

110 ] = _UNDEFINED_DEFAULT, 

111 ) -> _MetadataT: 

112 """ 

113 The same method as :func:`~libcst.MetadataDependent.get_metadata` except 

114 metadata is accessed from ``self._computed`` in addition to ``self.metadata``. 

115 See :func:`~libcst.MetadataDependent.get_metadata`. 

116 """ 

117 if key is type(self): 

118 if default is not _UNDEFINED_DEFAULT: 

119 ret = self._computed.get(node, default) 

120 else: 

121 ret = self._computed[node] 

122 if isinstance(ret, LazyValue): 

123 return ret() 

124 return ret 

125 

126 return super().get_metadata(key, node, default) 

127 

128 

129class VisitorMetadataProvider(CSTVisitor, BaseMetadataProvider[_ProvidedMetadataT]): 

130 """ 

131 The low-level base class for all non-batchable visitor-based metadata 

132 providers. Inherits from :class:`~libcst.CSTVisitor`. 

133 

134 This class is generic. A subclass of ``VisitorMetadataProvider[T]`` will 

135 provider metadata of type ``T``. 

136 """ 

137 

138 def _gen_impl(self, module: "_ModuleT") -> None: 

139 module.visit(self) 

140 

141 

142class BatchableMetadataProvider( 

143 BatchableCSTVisitor, BaseMetadataProvider[_ProvidedMetadataT] 

144): 

145 """ 

146 The low-level base class for all batchable visitor-based metadata providers. 

147 Batchable providers should be preferred when possible as they are more 

148 efficient to run compared to non-batchable visitor-based providers. 

149 Inherits from :class:`~libcst.BatchableCSTVisitor`. 

150 

151 This class is generic. A subclass of ``BatchableMetadataProvider[T]`` will 

152 provider metadata of type ``T``. 

153 """ 

154 

155 def _gen_impl(self, module: "Module") -> None: 

156 """ 

157 Batchables providers are resolved through _gen_batchable] so no 

158 implementation should be provided in _gen_impl. 

159 """ 

160 pass