From c9b83f7bee7e36678849d684de40331c278617fa Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sat, 12 Jul 2014 00:52:58 +0200 Subject: Work around for side effects in setup.py script Disables setup_requires and related magic for setup.py commands clean, egg_info and sdist and the options --version and --help. See also https://github.com/pyca/cryptography/issues/1253 --- setup.py | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index 347dbe82..7465c31f 100644 --- a/setup.py +++ b/setup.py @@ -140,6 +140,37 @@ class PyTest(test): sys.exit(errno) +def keywords_with_side_effects(): + """ + Get a dictionary with setup keywords that (can) have side effects. + + This setup.py script uses the setuptools 'setup_requires' feature because + this is required by the cffi package to compile extension modules. The + purpose of ``keywords_with_side_effects()`` is to avoid triggering the cffi + build process as a result of any of the following ``setup.py`` invocations: + + - ``python setup.py --help-commands`` + - ``python setup.py --help`` + - ``python setup.py --version`` + - ``python setup.py clean`` + - ``python setup.py egg_info`` + + This function is based on the `setup.py script of SciPy`_ (see also the + discussion in `pip issue #25`_). + + .. _pip issue #25: https://github.com/pypa/pip/issues/25 + .. _setup.py script of SciPy: https://github.com/scipy/scipy/blob/master/setup.py + """ + if len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or + sys.argv[1] in ('--help-commands', '--version', 'clean', 'egg_info')): + return {} + else: + return dict(setup_requires=requirements, + cmdclass=dict(build=CFFIBuild, + install=CFFIInstall, + test=PyTest)) + + with open(os.path.join(base_dir, "README.rst")) as f: long_description = f.read() @@ -182,19 +213,13 @@ setup( include_package_data=True, install_requires=requirements, - setup_requires=requirements, tests_require=test_requirements, # for cffi zip_safe=False, ext_package="cryptography", - cmdclass={ - "build": CFFIBuild, - "install": CFFIInstall, - "test": PyTest, - }, - entry_points={ "cryptography.backends": backends, - } + }, + **keywords_with_side_effects() ) -- cgit v1.2.3 From 51ec05fc2475213ffbf8a87c5ff2e309d9a68520 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sat, 12 Jul 2014 01:18:35 +0200 Subject: Make sys.argv an argument of keywords_with_side_effects() --- setup.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index 7465c31f..b0ad2db3 100644 --- a/setup.py +++ b/setup.py @@ -140,10 +140,13 @@ class PyTest(test): sys.exit(errno) -def keywords_with_side_effects(): +def keywords_with_side_effects(argv): """ Get a dictionary with setup keywords that (can) have side effects. + :param argv: A list of strings with command line arguments. + :returns: A dictionary with keyword arguments for the ``setup()`` function. + This setup.py script uses the setuptools 'setup_requires' feature because this is required by the cffi package to compile extension modules. The purpose of ``keywords_with_side_effects()`` is to avoid triggering the cffi @@ -161,8 +164,8 @@ def keywords_with_side_effects(): .. _pip issue #25: https://github.com/pypa/pip/issues/25 .. _setup.py script of SciPy: https://github.com/scipy/scipy/blob/master/setup.py """ - if len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or - sys.argv[1] in ('--help-commands', '--version', 'clean', 'egg_info')): + if len(argv) >= 2 and ('--help' in argv[1:] or + argv[1] in ('--help-commands', '--version', 'clean', 'egg_info')): return {} else: return dict(setup_requires=requirements, @@ -221,5 +224,5 @@ setup( entry_points={ "cryptography.backends": backends, }, - **keywords_with_side_effects() + **keywords_with_side_effects(sys.argv) ) -- cgit v1.2.3 From e327cf1f4ed2f45291866c6de1f035bd7f9bf80a Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sat, 12 Jul 2014 01:18:50 +0200 Subject: Change nested dictionary literal to match house style --- setup.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index b0ad2db3..64e31cae 100644 --- a/setup.py +++ b/setup.py @@ -168,10 +168,14 @@ def keywords_with_side_effects(argv): argv[1] in ('--help-commands', '--version', 'clean', 'egg_info')): return {} else: - return dict(setup_requires=requirements, - cmdclass=dict(build=CFFIBuild, - install=CFFIInstall, - test=PyTest)) + return { + "setup_requires": requirements, + "cmdclass": { + "build": CFFIBuild, + "install": CFFIInstall, + "test": PyTest, + } + } with open(os.path.join(base_dir, "README.rst")) as f: -- cgit v1.2.3 From 63ce5df83303380dab8b81a557fa9a8314d3ad5e Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sat, 12 Jul 2014 01:56:37 +0200 Subject: PEP-8 fixes pointed out by Travis CI --- setup.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index 64e31cae..145854a8 100644 --- a/setup.py +++ b/setup.py @@ -158,14 +158,15 @@ def keywords_with_side_effects(argv): - ``python setup.py clean`` - ``python setup.py egg_info`` - This function is based on the `setup.py script of SciPy`_ (see also the + This function is based on the `setup.py script`_ of SciPy (see also the discussion in `pip issue #25`_). .. _pip issue #25: https://github.com/pypa/pip/issues/25 - .. _setup.py script of SciPy: https://github.com/scipy/scipy/blob/master/setup.py + .. _setup.py script: https://github.com/scipy/scipy/blob/master/setup.py """ if len(argv) >= 2 and ('--help' in argv[1:] or - argv[1] in ('--help-commands', '--version', 'clean', 'egg_info')): + argv[1] in ('--help-commands', '--version', + 'clean', 'egg_info')): return {} else: return { -- cgit v1.2.3 From 3ae89a59ad6155363fe195852999a9b669e2b395 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sat, 12 Jul 2014 02:06:56 +0200 Subject: Replace commands that depend on setup_requires with no-op that raises error --- setup.py | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index 145854a8..aa915f0c 100644 --- a/setup.py +++ b/setup.py @@ -167,7 +167,13 @@ def keywords_with_side_effects(argv): if len(argv) >= 2 and ('--help' in argv[1:] or argv[1] in ('--help-commands', '--version', 'clean', 'egg_info')): - return {} + return { + "cmdclass": { + "build": DummyCFFIBuild, + "install": DummyCFFIInstall, + "test": DummyPyTest, + } + } else: return { "setup_requires": requirements, @@ -179,6 +185,47 @@ def keywords_with_side_effects(argv): } +setup_requires_error = ("Requested setup command that needs 'setup_requires' " + "while command line arguments implied a side effect " + "free command or option.") + + +class DummyCFFIBuild(CFFIBuild): + """ + This class makes it very obvious when ``keywords_with_side_effects()`` has + incorrectly interpreted the command line arguments to ``setup.py build`` as + one of the 'side effect free' commands or options. + """ + + def finalize_options(self): + raise RuntimeError(setup_requires_error) + + +class DummyCFFIInstall(CFFIInstall): + """ + This class makes it very obvious when ``keywords_with_side_effects()`` has + incorrectly interpreted the command line arguments to ``setup.py install`` + as one of the 'side effect free' commands or options. + """ + + def finalize_options(self): + raise RuntimeError(setup_requires_error) + + +class DummyPyTest(PyTest): + """ + This class makes it very obvious when ``keywords_with_side_effects()`` has + incorrectly interpreted the command line arguments to ``setup.py test`` as + one of the 'side effect free' commands or options. + """ + + def finalize_options(self): + raise RuntimeError(setup_requires_error) + + def run_tests(self): + raise RuntimeError(setup_requires_error) + + with open(os.path.join(base_dir, "README.rst")) as f: long_description = f.read() -- cgit v1.2.3 From dcce080527d6498eed0a453e73e4e9032b4a87d4 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sat, 12 Jul 2014 02:28:13 +0200 Subject: Bug fix for implementation of dummy commands Pointed out by Jenkins: https://jenkins.cryptography.io/job/cryptography-pr-experimental/2163/ --- setup.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index aa915f0c..ad3ffcfc 100644 --- a/setup.py +++ b/setup.py @@ -198,6 +198,9 @@ class DummyCFFIBuild(CFFIBuild): """ def finalize_options(self): + build.finalize_options(self) + + def run(self): raise RuntimeError(setup_requires_error) @@ -209,6 +212,9 @@ class DummyCFFIInstall(CFFIInstall): """ def finalize_options(self): + install.finalize_options(self) + + def run(self): raise RuntimeError(setup_requires_error) @@ -220,7 +226,7 @@ class DummyPyTest(PyTest): """ def finalize_options(self): - raise RuntimeError(setup_requires_error) + test.finalize_options(self) def run_tests(self): raise RuntimeError(setup_requires_error) -- cgit v1.2.3 From e9144566b6fe539256487687dfa5e863f7bdee96 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sat, 12 Jul 2014 03:14:55 +0200 Subject: Bullet proof (?) detection of arguments that don't need setup_requires --- setup.py | 56 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 11 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index ad3ffcfc..94a18ea8 100644 --- a/setup.py +++ b/setup.py @@ -150,23 +150,57 @@ def keywords_with_side_effects(argv): This setup.py script uses the setuptools 'setup_requires' feature because this is required by the cffi package to compile extension modules. The purpose of ``keywords_with_side_effects()`` is to avoid triggering the cffi - build process as a result of any of the following ``setup.py`` invocations: + build process as a result of setup.py invocations that don't need the cffi + module to be built (setup.py serves the dual purpose of exposing package + metadata). - - ``python setup.py --help-commands`` - - ``python setup.py --help`` - - ``python setup.py --version`` - - ``python setup.py clean`` - - ``python setup.py egg_info`` + All of the options listed by ``python setup.py --help`` that print + information should be recognized here. The commands ``clean``, + ``egg_info``, ``register``, ``sdist`` and ``upload`` are also recognized. + Any combination of these options and commands is also supported. - This function is based on the `setup.py script`_ of SciPy (see also the - discussion in `pip issue #25`_). + This function was originally based on the `setup.py script`_ of SciPy (see + also the discussion in `pip issue #25`_). .. _pip issue #25: https://github.com/pypa/pip/issues/25 .. _setup.py script: https://github.com/scipy/scipy/blob/master/setup.py """ - if len(argv) >= 2 and ('--help' in argv[1:] or - argv[1] in ('--help-commands', '--version', - 'clean', 'egg_info')): + no_setup_requires_arguments = ( + '-h', '--help', + '-n', '--dry-run', + '-q', '--quiet', + '-v', '--verbose', + '-V', '--version', + '--author', + '--author-email', + '--classifiers', + '--contact', + '--contact-email', + '--description', + '--fullname', + '--help-commands', + '--keywords', + '--licence', + '--license', + '--long-description', + '--maintainer', + '--maintainer-email', + '--name', + '--no-user-cfg', + '--obsoletes', + '--platforms', + '--provides', + '--requires', + '--url', + 'clean', + 'egg_info', + 'register', + 'sdist', + 'upload', + ) + if all((arg in no_setup_requires_arguments) or + all(('-' + char) in no_setup_requires_arguments for char in arg[1:]) + for arg in argv[1:]): return { "cmdclass": { "build": DummyCFFIBuild, -- cgit v1.2.3 From c9861f9bd496089faf29f2e0022727fcc17e413b Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Sun, 13 Jul 2014 04:17:20 +0200 Subject: Simplify dummy commands (fix inheritance, remove finalize_options()) --- setup.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index 94a18ea8..3dd2bd6e 100644 --- a/setup.py +++ b/setup.py @@ -224,44 +224,35 @@ setup_requires_error = ("Requested setup command that needs 'setup_requires' " "free command or option.") -class DummyCFFIBuild(CFFIBuild): +class DummyCFFIBuild(build): """ This class makes it very obvious when ``keywords_with_side_effects()`` has incorrectly interpreted the command line arguments to ``setup.py build`` as one of the 'side effect free' commands or options. """ - def finalize_options(self): - build.finalize_options(self) - def run(self): raise RuntimeError(setup_requires_error) -class DummyCFFIInstall(CFFIInstall): +class DummyCFFIInstall(install): """ This class makes it very obvious when ``keywords_with_side_effects()`` has incorrectly interpreted the command line arguments to ``setup.py install`` as one of the 'side effect free' commands or options. """ - def finalize_options(self): - install.finalize_options(self) - def run(self): raise RuntimeError(setup_requires_error) -class DummyPyTest(PyTest): +class DummyPyTest(test): """ This class makes it very obvious when ``keywords_with_side_effects()`` has incorrectly interpreted the command line arguments to ``setup.py test`` as one of the 'side effect free' commands or options. """ - def finalize_options(self): - test.finalize_options(self) - def run_tests(self): raise RuntimeError(setup_requires_error) -- cgit v1.2.3 From 6c1e9ef571c0f78dc252e7ddd43a577f1504da39 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Mon, 14 Jul 2014 15:50:31 +0200 Subject: Fix for keywords_with_side_effects() (compatibility with pip metadata discovery) Fixes a bug in 9e34c14b344f49d0721edc79d14ea5fc9c067d07 as described in https://github.com/pyca/cryptography/pull/1257#issuecomment-48855243 --- setup.py | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index 3dd2bd6e..59cff8db 100644 --- a/setup.py +++ b/setup.py @@ -177,6 +177,7 @@ def keywords_with_side_effects(argv): '--contact', '--contact-email', '--description', + '--egg-base', '--fullname', '--help-commands', '--keywords', @@ -198,9 +199,31 @@ def keywords_with_side_effects(argv): 'sdist', 'upload', ) - if all((arg in no_setup_requires_arguments) or - all(('-' + char) in no_setup_requires_arguments for char in arg[1:]) - for arg in argv[1:]): + def is_short_option(argument): + """Check whether a command line argument is a short option.""" + return len(argument) >= 2 and argument[0] == '-' and argument[1] != '-' + def expand_short_options(argument): + """Expand combined short options into canonical short options.""" + return ('-' + char for char in argument[1:]) + def argument_without_setup_requirements(argv, i): + """Check whether a command line argument needs setup requirements.""" + if argv[i] in no_setup_requires_arguments: + # Simple case: An argument which is either an option or a command + # which doesn't need setup requirements. + return True + elif is_short_option(argv[i]) and all(option in + no_setup_requires_arguments for option in + expand_short_options(argv[i])): + # Not so simple case: Combined short options none of which need + # setup requirements. + return True + elif argv[i - 1 : i] == ['--egg-base']: + # Tricky case: --egg-info takes an argument which should not make + # us use setup_requires (defeating the purpose of this code). + return True + else: + return False + if all(argument_without_setup_requirements(argv, i) for i in range(1, len(argv))): return { "cmdclass": { "build": DummyCFFIBuild, -- cgit v1.2.3 From 97f45302f16c64c5e3af1a895f4906857f3a5100 Mon Sep 17 00:00:00 2001 From: Peter Odding Date: Mon, 14 Jul 2014 21:40:35 +0200 Subject: Fix PEP-8 violations --- setup.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'setup.py') diff --git a/setup.py b/setup.py index 59cff8db..ca729275 100644 --- a/setup.py +++ b/setup.py @@ -199,31 +199,36 @@ def keywords_with_side_effects(argv): 'sdist', 'upload', ) + def is_short_option(argument): """Check whether a command line argument is a short option.""" return len(argument) >= 2 and argument[0] == '-' and argument[1] != '-' + def expand_short_options(argument): """Expand combined short options into canonical short options.""" return ('-' + char for char in argument[1:]) + def argument_without_setup_requirements(argv, i): """Check whether a command line argument needs setup requirements.""" if argv[i] in no_setup_requires_arguments: # Simple case: An argument which is either an option or a command # which doesn't need setup requirements. return True - elif is_short_option(argv[i]) and all(option in - no_setup_requires_arguments for option in - expand_short_options(argv[i])): + elif (is_short_option(argv[i]) and + all(option in no_setup_requires_arguments + for option in expand_short_options(argv[i]))): # Not so simple case: Combined short options none of which need # setup requirements. return True - elif argv[i - 1 : i] == ['--egg-base']: + elif argv[i - 1:i] == ['--egg-base']: # Tricky case: --egg-info takes an argument which should not make # us use setup_requires (defeating the purpose of this code). return True else: return False - if all(argument_without_setup_requirements(argv, i) for i in range(1, len(argv))): + + if all(argument_without_setup_requirements(argv, i) + for i in range(1, len(argv))): return { "cmdclass": { "build": DummyCFFIBuild, -- cgit v1.2.3