19
19
import json
20
20
import os .path
21
21
import re
22
+ import enum
22
23
import site
23
24
import stat
24
25
import sys
@@ -799,19 +800,32 @@ def is_file(path: str) -> bool:
799
800
return res
800
801
801
802
802
- class ModuleType :
803
- PACKAGE = 1
804
- MODULE = 2
805
- NAMESPACE = 3
803
+ class ModuleType ( enum . Enum ) :
804
+ package = 'package'
805
+ module = 'module'
806
+ namespace = 'namespace'
806
807
807
808
808
809
class ImportContext :
810
+ """
811
+ Describes module import context
812
+
813
+ Do we already discovered implementation?
814
+ What kind of module we discovered?
815
+ """
809
816
def __init__ (self ) -> None :
810
817
self .has_py = False # type: bool
811
- self .type = None # type: Optional[int]
818
+ self .type = None # type: Optional[ModuleType]
819
+ # Paths can contain only one ".py" path, but multiple stubs
812
820
self .paths = [] # type: List[str]
813
821
814
- def maybe_add_path (self , path : str , type : int ) -> None :
822
+ def maybe_add_path (self , path : str , type : ModuleType ) -> None :
823
+ """
824
+ Add path to import context.
825
+ Modifies self.paths in case if arguments satisfy import context state
826
+ """
827
+ assert path .endswith ((os .path .sep ,) + tuple (PYTHON_EXTENSIONS ))
828
+
815
829
if self .type is not None and self .type != type :
816
830
return None
817
831
@@ -821,7 +835,7 @@ def maybe_add_path(self, path: str, type: int) -> None:
821
835
if self .has_py and py_path :
822
836
return None
823
837
824
- if type == ModuleType .NAMESPACE :
838
+ if type == ModuleType .namespace :
825
839
ok = self ._verify_namespace (path )
826
840
else :
827
841
ok = self ._verify_module (path )
@@ -836,6 +850,8 @@ def maybe_add_path(self, path: str, type: int) -> None:
836
850
self .paths .append (path )
837
851
838
852
def _verify_module (self , path : str ) -> bool :
853
+ # At this point we already know that that it's valid python path
854
+ # We only need to check file existence
839
855
if not is_file (path ):
840
856
return False
841
857
@@ -879,6 +895,10 @@ def find_module(self, id: str) -> Optional[str]:
879
895
return None
880
896
881
897
def find_modules_recursive (self , module : str ) -> List [BuildSource ]:
898
+ """
899
+ Discover module and all it's children
900
+ Remove duplicates from discovered paths
901
+ """
882
902
hits = set () # type: Set[str]
883
903
result = [] # type: List[BuildSource]
884
904
for src in self ._find_modules_recursive (module ):
@@ -922,6 +942,9 @@ def _collect_paths(self, paths: List[str], last_comp: str) -> List[str]:
922
942
sepinit = '__init__'
923
943
ctx = ImportContext ()
924
944
945
+ # Detect modules in following order: package, module, namespace.
946
+ # First hit determines module type, consistency of paths to given type
947
+ # ensured in ImportContext
925
948
for path_item in paths :
926
949
if is_module_path (path_item ):
927
950
continue
@@ -931,15 +954,15 @@ def _collect_paths(self, paths: List[str], last_comp: str) -> List[str]:
931
954
932
955
for ext in PYTHON_EXTENSIONS :
933
956
path = os .path .join (path_item , last_comp , sepinit + ext )
934
- ctx .maybe_add_path (path , ModuleType .PACKAGE )
957
+ ctx .maybe_add_path (path , ModuleType .package )
935
958
936
959
for ext in PYTHON_EXTENSIONS :
937
960
path = os .path .join (path_item , last_comp + ext )
938
- ctx .maybe_add_path (path , ModuleType .MODULE )
961
+ ctx .maybe_add_path (path , ModuleType .module )
939
962
940
963
if self .namespaces_allowed :
941
964
path = os .path .join (path_item , last_comp )
942
- ctx .maybe_add_path (path + os .sep , ModuleType .NAMESPACE )
965
+ ctx .maybe_add_path (path + os .sep , ModuleType .namespace )
943
966
944
967
return ctx .paths
945
968
0 commit comments