[metadata] consolidate MetadataWrapper methods to the same file

This commit is contained in:
Jimmy Lai 2019-11-18 16:30:43 -08:00 committed by jimmylai
parent 0d77f653ec
commit 337abb26c9
4 changed files with 69 additions and 91 deletions

View file

@ -1,63 +0,0 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# pyre-strict
from typing import TYPE_CHECKING, Collection, MutableSet
from libcst._exceptions import MetadataException
from libcst.metadata.base_provider import (
BatchableMetadataProvider,
ProviderT,
_gen_batchable,
)
if TYPE_CHECKING:
from libcst.metadata.wrapper import MetadataWrapper # noqa: F401
def _gather_providers(
providers: Collection[ProviderT], gathered: MutableSet[ProviderT]
) -> MutableSet[ProviderT]:
"""
Recursively gathers all the given providers and their dependencies.
"""
for P in providers:
if P not in gathered:
gathered.add(P)
_gather_providers(P.METADATA_DEPENDENCIES, gathered)
return gathered
def _resolve_impl(wrapper: "MetadataWrapper", providers: Collection[ProviderT]) -> None:
"""
Updates the _metadata map on wrapper with metadata from the given providers
as well as their dependencies.
"""
providers = set(providers) - set(wrapper._metadata.keys())
remaining = _gather_providers(providers, set())
completed = set()
while len(remaining) > 0:
batchable = set()
for P in remaining:
if set(P.METADATA_DEPENDENCIES).issubset(completed):
if issubclass(P, BatchableMetadataProvider):
batchable.add(P)
else:
wrapper._metadata[P] = P()._gen(wrapper)
completed.add(P)
metadata_batch = _gen_batchable(wrapper, [p() for p in batchable])
wrapper._metadata.update(metadata_batch)
completed |= batchable
if len(completed) == 0 and len(batchable) == 0:
# remaining must be non-empty at this point
names = ", ".join([P.__name__ for P in remaining])
raise MetadataException(f"Detected circular dependencies in {names}")
remaining -= completed

View file

@ -5,17 +5,7 @@
# pyre-strict
from types import MappingProxyType
from typing import (
TYPE_CHECKING,
Any,
Generic,
Iterable,
Mapping,
MutableMapping,
Type,
TypeVar,
cast,
)
from typing import TYPE_CHECKING, Generic, Mapping, MutableMapping, Type, TypeVar, cast
from libcst._batched_visitor import BatchableCSTVisitor
from libcst._metadata_dependent import (
@ -144,18 +134,3 @@ class BatchableMetadataProvider(
implementation should be provided in _gen_impl.
"""
pass
def _gen_batchable(
wrapper: "MetadataWrapper",
# pyre-fixme[2]: Parameter `providers` must have a type that does not contain `Any`
providers: Iterable[BatchableMetadataProvider[Any]],
) -> Mapping[ProviderT, Mapping["CSTNode", object]]:
"""
Returns map of metadata mappings from resolving ``providers`` on ``wrapper``.
"""
wrapper.visit_batched(providers)
# Make immutable metadata mapping
# pyre-ignore[7]
return {type(p): MappingProxyType(dict(p._computed)) for p in providers}

View file

@ -13,7 +13,7 @@ from libcst.metadata import (
MetadataWrapper,
VisitorMetadataProvider,
)
from libcst.metadata.base_provider import _gen_batchable
from libcst.metadata.wrapper import _gen_batchable
from libcst.testing.utils import UnitTest

View file

@ -7,12 +7,15 @@
import textwrap
from contextlib import ExitStack
from types import MappingProxyType
from typing import (
TYPE_CHECKING,
Any,
Collection,
Iterable,
Mapping,
MutableMapping,
MutableSet,
Optional,
Type,
TypeVar,
@ -20,7 +23,8 @@ from typing import (
)
from libcst._batched_visitor import BatchableCSTVisitor, VisitorMethod, visit_batched
from libcst.metadata._resolver import _resolve_impl
from libcst._exceptions import MetadataException
from libcst.metadata.base_provider import BatchableMetadataProvider
if TYPE_CHECKING:
@ -36,6 +40,68 @@ if TYPE_CHECKING:
_T = TypeVar("_T")
def _gen_batchable(
wrapper: "MetadataWrapper",
# pyre-fixme[2]: Parameter `providers` must have a type that does not contain `Any`
providers: Iterable[BatchableMetadataProvider[Any]],
) -> Mapping["ProviderT", Mapping["CSTNode", object]]:
"""
Returns map of metadata mappings from resolving ``providers`` on ``wrapper``.
"""
wrapper.visit_batched(providers)
# Make immutable metadata mapping
# pyre-ignore[7]
return {type(p): MappingProxyType(dict(p._computed)) for p in providers}
def _gather_providers(
providers: Collection["ProviderT"], gathered: MutableSet["ProviderT"]
) -> MutableSet["ProviderT"]:
"""
Recursively gathers all the given providers and their dependencies.
"""
for P in providers:
if P not in gathered:
gathered.add(P)
_gather_providers(P.METADATA_DEPENDENCIES, gathered)
return gathered
def _resolve_impl(
wrapper: "MetadataWrapper", providers: Collection["ProviderT"]
) -> None:
"""
Updates the _metadata map on wrapper with metadata from the given providers
as well as their dependencies.
"""
providers = set(providers) - set(wrapper._metadata.keys())
remaining = _gather_providers(providers, set())
completed = set()
while len(remaining) > 0:
batchable = set()
for P in remaining:
if set(P.METADATA_DEPENDENCIES).issubset(completed):
if issubclass(P, BatchableMetadataProvider):
batchable.add(P)
else:
wrapper._metadata[P] = P()._gen(wrapper)
completed.add(P)
metadata_batch = _gen_batchable(wrapper, [p() for p in batchable])
wrapper._metadata.update(metadata_batch)
completed |= batchable
if len(completed) == 0 and len(batchable) == 0:
# remaining must be non-empty at this point
names = ", ".join([P.__name__ for P in remaining])
raise MetadataException(f"Detected circular dependencies in {names}")
remaining -= completed
class MetadataWrapper:
"""
A wrapper around a :class:`~libcst.Module` that stores associated metadata