@@ -198,16 +198,21 @@ def find_module(self, id: str, *, fast_path: bool = False) -> ModuleSearchResult
198198 top_level = id .partition ('.' )[0 ]
199199 use_typeshed = True
200200 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 )
204202 self .results [id ] = self ._find_module (id , use_typeshed )
205203 if (not fast_path
206204 and self .results [id ] is ModuleNotFoundReason .NOT_FOUND
207205 and self ._can_find_module_in_parent_dir (id )):
208206 self .results [id ] = ModuleNotFoundReason .WRONG_WORKING_DIRECTORY
209207 return self .results [id ]
210208
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+
211216 def _find_module_non_stub_helper (self , components : List [str ],
212217 pkg_dir : str ) -> Union [OnePackageDir , ModuleNotFoundReason ]:
213218 plausible_match = False
@@ -735,10 +740,14 @@ def compute_search_paths(sources: List[BuildSource],
735740 typeshed_path = tuple (lib_path ))
736741
737742
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)), ...}
740749
741- The contents look like {..., 'secrets': 3.6, 're': 2.7, ...} .
750+ None means there is no maximum version .
742751 """
743752 typeshed_dir = custom_typeshed_dir or os .path .join (os .path .dirname (__file__ ), "typeshed" )
744753 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
751760 line = line .strip ()
752761 if line .startswith ("#" ) or line == "" :
753762 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
757769
758770 # Modules that are Python 2 only or have separate Python 2 stubs
759771 # have stubs in @python2/ and may need an override.
760772 python2_dir = os .path .join (stdlib_dir , PYTHON2_STUB_DIR )
761773 for fnam in os .listdir (python2_dir ):
762774 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
764777
765778 return result
766779
767780
781+ def parse_version (version : str ) -> Tuple [int , int ]:
782+ major , minor = version .strip ().split ("." )
783+ return int (major ), int (minor )
784+
785+
768786def typeshed_py_version (options : Options ) -> Tuple [int , int ]:
769787 """Return Python version used for checking whether module supports typeshed."""
770788 # Typeshed no longer covers Python 3.x versions before 3.6, so 3.6 is
0 commit comments