mirror of
https://github.com/Instagram/LibCST.git
synced 2025-12-23 10:35:53 +00:00
Add sphinx docs to metadata modules
This commit is contained in:
parent
611f45e596
commit
79f0ebc2a4
8 changed files with 106 additions and 55 deletions
|
|
@ -21,6 +21,7 @@ LibCST
|
|||
parser
|
||||
nodes
|
||||
visitors
|
||||
metadata
|
||||
|
||||
|
||||
Indices and tables
|
||||
|
|
|
|||
16
docs/source/metadata.rst
Normal file
16
docs/source/metadata.rst
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
Metadata
|
||||
========
|
||||
|
||||
.. autoclass:: libcst.BatchableCSTVisitor
|
||||
.. autofunction:: libcst.visit_batched
|
||||
|
||||
.. autoclass:: libcst.BaseMetadataProvider
|
||||
.. autoclass:: libcst.VisitorMetadataProvider
|
||||
.. autoclass:: libcst.BatchableMetadataProvider
|
||||
|
||||
.. autoclass:: libcst._MetadataDepedent
|
||||
|
||||
.. autoclass:: libcst.BasicPositionProvider
|
||||
.. autoclass:: libcst.SyntacticPositionProvider
|
||||
|
||||
.. autoclass:: libcst.MetadataWrapper
|
||||
|
|
@ -185,6 +185,17 @@ from libcst._parser._entrypoints import parse_expression, parse_module, parse_st
|
|||
from libcst._parser._types.config import PartialParserConfig
|
||||
from libcst._removal_sentinel import RemovalSentinel
|
||||
from libcst._visitors import CSTNodeT, CSTTransformer, CSTVisitor, CSTVisitorT
|
||||
from libcst.metadata.base_provider import (
|
||||
BaseMetadataProvider,
|
||||
BatchableMetadataProvider,
|
||||
VisitorMetadataProvider,
|
||||
)
|
||||
from libcst.metadata.dependent import _MetadataDependent
|
||||
from libcst.metadata.position_provider import (
|
||||
BasicPositionProvider,
|
||||
SyntacticPositionProvider,
|
||||
)
|
||||
from libcst.metadata.wrapper import MetadataWrapper
|
||||
|
||||
|
||||
__all__ = [
|
||||
|
|
@ -370,4 +381,11 @@ __all__ = [
|
|||
"ParenthesizedWhitespace",
|
||||
"SimpleWhitespace",
|
||||
"TrailingWhitespace",
|
||||
"BaseMetadataProvider",
|
||||
"BatchableMetadataProvider",
|
||||
"VisitorMetadataProvider",
|
||||
"_MetadataDependent",
|
||||
"BasicPositionProvider",
|
||||
"SyntacticPositionProvider",
|
||||
"MetadataWrapper",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import inspect
|
|||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Callable,
|
||||
Collection,
|
||||
Iterable,
|
||||
List,
|
||||
Mapping,
|
||||
|
|
@ -33,13 +32,17 @@ _VisitorMethodCollection = Mapping[str, List[VisitorMethod]]
|
|||
|
||||
class BatchableCSTVisitor(CSTTypedVisitorFunctions, _MetadataDependent):
|
||||
"""
|
||||
Extend this class for each type of batched operation you want to perform.
|
||||
The low-level base visitor class for traversing a CST as part of a batched
|
||||
set of traversals. This should be used in conjunction with the
|
||||
:func:`~libcst.visit_batched` method or the
|
||||
:func:`~libcst.MetadataWrapper.visit_batched` method to visit a tree.
|
||||
Instances of this class cannot modify the tree.
|
||||
"""
|
||||
|
||||
def get_visitors(self) -> Mapping[str, VisitorMethod]:
|
||||
"""
|
||||
Returns a mapping of all the visit_* and leave_* methods defined by
|
||||
this visitor, excluding all empty stubs.
|
||||
Returns a mapping of all the ``visit_<Type[CSTNode]>`` and ``leave_<Type[CSTNode]>``
|
||||
methods defined by this visitor, excluding all empty stubs.
|
||||
"""
|
||||
|
||||
methods = inspect.getmembers(
|
||||
|
|
@ -60,18 +63,22 @@ class BatchableCSTVisitor(CSTTypedVisitorFunctions, _MetadataDependent):
|
|||
|
||||
def visit_batched(
|
||||
node: CSTNodeT,
|
||||
visitors: Iterable[BatchableCSTVisitor],
|
||||
batchable_visitors: Iterable[BatchableCSTVisitor],
|
||||
before_visit: Optional[VisitorMethod] = None,
|
||||
after_leave: Optional[VisitorMethod] = None,
|
||||
) -> CSTNodeT:
|
||||
"""
|
||||
Returns the result of running all visitors [visitors] over [node].
|
||||
Do a batched traversal over ``node`` with all ``visitors``.
|
||||
|
||||
[before_visit] and [after_leave] are provided as optional hooks to
|
||||
execute before visit_* and after leave_* methods are executed by the
|
||||
batched visitor.
|
||||
``before_visit`` and ``after_leave`` are provided as optional hooks to
|
||||
execute before the ``visit_<Type[CSTNode]>`` and ``leave_<Type[CSTNode]>``
|
||||
methods from each visitor in ``visitor`` are executed by the batched visitor.
|
||||
|
||||
This function does not handle metadata dependency resolution for ``visitors``.
|
||||
See :func:`~libcst.MetadataWrapper.visit_batched` for batched traversal with
|
||||
metadata dependency resolution.
|
||||
"""
|
||||
visitor_methods = _get_visitor_methods(visitors)
|
||||
visitor_methods = _get_visitor_methods(batchable_visitors)
|
||||
batched_visitor = _BatchedCSTVisitor(
|
||||
visitor_methods, before_visit=before_visit, after_leave=after_leave
|
||||
)
|
||||
|
|
@ -81,6 +88,10 @@ def visit_batched(
|
|||
def _get_visitor_methods(
|
||||
batchable_visitors: Iterable[BatchableCSTVisitor]
|
||||
) -> _VisitorMethodCollection:
|
||||
"""
|
||||
Gather all ``visit_<Type[CSTNode]>`` and ``leave_<Type[CSTNode]>`` methods
|
||||
from ``batchabled_visitors``.
|
||||
"""
|
||||
visitor_methods: MutableMapping[str, List[VisitorMethod]] = {}
|
||||
for bv in batchable_visitors:
|
||||
for name, fn in bv.get_visitors().items():
|
||||
|
|
@ -88,17 +99,10 @@ def _get_visitor_methods(
|
|||
return visitor_methods
|
||||
|
||||
|
||||
def _get_visitor_dependencies(
|
||||
batchable_visitors: Iterable[BatchableCSTVisitor]
|
||||
) -> Collection["ProviderT"]:
|
||||
dependencies = set()
|
||||
for visitor in batchable_visitors:
|
||||
dependencies.update(visitor.METADATA_DEPENDENCIES)
|
||||
|
||||
return dependencies
|
||||
|
||||
|
||||
class _BatchedCSTVisitor(CSTVisitor):
|
||||
"""
|
||||
Internal visitor class to perform batched traversal over a tree.
|
||||
"""
|
||||
|
||||
visitor_methods: _VisitorMethodCollection
|
||||
before_visit: Optional[VisitorMethod]
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ _T = TypeVar("_T")
|
|||
# We can't use an ABCMeta here, because of metaclass conflicts
|
||||
class BaseMetadataProvider(_MetadataDependent, Generic[_T]):
|
||||
"""
|
||||
Abstract base class for all metadata providers.
|
||||
The low-level base class for all metadata providers. This class should be
|
||||
extended for metadata providers that are not visitor-based.
|
||||
"""
|
||||
|
||||
# Cache of metadata computed by this provider
|
||||
|
|
@ -51,9 +52,10 @@ class BaseMetadataProvider(_MetadataDependent, Generic[_T]):
|
|||
|
||||
def _gen(self, wrapper: "MetadataWrapper") -> Mapping["CSTNode", _T]:
|
||||
"""
|
||||
Returns metadata mapping for this provider on wrapper.
|
||||
Resolves and returns metadata mapping for the module in ``wrapper``.
|
||||
|
||||
This is a hook for metadata resolver and should not be called directly.
|
||||
This method is used by the metadata resolver and should not be called
|
||||
directly.
|
||||
"""
|
||||
|
||||
self._computed = {}
|
||||
|
|
@ -66,13 +68,13 @@ class BaseMetadataProvider(_MetadataDependent, Generic[_T]):
|
|||
|
||||
def _gen_impl(self, module: "Module") -> None:
|
||||
"""
|
||||
Override this method to compute metadata using set_metadata.
|
||||
Override this method with a metadata computation implementation.
|
||||
"""
|
||||
...
|
||||
|
||||
def set_metadata(self, node: "CSTNode", value: _T) -> None:
|
||||
"""
|
||||
Map a given node to a metadata value.
|
||||
Record a metadata value ``value`` for ``node``.
|
||||
"""
|
||||
self._computed[node] = value
|
||||
|
||||
|
|
@ -83,7 +85,8 @@ class BaseMetadataProvider(_MetadataDependent, Generic[_T]):
|
|||
default: _MetadataT = _UNDEFINED_DEFAULT,
|
||||
) -> _MetadataT:
|
||||
"""
|
||||
Override to query from self._computed in addition to self.metadata.
|
||||
The same method as :func:`~libcst._MetadataDependent` except metadata
|
||||
is accessed from ``self._computed`` in addition to ``self.metadata``.
|
||||
"""
|
||||
if key is type(self):
|
||||
if default is not _UNDEFINED_DEFAULT:
|
||||
|
|
@ -96,7 +99,8 @@ class BaseMetadataProvider(_MetadataDependent, Generic[_T]):
|
|||
|
||||
class VisitorMetadataProvider(CSTVisitor, BaseMetadataProvider[_T]):
|
||||
"""
|
||||
Extend this to compute metadata with a non-batchable visitor.
|
||||
The low-level base class for all non-batchable visitor-based metadata
|
||||
providers.
|
||||
"""
|
||||
|
||||
def _gen_impl(self, module: "_ModuleT") -> None:
|
||||
|
|
@ -105,7 +109,7 @@ class VisitorMetadataProvider(CSTVisitor, BaseMetadataProvider[_T]):
|
|||
|
||||
class BatchableMetadataProvider(BatchableCSTVisitor, BaseMetadataProvider[_T]):
|
||||
"""
|
||||
Extend this to compute metadata with a batchable visitor.
|
||||
The low-level base class for all batchable visitor-based metadata providers.
|
||||
"""
|
||||
|
||||
def _gen_impl(self, module: "Module") -> None:
|
||||
|
|
@ -122,8 +126,7 @@ def _gen_batchable(
|
|||
providers: Iterable[BatchableMetadataProvider[Any]],
|
||||
) -> Mapping[ProviderT, Mapping["CSTNode", object]]:
|
||||
"""
|
||||
Returns map of metadata mappings from the given batchable providers on
|
||||
wrapper.
|
||||
Returns map of metadata mappings from resolving ``providers`` on ``wrapper``.
|
||||
"""
|
||||
wrapper.visit_batched(providers)
|
||||
|
||||
|
|
|
|||
|
|
@ -37,11 +37,8 @@ _UNDEFINED_DEFAULT = object()
|
|||
# add this functionality back
|
||||
class _MetadataDependent:
|
||||
"""
|
||||
Base class for all types that declare required metadata dependencies.
|
||||
|
||||
By default, metadata dependencies are computed upon visiting a Module node.
|
||||
An exception will be raised if a visitor that declares metadata is used to
|
||||
directly visit a node of type other than Module.
|
||||
The low-level base class for all types that declare required metadata
|
||||
dependencies.
|
||||
"""
|
||||
|
||||
# pyre-ignore[4]: Attribute `metadata` of class
|
||||
|
|
@ -57,7 +54,8 @@ class _MetadataDependent:
|
|||
@classmethod
|
||||
def get_inherited_dependencies(cls) -> Collection["ProviderT"]:
|
||||
"""
|
||||
Compute and cache all metadata dependencies from mro chain.
|
||||
Returns all metadata dependencies from the each class in the mro chain
|
||||
of a subclass of this class.
|
||||
"""
|
||||
try:
|
||||
# pyre-fixme[16]: use a hidden attribute to cache the property
|
||||
|
|
@ -73,6 +71,14 @@ class _MetadataDependent:
|
|||
|
||||
@contextmanager
|
||||
def resolve(self, wrapper: "MetadataWrapper") -> Iterator[None]:
|
||||
"""
|
||||
Context manager that resolves all metadata dependencies declared by
|
||||
this instance of this class on ``wrapper`` and caches it for use with
|
||||
:func:`~libcst._MetadataDependent.get_metadata`.
|
||||
|
||||
Upon exiting this context manager, the metadata cache on the instance is
|
||||
cleared.
|
||||
"""
|
||||
self.metadata = wrapper.resolve_many(self.get_inherited_dependencies())
|
||||
yield
|
||||
self.metadata = {}
|
||||
|
|
@ -84,9 +90,9 @@ class _MetadataDependent:
|
|||
default: _T = _UNDEFINED_DEFAULT,
|
||||
) -> _T:
|
||||
"""
|
||||
Gets metadata provided by the [key] provider if it is accessible from
|
||||
this vistor. Metadata is accessible if [key] is the same as [cls] or
|
||||
if [key] is in METADATA_DEPENDENCIES.
|
||||
Returns the metadata provided by the ``key`` if it is accessible from
|
||||
this vistor. Metadata is accessible if ``key`` is the same as ``type(self)``
|
||||
or if ``key`` is in ``self.METADATA_DEPENDENCIES``.
|
||||
"""
|
||||
if key not in self.get_inherited_dependencies():
|
||||
raise KeyError(
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ PositionProvider = Union["BasicPositionProvider", "SyntacticPositionProvider"]
|
|||
class BasicPositionProvider(BaseMetadataProvider[CodeRange]):
|
||||
"""
|
||||
Generates basic line and column metadata. Basic position is defined by the
|
||||
start and ending bounds of a node including all whitespace
|
||||
owned by that node.
|
||||
start and ending bounds of a node including all whitespace owned by that node.
|
||||
"""
|
||||
|
||||
def _gen_impl(self, module: _ModuleT) -> None:
|
||||
|
|
@ -27,7 +26,7 @@ class BasicPositionProvider(BaseMetadataProvider[CodeRange]):
|
|||
|
||||
class SyntacticPositionProvider(BasicPositionProvider):
|
||||
"""
|
||||
Generates Syntactic line and column metadata. Syntactic position is defined
|
||||
Generates syntactic line and column metadata. Syntactic position is defined
|
||||
by the start and ending bounds of a node ignoring most instances of leading
|
||||
and trailing whitespace when it is not syntactically significant.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -37,24 +37,27 @@ _T = TypeVar("_T")
|
|||
|
||||
@dataclass(frozen=True)
|
||||
class MetadataWrapper:
|
||||
"""
|
||||
A wrapper around a :class:`~libcst.Module` that stores associated metadata
|
||||
for that module. When a :class:`MetadataWrapper` is constructed over
|
||||
a module, the wrapper will store a deep copy of the original module.
|
||||
"""
|
||||
|
||||
module: "Module"
|
||||
_metadata: MutableMapping["ProviderT", Mapping["CSTNode", object]] = field(
|
||||
init=False, default_factory=dict
|
||||
)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
# Ensure that module is safe to use by copying
|
||||
# module is never mutated after this point which allows a
|
||||
# ModuleMetadata instance to be reuse as all metadata
|
||||
# computation should be deterministic
|
||||
# Ensure that module is safe to use by copying the module to remove
|
||||
# any duplicate nodes.
|
||||
object.__setattr__(self, "module", self.module.deep_clone())
|
||||
|
||||
def resolve(
|
||||
self, provider: Type["BaseMetadataProvider[_T]"]
|
||||
) -> Mapping["CSTNode", _T]:
|
||||
"""
|
||||
Resolves all the given metadata provider on the wrapped module and
|
||||
returns a copy of the metadata mapping.
|
||||
Returns a copy of the metadata mapping computed by ``provider``.
|
||||
"""
|
||||
if provider in self._metadata:
|
||||
metadata = self._metadata[provider]
|
||||
|
|
@ -68,10 +71,11 @@ class MetadataWrapper:
|
|||
self, providers: Collection["ProviderT"]
|
||||
) -> Mapping["ProviderT", Mapping["CSTNode", object]]:
|
||||
"""
|
||||
Resolves all the given metadata providers on the wrapped module and
|
||||
returns a copy of the map of metadata mappings.
|
||||
Returns a copy of the map of metadata mapping computed by each provider
|
||||
in ``providers``.
|
||||
|
||||
The returned map containing only metadata from the given providers.
|
||||
The returned map does not contain any metadata from undeclared metadata
|
||||
dependencies that ``providers`` has.
|
||||
"""
|
||||
_resolve_impl(self, providers)
|
||||
|
||||
|
|
@ -80,8 +84,8 @@ class MetadataWrapper:
|
|||
|
||||
def visit(self, visitor: "CSTVisitorT") -> "Module":
|
||||
"""
|
||||
Convenience function for visitors to resolve metadata before
|
||||
performing a visit pass.
|
||||
Convenience method to resolve metadata before performing a traversal over
|
||||
``self.module`` with ``visitor``. See :func:`~libcst.CSTNode.visit`.
|
||||
"""
|
||||
with visitor.resolve(self):
|
||||
return self.module.visit(visitor)
|
||||
|
|
@ -93,8 +97,8 @@ class MetadataWrapper:
|
|||
after_leave: Optional[VisitorMethod] = None,
|
||||
) -> "CSTNode":
|
||||
"""
|
||||
Convenience function for visitors to resolve metadata before
|
||||
performing a batched visit pass.
|
||||
Convenience method to resolve metadata before performing a traversal over
|
||||
``self.module`` with ``visitors``. See :func:`~libcst.visit_batched`.
|
||||
"""
|
||||
with ExitStack() as stack:
|
||||
# Resolve dependencies of visitors
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue