|
1 |
| -#!/usr/bin/env python |
2 |
| -# -*- coding: utf-8 -*- |
3 |
| - |
| 1 | +# !/usr/bin/env python |
4 | 2 | import setuptools
|
5 | 3 |
|
6 |
| -HAS_DIST_INFO_CMD = False |
7 |
| -try: |
8 |
| - import setuptools.command.dist_info |
9 |
| - |
10 |
| - HAS_DIST_INFO_CMD = True |
11 |
| -except ImportError: |
12 |
| - """Setuptools version is too old.""" |
13 |
| - |
14 |
| - |
15 |
| -ALL_STRING_TYPES = tuple(map(type, ("", b"", u""))) |
16 |
| -MIN_NATIVE_SETUPTOOLS_VERSION = 34, 4, 0 |
17 |
| -"""Minimal setuptools having good read_configuration implementation.""" |
18 |
| - |
19 |
| -RUNTIME_SETUPTOOLS_VERSION = tuple(map(int, setuptools.__version__.split("."))) |
20 |
| -"""Setuptools imported now.""" |
21 |
| - |
22 |
| -READ_CONFIG_SHIM_NEEDED = RUNTIME_SETUPTOOLS_VERSION < MIN_NATIVE_SETUPTOOLS_VERSION |
23 |
| - |
24 |
| - |
25 |
| -def str_if_nested_or_str(s): |
26 |
| - """Turn input into a native string if possible.""" |
27 |
| - if isinstance(s, ALL_STRING_TYPES): |
28 |
| - return str(s) |
29 |
| - if isinstance(s, (list, tuple)): |
30 |
| - return type(s)(map(str_if_nested_or_str, s)) |
31 |
| - if isinstance(s, (dict,)): |
32 |
| - return stringify_dict_contents(s) |
33 |
| - return s |
34 |
| - |
35 |
| - |
36 |
| -def stringify_dict_contents(dct): |
37 |
| - """Turn dict keys and values into native strings.""" |
38 |
| - return {str_if_nested_or_str(k): str_if_nested_or_str(v) for k, v in dct.items()} |
39 |
| - |
40 |
| - |
41 |
| -if not READ_CONFIG_SHIM_NEEDED: |
42 |
| - from setuptools.config import read_configuration, ConfigOptionsHandler |
43 |
| - import setuptools.config |
44 |
| - import setuptools.dist |
45 |
| - |
46 |
| - # Set default value for 'use_scm_version' |
47 |
| - setattr(setuptools.dist.Distribution, "use_scm_version", False) |
48 |
| - |
49 |
| - # Attach bool parser to 'use_scm_version' option |
50 |
| - class ShimConfigOptionsHandler(ConfigOptionsHandler): |
51 |
| - """Extension class for ConfigOptionsHandler.""" |
52 |
| - |
53 |
| - @property |
54 |
| - def parsers(self): |
55 |
| - """Return an option mapping with default data type parsers.""" |
56 |
| - _orig_parsers = super(ShimConfigOptionsHandler, self).parsers |
57 |
| - return dict(use_scm_version=self._parse_bool, **_orig_parsers) |
58 |
| - |
59 |
| - def parse_section_packages__find(self, section_options): |
60 |
| - find_kwargs = super( |
61 |
| - ShimConfigOptionsHandler, self |
62 |
| - ).parse_section_packages__find(section_options) |
63 |
| - return stringify_dict_contents(find_kwargs) |
64 |
| - |
65 |
| - setuptools.config.ConfigOptionsHandler = ShimConfigOptionsHandler |
66 |
| -else: |
67 |
| - """This is a shim for setuptools<required.""" |
68 |
| - import functools |
69 |
| - import io |
70 |
| - import json |
71 |
| - import sys |
72 |
| - import warnings |
73 |
| - |
74 |
| - try: |
75 |
| - import setuptools.config |
76 |
| - |
77 |
| - def filter_out_unknown_section(i): |
78 |
| - def chi(self, *args, **kwargs): |
79 |
| - i(self, *args, **kwargs) |
80 |
| - self.sections = { |
81 |
| - s: v for s, v in self.sections.items() if s != "packages.find" |
82 |
| - } |
83 |
| - |
84 |
| - return chi |
85 |
| - |
86 |
| - setuptools.config.ConfigHandler.__init__ = filter_out_unknown_section( |
87 |
| - setuptools.config.ConfigHandler.__init__ |
88 |
| - ) |
89 |
| - except ImportError: |
90 |
| - pass |
91 |
| - |
92 |
| - def ignore_unknown_options(s): |
93 |
| - @functools.wraps(s) |
94 |
| - def sw(**attrs): |
95 |
| - try: |
96 |
| - ignore_warning_regex = ( |
97 |
| - r"Unknown distribution option: " |
98 |
| - r"'(license_file|project_urls|python_requires)'" |
99 |
| - ) |
100 |
| - warnings.filterwarnings( |
101 |
| - "ignore", |
102 |
| - message=ignore_warning_regex, |
103 |
| - category=UserWarning, |
104 |
| - module="distutils.dist", |
105 |
| - ) |
106 |
| - return s(**attrs) |
107 |
| - finally: |
108 |
| - warnings.resetwarnings() |
109 |
| - |
110 |
| - return sw |
111 |
| - |
112 |
| - def parse_predicates(python_requires): |
113 |
| - import itertools |
114 |
| - import operator |
115 |
| - |
116 |
| - sorted_operators_map = tuple( |
117 |
| - sorted( |
118 |
| - { |
119 |
| - ">": operator.gt, |
120 |
| - "<": operator.lt, |
121 |
| - ">=": operator.ge, |
122 |
| - "<=": operator.le, |
123 |
| - "==": operator.eq, |
124 |
| - "!=": operator.ne, |
125 |
| - "": operator.eq, |
126 |
| - }.items(), |
127 |
| - key=lambda i: len(i[0]), |
128 |
| - reverse=True, |
129 |
| - ) |
130 |
| - ) |
131 |
| - |
132 |
| - def is_decimal(s): |
133 |
| - return type(u"")(s).isdecimal() |
134 |
| - |
135 |
| - conditions = map(str.strip, python_requires.split(",")) |
136 |
| - for c in conditions: |
137 |
| - for op_sign, op_func in sorted_operators_map: |
138 |
| - if not c.startswith(op_sign): |
139 |
| - continue |
140 |
| - raw_ver = itertools.takewhile( |
141 |
| - is_decimal, c[len(op_sign) :].strip().split(".") |
142 |
| - ) |
143 |
| - ver = tuple(map(int, raw_ver)) |
144 |
| - yield op_func, ver |
145 |
| - break |
146 |
| - |
147 |
| - def validate_required_python_or_fail(python_requires=None): |
148 |
| - if python_requires is None: |
149 |
| - return |
150 |
| - |
151 |
| - python_version = sys.version_info |
152 |
| - preds = parse_predicates(python_requires) |
153 |
| - for op, v in preds: |
154 |
| - py_ver_slug = python_version[: max(len(v), 3)] |
155 |
| - condition_matches = op(py_ver_slug, v) |
156 |
| - if not condition_matches: |
157 |
| - raise RuntimeError( |
158 |
| - "requires Python '{}' but the running Python is {}".format( |
159 |
| - python_requires, ".".join(map(str, python_version[:3])) |
160 |
| - ) |
161 |
| - ) |
162 |
| - |
163 |
| - def verify_required_python_runtime(s): |
164 |
| - @functools.wraps(s) |
165 |
| - def sw(**attrs): |
166 |
| - try: |
167 |
| - validate_required_python_or_fail(attrs.get("python_requires")) |
168 |
| - except RuntimeError as re: |
169 |
| - sys.exit("{} {!s}".format(attrs["name"], re)) |
170 |
| - return s(**attrs) |
171 |
| - |
172 |
| - return sw |
173 |
| - |
174 |
| - setuptools.setup = ignore_unknown_options(setuptools.setup) |
175 |
| - setuptools.setup = verify_required_python_runtime(setuptools.setup) |
176 |
| - |
177 |
| - try: |
178 |
| - from configparser import ConfigParser, NoSectionError |
179 |
| - except ImportError: |
180 |
| - from ConfigParser import ConfigParser, NoSectionError |
181 |
| - |
182 |
| - ConfigParser.read_file = ConfigParser.readfp |
183 |
| - |
184 |
| - def maybe_read_files(d): |
185 |
| - """Read files if the string starts with `file:` marker.""" |
186 |
| - FILE_FUNC_MARKER = "file:" |
187 |
| - |
188 |
| - d = d.strip() |
189 |
| - if not d.startswith(FILE_FUNC_MARKER): |
190 |
| - return d |
191 |
| - descs = [] |
192 |
| - for fname in map(str.strip, str(d[len(FILE_FUNC_MARKER) :]).split(",")): |
193 |
| - with io.open(fname, encoding="utf-8") as f: |
194 |
| - descs.append(f.read()) |
195 |
| - return "".join(descs) |
196 |
| - |
197 |
| - def cfg_val_to_list(v): |
198 |
| - """Turn config val to list and filter out empty lines.""" |
199 |
| - return list(filter(bool, map(str.strip, str(v).strip().splitlines()))) |
200 |
| - |
201 |
| - def cfg_val_to_dict(v): |
202 |
| - """Turn config val to dict and filter out empty lines.""" |
203 |
| - return dict( |
204 |
| - map( |
205 |
| - lambda l: list(map(str.strip, l.split("=", 1))), |
206 |
| - filter(bool, map(str.strip, str(v).strip().splitlines())), |
207 |
| - ) |
208 |
| - ) |
209 |
| - |
210 |
| - def cfg_val_to_primitive(v): |
211 |
| - """Parse primitive config val to appropriate data type.""" |
212 |
| - return json.loads(v.strip().lower()) |
213 |
| - |
214 |
| - def read_configuration(filepath): |
215 |
| - """Read metadata and options from setup.cfg located at filepath.""" |
216 |
| - cfg = ConfigParser() |
217 |
| - with io.open(filepath, encoding="utf-8") as f: |
218 |
| - cfg.read_file(f) |
219 |
| - |
220 |
| - md = dict(cfg.items("metadata")) |
221 |
| - for list_key in "classifiers", "keywords", "project_urls": |
222 |
| - try: |
223 |
| - md[list_key] = cfg_val_to_list(md[list_key]) |
224 |
| - except KeyError: |
225 |
| - pass |
226 |
| - try: |
227 |
| - md["long_description"] = maybe_read_files(md["long_description"]) |
228 |
| - except KeyError: |
229 |
| - pass |
230 |
| - opt = dict(cfg.items("options")) |
231 |
| - for list_key in "include_package_data", "use_scm_version", "zip_safe": |
232 |
| - try: |
233 |
| - opt[list_key] = cfg_val_to_primitive(opt[list_key]) |
234 |
| - except KeyError: |
235 |
| - pass |
236 |
| - for list_key in "scripts", "install_requires", "setup_requires": |
237 |
| - try: |
238 |
| - opt[list_key] = cfg_val_to_list(opt[list_key]) |
239 |
| - except KeyError: |
240 |
| - pass |
241 |
| - try: |
242 |
| - opt["package_dir"] = cfg_val_to_dict(opt["package_dir"]) |
243 |
| - except KeyError: |
244 |
| - pass |
245 |
| - try: |
246 |
| - opt_package_data = dict(cfg.items("options.package_data")) |
247 |
| - if not opt_package_data.get("", "").strip(): |
248 |
| - opt_package_data[""] = opt_package_data["*"] |
249 |
| - del opt_package_data["*"] |
250 |
| - except (KeyError, NoSectionError): |
251 |
| - opt_package_data = {} |
252 |
| - try: |
253 |
| - opt_extras_require = dict(cfg.items("options.extras_require")) |
254 |
| - opt["extras_require"] = {} |
255 |
| - for k, v in opt_extras_require.items(): |
256 |
| - opt["extras_require"][k] = cfg_val_to_list(v) |
257 |
| - except NoSectionError: |
258 |
| - pass |
259 |
| - opt["package_data"] = {} |
260 |
| - for k, v in opt_package_data.items(): |
261 |
| - opt["package_data"][k] = cfg_val_to_list(v) |
262 |
| - try: |
263 |
| - opt_exclude_package_data = dict(cfg.items("options.exclude_package_data")) |
264 |
| - if ( |
265 |
| - not opt_exclude_package_data.get("", "").strip() |
266 |
| - and "*" in opt_exclude_package_data |
267 |
| - ): |
268 |
| - opt_exclude_package_data[""] = opt_exclude_package_data["*"] |
269 |
| - del opt_exclude_package_data["*"] |
270 |
| - except NoSectionError: |
271 |
| - pass |
272 |
| - else: |
273 |
| - opt["exclude_package_data"] = {} |
274 |
| - for k, v in opt_exclude_package_data.items(): |
275 |
| - opt["exclude_package_data"][k] = cfg_val_to_list(v) |
276 |
| - cur_pkgs = opt.get("packages", "").strip() |
277 |
| - if "\n" in cur_pkgs: |
278 |
| - opt["packages"] = cfg_val_to_list(opt["packages"]) |
279 |
| - elif cur_pkgs.startswith("find:"): |
280 |
| - opt_packages_find = stringify_dict_contents( |
281 |
| - dict(cfg.items("options.packages.find")) |
282 |
| - ) |
283 |
| - opt["packages"] = setuptools.find_packages(**opt_packages_find) |
284 |
| - return {"metadata": md, "options": opt} |
285 |
| - |
286 |
| - |
287 |
| -def cut_local_version_on_upload(version): |
288 |
| - """Generate a PEP440 local version if uploading to PyPI.""" |
289 |
| - import os |
290 |
| - import setuptools_scm.version # only present during setup time |
291 |
| - |
292 |
| - IS_PYPI_UPLOAD = os.getenv("PYPI_UPLOAD") == "true" # set in tox.ini |
293 |
| - return ( |
294 |
| - "" |
295 |
| - if IS_PYPI_UPLOAD |
296 |
| - else setuptools_scm.version.get_local_node_and_date(version) |
297 |
| - ) |
298 |
| - |
299 |
| - |
300 |
| -if HAS_DIST_INFO_CMD: |
301 |
| - |
302 |
| - class patched_dist_info(setuptools.command.dist_info.dist_info): |
303 |
| - def run(self): |
304 |
| - self.egg_base = str_if_nested_or_str(self.egg_base) |
305 |
| - return setuptools.command.dist_info.dist_info.run(self) |
306 |
| - |
307 |
| - |
308 |
| -declarative_setup_params = read_configuration("setup.cfg") |
309 |
| -"""Declarative metadata and options as read by setuptools.""" |
310 |
| - |
311 |
| - |
312 |
| -setup_params = {} |
313 |
| -"""Explicit metadata for passing into setuptools.setup() call.""" |
314 |
| - |
315 |
| -setup_params = dict(setup_params, **declarative_setup_params["metadata"]) |
316 |
| -setup_params = dict(setup_params, **declarative_setup_params["options"]) |
317 |
| - |
318 |
| -if HAS_DIST_INFO_CMD: |
319 |
| - setup_params["cmdclass"] = {"dist_info": patched_dist_info} |
320 |
| - |
321 |
| -setup_params["use_scm_version"] = {"local_scheme": cut_local_version_on_upload} |
322 |
| - |
323 |
| -# Patch incorrectly decoded package_dir option |
324 |
| -# ``egg_info`` demands native strings failing with unicode under Python 2 |
325 |
| -# Ref https://github.com/pypa/setuptools/issues/1136 |
326 |
| -setup_params = stringify_dict_contents(setup_params) |
327 |
| - |
328 | 4 |
|
329 | 5 | if __name__ == "__main__":
|
330 |
| - setuptools.setup(**setup_params) |
| 6 | + setuptools.setup(use_scm_version=True) |
0 commit comments