From 5a0f4b9784a35e514f53ea08adb29d999f511cac Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 12 Oct 2017 10:14:43 +0200 Subject: Renamed 'pep517' to 'build_meta' --- setuptools/build_meta.py | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 setuptools/build_meta.py (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py new file mode 100644 index 00000000..54f2987b --- /dev/null +++ b/setuptools/build_meta.py @@ -0,0 +1,148 @@ +"""A PEP 517 interface to setuptools + +Previously, when a user or a command line tool (let's call it a "frontend") +needed to make a request of setuptools to take a certain action, for +example, generating a list of installation requirements, the frontend would +would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line. + +PEP 517 defines a different method of interfacing with setuptools. Rather +than calling "setup.py" directly, the frontend should: + + 1. Set the current directory to the directory with a setup.py file + 2. Import this module into a safe python interpreter (one in which + setuptools can potentially set global variables or crash hard). + 3. Call one of the functions defined in PEP 517. + +What each function does is defined in PEP 517. However, here is a "casual" +definition of the functions (this definition should not be relied on for +bug reports or API stability): + + - `build_wheel`: build a wheel in the folder and return the basename + - `get_requires_for_build_wheel`: get the `setup_requires` to build + - `prepare_metadata_for_build_wheel`: get the `install_requires` + - `build_sdist`: build an sdist in the folder and return the basename + - `get_requires_for_build_sdist`: get the `setup_requires` to build + +Again, this is not a formal definition! Just a "taste" of the module. +""" + +import os +import sys +import tokenize +import shutil +import contextlib + +import setuptools +import distutils + + +class SetupRequirementsError(BaseException): + def __init__(self, specifiers): + self.specifiers = specifiers + + +class Distribution(setuptools.dist.Distribution): + def fetch_build_eggs(self, specifiers): + raise SetupRequirementsError(specifiers) + + @classmethod + @contextlib.contextmanager + def patch(cls): + """ + Replace + distutils.dist.Distribution with this class + for the duration of this context. + """ + orig = distutils.core.Distribution + distutils.core.Distribution = cls + try: + yield + finally: + distutils.core.Distribution = orig + + +def _run_setup(setup_script='setup.py'): + # Note that we can reuse our build directory between calls + # Correctness comes first, then optimization later + __file__ = setup_script + f = getattr(tokenize, 'open', open)(__file__) + code = f.read().replace('\\r\\n', '\\n') + f.close() + exec(compile(code, __file__, 'exec')) + + +def _fix_config(config_settings): + config_settings = config_settings or {} + config_settings.setdefault('--global-option', []) + return config_settings + + +def _get_build_requires(config_settings): + config_settings = _fix_config(config_settings) + requirements = ['setuptools', 'wheel'] + + sys.argv = sys.argv[:1] + ['egg_info'] + \ + config_settings["--global-option"] + try: + with Distribution.patch(): + _run_setup() + except SetupRequirementsError as e: + requirements += e.specifiers + + return requirements + + +def get_requires_for_build_wheel(config_settings=None): + config_settings = _fix_config(config_settings) + return _get_build_requires(config_settings) + + +def get_requires_for_build_sdist(config_settings=None): + config_settings = _fix_config(config_settings) + return _get_build_requires(config_settings) + + +def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): + sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', metadata_directory] + _run_setup() + + dist_infos = [f for f in os.listdir(metadata_directory) + if f.endswith('.dist-info')] + + assert len(dist_infos) == 1 + return dist_infos[0] + + +def build_wheel(wheel_directory, config_settings=None, + metadata_directory=None): + config_settings = _fix_config(config_settings) + wheel_directory = os.path.abspath(wheel_directory) + sys.argv = sys.argv[:1] + ['bdist_wheel'] + \ + config_settings["--global-option"] + _run_setup() + if wheel_directory != 'dist': + shutil.rmtree(wheel_directory) + shutil.copytree('dist', wheel_directory) + + wheels = [f for f in os.listdir(wheel_directory) + if f.endswith('.whl')] + + assert len(wheels) == 1 + return wheels[0] + + +def build_sdist(sdist_directory, config_settings=None): + config_settings = _fix_config(config_settings) + sdist_directory = os.path.abspath(sdist_directory) + sys.argv = sys.argv[:1] + ['sdist'] + \ + config_settings["--global-option"] + _run_setup() + if sdist_directory != 'dist': + shutil.rmtree(sdist_directory) + shutil.copytree('dist', sdist_directory) + + sdists = [f for f in os.listdir(sdist_directory) + if f.endswith('.tar.gz')] + + assert len(sdists) == 1 + return sdists[0] -- cgit v1.2.1 From ffb2e6994a3405c2ab007ab9564bb02c9263eb6c Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 15 Oct 2017 12:48:33 -0500 Subject: BUG: re-initialize the master working set In some cases (specifically when pip imports this module in a virtualenv), pkg_resources can already be imported, causing setuptools to load entry_points from an older version. Here, we re-initialize the master working set to fix the case where the entry points from an older setuptools are loaded. --- setuptools/build_meta.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 54f2987b..365e24ee 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -35,6 +35,8 @@ import contextlib import setuptools import distutils +from pkg_resources import _initialize_master_working_set + class SetupRequirementsError(BaseException): def __init__(self, specifiers): @@ -64,6 +66,7 @@ class Distribution(setuptools.dist.Distribution): def _run_setup(setup_script='setup.py'): # Note that we can reuse our build directory between calls # Correctness comes first, then optimization later + _initialize_master_working_set() __file__ = setup_script f = getattr(tokenize, 'open', open)(__file__) code = f.read().replace('\\r\\n', '\\n') -- cgit v1.2.1 From cf130d32a57eddc455b39295c09ac5758187e549 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 15 Oct 2017 13:01:18 -0500 Subject: build_meta: print dist_info directories --- setuptools/build_meta.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 365e24ee..99ca0339 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -112,6 +112,8 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): dist_infos = [f for f in os.listdir(metadata_directory) if f.endswith('.dist-info')] + print(dist_infos) + assert len(dist_infos) == 1 return dist_infos[0] -- cgit v1.2.1 From efc7b7b5fb61125b888a615d6ef4b1fca85332c0 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 15 Oct 2017 13:12:47 -0500 Subject: FIX: revert changes --- setuptools/build_meta.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 99ca0339..365e24ee 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -112,8 +112,6 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): dist_infos = [f for f in os.listdir(metadata_directory) if f.endswith('.dist-info')] - print(dist_infos) - assert len(dist_infos) == 1 return dist_infos[0] -- cgit v1.2.1 From 1a37f5713e08a0320038ec4e5d2164f95a29abef Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 15 Oct 2017 13:28:32 -0500 Subject: FIX: setup the correct environment before loading setup.py --- setuptools/build_meta.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 365e24ee..02ad91cc 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -68,10 +68,11 @@ def _run_setup(setup_script='setup.py'): # Correctness comes first, then optimization later _initialize_master_working_set() __file__ = setup_script + __name__ = '__main__' f = getattr(tokenize, 'open', open)(__file__) code = f.read().replace('\\r\\n', '\\n') f.close() - exec(compile(code, __file__, 'exec')) + exec(compile(code, __file__, 'exec'), locals()) def _fix_config(config_settings): -- cgit v1.2.1 From 55e1b97a8a06956d60f7e441ebe46200efc775df Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 16 Oct 2017 10:42:52 -0500 Subject: FIX: drop the more contraversial changes --- setuptools/build_meta.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 02ad91cc..f89f82d6 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -35,8 +35,6 @@ import contextlib import setuptools import distutils -from pkg_resources import _initialize_master_working_set - class SetupRequirementsError(BaseException): def __init__(self, specifiers): @@ -66,7 +64,6 @@ class Distribution(setuptools.dist.Distribution): def _run_setup(setup_script='setup.py'): # Note that we can reuse our build directory between calls # Correctness comes first, then optimization later - _initialize_master_working_set() __file__ = setup_script __name__ = '__main__' f = getattr(tokenize, 'open', open)(__file__) -- cgit v1.2.1 From ca5a81864d5fc3b6bcb1e9186a38e3fbc0d0beff Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 19 Oct 2017 14:35:48 -0500 Subject: BUG: look for dist-infos in subdirectories This code is a bit ugly, but it's also been tested with the pip test suite It's not the best solution long term (the best solution is to get the egg_info directory directly from egg_info), but it works for now and avoids technical risk. --- setuptools/build_meta.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index f89f82d6..609ea1e5 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -93,6 +93,11 @@ def _get_build_requires(config_settings): return requirements +def _get_immediate_subdirectories(a_dir): + return [name for name in os.listdir(a_dir) + if os.path.isdir(os.path.join(a_dir, name))] + + def get_requires_for_build_wheel(config_settings=None): config_settings = _fix_config(config_settings) return _get_build_requires(config_settings) @@ -106,11 +111,29 @@ def get_requires_for_build_sdist(config_settings=None): def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', metadata_directory] _run_setup() + + dist_info_directory = metadata_directory + while True: + dist_infos = [f for f in os.listdir(dist_info_directory) + if f.endswith('.dist-info')] + + if len(dist_infos) == 0 and \ + len(_get_immediate_subdirectories(dist_info_directory)) == 1: + dist_info_directory = os.path.join( + dist_info_directory, os.listdir(dist_info_directory)[0]) + continue + + assert len(dist_infos) == 1 + break + + # PEP 517 requires that the .dist-info directory be placed in the + # metadata_directory. To comply, we MUST copy the directory to the root + if dist_info_directory != metadata_directory: + shutil.move( + os.path.join(dist_info_directory, dist_infos[0]), + metadata_directory) + shutil.rmtree(dist_info_directory, ignore_errors=True) - dist_infos = [f for f in os.listdir(metadata_directory) - if f.endswith('.dist-info')] - - assert len(dist_infos) == 1 return dist_infos[0] -- cgit v1.2.1 From 83c7d77abdaf4f802cd651fb59de77c72dc94cfe Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Mon, 20 Aug 2018 15:25:14 +0100 Subject: PEP 517 hook arguments are unicode, not str (and distutils objects to that) --- setuptools/build_meta.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 609ea1e5..fb657a54 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -61,6 +61,19 @@ class Distribution(setuptools.dist.Distribution): distutils.core.Distribution = orig +def _to_str(s): + """ + Convert a filename to a string (on Python 2, explicitly + a byte string, not Unicode) as distutils checks for the + exact type str. + """ + if sys.version_info[0] == 2 and not isinstance(s, str): + # Assume it's Unicode, as that's what the PEP says + # should be provided. + return s.encode(sys.getfilesystemencoding()) + return s + + def _run_setup(setup_script='setup.py'): # Note that we can reuse our build directory between calls # Correctness comes first, then optimization later @@ -109,7 +122,7 @@ def get_requires_for_build_sdist(config_settings=None): def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): - sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', metadata_directory] + sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', _to_str(metadata_directory)] _run_setup() dist_info_directory = metadata_directory -- cgit v1.2.1 From 2fabfd3a66e6984bd6fccf07b46356f956af0297 Mon Sep 17 00:00:00 2001 From: Bernat Gabor Date: Thu, 13 Sep 2018 10:03:06 +0100 Subject: build_meta.get_requires_for_build_sdist does not include wheel the wheel package is not required to build a source distribution Resolves #1474. --- setuptools/build_meta.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index fb657a54..f7f9bda2 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -91,9 +91,8 @@ def _fix_config(config_settings): return config_settings -def _get_build_requires(config_settings): +def _get_build_requires(config_settings, requirements): config_settings = _fix_config(config_settings) - requirements = ['setuptools', 'wheel'] sys.argv = sys.argv[:1] + ['egg_info'] + \ config_settings["--global-option"] @@ -113,20 +112,20 @@ def _get_immediate_subdirectories(a_dir): def get_requires_for_build_wheel(config_settings=None): config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings) + return _get_build_requires(config_settings, requirements=['setuptools', 'wheel']) def get_requires_for_build_sdist(config_settings=None): config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings) + return _get_build_requires(config_settings, requirements=['setuptools']) def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', _to_str(metadata_directory)] _run_setup() - + dist_info_directory = metadata_directory - while True: + while True: dist_infos = [f for f in os.listdir(dist_info_directory) if f.endswith('.dist-info')] -- cgit v1.2.1 From d39791489ce78d16e0238f60c429f0be08f4a994 Mon Sep 17 00:00:00 2001 From: Bernat Gabor Date: Fri, 14 Sep 2018 15:01:41 +0100 Subject: build_meta sdist directory delegate to --dist-dir --- setuptools/build_meta.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index f7f9bda2..0067a7ac 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -171,11 +171,9 @@ def build_sdist(sdist_directory, config_settings=None): config_settings = _fix_config(config_settings) sdist_directory = os.path.abspath(sdist_directory) sys.argv = sys.argv[:1] + ['sdist'] + \ - config_settings["--global-option"] + config_settings["--global-option"] + \ + ["--dist-dir", sdist_directory] _run_setup() - if sdist_directory != 'dist': - shutil.rmtree(sdist_directory) - shutil.copytree('dist', sdist_directory) sdists = [f for f in os.listdir(sdist_directory) if f.endswith('.tar.gz')] -- cgit v1.2.1 From ed22402b7b41f608eaacebaae67c805503904f7d Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Wed, 14 Nov 2018 18:07:37 +0000 Subject: Backend should not say that setuptools is needed to build --- setuptools/build_meta.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 0067a7ac..463d3757 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -112,12 +112,12 @@ def _get_immediate_subdirectories(a_dir): def get_requires_for_build_wheel(config_settings=None): config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings, requirements=['setuptools', 'wheel']) + return _get_build_requires(config_settings, requirements=['wheel']) def get_requires_for_build_sdist(config_settings=None): config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings, requirements=['setuptools']) + return _get_build_requires(config_settings, requirements=[]) def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): -- cgit v1.2.1 From 731df905fb0282c7255e4e0d4acf339a98e3db7e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 2 Jan 2019 14:28:33 -0500 Subject: Always specify formats=gztar, overriding the project's legacy expectation that a zip sdist should be generated. Fixes #1623. --- setuptools/build_meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 463d3757..75178a7a 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -170,7 +170,7 @@ def build_wheel(wheel_directory, config_settings=None, def build_sdist(sdist_directory, config_settings=None): config_settings = _fix_config(config_settings) sdist_directory = os.path.abspath(sdist_directory) - sys.argv = sys.argv[:1] + ['sdist'] + \ + sys.argv = sys.argv[:1] + ['sdist', '--formats', 'gztar'] + \ config_settings["--global-option"] + \ ["--dist-dir", sdist_directory] _run_setup() -- cgit v1.2.1 From cc9305b9106eaf409c01e8a399a00137583e2a04 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 2 Jan 2019 14:37:45 -0500 Subject: Rely on iterable unpacking to extract one element from generator expression. --- setuptools/build_meta.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 463d3757..7f2786c4 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -160,11 +160,11 @@ def build_wheel(wheel_directory, config_settings=None, shutil.rmtree(wheel_directory) shutil.copytree('dist', wheel_directory) - wheels = [f for f in os.listdir(wheel_directory) - if f.endswith('.whl')] + wheels = (f for f in os.listdir(wheel_directory) + if f.endswith('.whl')) - assert len(wheels) == 1 - return wheels[0] + wheel, = wheels + return wheel def build_sdist(sdist_directory, config_settings=None): @@ -175,8 +175,8 @@ def build_sdist(sdist_directory, config_settings=None): ["--dist-dir", sdist_directory] _run_setup() - sdists = [f for f in os.listdir(sdist_directory) - if f.endswith('.tar.gz')] + sdists = (f for f in os.listdir(sdist_directory) + if f.endswith('.tar.gz')) - assert len(sdists) == 1 - return sdists[0] + sdist, = sdists + return sdist -- cgit v1.2.1 From 7378e6be2f8f8a0d96b748e256dfa6b53821c3f6 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 2 Jan 2019 14:39:37 -0500 Subject: Avoid hanging indent --- setuptools/build_meta.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 7f2786c4..5a69d284 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -160,8 +160,10 @@ def build_wheel(wheel_directory, config_settings=None, shutil.rmtree(wheel_directory) shutil.copytree('dist', wheel_directory) - wheels = (f for f in os.listdir(wheel_directory) - if f.endswith('.whl')) + wheels = ( + f for f in os.listdir(wheel_directory) + if f.endswith('.whl') + ) wheel, = wheels return wheel @@ -175,8 +177,10 @@ def build_sdist(sdist_directory, config_settings=None): ["--dist-dir", sdist_directory] _run_setup() - sdists = (f for f in os.listdir(sdist_directory) - if f.endswith('.tar.gz')) + sdists = ( + f for f in os.listdir(sdist_directory) + if f.endswith('.tar.gz') + ) sdist, = sdists return sdist -- cgit v1.2.1 From 2bb8225a6efa6f429d4522f47308b779a48cd07f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 2 Jan 2019 14:42:23 -0500 Subject: Extract common behavior into a function --- setuptools/build_meta.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 5a69d284..02de4427 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -149,6 +149,15 @@ def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): return dist_infos[0] +def _file_with_extension(directory, extension): + matching = ( + f for f in os.listdir(directory) + if f.endswith(extension) + ) + file, = matching + return file + + def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): config_settings = _fix_config(config_settings) @@ -160,13 +169,7 @@ def build_wheel(wheel_directory, config_settings=None, shutil.rmtree(wheel_directory) shutil.copytree('dist', wheel_directory) - wheels = ( - f for f in os.listdir(wheel_directory) - if f.endswith('.whl') - ) - - wheel, = wheels - return wheel + return _file_with_extension(wheel_directory, '.whl') def build_sdist(sdist_directory, config_settings=None): @@ -177,10 +180,4 @@ def build_sdist(sdist_directory, config_settings=None): ["--dist-dir", sdist_directory] _run_setup() - sdists = ( - f for f in os.listdir(sdist_directory) - if f.endswith('.tar.gz') - ) - - sdist, = sdists - return sdist + return _file_with_extension(sdist_directory, '.tar.gz') -- cgit v1.2.1 From 74c323d1658f554b879ef6ac2867faf77776a2ac Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sun, 27 Jan 2019 11:45:10 -0500 Subject: Wrap build_meta backend in a class In order to support both the `build_meta` and `build_meta_legacy` backends, the core functionality is wrapped in a class with methods to be overridden in build_meta_legacy. The class is an implementation detail and should remain private. --- setuptools/build_meta.py | 187 ++++++++++++++++++++++++----------------------- 1 file changed, 97 insertions(+), 90 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index c883d92f..f40549e7 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -74,81 +74,11 @@ def _to_str(s): return s -def _run_setup(setup_script='setup.py'): - # Note that we can reuse our build directory between calls - # Correctness comes first, then optimization later - __file__ = setup_script - __name__ = '__main__' - f = getattr(tokenize, 'open', open)(__file__) - code = f.read().replace('\\r\\n', '\\n') - f.close() - exec(compile(code, __file__, 'exec'), locals()) - - -def _fix_config(config_settings): - config_settings = config_settings or {} - config_settings.setdefault('--global-option', []) - return config_settings - - -def _get_build_requires(config_settings, requirements): - config_settings = _fix_config(config_settings) - - sys.argv = sys.argv[:1] + ['egg_info'] + \ - config_settings["--global-option"] - try: - with Distribution.patch(): - _run_setup() - except SetupRequirementsError as e: - requirements += e.specifiers - - return requirements - - def _get_immediate_subdirectories(a_dir): return [name for name in os.listdir(a_dir) if os.path.isdir(os.path.join(a_dir, name))] -def get_requires_for_build_wheel(config_settings=None): - config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings, requirements=['wheel']) - - -def get_requires_for_build_sdist(config_settings=None): - config_settings = _fix_config(config_settings) - return _get_build_requires(config_settings, requirements=[]) - - -def prepare_metadata_for_build_wheel(metadata_directory, config_settings=None): - sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', _to_str(metadata_directory)] - _run_setup() - - dist_info_directory = metadata_directory - while True: - dist_infos = [f for f in os.listdir(dist_info_directory) - if f.endswith('.dist-info')] - - if len(dist_infos) == 0 and \ - len(_get_immediate_subdirectories(dist_info_directory)) == 1: - dist_info_directory = os.path.join( - dist_info_directory, os.listdir(dist_info_directory)[0]) - continue - - assert len(dist_infos) == 1 - break - - # PEP 517 requires that the .dist-info directory be placed in the - # metadata_directory. To comply, we MUST copy the directory to the root - if dist_info_directory != metadata_directory: - shutil.move( - os.path.join(dist_info_directory, dist_infos[0]), - metadata_directory) - shutil.rmtree(dist_info_directory, ignore_errors=True) - - return dist_infos[0] - - def _file_with_extension(directory, extension): matching = ( f for f in os.listdir(directory) @@ -158,26 +88,103 @@ def _file_with_extension(directory, extension): return file -def build_wheel(wheel_directory, config_settings=None, - metadata_directory=None): - config_settings = _fix_config(config_settings) - wheel_directory = os.path.abspath(wheel_directory) - sys.argv = sys.argv[:1] + ['bdist_wheel'] + \ - config_settings["--global-option"] - _run_setup() - if wheel_directory != 'dist': - shutil.rmtree(wheel_directory) - shutil.copytree('dist', wheel_directory) +class _BuildMetaBackend(object): - return _file_with_extension(wheel_directory, '.whl') + def _fix_config(self, config_settings): + config_settings = config_settings or {} + config_settings.setdefault('--global-option', []) + return config_settings + def _get_build_requires(self, config_settings, requirements): + config_settings = self._fix_config(config_settings) -def build_sdist(sdist_directory, config_settings=None): - config_settings = _fix_config(config_settings) - sdist_directory = os.path.abspath(sdist_directory) - sys.argv = sys.argv[:1] + ['sdist', '--formats', 'gztar'] + \ - config_settings["--global-option"] + \ - ["--dist-dir", sdist_directory] - _run_setup() - - return _file_with_extension(sdist_directory, '.tar.gz') + sys.argv = sys.argv[:1] + ['egg_info'] + \ + config_settings["--global-option"] + try: + with Distribution.patch(): + self.run_setup() + except SetupRequirementsError as e: + requirements += e.specifiers + + return requirements + + def run_setup(self, setup_script='setup.py'): + # Note that we can reuse our build directory between calls + # Correctness comes first, then optimization later + __file__ = setup_script + __name__ = '__main__' + f = getattr(tokenize, 'open', open)(__file__) + code = f.read().replace('\\r\\n', '\\n') + f.close() + exec(compile(code, __file__, 'exec'), locals()) + + def get_requires_for_build_wheel(self, config_settings=None): + config_settings = self._fix_config(config_settings) + return self._get_build_requires(config_settings, requirements=['wheel']) + + def get_requires_for_build_sdist(self, config_settings=None): + config_settings = self._fix_config(config_settings) + return self._get_build_requires(config_settings, requirements=[]) + + def prepare_metadata_for_build_wheel(self, metadata_directory, + config_settings=None): + sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', + _to_str(metadata_directory)] + self.run_setup() + + dist_info_directory = metadata_directory + while True: + dist_infos = [f for f in os.listdir(dist_info_directory) + if f.endswith('.dist-info')] + + if (len(dist_infos) == 0 and + len(_get_immediate_subdirectories(dist_info_directory)) == 1): + + dist_info_directory = os.path.join( + dist_info_directory, os.listdir(dist_info_directory)[0]) + continue + + assert len(dist_infos) == 1 + break + + # PEP 517 requires that the .dist-info directory be placed in the + # metadata_directory. To comply, we MUST copy the directory to the root + if dist_info_directory != metadata_directory: + shutil.move( + os.path.join(dist_info_directory, dist_infos[0]), + metadata_directory) + shutil.rmtree(dist_info_directory, ignore_errors=True) + + return dist_infos[0] + + def build_wheel(self, wheel_directory, config_settings=None, + metadata_directory=None): + config_settings = self._fix_config(config_settings) + wheel_directory = os.path.abspath(wheel_directory) + sys.argv = sys.argv[:1] + ['bdist_wheel'] + \ + config_settings["--global-option"] + self.run_setup() + if wheel_directory != 'dist': + shutil.rmtree(wheel_directory) + shutil.copytree('dist', wheel_directory) + + return _file_with_extension(wheel_directory, '.whl') + + def build_sdist(self, sdist_directory, config_settings=None): + config_settings = self._fix_config(config_settings) + sdist_directory = os.path.abspath(sdist_directory) + sys.argv = sys.argv[:1] + ['sdist', '--formats', 'gztar'] + \ + config_settings["--global-option"] + \ + ["--dist-dir", sdist_directory] + self.run_setup() + + return _file_with_extension(sdist_directory, '.tar.gz') + + +_BACKEND = _BuildMetaBackend() + +get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel +get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist +prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel +build_wheel = _BACKEND.build_wheel +build_sdist = _BACKEND.build_sdist -- cgit v1.2.1 From f40a47a776904b09747502a1f210af9fc92ec542 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sun, 27 Jan 2019 11:46:21 -0500 Subject: Add __all__ to setuptools.build_meta --- setuptools/build_meta.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index f40549e7..8e31a04d 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -35,6 +35,12 @@ import contextlib import setuptools import distutils +__all__ = ['get_requires_for_build_sdist', + 'get_requires_for_build_wheel', + 'prepare_metadata_for_build_wheel', + 'build_wheel', + 'build_sdist', + 'SetupRequirementsError'] class SetupRequirementsError(BaseException): def __init__(self, specifiers): -- cgit v1.2.1 From 11fb3f38d23ff1e0d81e64ba3b68b3de2d2b990a Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sun, 3 Feb 2019 12:17:46 -0500 Subject: Move build_meta_legacy to build_meta:legacy Rather than exposing a top-level module for the legacy backend, we will move the legacy backend into the `setuptools.build_meta` module and specify it using the module:object syntax. --- setuptools/build_meta.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 8e31a04d..e16f319e 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -40,6 +40,7 @@ __all__ = ['get_requires_for_build_sdist', 'prepare_metadata_for_build_wheel', 'build_wheel', 'build_sdist', + 'legacy', 'SetupRequirementsError'] class SetupRequirementsError(BaseException): @@ -187,6 +188,36 @@ class _BuildMetaBackend(object): return _file_with_extension(sdist_directory, '.tar.gz') +class _BuildMetaLegacyBackend(_BuildMetaBackend): + """Compatibility backend for setuptools + + This is a version of setuptools.build_meta that endeavors to maintain backwards + compatibility with pre-PEP 517 modes of invocation. It exists as a temporary + bridge between the old packaging mechanism and the new packaging mechanism, + and will eventually be removed. + """ + def run_setup(self, setup_script='setup.py'): + # In order to maintain compatibility with scripts assuming that + # the setup.py script is in a directory on the PYTHONPATH, inject + # '' into sys.path. (pypa/setuptools#1642) + sys_path = list(sys.path) # Save the original path + + script_dir = os.path.dirname(os.path.abspath(setup_script)) + if script_dir not in sys.path: + sys.path.insert(0, script_dir) + + try: + super(_BuildMetaLegacyBackend, + self).run_setup(setup_script=setup_script) + finally: + # While PEP 517 frontends should be calling each hook in a fresh + # subprocess according to the standard (and thus it should not be + # strictly necessary to restore the old sys.path), we'll restore + # the original path so that the path manipulation does not persist + # within the hook after run_setup is called. + sys.path[:] = sys_path + +# The primary backend _BACKEND = _BuildMetaBackend() get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel @@ -194,3 +225,7 @@ get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel build_wheel = _BACKEND.build_wheel build_sdist = _BACKEND.build_sdist + + +# The legacy backend +legacy = _BuildMetaLegacyBackend() -- cgit v1.2.1 From e04a41e3129fa9945e15b16fd6d65cc212c1d946 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Tue, 5 Feb 2019 08:42:36 -0500 Subject: Rename build_meta:legacy to build_meta:__legacy__ --- setuptools/build_meta.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index e16f319e..70b7ab23 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -40,7 +40,7 @@ __all__ = ['get_requires_for_build_sdist', 'prepare_metadata_for_build_wheel', 'build_wheel', 'build_sdist', - 'legacy', + '__legacy__', 'SetupRequirementsError'] class SetupRequirementsError(BaseException): @@ -228,4 +228,4 @@ build_sdist = _BACKEND.build_sdist # The legacy backend -legacy = _BuildMetaLegacyBackend() +__legacy__ = _BuildMetaLegacyBackend() -- cgit v1.2.1 From 179115b198387a21202433ea61cc53f2efd383fc Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Thu, 31 Jan 2019 08:29:36 -0500 Subject: Add support for setup.cfg-only projects Many projects can get away with an empty `setup.py` and use *only* the declarative `setup.cfg`. With the new PEP 517 backend, we can supply a default empty `setup.py` if one is not provided. --- setuptools/build_meta.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 70b7ab23..047cc07b 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -26,6 +26,7 @@ bug reports or API stability): Again, this is not a formal definition! Just a "taste" of the module. """ +import io import os import sys import tokenize @@ -95,6 +96,14 @@ def _file_with_extension(directory, extension): return file +def _open_setup_script(setup_script): + if not os.path.exists(setup_script): + # Supply a default setup.py + return io.StringIO(u"from setuptools import setup; setup()") + + return getattr(tokenize, 'open', open)(setup_script) + + class _BuildMetaBackend(object): def _fix_config(self, config_settings): @@ -120,9 +129,10 @@ class _BuildMetaBackend(object): # Correctness comes first, then optimization later __file__ = setup_script __name__ = '__main__' - f = getattr(tokenize, 'open', open)(__file__) - code = f.read().replace('\\r\\n', '\\n') - f.close() + + with _open_setup_script(__file__) as f: + code = f.read().replace(r'\r\n', r'\n') + exec(compile(code, __file__, 'exec'), locals()) def get_requires_for_build_wheel(self, config_settings=None): -- cgit v1.2.1 From 318f739d14a810042e6803fa3eb4c4e140f0ef88 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 16 Mar 2019 12:53:05 -0400 Subject: Add requirement parsing in setuptools.build_meta This fixes GH #1682 by porting the pkg_resources requirement parsing logic into setuptools.build_meta, so that all valid requirement specifiers passed to setup_requires will be added to the get_requires_for_build_* function outputs. Fixes GH #1682 --- setuptools/build_meta.py | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 047cc07b..fb37c02a 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -36,6 +36,8 @@ import contextlib import setuptools import distutils +from setuptools._vendor import six + __all__ = ['get_requires_for_build_sdist', 'get_requires_for_build_wheel', 'prepare_metadata_for_build_wheel', @@ -51,7 +53,9 @@ class SetupRequirementsError(BaseException): class Distribution(setuptools.dist.Distribution): def fetch_build_eggs(self, specifiers): - raise SetupRequirementsError(specifiers) + specifier_list = self._parse_requirements(specifiers) + + raise SetupRequirementsError(specifier_list) @classmethod @contextlib.contextmanager @@ -68,6 +72,45 @@ class Distribution(setuptools.dist.Distribution): finally: distutils.core.Distribution = orig + def _yield_lines(self, strs): + """Yield non-empty/non-comment lines of a string or sequence""" + if isinstance(strs, six.string_types): + for s in strs.splitlines(): + s = s.strip() + # skip blank lines/comments + if s and not s.startswith('#'): + yield s + else: + for ss in strs: + for s in self._yield_lines(ss): + yield s + + def _parse_requirements(self, strs): + """Parse requirement specifiers into a list of requirement strings + + This is forked from pkg_resources.parse_requirements. + + `strs` must be a string, or a (possibly-nested) iterable thereof. + """ + # create a steppable iterator, so we can handle \-continuations + lines = iter(self._yield_lines(strs)) + + requirements = [] + + for line in lines: + # Drop comments -- a hash without a space may be in a URL. + if ' #' in line: + line = line[:line.find(' #')] + # If there is a line continuation, drop it, and append the next line. + if line.endswith('\\'): + line = line[:-2].strip() + try: + line += next(lines) + except StopIteration: + return + requirements.append(line) + + return requirements def _to_str(s): """ -- cgit v1.2.1 From 5efdf816fddcd8fbc9c3d1e6867a25848b1f9a06 Mon Sep 17 00:00:00 2001 From: Paul Ganssle Date: Sat, 16 Mar 2019 13:24:36 -0400 Subject: Use pkg_resources.parse_requirements in build_meta Since pkg_resources is imported elsewhere anyway, we don't get much value out of porting the requirement parser locally. --- setuptools/build_meta.py | 43 ++----------------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index fb37c02a..47cbcbf6 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -36,7 +36,7 @@ import contextlib import setuptools import distutils -from setuptools._vendor import six +from pkg_resources import parse_requirements __all__ = ['get_requires_for_build_sdist', 'get_requires_for_build_wheel', @@ -53,7 +53,7 @@ class SetupRequirementsError(BaseException): class Distribution(setuptools.dist.Distribution): def fetch_build_eggs(self, specifiers): - specifier_list = self._parse_requirements(specifiers) + specifier_list = list(map(str, parse_requirements(specifiers))) raise SetupRequirementsError(specifier_list) @@ -72,45 +72,6 @@ class Distribution(setuptools.dist.Distribution): finally: distutils.core.Distribution = orig - def _yield_lines(self, strs): - """Yield non-empty/non-comment lines of a string or sequence""" - if isinstance(strs, six.string_types): - for s in strs.splitlines(): - s = s.strip() - # skip blank lines/comments - if s and not s.startswith('#'): - yield s - else: - for ss in strs: - for s in self._yield_lines(ss): - yield s - - def _parse_requirements(self, strs): - """Parse requirement specifiers into a list of requirement strings - - This is forked from pkg_resources.parse_requirements. - - `strs` must be a string, or a (possibly-nested) iterable thereof. - """ - # create a steppable iterator, so we can handle \-continuations - lines = iter(self._yield_lines(strs)) - - requirements = [] - - for line in lines: - # Drop comments -- a hash without a space may be in a URL. - if ' #' in line: - line = line[:line.find(' #')] - # If there is a line continuation, drop it, and append the next line. - if line.endswith('\\'): - line = line[:-2].strip() - try: - line += next(lines) - except StopIteration: - return - requirements.append(line) - - return requirements def _to_str(s): """ -- cgit v1.2.1 From 901f7cc2a036bfeb93bfbe480608e04c76c2c5ec Mon Sep 17 00:00:00 2001 From: Shashank Singh Date: Sat, 20 Apr 2019 23:24:41 -0400 Subject: Fix error when wheels already exist in dist/ `build_meta.build_wheel` assumes that the only wheel in its output directory is the one it builds, but prior to this, it also used the `dist/` folder as its working output directory. This commit uses a temporary directory instead, preventing an error that was triggered when previously-generated wheel files were still sitting in `dist/`. Fixes GH #1671 --- setuptools/build_meta.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 47cbcbf6..e40904a5 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -35,6 +35,7 @@ import contextlib import setuptools import distutils +from setuptools.py31compat import TemporaryDirectory from pkg_resources import parse_requirements @@ -182,14 +183,22 @@ class _BuildMetaBackend(object): metadata_directory=None): config_settings = self._fix_config(config_settings) wheel_directory = os.path.abspath(wheel_directory) - sys.argv = sys.argv[:1] + ['bdist_wheel'] + \ - config_settings["--global-option"] - self.run_setup() - if wheel_directory != 'dist': - shutil.rmtree(wheel_directory) - shutil.copytree('dist', wheel_directory) - return _file_with_extension(wheel_directory, '.whl') + # Build the wheel in a temporary directory, then copy to the target + with TemporaryDirectory(dir=wheel_directory) as tmp_dist_dir: + sys.argv = (sys.argv[:1] + + ['bdist_wheel', '--dist-dir', tmp_dist_dir] + + config_settings["--global-option"]) + self.run_setup() + + wheel_basename = _file_with_extension(tmp_dist_dir, '.whl') + wheel_path = os.path.join(wheel_directory, wheel_basename) + if os.path.exists(wheel_path): + # os.rename will fail overwriting on non-unix env + os.remove(wheel_path) + os.rename(os.path.join(tmp_dist_dir, wheel_basename), wheel_path) + + return wheel_basename def build_sdist(self, sdist_directory, config_settings=None): config_settings = self._fix_config(config_settings) -- cgit v1.2.1 From 5f88c42f3b4529956e4d02453ae571e32bc4692a Mon Sep 17 00:00:00 2001 From: Benoit Pierre Date: Mon, 22 Apr 2019 22:18:50 +0200 Subject: build_meta: fix 2 issues with `build_wheel` / `build_sdist` Fix the following cases: * `build_sdist` is called with another sdist already present in the destination directory * `build_wheel` is called with the destination directory not already created --- setuptools/build_meta.py | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index e40904a5..10c4b528 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -38,6 +38,7 @@ import distutils from setuptools.py31compat import TemporaryDirectory from pkg_resources import parse_requirements +from pkg_resources.py31compat import makedirs __all__ = ['get_requires_for_build_sdist', 'get_requires_for_build_wheel', @@ -179,36 +180,38 @@ class _BuildMetaBackend(object): return dist_infos[0] - def build_wheel(self, wheel_directory, config_settings=None, - metadata_directory=None): + def _build_with_temp_dir(self, setup_command, result_extension, + result_directory, config_settings): config_settings = self._fix_config(config_settings) - wheel_directory = os.path.abspath(wheel_directory) + result_directory = os.path.abspath(result_directory) - # Build the wheel in a temporary directory, then copy to the target - with TemporaryDirectory(dir=wheel_directory) as tmp_dist_dir: - sys.argv = (sys.argv[:1] + - ['bdist_wheel', '--dist-dir', tmp_dist_dir] + + # Build in a temporary directory, then copy to the target. + makedirs(result_directory, exist_ok=True) + with TemporaryDirectory(dir=result_directory) as tmp_dist_dir: + sys.argv = (sys.argv[:1] + setup_command + + ['--dist-dir', tmp_dist_dir] + config_settings["--global-option"]) self.run_setup() - wheel_basename = _file_with_extension(tmp_dist_dir, '.whl') - wheel_path = os.path.join(wheel_directory, wheel_basename) - if os.path.exists(wheel_path): - # os.rename will fail overwriting on non-unix env - os.remove(wheel_path) - os.rename(os.path.join(tmp_dist_dir, wheel_basename), wheel_path) + result_basename = _file_with_extension(tmp_dist_dir, result_extension) + result_path = os.path.join(result_directory, result_basename) + if os.path.exists(result_path): + # os.rename will fail overwriting on non-Unix. + os.remove(result_path) + os.rename(os.path.join(tmp_dist_dir, result_basename), result_path) - return wheel_basename + return result_basename - def build_sdist(self, sdist_directory, config_settings=None): - config_settings = self._fix_config(config_settings) - sdist_directory = os.path.abspath(sdist_directory) - sys.argv = sys.argv[:1] + ['sdist', '--formats', 'gztar'] + \ - config_settings["--global-option"] + \ - ["--dist-dir", sdist_directory] - self.run_setup() - return _file_with_extension(sdist_directory, '.tar.gz') + def build_wheel(self, wheel_directory, config_settings=None, + metadata_directory=None): + return self._build_with_temp_dir(['bdist_wheel'], '.whl', + wheel_directory, config_settings) + + def build_sdist(self, sdist_directory, config_settings=None): + return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], + '.tar.gz', sdist_directory, + config_settings) class _BuildMetaLegacyBackend(_BuildMetaBackend): -- cgit v1.2.1 From 8f227af516c8c6b991c8e6c76f5bf4672f36c41e Mon Sep 17 00:00:00 2001 From: Emiel Wiedijk Date: Sat, 23 Feb 2019 20:51:09 +0100 Subject: Set sys.argv[0] in build scripts run by build_meta Some setup.py scripts, use sys.argv[0] to locate the source directory of a project. I added this to build_meta.__legacy__ since that is focused on backwards compatibility with old scripts. However, @pganssle said this behaviour should not be added to setuptools.build_meta. Fixes #1628 --- setuptools/build_meta.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 10c4b528..eb9e815e 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -232,6 +232,12 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend): if script_dir not in sys.path: sys.path.insert(0, script_dir) + # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to + # get the directory of the source code. They expect it to refer to the + # setup.py script. + sys_argv_0 = sys.argv[0] + sys.argv[0] = setup_script + try: super(_BuildMetaLegacyBackend, self).run_setup(setup_script=setup_script) @@ -242,6 +248,7 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend): # the original path so that the path manipulation does not persist # within the hook after run_setup is called. sys.path[:] = sys_path + sys.argv[0] = sys_argv_0 # The primary backend _BACKEND = _BuildMetaBackend() -- cgit v1.2.1 From 3d4d8b9dde61b87271861b8c7ebeb168ac4fa72b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 19 Jan 2020 12:46:30 -0500 Subject: =?UTF-8?q?=F0=9F=91=B9=20Feed=20the=20hobgoblins=20(delint).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setuptools/build_meta.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index eb9e815e..a1c951cf 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -48,6 +48,7 @@ __all__ = ['get_requires_for_build_sdist', '__legacy__', 'SetupRequirementsError'] + class SetupRequirementsError(BaseException): def __init__(self, specifiers): self.specifiers = specifiers @@ -143,7 +144,8 @@ class _BuildMetaBackend(object): def get_requires_for_build_wheel(self, config_settings=None): config_settings = self._fix_config(config_settings) - return self._get_build_requires(config_settings, requirements=['wheel']) + return self._get_build_requires( + config_settings, requirements=['wheel']) def get_requires_for_build_sdist(self, config_settings=None): config_settings = self._fix_config(config_settings) @@ -160,8 +162,10 @@ class _BuildMetaBackend(object): dist_infos = [f for f in os.listdir(dist_info_directory) if f.endswith('.dist-info')] - if (len(dist_infos) == 0 and - len(_get_immediate_subdirectories(dist_info_directory)) == 1): + if ( + len(dist_infos) == 0 and + len(_get_immediate_subdirectories(dist_info_directory)) == 1 + ): dist_info_directory = os.path.join( dist_info_directory, os.listdir(dist_info_directory)[0]) @@ -193,7 +197,8 @@ class _BuildMetaBackend(object): config_settings["--global-option"]) self.run_setup() - result_basename = _file_with_extension(tmp_dist_dir, result_extension) + result_basename = _file_with_extension( + tmp_dist_dir, result_extension) result_path = os.path.join(result_directory, result_basename) if os.path.exists(result_path): # os.rename will fail overwriting on non-Unix. @@ -202,7 +207,6 @@ class _BuildMetaBackend(object): return result_basename - def build_wheel(self, wheel_directory, config_settings=None, metadata_directory=None): return self._build_with_temp_dir(['bdist_wheel'], '.whl', @@ -217,9 +221,12 @@ class _BuildMetaBackend(object): class _BuildMetaLegacyBackend(_BuildMetaBackend): """Compatibility backend for setuptools - This is a version of setuptools.build_meta that endeavors to maintain backwards - compatibility with pre-PEP 517 modes of invocation. It exists as a temporary - bridge between the old packaging mechanism and the new packaging mechanism, + This is a version of setuptools.build_meta that endeavors + to maintain backwards + compatibility with pre-PEP 517 modes of invocation. It + exists as a temporary + bridge between the old packaging mechanism and the new + packaging mechanism, and will eventually be removed. """ def run_setup(self, setup_script='setup.py'): @@ -250,6 +257,7 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend): sys.path[:] = sys_path sys.argv[0] = sys_argv_0 + # The primary backend _BACKEND = _BuildMetaBackend() -- cgit v1.2.1 From b3de7989665740cd4218d7d814e719d90e75de73 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Sat, 18 Jan 2020 08:13:23 -0800 Subject: Remove pkg_resources.py31compat.makedirs() in favor of the stdlib As setuptools is now python 3.5+, this compatibility shim is no longer necessary. --- setuptools/build_meta.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index a1c951cf..46266814 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -38,7 +38,6 @@ import distutils from setuptools.py31compat import TemporaryDirectory from pkg_resources import parse_requirements -from pkg_resources.py31compat import makedirs __all__ = ['get_requires_for_build_sdist', 'get_requires_for_build_wheel', @@ -190,7 +189,7 @@ class _BuildMetaBackend(object): result_directory = os.path.abspath(result_directory) # Build in a temporary directory, then copy to the target. - makedirs(result_directory, exist_ok=True) + os.makedirs(result_directory, exist_ok=True) with TemporaryDirectory(dir=result_directory) as tmp_dist_dir: sys.argv = (sys.argv[:1] + setup_command + ['--dist-dir', tmp_dist_dir] + -- cgit v1.2.1 From fe79e6ca8ef48edb3ee2ea42b3021aa7de963a49 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 6 Aug 2020 08:51:10 +0100 Subject: Don't install setup_requires when run as a PEP-517 backend. Under PEP-517, installing build dependencies is up to the frontend. Closes gh-2303 --- setuptools/build_meta.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 46266814..49b4cc28 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -75,6 +75,22 @@ class Distribution(setuptools.dist.Distribution): distutils.core.Distribution = orig +@contextlib.contextmanager +def no_install_setup_requires(): + """Temporarily disable installing setup_requires + + Under PEP 517, the backend reports build dependencies to the frontend, + and the frontend is responsible for ensuring they're installed. + So setuptools (acting as a backend) should not try to install them. + """ + orig = setuptools._install_setup_requires + setuptools._install_setup_requires = lambda attrs: None + try: + yield + finally: + setuptools._install_setup_requires = orig + + def _to_str(s): """ Convert a filename to a string (on Python 2, explicitly @@ -139,7 +155,8 @@ class _BuildMetaBackend(object): with _open_setup_script(__file__) as f: code = f.read().replace(r'\r\n', r'\n') - exec(compile(code, __file__, 'exec'), locals()) + with no_install_setup_requires(): + exec(compile(code, __file__, 'exec'), locals()) def get_requires_for_build_wheel(self, config_settings=None): config_settings = self._fix_config(config_settings) -- cgit v1.2.1 From 21c81324f9e37aee92301f64b95947accfafbaa4 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 6 Aug 2020 10:10:13 +0100 Subject: get_requires_for_build* hooks rely on 'installing' setup_requires --- setuptools/build_meta.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 49b4cc28..37132187 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -155,8 +155,7 @@ class _BuildMetaBackend(object): with _open_setup_script(__file__) as f: code = f.read().replace(r'\r\n', r'\n') - with no_install_setup_requires(): - exec(compile(code, __file__, 'exec'), locals()) + exec(compile(code, __file__, 'exec'), locals()) def get_requires_for_build_wheel(self, config_settings=None): config_settings = self._fix_config(config_settings) @@ -171,7 +170,8 @@ class _BuildMetaBackend(object): config_settings=None): sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', _to_str(metadata_directory)] - self.run_setup() + with no_install_setup_requires(): + self.run_setup() dist_info_directory = metadata_directory while True: @@ -211,7 +211,8 @@ class _BuildMetaBackend(object): sys.argv = (sys.argv[:1] + setup_command + ['--dist-dir', tmp_dist_dir] + config_settings["--global-option"]) - self.run_setup() + with no_install_setup_requires(): + self.run_setup() result_basename = _file_with_extension( tmp_dist_dir, result_extension) -- cgit v1.2.1 From fb7ab81a3d080422687bad71f9ae9d36eeefbee2 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 16 Aug 2020 00:29:24 -0400 Subject: Remove Python 2 compatibility --- setuptools/build_meta.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 37132187..b9e8a2b3 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -32,10 +32,10 @@ import sys import tokenize import shutil import contextlib +import tempfile import setuptools import distutils -from setuptools.py31compat import TemporaryDirectory from pkg_resources import parse_requirements @@ -91,19 +91,6 @@ def no_install_setup_requires(): setuptools._install_setup_requires = orig -def _to_str(s): - """ - Convert a filename to a string (on Python 2, explicitly - a byte string, not Unicode) as distutils checks for the - exact type str. - """ - if sys.version_info[0] == 2 and not isinstance(s, str): - # Assume it's Unicode, as that's what the PEP says - # should be provided. - return s.encode(sys.getfilesystemencoding()) - return s - - def _get_immediate_subdirectories(a_dir): return [name for name in os.listdir(a_dir) if os.path.isdir(os.path.join(a_dir, name))] @@ -168,8 +155,8 @@ class _BuildMetaBackend(object): def prepare_metadata_for_build_wheel(self, metadata_directory, config_settings=None): - sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', - _to_str(metadata_directory)] + sys.argv = sys.argv[:1] + [ + 'dist_info', '--egg-base', metadata_directory] with no_install_setup_requires(): self.run_setup() @@ -207,7 +194,7 @@ class _BuildMetaBackend(object): # Build in a temporary directory, then copy to the target. os.makedirs(result_directory, exist_ok=True) - with TemporaryDirectory(dir=result_directory) as tmp_dist_dir: + with tempfile.TemporaryDirectory(dir=result_directory) as tmp_dist_dir: sys.argv = (sys.argv[:1] + setup_command + ['--dist-dir', tmp_dist_dir] + config_settings["--global-option"]) -- cgit v1.2.1 From 024b1e13b644cc9829d2a15cd5867920e11c9a9e Mon Sep 17 00:00:00 2001 From: layday Date: Tue, 16 Mar 2021 18:58:11 +0200 Subject: build_meta: produce informative error when a dist is not found Previously, when `build_sdist` or `build_wheel` were unable to build a distribution (and were therefore unable to find the distribution file), they would throw a ValueError: not enough values to unpack (expected 1, got 0) which did not offer any clues as to where the issue might lie. --- setuptools/build_meta.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index b9e8a2b3..3c45db72 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -101,8 +101,12 @@ def _file_with_extension(directory, extension): f for f in os.listdir(directory) if f.endswith(extension) ) - file, = matching - return file + try: + return next(matching) + except StopIteration: + raise ValueError('No distribution was found. The distribution was ' + 'possibly not built. Ensure that your `setup.py` ' + 'is not empty and that it calls `setup()`.') def _open_setup_script(setup_script): -- cgit v1.2.1 From f3ba2139eacd5d27d052f0659b5d7dc1413977b0 Mon Sep 17 00:00:00 2001 From: layday Date: Sun, 21 Mar 2021 19:36:14 +0200 Subject: fixup! fixup! build_meta: produce informative error when a dist is not found --- setuptools/build_meta.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 3c45db72..36fbc9e8 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -104,9 +104,9 @@ def _file_with_extension(directory, extension): try: return next(matching) except StopIteration: - raise ValueError('No distribution was found. The distribution was ' - 'possibly not built. Ensure that your `setup.py` ' - 'is not empty and that it calls `setup()`.') + raise ValueError( + 'No distribution was found. Ensure that `setup.py` ' + 'is not empty and that it calls `setup()`.') def _open_setup_script(setup_script): -- cgit v1.2.1 From 2cec54e4f451d6318ad9fc18213d0f8f7d4aa669 Mon Sep 17 00:00:00 2001 From: layday Date: Sun, 21 Mar 2021 22:00:29 +0200 Subject: fixup! build_meta: produce informative error when a dist is not found --- setuptools/build_meta.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 36fbc9e8..de856854 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -102,11 +102,13 @@ def _file_with_extension(directory, extension): if f.endswith(extension) ) try: - return next(matching) - except StopIteration: + file, = matching + except ValueError: raise ValueError( 'No distribution was found. Ensure that `setup.py` ' 'is not empty and that it calls `setup()`.') + else: + return file def _open_setup_script(setup_script): -- cgit v1.2.1 From e0655f6459c8ba7ee8a0befbaf55c0e89d25512a Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 22 Mar 2021 08:44:55 -0400 Subject: Remove superfluous else. --- setuptools/build_meta.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index de856854..9dfb2f24 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -107,8 +107,7 @@ def _file_with_extension(directory, extension): raise ValueError( 'No distribution was found. Ensure that `setup.py` ' 'is not empty and that it calls `setup()`.') - else: - return file + return file def _open_setup_script(setup_script): -- cgit v1.2.1 From fad059e2d22cf1813cef1c96b7b1be1da2ac1158 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Nov 2021 19:27:26 -0400 Subject: Suppress 'setup.py install' warning under bdist_wheel. Fixes #2847. --- setuptools/build_meta.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'setuptools/build_meta.py') diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index 9dfb2f24..d0ac613b 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -33,6 +33,7 @@ import tokenize import shutil import contextlib import tempfile +import warnings import setuptools import distutils @@ -118,6 +119,13 @@ def _open_setup_script(setup_script): return getattr(tokenize, 'open', open)(setup_script) +@contextlib.contextmanager +def suppress_known_deprecation(): + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', 'setup.py install is deprecated') + yield + + class _BuildMetaBackend(object): def _fix_config(self, config_settings): @@ -218,8 +226,9 @@ class _BuildMetaBackend(object): def build_wheel(self, wheel_directory, config_settings=None, metadata_directory=None): - return self._build_with_temp_dir(['bdist_wheel'], '.whl', - wheel_directory, config_settings) + with suppress_known_deprecation(): + return self._build_with_temp_dir(['bdist_wheel'], '.whl', + wheel_directory, config_settings) def build_sdist(self, sdist_directory, config_settings=None): return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], -- cgit v1.2.1