예제 #1
0
 def __name2annotation(self, type_name: str):
     """
     Converts Name nodes to valid annotation nodes
     """
     try:
         return match.extract(
             cst.parse_module("x: %s=None" % type_name).body[0].body[0],
             match.AnnAssign(target=match.Name(value=match.DoNotCare()),
                             annotation=match.SaveMatchedNode(
                                 match.DoNotCare(), "type")))['type']
     except cst._exceptions.ParserSyntaxError:
         # To handle a bug in LibCST's scope provider where a local name shadows a type annotation with the same name
         if (self.last_visited_name.value,
                 cst.metadata.QualifiedNameSource.IMPORT
             ) in self.q_names_cache:
             return match.extract(
                 cst.parse_module(
                     "x: %s=None" %
                     self.q_names_cache[(self.last_visited_name.value,
                                         cst.metadata.QualifiedNameSource.
                                         IMPORT)]).body[0].body[0],
                 match.AnnAssign(target=match.Name(value=match.DoNotCare()),
                                 annotation=match.SaveMatchedNode(
                                     match.DoNotCare(), "type")))['type']
         else:
             return match.extract(
                 cst.parse_module(
                     "x: %s=None" %
                     self.last_visited_name.value).body[0].body[0],
                 match.AnnAssign(target=match.Name(value=match.DoNotCare()),
                                 annotation=match.SaveMatchedNode(
                                     match.DoNotCare(), "type")))['type']
예제 #2
0
 def leave_AnnAssign(
     self, original_node: cst.AnnAssign, updated_node: cst.AnnAssign
 ) -> Union[cst.BaseSmallStatement, cst.RemovalSentinel]:
     # It handles a special case where a type-annotated variable has not initialized, e.g. foo: str
     # This case will be converted to foo = ... so that nodes traversal won't encounter exceptions later on
     if match.matches(
             original_node,
             match.AnnAssign(
                 target=match.Name(value=match.DoNotCare()),
                 annotation=match.Annotation(annotation=match.DoNotCare()),
                 value=None)):
         updated_node = cst.Assign(
             targets=[cst.AssignTarget(target=original_node.target)],
             value=cst.Ellipsis())
     # Handles type-annotated class attributes that has not been initialized, e.g. self.foo: str
     elif match.matches(
             original_node,
             match.AnnAssign(
                 target=match.Attribute(value=match.DoNotCare()),
                 annotation=match.Annotation(annotation=match.DoNotCare()),
                 value=None)):
         updated_node = cst.Assign(
             targets=[cst.AssignTarget(target=original_node.target)],
             value=cst.Ellipsis())
     else:
         updated_node = cst.Assign(
             targets=[cst.AssignTarget(target=original_node.target)],
             value=original_node.value)
     return updated_node
예제 #3
0
 def __extract_variable_name_type(self, node: cst.AnnAssign):
     """
     Extracts a variable's identifier name and its type annotation
     """
     return match.extract(
         node,
         match.AnnAssign(  # Annotated Assignment
             target=match.OneOf(
                 match.Name(  # Variable name of assignment (only one)
                     value=match.SaveMatchedNode(  # Save result
                         match.MatchRegex(
                             r'(.)+'),  # Match any string literal
                         "name")),
                 # This extracts variables inside __init__ which typically starts with self (e.g. self.x:int=2)
                 match.Attribute(
                     value=match.Name(value=match.SaveMatchedNode(
                         match.MatchRegex(r'(.)+'),
                         "obj_name"  # Object name
                     )),
                     attr=match.Name(
                         match.SaveMatchedNode(match.MatchRegex(r'(.)+'),
                                               "name")),
                 )),
             annotation=match.SaveMatchedNode(  # Save result
                 match.DoNotCare(),  # Match any string literal
                 "type")))
예제 #4
0
 def __name2annotation(self, type_name: str):
     ext_annot = lambda t: match.extract(
         cst.parse_module("x: %s=None" % t).body[0].body[0],
         match.AnnAssign(target=match.Name(value=match.DoNotCare()),
                         annotation=match.SaveMatchedNode(
                             match.DoNotCare(), "type")))['type']
     try:
         return ext_annot(type_name)
     except cst._exceptions.ParserSyntaxError:
         return None
예제 #5
0
 def visit_AnnAssign(self, node: cst.AnnAssign) -> None:
     # The assignment value is optional, as it is possible to annotate an
     # expression without assigning to it: ``var: int``
     if m.matches(
             node,
             m.AnnAssign(
                 target=m.Name(),
                 value=m.MatchIfTrue(lambda value: value is not None)),
     ):
         nodename = cst.ensure_type(node.target, cst.Name).value
         self._validate_nodename(node, nodename,
                                 NamingConvention.SNAKE_CASE)
예제 #6
0
 def __get_var_names_counter(self, node, scope):
     vars_name = match.extractall(
         node,
         match.OneOf(
             match.AssignTarget(target=match.SaveMatchedNode(
                 match.Name(value=match.DoNotCare()), "name")),
             match.AnnAssign(target=match.SaveMatchedNode(
                 match.Name(value=match.DoNotCare()), "name"))))
     return Counter([
         n['name'].value for n in vars_name if isinstance(
             self.get_metadata(cst.metadata.ScopeProvider, n['name']),
             scope)
     ])
예제 #7
0
    def leave_SimpleStatementLine(self, original_node: cst.SimpleStatementLine,
                                  updated_node: cst.SimpleStatementLine):
        if match.matches(
                original_node,
                match.SimpleStatementLine(body=[
                    match.Assign(targets=[
                        match.AssignTarget(target=match.Name(
                            value=match.DoNotCare()))
                    ])
                ])):
            t = self.__get_var_type_assign_t(
                original_node.body[0].targets[0].target.value)

            if t is not None:
                t_annot_node_resolved = self.resolve_type_alias(t)
                t_annot_node = self.__name2annotation(t_annot_node_resolved)
                if t_annot_node is not None:
                    self.all_applied_types.add(
                        (t_annot_node_resolved, t_annot_node))
                    return updated_node.with_changes(body=[
                        cst.AnnAssign(
                            target=original_node.body[0].targets[0].target,
                            value=original_node.body[0].value,
                            annotation=t_annot_node,
                            equal=cst.AssignEqual(
                                whitespace_after=original_node.body[0].
                                targets[0].whitespace_after_equal,
                                whitespace_before=original_node.body[0].
                                targets[0].whitespace_before_equal))
                    ])
        elif match.matches(
                original_node,
                match.SimpleStatementLine(body=[
                    match.AnnAssign(target=match.Name(value=match.DoNotCare()))
                ])):
            t = self.__get_var_type_an_assign(
                original_node.body[0].target.value)
            if t is not None:
                t_annot_node_resolved = self.resolve_type_alias(t)
                t_annot_node = self.__name2annotation(t_annot_node_resolved)
                if t_annot_node is not None:
                    self.all_applied_types.add(
                        (t_annot_node_resolved, t_annot_node))
                    return updated_node.with_changes(body=[
                        cst.AnnAssign(target=original_node.body[0].target,
                                      value=original_node.body[0].value,
                                      annotation=t_annot_node,
                                      equal=original_node.body[0].equal)
                    ])

        return original_node
예제 #8
0
_django_model_field_name_value = m.Call(func=m.Attribute(
    attr=m.Name(m.MatchIfTrue(is_model_field_type)))) | m.Call(
        func=m.Name(m.MatchIfTrue(is_model_field_type)))

_django_model_field_name_with_leading_comment_value = m.Call(
    func=m.Attribute(attr=m.Name(m.MatchIfTrue(is_model_field_type))),
    whitespace_before_args=m.ParenthesizedWhitespace(_any_comment),
) | m.Call(
    func=m.Name(m.MatchIfTrue(is_model_field_type)),
    whitespace_before_args=m.ParenthesizedWhitespace(_any_comment),
)

_django_model_field_with_leading_comment = m.SimpleStatementLine(body=[
    m.Assign(value=_django_model_field_name_with_leading_comment_value)
    | m.AnnAssign(value=_django_model_field_name_with_leading_comment_value)
])

_django_model_field_with_trailing_comment = m.SimpleStatementLine(
    body=[
        m.Assign(value=_django_model_field_name_value)
        | m.AnnAssign(value=_django_model_field_name_value)
    ],
    trailing_whitespace=_any_comment,
)

django_model_field_with_comments = (_django_model_field_with_leading_comment |
                                    _django_model_field_with_trailing_comment)


def get_leading_comment(node: cst.SimpleStatementLine) -> typing.Optional[str]: