Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def _get_do_not_care() -> cst.SubscriptElement:
"""
Construct a DoNotCareSentinel entry appropriate for going into a Union.
"""
return cst.SubscriptElement(cst.Index(cst.Name("DoNotCareSentinel")))
def _get_alias_name(node: cst.CSTNode) -> Optional[str]:
if isinstance(node, (cst.Name, cst.SimpleString)):
return f"{_get_raw_name(node)}MatchType"
elif isinstance(node, cst.Subscript):
if node.value.deep_equals(cst.Name("Union")):
slc = node.slice
# TODO: This instance check can go away once we deprecate ExtSlice
if isinstance(slc, Sequence):
names = [_get_raw_name(s) for s in slc]
if any(n is None for n in names):
return None
return "Or".join(n for n in names if n is not None) + "MatchType"
return None
def _get_match_if_true(oldtype: cst.BaseExpression) -> cst.SubscriptElement:
"""
Construct a MatchIfTrue type node appropriate for going into a Union.
"""
return cst.SubscriptElement(
cst.Index(
cst.Subscript(
cst.Name("MatchIfTrue"),
slice=(
cst.SubscriptElement(
cst.Index(
cst.Subscript(
cst.Name("Callable"),
slice=(
cst.SubscriptElement(
cst.Index(
cst.List(
[
cst.Element(
# MatchIfTrue takes in the original node type,
# and returns a boolean. So, lets convert our
# quoted classes (forward refs to other
# matchers) back to the CSTNode they refer to.
# We can do this because there's always a 1:1
# name mapping.
_convert_match_nodes_to_cst_nodes(
oldtype
)
)
def _get_clean_type_from_subscript(
aliases: List[Alias], typecst: cst.Subscript
) -> cst.BaseExpression:
if typecst.value.deep_equals(cst.Name("Sequence")):
# Lets attempt to widen the sequence type and alias it.
slc = typecst.slice
# TODO: This instance check can go away once we deprecate ExtSlice
if not isinstance(slc, Sequence):
raise Exception("Logic error, expected Sequence to have children!")
if len(slc) != 1:
raise Exception("Logic error, Sequence shouldn't have more than one param!")
inner_type = slc[0].slice
if not isinstance(inner_type, cst.Index):
raise Exception("Logic error, expecting Index for only Sequence element!")
inner_type = inner_type.value
if isinstance(inner_type, cst.Subscript):
clean_inner_type = _get_clean_type_from_subscript(aliases, inner_type)
elif isinstance(inner_type, (cst.Name, cst.SimpleString)):
def _add_generic(name: str, oldtype: cst.BaseExpression) -> cst.BaseExpression:
return cst.Subscript(cst.Name(name), (cst.SubscriptElement(cst.Index(oldtype)),))
def _wrap_clean_type(
aliases: List[Alias], name: Optional[str], value: cst.Subscript
) -> cst.BaseExpression:
if name is not None:
# We created an alias, lets use that, wrapping the alias in a do not care.
aliases.append(Alias(name=name, type=cst.Module(body=()).code_for_node(value)))
return _get_wrapped_union_type(cst.Name(name), _get_do_not_care())
else:
# Couldn't name the alias, fall back to regular node creation, add do not
# care to the resulting type we widened.
return value.with_changes(slice=[*value.slice, _get_do_not_care()])
def _get_wrapped_union_type(
node: cst.BaseExpression,
addition: cst.SubscriptElement,
*additions: cst.SubscriptElement,
) -> cst.Subscript:
"""
Take two or more nodes, wrap them in a union type. Function signature is
explicitly defined as taking at least one addition for type safety.
"""
return cst.Subscript(
cst.Name("Union"), [cst.SubscriptElement(cst.Index(node)), addition, *additions]
)
An Access records an access of an assignment.
.. note::
This scope analysis only analyzes access via a :class:`~libcst.Name` or a :class:`~libcst.Name`
node embedded in other node like :class:`~libcst.Call` or :class:`~libcst.Attribute`.
It doesn't support type annontation using :class:`~libcst.SimpleString` literal for forward
references. E.g. in this example, the ``"Tree"`` isn't parsed as as an access::
class Tree:
def __new__(cls) -> "Tree":
...
"""
#: The name node of the access. A name is an access when the expression context is
#: :attr:`ExpressionContext.LOAD`.
node: cst.Name
#: The scope of the access. Note that a access could be in a child scope of its assignment.
scope: "Scope"
__assignments: Set["BaseAssignment"]
def __init__(self, node: cst.Name, scope: "Scope") -> None:
self.node = node
self.scope = scope
self.__assignments = set()
def __hash__(self) -> int:
return id(self)
@property
def referents(self) -> Collection["BaseAssignment"]:
def get_full_name_for(node: Union[str, cst.CSTNode]) -> Optional[str]:
if isinstance(node, cst.Name):
return node.value
elif isinstance(node, str):
return node
elif isinstance(node, cst.Attribute):
return f"{_NameUtil.get_full_name_for(node.value)}.{node.attr.value}"
elif isinstance(node, cst.Call):
return _NameUtil.get_full_name_for(node.func)
elif isinstance(node, cst.Subscript):
return _NameUtil.get_full_name_for(node.value)
elif isinstance(node, (cst.FunctionDef, cst.ClassDef)):
return _NameUtil.get_full_name_for(node.name)
return None
cst.Element(
# MatchIfTrue takes in the original node type,
# and returns a boolean. So, lets convert our
# quoted classes (forward refs to other
# matchers) back to the CSTNode they refer to.
# We can do this because there's always a 1:1
# name mapping.
_convert_match_nodes_to_cst_nodes(
oldtype
)
)
]
)
)
),
cst.SubscriptElement(cst.Index(cst.Name("bool"))),
),