@@ -198,16 +198,21 @@ def find_module(self, id: str, *, fast_path: bool = False) -> ModuleSearchResult
198
198
top_level = id .partition ('.' )[0 ]
199
199
use_typeshed = True
200
200
if top_level in self .stdlib_py_versions :
201
- min_version = self .stdlib_py_versions [top_level ]
202
- use_typeshed = (self .options is None
203
- or typeshed_py_version (self .options ) >= min_version )
201
+ use_typeshed = self ._typeshed_has_version (top_level )
204
202
self .results [id ] = self ._find_module (id , use_typeshed )
205
203
if (not fast_path
206
204
and self .results [id ] is ModuleNotFoundReason .NOT_FOUND
207
205
and self ._can_find_module_in_parent_dir (id )):
208
206
self .results [id ] = ModuleNotFoundReason .WRONG_WORKING_DIRECTORY
209
207
return self .results [id ]
210
208
209
+ def _typeshed_has_version (self , module : str ) -> bool :
210
+ if not self .options :
211
+ return True
212
+ version = typeshed_py_version (self .options )
213
+ min_version , max_version = self .stdlib_py_versions [module ]
214
+ return version >= min_version and (max_version is None or version <= max_version )
215
+
211
216
def _find_module_non_stub_helper (self , components : List [str ],
212
217
pkg_dir : str ) -> Union [OnePackageDir , ModuleNotFoundReason ]:
213
218
plausible_match = False
@@ -735,10 +740,14 @@ def compute_search_paths(sources: List[BuildSource],
735
740
typeshed_path = tuple (lib_path ))
736
741
737
742
738
- def load_stdlib_py_versions (custom_typeshed_dir : Optional [str ]) -> Dict [str , Tuple [int , int ]]:
739
- """Return dict with minimum Python versions of stdlib modules.
743
+ def load_stdlib_py_versions (custom_typeshed_dir : Optional [str ]
744
+ ) -> Dict [str , Tuple [Tuple [int , int ], Optional [Tuple [int , int ]]]]:
745
+ """Return dict with minimum and maximum Python versions of stdlib modules.
746
+
747
+ The contents look like
748
+ {..., 'secrets': ((3, 6), None), 'symbol': (2, 7), (3, 9)), ...}
740
749
741
- The contents look like {..., 'secrets': 3.6, 're': 2.7, ...} .
750
+ None means there is no maximum version .
742
751
"""
743
752
typeshed_dir = custom_typeshed_dir or os .path .join (os .path .dirname (__file__ ), "typeshed" )
744
753
stdlib_dir = os .path .join (typeshed_dir , "stdlib" )
@@ -751,20 +760,29 @@ def load_stdlib_py_versions(custom_typeshed_dir: Optional[str]) -> Dict[str, Tup
751
760
line = line .strip ()
752
761
if line .startswith ("#" ) or line == "" :
753
762
continue
754
- module , version = line .split (":" )
755
- major , minor = version .strip ().split ("." )
756
- result [module ] = int (major ), int (minor )
763
+ module , version_range = line .split (":" )
764
+ versions = version_range .split ("-" )
765
+ min_version = parse_version (versions [0 ])
766
+ max_version = (parse_version (versions [1 ])
767
+ if len (versions ) >= 2 and versions [1 ].strip () else None )
768
+ result [module ] = min_version , max_version
757
769
758
770
# Modules that are Python 2 only or have separate Python 2 stubs
759
771
# have stubs in @python2/ and may need an override.
760
772
python2_dir = os .path .join (stdlib_dir , PYTHON2_STUB_DIR )
761
773
for fnam in os .listdir (python2_dir ):
762
774
fnam = fnam .replace (".pyi" , "" )
763
- result [fnam ] = (2 , 7 )
775
+ max_version = result .get (fnam , ((2 , 7 ), None ))[1 ]
776
+ result [fnam ] = (2 , 7 ), max_version
764
777
765
778
return result
766
779
767
780
781
+ def parse_version (version : str ) -> Tuple [int , int ]:
782
+ major , minor = version .strip ().split ("." )
783
+ return int (major ), int (minor )
784
+
785
+
768
786
def typeshed_py_version (options : Options ) -> Tuple [int , int ]:
769
787
"""Return Python version used for checking whether module supports typeshed."""
770
788
# Typeshed no longer covers Python 3.x versions before 3.6, so 3.6 is
0 commit comments