@@ -559,10 +559,33 @@ def visit_mypy_file(self, o: MypyFile) -> None:
559
559
for name in sorted (undefined_names ):
560
560
self .add ('# %s\n ' % name )
561
561
562
- def visit_func_def (self , o : FuncDef , is_abstract : bool = False ) -> None :
562
+ def visit_overloaded_func_def (self , o : OverloadedFuncDef ) -> None :
563
+ """@property with setters and getters, or @overload chain"""
564
+ overload_chain = False
565
+ for item in o .items :
566
+ if not isinstance (item , Decorator ):
567
+ continue
568
+
569
+ if self .is_private_name (item .func .name , item .func .fullname ):
570
+ continue
571
+
572
+ is_abstract , is_overload = self .process_decorator (item )
573
+
574
+ if not overload_chain :
575
+ self .visit_func_def (item .func , is_abstract = is_abstract , is_overload = is_overload )
576
+ if is_overload :
577
+ overload_chain = True
578
+ elif overload_chain and is_overload :
579
+ self .visit_func_def (item .func , is_abstract = is_abstract , is_overload = is_overload )
580
+ else :
581
+ # skip the overload implementation and clear the decorator we just processed
582
+ self .clear_decorators ()
583
+
584
+ def visit_func_def (self , o : FuncDef , is_abstract : bool = False ,
585
+ is_overload : bool = False ) -> None :
563
586
if (self .is_private_name (o .name , o .fullname )
564
587
or self .is_not_in_all (o .name )
565
- or self .is_recorded_name (o .name )):
588
+ or ( self .is_recorded_name (o .name ) and not is_overload )):
566
589
self .clear_decorators ()
567
590
return
568
591
if not self ._indent and self ._state not in (EMPTY , FUNC ) and not o .is_awaitable_coroutine :
@@ -599,7 +622,7 @@ def visit_func_def(self, o: FuncDef, is_abstract: bool = False) -> None:
599
622
and not is_cls_arg ):
600
623
self .add_typing_import ("Any" )
601
624
annotation = ": {}" .format (self .typing_name ("Any" ))
602
- elif annotated_type and not is_self_arg :
625
+ elif annotated_type and not is_self_arg and not is_cls_arg :
603
626
annotation = ": {}" .format (self .print_annotation (annotated_type ))
604
627
else :
605
628
annotation = ""
@@ -642,24 +665,43 @@ def visit_func_def(self, o: FuncDef, is_abstract: bool = False) -> None:
642
665
def visit_decorator (self , o : Decorator ) -> None :
643
666
if self .is_private_name (o .func .name , o .func .fullname ):
644
667
return
668
+
669
+ is_abstract , _ = self .process_decorator (o )
670
+ self .visit_func_def (o .func , is_abstract = is_abstract )
671
+
672
+ def process_decorator (self , o : Decorator ) -> Tuple [bool , bool ]:
673
+ """Process a series of decorataors.
674
+
675
+ Only preserve certain special decorators such as @abstractmethod.
676
+
677
+ Return a pair of booleans:
678
+ - True if any of the decorators makes a method abstract.
679
+ - True if any of the decorators is typing.overload.
680
+ """
645
681
is_abstract = False
682
+ is_overload = False
646
683
for decorator in o .original_decorators :
647
684
if isinstance (decorator , NameExpr ):
648
- if self .process_name_expr_decorator (decorator , o ):
649
- is_abstract = True
685
+ i_is_abstract , i_is_overload = self .process_name_expr_decorator (decorator , o )
686
+ is_abstract = is_abstract or i_is_abstract
687
+ is_overload = is_overload or i_is_overload
650
688
elif isinstance (decorator , MemberExpr ):
651
- if self .process_member_expr_decorator (decorator , o ):
652
- is_abstract = True
653
- self .visit_func_def (o .func , is_abstract = is_abstract )
689
+ i_is_abstract , i_is_overload = self .process_member_expr_decorator (decorator , o )
690
+ is_abstract = is_abstract or i_is_abstract
691
+ is_overload = is_overload or i_is_overload
692
+ return is_abstract , is_overload
654
693
655
- def process_name_expr_decorator (self , expr : NameExpr , context : Decorator ) -> bool :
694
+ def process_name_expr_decorator (self , expr : NameExpr , context : Decorator ) -> Tuple [ bool , bool ] :
656
695
"""Process a function decorator of form @foo.
657
696
658
697
Only preserve certain special decorators such as @abstractmethod.
659
698
660
- Return True if the decorator makes a method abstract.
699
+ Return a pair of booleans:
700
+ - True if the decorator makes a method abstract.
701
+ - True if the decorator is typing.overload.
661
702
"""
662
703
is_abstract = False
704
+ is_overload = False
663
705
name = expr .name
664
706
if name in ('property' , 'staticmethod' , 'classmethod' ):
665
707
self .add_decorator (name )
@@ -675,27 +717,35 @@ def process_name_expr_decorator(self, expr: NameExpr, context: Decorator) -> boo
675
717
self .add_decorator ('property' )
676
718
self .add_decorator ('abc.abstractmethod' )
677
719
is_abstract = True
678
- return is_abstract
720
+ elif self .refers_to_fullname (name , 'typing.overload' ):
721
+ self .add_decorator (name )
722
+ self .add_typing_import ('overload' )
723
+ is_overload = True
724
+ return is_abstract , is_overload
679
725
680
726
def refers_to_fullname (self , name : str , fullname : str ) -> bool :
681
727
module , short = fullname .rsplit ('.' , 1 )
682
728
return (self .import_tracker .module_for .get (name ) == module and
683
729
(name == short or
684
730
self .import_tracker .reverse_alias .get (name ) == short ))
685
731
686
- def process_member_expr_decorator (self , expr : MemberExpr , context : Decorator ) -> bool :
732
+ def process_member_expr_decorator (self , expr : MemberExpr , context : Decorator ) -> Tuple [bool ,
733
+ bool ]:
687
734
"""Process a function decorator of form @foo.bar.
688
735
689
736
Only preserve certain special decorators such as @abstractmethod.
690
737
691
- Return True if the decorator makes a method abstract.
738
+ Return a pair of booleans:
739
+ - True if the decorator makes a method abstract.
740
+ - True if the decorator is typing.overload.
692
741
"""
693
742
is_abstract = False
743
+ is_overload = False
694
744
if expr .name == 'setter' and isinstance (expr .expr , NameExpr ):
695
745
self .add_decorator ('%s.setter' % expr .expr .name )
696
746
elif (isinstance (expr .expr , NameExpr ) and
697
747
(expr .expr .name == 'abc' or
698
- self .import_tracker .reverse_alias .get ('abc' ) ) and
748
+ self .import_tracker .reverse_alias .get (expr . expr . name ) == 'abc' ) and
699
749
expr .name in ('abstractmethod' , 'abstractproperty' )):
700
750
if expr .name == 'abstractproperty' :
701
751
self .import_tracker .require_name (expr .expr .name )
@@ -723,7 +773,14 @@ def process_member_expr_decorator(self, expr: MemberExpr, context: Decorator) ->
723
773
self .add_coroutine_decorator (context .func ,
724
774
expr .expr .name + '.coroutine' ,
725
775
expr .expr .name )
726
- return is_abstract
776
+ elif (isinstance (expr .expr , NameExpr ) and
777
+ (expr .expr .name == 'typing' or
778
+ self .import_tracker .reverse_alias .get (expr .expr .name ) == 'typing' ) and
779
+ expr .name == 'overload' ):
780
+ self .import_tracker .require_name (expr .expr .name )
781
+ self .add_decorator ('%s.%s' % (expr .expr .name , 'overload' ))
782
+ is_overload = True
783
+ return is_abstract , is_overload
727
784
728
785
def visit_class_def (self , o : ClassDef ) -> None :
729
786
self .method_names = find_method_names (o .defs .body )
0 commit comments