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
« 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.
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)
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
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
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]
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.
49 This class is generic. A subclass of ``BaseMetadataProvider[T]`` will
50 provider metadata of type ``T``.
51 """
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]
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
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
74 def _gen(
75 self, wrapper: "MetadataWrapper"
76 ) -> Mapping["CSTNode", MaybeLazyMetadataT]:
77 """
78 Resolves and returns metadata mapping for the module in ``wrapper``.
80 This method is used by the metadata resolver and should not be called
81 directly.
82 """
84 self._computed = {}
85 # Resolve metadata dependencies for this provider
86 with self.resolve(wrapper):
87 self._gen_impl(wrapper.module)
89 # Copy into a mapping proxy to ensure immutability
90 return MappingProxyType(dict(self._computed))
92 def _gen_impl(self, module: "Module") -> None:
93 """
94 Override this method with a metadata computation implementation.
95 """
96 ...
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
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
126 return super().get_metadata(key, node, default)
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`.
134 This class is generic. A subclass of ``VisitorMetadataProvider[T]`` will
135 provider metadata of type ``T``.
136 """
138 def _gen_impl(self, module: "_ModuleT") -> None:
139 module.visit(self)
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`.
151 This class is generic. A subclass of ``BatchableMetadataProvider[T]`` will
152 provider metadata of type ``T``.
153 """
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