19
19
import json
20
20
import os .path
21
21
import re
22
+ import enum
22
23
import site
23
24
import sys
24
25
import time
@@ -780,19 +781,32 @@ def is_file(path: str) -> bool:
780
781
return os .path .isfile (path )
781
782
782
783
783
- class ModuleType :
784
- PACKAGE = 1
785
- MODULE = 2
786
- NAMESPACE = 3
784
+ class ModuleType ( enum . Enum ) :
785
+ package = 'package'
786
+ module = 'module'
787
+ namespace = 'namespace'
787
788
788
789
789
790
class ImportContext :
791
+ """
792
+ Describes module import context
793
+
794
+ Do we already discovered implementation?
795
+ What kind of module we discovered?
796
+ """
790
797
def __init__ (self ) -> None :
791
798
self .has_py = False # type: bool
792
- self .type = None # type: Optional[int]
799
+ self .type = None # type: Optional[ModuleType]
800
+ # Paths can contain only one ".py" path, but multiple stubs
793
801
self .paths = [] # type: List[str]
794
802
795
- def maybe_add_path (self , path : str , type : int ) -> None :
803
+ def maybe_add_path (self , path : str , type : ModuleType ) -> None :
804
+ """
805
+ Add path to import context.
806
+ Modifies self.paths in case if arguments satisfy import context state
807
+ """
808
+ assert path .endswith ((os .path .sep ,) + tuple (PYTHON_EXTENSIONS ))
809
+
796
810
if self .type is not None and self .type != type :
797
811
return None
798
812
@@ -802,7 +816,7 @@ def maybe_add_path(self, path: str, type: int) -> None:
802
816
if self .has_py and py_path :
803
817
return None
804
818
805
- if type == ModuleType .NAMESPACE :
819
+ if type == ModuleType .namespace :
806
820
ok = self ._verify_namespace (path )
807
821
else :
808
822
ok = self ._verify_module (path )
@@ -817,6 +831,8 @@ def maybe_add_path(self, path: str, type: int) -> None:
817
831
self .paths .append (path )
818
832
819
833
def _verify_module (self , path : str ) -> bool :
834
+ # At this point we already know that that it's valid python path
835
+ # We only need to check file existence
820
836
if not is_file (path ):
821
837
return False
822
838
@@ -860,6 +876,10 @@ def find_module(self, id: str) -> Optional[str]:
860
876
return None
861
877
862
878
def find_modules_recursive (self , module : str ) -> List [BuildSource ]:
879
+ """
880
+ Discover module and all it's children
881
+ Remove duplicates from discovered paths
882
+ """
863
883
hits = set () # type: Set[str]
864
884
result = [] # type: List[BuildSource]
865
885
for src in self ._find_modules_recursive (module ):
@@ -903,6 +923,9 @@ def _collect_paths(self, paths: List[str], last_comp: str) -> List[str]:
903
923
sepinit = '__init__'
904
924
ctx = ImportContext ()
905
925
926
+ # Detect modules in following order: package, module, namespace.
927
+ # First hit determines module type, consistency of paths to given type
928
+ # ensured in ImportContext
906
929
for path_item in paths :
907
930
if is_module_path (path_item ):
908
931
continue
@@ -912,15 +935,15 @@ def _collect_paths(self, paths: List[str], last_comp: str) -> List[str]:
912
935
913
936
for ext in PYTHON_EXTENSIONS :
914
937
path = os .path .join (path_item , last_comp , sepinit + ext )
915
- ctx .maybe_add_path (path , ModuleType .PACKAGE )
938
+ ctx .maybe_add_path (path , ModuleType .package )
916
939
917
940
for ext in PYTHON_EXTENSIONS :
918
941
path = os .path .join (path_item , last_comp + ext )
919
- ctx .maybe_add_path (path , ModuleType .MODULE )
942
+ ctx .maybe_add_path (path , ModuleType .module )
920
943
921
944
if self .namespaces_allowed :
922
945
path = os .path .join (path_item , last_comp )
923
- ctx .maybe_add_path (path + os .sep , ModuleType .NAMESPACE )
946
+ ctx .maybe_add_path (path + os .sep , ModuleType .namespace )
924
947
925
948
return ctx .paths
926
949
0 commit comments