8
8
from subprocess import PIPE , Popen
9
9
from typing import Any , Dict , List , Optional , Tuple , Union
10
10
11
- from packaging .specifiers import SpecifierSet
12
- from pkg_resources import parse_requirements
11
+ from packaging .requirements import Requirement
12
+ from packaging . specifiers import Specifier , SpecifierSet
13
13
from tomlkit import TOMLDocument , load
14
14
from tomlkit .container import Container
15
15
from tomlkit .items import Array , Item , String , Table
@@ -97,7 +97,11 @@ def convert_requirements(requirements: str, conf: Optional[Dict] = None) -> Dict
97
97
A configuration dictionary.
98
98
"""
99
99
conf = {"envs" : []} if conf is None else conf
100
- pkgs = [pkg .project_name for pkg in parse_requirements (requirements )]
100
+ pkgs = [
101
+ Requirement (val ).name
102
+ for val in requirements .splitlines ()
103
+ if not (val .strip ().startswith ("#" ) or val .strip () == "" )
104
+ ]
101
105
for pkg in pkgs :
102
106
conf ["envs" ].append ({})
103
107
conf ["envs" ][- 1 ]["name" ] = pkg
@@ -119,7 +123,7 @@ def gen_requirements_config(fname_or_buf: str, **options) -> Dict:
119
123
Parameters
120
124
----------
121
125
fname_or_buf : str
122
- Path to the requirements file to parse using ``pkg_resources.parse_requirements ``
126
+ Path to the requirements file to parse using ``packaging.requirements.Requirement ``
123
127
or the string representing the requirements file.
124
128
**options
125
129
Options to apply to each test environment.
@@ -387,7 +391,7 @@ def upgrade_requirements(
387
391
Parameters
388
392
----------
389
393
fname_or_buf : str
390
- Path to the requirements file to parse using ``pkg_resources.parse_requirements ``
394
+ Path to the requirements file to parse using ``packaging.requirements.Requirement ``
391
395
or the string representing the requirements file.
392
396
upgraded_packages : list
393
397
A list of packages upgraded in the testing procedure.
@@ -407,23 +411,32 @@ def upgrade_requirements(
407
411
except OSError :
408
412
# Filename too long for the is_file() function
409
413
cfg = fname_or_buf
410
- pkgs = list (parse_requirements (cfg ))
414
+ pkgs = [
415
+ Requirement (val )
416
+ for val in cfg .splitlines ()
417
+ if not (val .strip ().startswith ("#" ) or val .strip () == "" )
418
+ ]
411
419
upgrades = {pkg ["name" ]: pkg ["version" ] for pkg in upgraded_packages }
412
420
413
421
for pkg in pkgs :
414
- if pkg .project_name not in upgrades :
422
+ if pkg .name not in upgrades :
415
423
continue
416
424
# Replace the spec
417
- specs = deepcopy (pkg .specs )
425
+ specs = list (pkg .specifier )
426
+ new_spec = list (pkg .specifier )
418
427
for index , value in enumerate (specs ):
419
- if value [0 ] == "<=" :
420
- pkg .specs [index ] = ("<=" , upgrades [pkg .project_name ])
421
- elif value [0 ] == "<" :
422
- pkg .specs [index ] = ("!=" , value [1 ])
423
- pkg .specs .append (("<=" , upgrades [pkg .project_name ]))
424
- elif value [0 ] == "==" :
425
- pkg .specs = [(">=" , value [1 ]), ("<=" , upgrades [pkg .project_name ])]
426
- pkg .specifier = SpecifierSet ("," .join ("" .join (spec ) for spec in pkg .specs )) # type: ignore
428
+ if value .operator == "<=" :
429
+ new_spec [index ] = Specifier (f"<={ upgrades [pkg .name ]} " )
430
+ elif value .operator == "<" :
431
+ new_spec [index ] = Specifier (f"!={ value .version } " )
432
+ new_spec .append (Specifier (f"<={ upgrades [pkg .name ]} " ))
433
+ elif value .operator == "==" :
434
+ new_spec = Specifier (f">={ value .version } " ) & Specifier (
435
+ f"<={ upgrades [pkg .name ]} "
436
+ ) # type: ignore
437
+ # End the loop
438
+ break
439
+ pkg .specifier = SpecifierSet ("," .join (str (spec ) for spec in new_spec ))
427
440
428
441
return "\n " .join (str (pkg ) for pkg in pkgs )
429
442
@@ -522,15 +535,15 @@ def _isin_case_dashhyphen_ins(a: str, vals: List[str]) -> bool:
522
535
return any (a .replace ("_" , "-" ).lower () == b .replace ("_" , "-" ).lower () for b in vals )
523
536
524
537
525
- def get_lower_bounds (requirements : str , lower : str ) -> str :
538
+ def get_lower_bounds (requirements : Union [ str , List [ str ]] , lower : str ) -> str :
526
539
r"""Get lower bounds of requested packages from installation requirements.
527
540
528
541
Parses through the project ``requirements`` and the newline-delimited
529
542
packages requested in ``lower`` to find the lower bounds.
530
543
531
544
Parameters
532
545
----------
533
- requirements : str
546
+ requirements : str or list
534
547
Project setup requirements,
535
548
e.g. ``"pandas>=1.5.1,<=1.4.2\nnumpy>=1.22.1,<=1.25.4"``
536
549
lower : str
@@ -542,12 +555,21 @@ def get_lower_bounds(requirements: str, lower: str) -> str:
542
555
str
543
556
The packages along with the lower bound, e.g. ``"pandas==1.5.1\nnumpy==1.22.1"``.
544
557
"""
545
- all_lower_bounds = {
546
- pkg .project_name + (f"[{ ',' .join (pkg .extras )} ]" if pkg .extras else "" ): dict (
547
- pkg .specs
548
- ).get (">=" )
549
- for pkg in parse_requirements (requirements )
550
- }
558
+ if isinstance (requirements , str ):
559
+ pkgs = [
560
+ Requirement (val )
561
+ for val in requirements .splitlines ()
562
+ if not (val .strip ().startswith ("#" ) or val .strip () == "" )
563
+ ]
564
+ elif isinstance (requirements , list ):
565
+ pkgs = [Requirement (val ) for val in requirements ]
566
+ all_lower_bounds : Dict [str , str ] = {}
567
+ for pkg in pkgs :
568
+ full_name = pkg .name + (f"[{ ',' .join (pkg .extras )} ]" if pkg .extras else "" )
569
+ for spec in pkg .specifier :
570
+ if spec .operator == ">=" :
571
+ all_lower_bounds [full_name ] = spec .version
572
+ break
551
573
552
574
lower_with_bounds = ""
553
575
for pkg_name , lower_bound in all_lower_bounds .items ():
0 commit comments