Add sphinx docs to metadata modules

This commit is contained in:
Ray Zeng 2019-08-12 17:14:50 -07:00 committed by Ray Zeng
parent 611f45e596
commit 79f0ebc2a4
8 changed files with 106 additions and 55 deletions

View file

@ -21,6 +21,7 @@ LibCST
parser
nodes
visitors
metadata
Indices and tables

16
docs/source/metadata.rst Normal file
View 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

View file

@ -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",
]

View file

@ -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]

View file

@ -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)

View file

@ -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(

View file

@ -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.
"""

View file

@ -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