40
40
import importlib
41
41
import json
42
42
import os .path
43
+ import pkgutil
43
44
import subprocess
44
45
import sys
45
46
import textwrap
@@ -574,6 +575,16 @@ def get_qualified_name(o: Node) -> str:
574
575
return '<ERROR>'
575
576
576
577
578
+ def walk_packages (packages : List [str ]):
579
+ for package_name in packages :
580
+ package = __import__ (package_name )
581
+ yield package .__name__
582
+ for importer , qualified_name , ispkg in pkgutil .walk_packages (package .__path__ ,
583
+ prefix = package .__name__ + "." ,
584
+ onerror = lambda r : None ):
585
+ yield qualified_name
586
+
587
+
577
588
def main () -> None :
578
589
options = parse_options ()
579
590
if not os .path .isdir ('out' ):
@@ -589,21 +600,29 @@ def main() -> None:
589
600
all_class_sigs += class_sigs
590
601
sigs = dict (find_unique_signatures (all_sigs ))
591
602
class_sigs = dict (find_unique_signatures (all_class_sigs ))
592
- for module in options .modules :
593
- generate_stub_for_module (module , 'out' ,
594
- add_header = True ,
595
- sigs = sigs ,
596
- class_sigs = class_sigs ,
597
- pyversion = options .pyversion ,
598
- no_import = options .no_import ,
599
- search_path = options .search_path ,
600
- interpreter = options .interpreter )
603
+ for module in (options .modules if not options .recursive else walk_packages (options .modules )):
604
+ try :
605
+ generate_stub_for_module (module , 'out' ,
606
+ add_header = True ,
607
+ sigs = sigs ,
608
+ class_sigs = class_sigs ,
609
+ pyversion = options .pyversion ,
610
+ no_import = options .no_import ,
611
+ search_path = options .search_path ,
612
+ interpreter = options .interpreter )
613
+ except Exception as e :
614
+ if not options .lenient :
615
+ raise e
616
+ else :
617
+ print ("Stub generation failed for : " , module )
601
618
602
619
603
620
def parse_options () -> Options :
604
621
args = sys .argv [1 :]
605
622
pyversion = defaults .PYTHON3_VERSION
606
623
no_import = False
624
+ recursive = False
625
+ lenient = False
607
626
doc_dir = ''
608
627
search_path = [] # type: List[str]
609
628
interpreter = ''
@@ -619,6 +638,10 @@ def parse_options() -> Options:
619
638
elif args [0 ] == '-p' :
620
639
interpreter = args [1 ]
621
640
args = args [1 :]
641
+ elif args [0 ] == '--recursive' :
642
+ recursive = True
643
+ elif args [0 ] == '--lenient' :
644
+ lenient = True
622
645
elif args [0 ] == '--py2' :
623
646
pyversion = defaults .PYTHON2_VERSION
624
647
elif args [0 ] == '--no-import' :
@@ -664,6 +687,8 @@ def usage() -> None:
664
687
665
688
Options:
666
689
--py2 run in Python 2 mode (default: Python 3 mode)
690
+ --recursive traverse listed modules to generate inner package modules as well
691
+ --lenient ignore exceptions when trying to generate stubs for modules
667
692
--no-import don't import the modules, just parse and analyze them
668
693
(doesn't work with C extension modules and doesn't
669
694
respect __all__)
0 commit comments