@@ -256,6 +256,49 @@ def _get_html_page(link, session=None):
256
256
return None
257
257
258
258
259
+ def _check_link_requires_python (
260
+ link , # type: Link
261
+ version_info , # type: Tuple[int, ...]
262
+ ignore_requires_python = False , # type: bool
263
+ ):
264
+ # type: (...) -> bool
265
+ """
266
+ Return whether the given Python version is compatible with a link's
267
+ "Requires-Python" value.
268
+
269
+ :param version_info: The Python version to use to check, as a 3-tuple
270
+ of ints (major-minor-micro).
271
+ :param ignore_requires_python: Whether to ignore the "Requires-Python"
272
+ value if the given Python version isn't compatible.
273
+ """
274
+ try :
275
+ support_this_python = check_requires_python (
276
+ link .requires_python , version_info = version_info ,
277
+ )
278
+ except specifiers .InvalidSpecifier :
279
+ logger .debug (
280
+ "Ignoring invalid Requires-Python (%r) for link: %s" ,
281
+ link .requires_python , link ,
282
+ )
283
+ else :
284
+ if not support_this_python :
285
+ version = '.' .join (map (str , version_info ))
286
+ if not ignore_requires_python :
287
+ logger .debug (
288
+ 'Link requires a different Python (%s not in: %r): %s' ,
289
+ version , link .requires_python , link ,
290
+ )
291
+ return False
292
+
293
+ logger .debug (
294
+ 'Ignoring failed Requires-Python check (%s not in: %r) '
295
+ 'for link: %s' ,
296
+ version , link .requires_python , link ,
297
+ )
298
+
299
+ return True
300
+
301
+
259
302
class CandidateEvaluator (object ):
260
303
261
304
"""
@@ -269,6 +312,7 @@ def __init__(
269
312
prefer_binary = False , # type: bool
270
313
allow_all_prereleases = False , # type: bool
271
314
py_version_info = None , # type: Optional[Tuple[int, ...]]
315
+ ignore_requires_python = None , # type: Optional[bool]
272
316
):
273
317
# type: (...) -> None
274
318
"""
@@ -277,12 +321,17 @@ def __init__(
277
321
representing a major-minor-micro version, to use to check both
278
322
the Python version embedded in the filename and the package's
279
323
"Requires-Python" metadata. Defaults to `sys.version_info[:3]`.
324
+ :param ignore_requires_python: Whether to ignore incompatible
325
+ "Requires-Python" values in links. Defaults to False.
280
326
"""
281
327
if py_version_info is None :
282
328
py_version_info = sys .version_info [:3 ]
329
+ if ignore_requires_python is None :
330
+ ignore_requires_python = False
283
331
284
332
py_version = '.' .join (map (str , py_version_info [:2 ]))
285
333
334
+ self ._ignore_requires_python = ignore_requires_python
286
335
self ._prefer_binary = prefer_binary
287
336
self ._py_version = py_version
288
337
self ._py_version_info = py_version_info
@@ -354,23 +403,15 @@ def evaluate_link(self, link, search):
354
403
py_version = match .group (1 )
355
404
if py_version != self ._py_version :
356
405
return (False , 'Python version is incorrect' )
357
- try :
358
- support_this_python = check_requires_python (
359
- link .requires_python , version_info = self ._py_version_info ,
360
- )
361
- except specifiers .InvalidSpecifier :
362
- logger .debug ("Package %s has an invalid Requires-Python entry: %s" ,
363
- link .filename , link .requires_python )
364
- else :
365
- if not support_this_python :
366
- logger .debug (
367
- "The package %s is incompatible with the python "
368
- "version in use. Acceptable python versions are: %s" ,
369
- link , link .requires_python ,
370
- )
371
- # Return None for the reason text to suppress calling
372
- # _log_skipped_link().
373
- return (False , None )
406
+
407
+ supports_python = _check_link_requires_python (
408
+ link , version_info = self ._py_version_info ,
409
+ ignore_requires_python = self ._ignore_requires_python ,
410
+ )
411
+ if not supports_python :
412
+ # Return None for the reason text to suppress calling
413
+ # _log_skipped_link().
414
+ return (False , None )
374
415
375
416
logger .debug ('Found link %s, version: %s' , link , version )
376
417
@@ -558,7 +599,8 @@ def create(
558
599
versions = None , # type: Optional[List[str]]
559
600
abi = None , # type: Optional[str]
560
601
implementation = None , # type: Optional[str]
561
- prefer_binary = False # type: bool
602
+ prefer_binary = False , # type: bool
603
+ ignore_requires_python = None , # type: Optional[bool]
562
604
):
563
605
# type: (...) -> PackageFinder
564
606
"""Create a PackageFinder.
@@ -582,6 +624,8 @@ def create(
582
624
to pep425tags.py in the get_supported() method.
583
625
:param prefer_binary: Whether to prefer an old, but valid, binary
584
626
dist over a new source dist.
627
+ :param ignore_requires_python: Whether to ignore incompatible
628
+ "Requires-Python" values in links. Defaults to False.
585
629
"""
586
630
if session is None :
587
631
raise TypeError (
@@ -617,6 +661,7 @@ def create(
617
661
candidate_evaluator = CandidateEvaluator (
618
662
valid_tags = valid_tags , prefer_binary = prefer_binary ,
619
663
allow_all_prereleases = allow_all_prereleases ,
664
+ ignore_requires_python = ignore_requires_python ,
620
665
)
621
666
622
667
# If we don't have TLS enabled, then WARN if anyplace we're looking
0 commit comments