mirror of https://github.com/kivy/kivy.git
Change check for Cython to attempt fallback to setuptools on supporte… (#5998)
* Change check for Cython to attempt fallback to setuptools on supported platforms. This attempts to solve Issue #5984 without causing more problems for Issue #5558. * Correct argument to extras_require. * Refactor the declaration and usage of Cython - Use setuptools.setup by default if available for import. - The objective for that complicated import/cython is commented. - Also have more specific variable names, and have their usage be clarified. - Remove Cython from install_requires as it already is declared under setup_requires, and that it conflicts with install_requires due to issues in setuptools. - https://github.com/pypa/setuptools/issues/209 - https://github.com/pypa/setuptools/issues/391 - This commit goes back to breaking installation in environments without Cython, but should be rectified in the next commit. * Actually fix the specific usage of Cython - In order for setup.py to make use of the Cython installed during by the setup_requires to be usable, it must be imported after it is installed by that step, thus it cannot be done at the top level and this can be achieved by importing it when it's actually called. A build_ext factory function is created for this. - Still allow whatever Cython already present on the current environment be attempted to be used. This may end up being unnecessary as if it is always declared in setup_requires (which isn't currently the case due to the complicated/documented block), it _should_ pull in the exact/supported version of Cython for usage. This should be investigated so that this complicated logic may be avoided. * Make distutils happy by not using factory function - As it turns out, calling setup.py build_ext will result in a code path within setuptools that will invoke distutils in a way that forces an issubclass check, which ultimately results in an exception due to that function not being a class. - To fix this, we go back to constructing a base class except also using the "new" style class (to make Python 2 happy) so that the __new__ method will actually be called so that the logic to select the Cython version of build_ext will be invoked. - Also use the super class protocol to invoke parent methods. * Declare version bounds directly on setup_requires - This allows us to fully remove the brittle version checks - Also this allows us to directly declare setup_requires if Cython is definitely required, as this would allow the correct version to be installed directly by setuptools during the execution of the setup step. - No need to check for failed Cython imports due to the presence of the setup_requires declaration. * Add comment explaining the initialisation routine for KivyBuildExt. Details of how setuptools deals with both cmdclass and when setup_requires dependencies come in to scope are both relevant. * Bring comment in to line with earlier changes. The cython checks are significantly simpler now, and the rationale is also slightly different.
This commit is contained in:
parent
900237424e
commit
a6a276b0a7
107
setup.py
107
setup.py
|
@ -14,17 +14,18 @@ from copy import deepcopy
|
|||
import os
|
||||
from os.path import join, dirname, sep, exists, basename, isdir
|
||||
from os import walk, environ, makedirs
|
||||
from distutils.command.build_ext import build_ext
|
||||
from distutils.version import LooseVersion
|
||||
from distutils.sysconfig import get_python_inc
|
||||
from collections import OrderedDict
|
||||
from time import sleep, time
|
||||
from time import time
|
||||
from subprocess import check_output, CalledProcessError
|
||||
from datetime import datetime
|
||||
|
||||
if environ.get('KIVY_USE_SETUPTOOLS'):
|
||||
try:
|
||||
from setuptools import setup, Extension
|
||||
print('Using setuptools')
|
||||
else:
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
print('Using distutils')
|
||||
|
@ -83,6 +84,13 @@ CYTHON_UNSUPPORTED = (
|
|||
# ref https://github.com/cython/cython/issues/1968
|
||||
'0.27', '0.27.2'
|
||||
)
|
||||
CYTHON_REQUIRES_STRING = (
|
||||
'cython>={min_version},<={max_version},{exclusion}'.format(
|
||||
min_version=MIN_CYTHON_STRING,
|
||||
max_version=MAX_CYTHON_STRING,
|
||||
exclusion=','.join('!=%s' % excl for excl in CYTHON_UNSUPPORTED),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def getoutput(cmd, env=None):
|
||||
|
@ -231,35 +239,24 @@ cython_unsupported = '''\
|
|||
'''.format(MIN_CYTHON_STRING, MAX_CYTHON_STRING,
|
||||
cython_unsupported_append)
|
||||
|
||||
have_cython = False
|
||||
skip_cython = False
|
||||
if platform in ('ios', 'android'):
|
||||
print('\nCython check avoided.')
|
||||
skip_cython = True
|
||||
else:
|
||||
try:
|
||||
# check for cython
|
||||
from Cython.Distutils import build_ext
|
||||
have_cython = True
|
||||
import Cython
|
||||
cy_version_str = Cython.__version__
|
||||
cy_ver = LooseVersion(cy_version_str)
|
||||
print('\nDetected Cython version {}'.format(cy_version_str))
|
||||
if cy_ver < MIN_CYTHON_VERSION:
|
||||
print(cython_min)
|
||||
raise ImportError('Incompatible Cython Version')
|
||||
if cy_ver in CYTHON_UNSUPPORTED:
|
||||
print(cython_unsupported)
|
||||
raise ImportError('Incompatible Cython Version')
|
||||
if cy_ver > MAX_CYTHON_VERSION:
|
||||
print(cython_max)
|
||||
sleep(1)
|
||||
except ImportError:
|
||||
print("\nCython is missing, it's required for compiling kivy !\n\n")
|
||||
raise
|
||||
# We want to be able to install kivy as a wheel without a dependency
|
||||
# on cython, but we also want to use cython where possible as a setup
|
||||
# time dependency through `setup_requires` if building from source.
|
||||
|
||||
if not have_cython:
|
||||
from distutils.command.build_ext import build_ext
|
||||
# There are issues with using cython at all on some platforms;
|
||||
# exclude them from using or declaring cython.
|
||||
|
||||
# This determines whether Cython specific functionality may be used.
|
||||
can_use_cython = True
|
||||
# This sets whether or not Cython gets added to setup_requires.
|
||||
declare_cython = False
|
||||
|
||||
if platform in ('ios', 'android'):
|
||||
# NEVER use or declare cython on these platforms
|
||||
print('Not using cython on %s' % platform)
|
||||
can_use_cython = False
|
||||
else:
|
||||
declare_cython = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Setup classes
|
||||
|
@ -268,10 +265,31 @@ if not have_cython:
|
|||
src_path = build_path = dirname(__file__)
|
||||
|
||||
|
||||
class KivyBuildExt(build_ext):
|
||||
class KivyBuildExt(build_ext, object):
|
||||
|
||||
def __new__(cls, *a, **kw):
|
||||
# Note how this class is declared as a subclass of distutils
|
||||
# build_ext as the Cython version may not be available in the
|
||||
# environment it is initially started in. However, if Cython
|
||||
# can be used, setuptools will bring Cython into the environment
|
||||
# thus its version of build_ext will become available.
|
||||
# The reason why this is done as a __new__ rather than through a
|
||||
# factory function is because there are distutils functions that check
|
||||
# the values provided by cmdclass with issublcass, and so it would
|
||||
# result in an exception.
|
||||
# The following essentially supply a dynamically generated subclass
|
||||
# that mix in the cython version of build_ext so that the
|
||||
# functionality provided will also be executed.
|
||||
if can_use_cython:
|
||||
from Cython.Distutils import build_ext as cython_build_ext
|
||||
build_ext_cls = type(
|
||||
'KivyBuildExt', (KivyBuildExt, cython_build_ext), {})
|
||||
return super(KivyBuildExt, cls).__new__(build_ext_cls)
|
||||
else:
|
||||
return super(KivyBuildExt, cls).__new__(cls)
|
||||
|
||||
def finalize_options(self):
|
||||
retval = build_ext.finalize_options(self)
|
||||
retval = super(KivyBuildExt, self).finalize_options()
|
||||
global build_path
|
||||
if (self.build_lib is not None and exists(self.build_lib) and
|
||||
not self.inplace):
|
||||
|
@ -328,7 +346,7 @@ class KivyBuildExt(build_ext):
|
|||
for e in self.extensions:
|
||||
e.extra_link_args += ['-lm']
|
||||
|
||||
build_ext.build_extensions(self)
|
||||
super(KivyBuildExt, self).build_extensions()
|
||||
|
||||
def update_if_changed(self, fn, content):
|
||||
need_update = True
|
||||
|
@ -949,7 +967,8 @@ def get_extensions_from_sources(sources):
|
|||
pyx = expand(src_path, pyx)
|
||||
depends = [expand(src_path, x) for x in flags.pop('depends', [])]
|
||||
c_depends = [expand(src_path, x) for x in flags.pop('c_depends', [])]
|
||||
if not have_cython:
|
||||
if not can_use_cython:
|
||||
# can't use cython, so use the .c files instead.
|
||||
pyx = '%s.c' % pyx[:-4]
|
||||
if is_graphics:
|
||||
depends = resolve_dependencies(pyx, depends)
|
||||
|
@ -998,6 +1017,12 @@ if isdir(binary_deps_path):
|
|||
# -----------------------------------------------------------------------------
|
||||
# setup !
|
||||
if not build_examples:
|
||||
install_requires = [
|
||||
'Kivy-Garden>=0.1.4', 'docutils', 'pygments'
|
||||
]
|
||||
setup_requires = []
|
||||
if declare_cython:
|
||||
setup_requires.append(CYTHON_REQUIRES_STRING)
|
||||
setup(
|
||||
name='Kivy',
|
||||
version=get_version(),
|
||||
|
@ -1127,15 +1152,11 @@ if not build_examples:
|
|||
'Topic :: Software Development :: User Interfaces'],
|
||||
dependency_links=[
|
||||
'https://github.com/kivy-garden/garden/archive/master.zip'],
|
||||
install_requires=[
|
||||
'Kivy-Garden>=0.1.4', 'docutils', 'pygments'
|
||||
],
|
||||
extra_requires={
|
||||
install_requires=install_requires,
|
||||
setup_requires=setup_requires,
|
||||
extras_require={
|
||||
'tuio': ['oscpy']
|
||||
},
|
||||
setup_requires=[
|
||||
'cython>=' + MIN_CYTHON_STRING
|
||||
] if not skip_cython else [])
|
||||
})
|
||||
else:
|
||||
setup(
|
||||
name='Kivy-examples',
|
||||
|
|
Loading…
Reference in New Issue