99#
1010"""Generate requirements from `setup.py` and `requirements-devel.txt`."""
1111
12- from __future__ import absolute_import
13- from __future__ import print_function
14-
1512import os
1613import re
1714import sys
2219 import ConfigParser as configparser
2320
2421import mock
25- import pkg_resources
2622import setuptools
27-
28-
29- def parse_set (string ):
30- """Parse set from comma separated string."""
31- string = string .strip ()
32- if string :
33- return set (string .split ("," ))
34- else :
35- return set ()
23+ from commoncode .command import pushd
24+ from packaging .requirements import Requirement
3625
3726
3827def minver_error (pkg_name ):
@@ -47,49 +36,8 @@ def minver_error(pkg_name):
4736def build_pkg_name (pkg ):
4837 """Build package name, including extras if present."""
4938 if pkg .extras :
50- return "{0}[{1}]" .format (pkg .project_name , "," .join (sorted (pkg .extras )))
51- return pkg .project_name
52-
53-
54- def parse_pip_file (path ):
55- """Parse pip requirements file."""
56- # requirement lines sorted by importance
57- # also collect other pip commands
58- rdev = {}
59- rnormal = []
60- stuff = []
61-
62- try :
63- with open (path ) as f :
64- for line in f :
65- line = line .strip ()
66-
67- # see https://pip.readthedocs.io/en/1.1/requirements.html
68- if line .startswith ("-e" ):
69- # devel requirement
70- splitted = line .split ("#egg=" )
71- rdev [splitted [1 ].lower ()] = line
72-
73- elif line .startswith ("-r" ):
74- # recursive file command
75- splitted = re .split ("-r\\ s+" , line )
76- subrdev , subrnormal , substuff = parse_pip_file (
77- os .path .join (os .path .dirname (path ), splitted [1 ])
78- )
79- for k , v in subrdev .items ():
80- if k not in rdev :
81- rdev [k ] = v
82- rnormal .extend (subrnormal )
83- elif line .startswith ("-" ):
84- # another special command we don't recognize
85- stuff .append (line )
86- else :
87- # ordinary requirement, similarly to them used in setup.py
88- rnormal .append (line )
89- except IOError :
90- print ('Warning: could not parse requirements file "{0}"!' .format (path ), file = sys .stderr )
91-
92- return rdev , rnormal , stuff
39+ return "{0}[{1}]" .format (str (pkg .name ), "," .join (sorted (pkg .extras )))
40+ return str (pkg .name )
9341
9442
9543def iter_requirements (level , extras , setup_file ):
@@ -100,24 +48,26 @@ def iter_requirements(level, extras, setup_file):
10048 result = dict ()
10149 requires = []
10250 stuff = []
103- cd = os .getcwd ()
104- os .chdir (os .path .dirname (setup_file ))
10551 install_requires = []
10652 requires_extras = {}
53+ test_requires = {}
54+ setup_requires = {}
10755 # change directory to setup.py path
108- with mock .patch .object (setuptools , "setup" ) as mock_setup :
109- sys .path .append (os .path .dirname (setup_file ))
110- g = {"__file__" : setup_file , "__name__" : "__main__" }
111- with open (setup_file ) as sf :
112- exec (sf .read (), g )
113- sys .path .pop ()
114- assert g ["setup" ] # silence warning about unused imports
56+ with pushd (os .path .dirname (setup_file )):
57+ with mock .patch .object (setuptools , "setup" ) as mock_setup :
58+ sys .path .append (os .path .dirname (setup_file ))
59+ g = {"__file__" : setup_file , "__name__" : "__main__" }
60+ with open (setup_file ) as sf :
61+ exec (sf .read (), g )
62+ sys .path .pop ()
63+ assert g ["setup" ] # silence warning about unused imports
11564 # called arguments are in `mock_setup.call_args`
116- os .chdir (cd )
11765 mock_args , mock_kwargs = mock_setup .call_args
11866 install_requires = mock_kwargs .get ("install_requires" , install_requires )
11967
12068 requires_extras = mock_kwargs .get ("extras_require" , requires_extras )
69+ test_requires = mock_kwargs .get ("test_requires" , test_requires )
70+ setup_requires = mock_kwargs .get ("setup_requires" , setup_requires )
12171
12272 for e , reqs in requires_extras .items ():
12373 # Handle conditions on extras. See pkginfo_to_metadata function
@@ -130,10 +80,18 @@ def iter_requirements(level, extras, setup_file):
13080 reqs = ["{0}; {1}" .format (r , condition ) for r in reqs ]
13181 install_requires .extend (reqs )
13282
133- for pkg in pkg_resources .parse_requirements (install_requires ):
83+ for reqs in test_requires :
84+ if "test" in extras :
85+ install_requires .extend (reqs )
86+
87+ for reqs in setup_requires :
88+ if "setup" in extras :
89+ install_requires .extend (reqs )
90+
91+ for req in install_requires :
13492 # skip things we already know
13593 # FIXME be smarter about merging things
136-
94+ pkg = Requirement ( req )
13795 # Evaluate environment markers skip if not applicable
13896 if hasattr (pkg , "marker" ) and pkg .marker is not None :
13997 if not pkg .marker .evaluate ():
@@ -142,10 +100,11 @@ def iter_requirements(level, extras, setup_file):
142100 # Remove markers from the output
143101 pkg .marker = None
144102
145- if pkg .key in result :
103+ if pkg .name in result :
146104 continue
147105
148- specs = dict (pkg .specs )
106+ specs = pkg .specifier
107+ specs = {s .operator : s .version for s in specs ._specs }
149108 if ((">=" in specs ) and (">" in specs )) or (("<=" in specs ) and ("<" in specs )):
150109 print (
151110 "ERROR: Do not specify such weird constraints! " '("{0}")' .format (pkg ),
@@ -154,32 +113,32 @@ def iter_requirements(level, extras, setup_file):
154113 sys .exit (1 )
155114
156115 if "==" in specs :
157- result [pkg .key ] = "{0}=={1}" .format (build_pkg_name (pkg ), specs ["==" ])
116+ result [pkg .name ] = "{0}=={1}" .format (build_pkg_name (pkg ), specs ["==" ])
158117
159118 elif ">=" in specs :
160119 if level == "min" :
161- result [pkg .key ] = "{0}=={1}" .format (build_pkg_name (pkg ), specs [">=" ])
120+ result [pkg .name ] = "{0}=={1}" .format (build_pkg_name (pkg ), specs [">=" ])
162121 else :
163- result [pkg .key ] = pkg
122+ result [pkg .name ] = pkg
164123
165124 elif ">" in specs :
166125 if level == "min" :
167126 minver_error (build_pkg_name (pkg ))
168127 else :
169- result [pkg .key ] = pkg
128+ result [pkg .name ] = pkg
170129
171130 elif "~=" in specs :
172131 if level == "min" :
173- result [pkg .key ] = "{0}=={1}" .format (build_pkg_name (pkg ), specs ["~=" ])
132+ result [pkg .name ] = "{0}=={1}" .format (build_pkg_name (pkg ), specs ["~=" ])
174133 else :
175134 ver , _ = os .path .splitext (specs ["~=" ])
176- result [pkg .key ] = "{0}>={1},=={2}.*" .format (build_pkg_name (pkg ), specs ["~=" ], ver )
135+ result [pkg .name ] = "{0}>={1},=={2}.*" .format (build_pkg_name (pkg ), specs ["~=" ], ver )
177136
178137 else :
179138 if level == "min" :
180139 minver_error (build_pkg_name (pkg ))
181140 else :
182- result [pkg .key ] = build_pkg_name (pkg )
141+ result [pkg .name ] = build_pkg_name (pkg )
183142
184143 for s in stuff :
185144 yield s
0 commit comments