summaryrefslogtreecommitdiff
path: root/setup.py
diff options
context:
space:
mode:
Diffstat (limited to 'setup.py')
-rw-r--r--setup.py155
1 files changed, 127 insertions, 28 deletions
diff --git a/setup.py b/setup.py
index 7112227..dbb552e 100644
--- a/setup.py
+++ b/setup.py
@@ -15,6 +15,8 @@ from ast import parse # NOQA
from setuptools import setup, Extension, Distribution # NOQA
from setuptools.command import install_lib # NOQA
+from setuptools.command.sdist import sdist as _sdist # NOQA
+from wheel.bdist_wheel import bdist_wheel as _bdist_wheel # NOQA
if __name__ != '__main__':
raise NotImplementedError('should never include setup.py')
@@ -231,6 +233,28 @@ class MyInstallLib(install_lib.install_lib):
return alt_files
+class MySdist(_sdist):
+ def initialize_options(self):
+ _sdist.initialize_options(self)
+ # because of unicode_literals
+ self.formats = [b'bztar'] if sys.version_info < (3, ) else ['bztar']
+ dist_base = os.environ.get('PYDISTBASE')
+ fpn = getattr(getattr(self, 'nsp', self), 'full_package_name', None)
+ if fpn and dist_base:
+ print('setting distdir {}/{}'.format(dist_base, fpn))
+ self.dist_dir = os.path.join(dist_base, fpn)
+
+
+class MyBdistWheel(_bdist_wheel):
+ def initialize_options(self):
+ _bdist_wheel.initialize_options(self)
+ dist_base = os.environ.get('PYDISTBASE')
+ fpn = getattr(getattr(self, 'nsp', self), 'full_package_name', None)
+ if fpn and dist_base:
+ print('setting distdir {}/{}'.format(dist_base, fpn))
+ self.dist_dir = os.path.join(dist_base, fpn)
+
+
class InMemoryZipFile(object):
def __init__(self, file_name=None):
try:
@@ -308,14 +332,16 @@ class NameSpacePackager(object):
self.depth = self.full_package_name.count('.')
self.nested = self._pkg_data.get('nested', False)
self.command = None
+ self.python_version()
self._pkg = [None, None] # required and pre-installable packages
if sys.argv[0] == 'setup.py' and sys.argv[1] == 'install' and \
'--single-version-externally-managed' not in sys.argv:
if os.environ.get('READTHEDOCS', None) == 'True':
os.system('pip install .')
sys.exit(0)
- print('error: you have to install with "pip install ."')
- sys.exit(1)
+ if not os.environ.get('RUAMEL_NO_PIP_INSTALL_CHECK', False):
+ print('error: you have to install with "pip install ."')
+ sys.exit(1)
# If you only support an extension module on Linux, Windows thinks it
# is pure. That way you would get pure python .whl files that take
# precedence for downloading on Linux over source with compilable C
@@ -351,14 +377,11 @@ class NameSpacePackager(object):
if not os.path.isdir(d) or d == self._split[0] or d[0] in '._':
continue
# prevent sub-packages in namespace from being included
- x = os.path.join(d, 'setup.py')
- if os.path.exists(x):
- if not os.path.exists(os.path.join(d, 'tox.ini')):
- print('\n>>>>> found "{0}" without tox.ini <<<<<\n'
- ''.format(x))
- continue
x = os.path.join(d, '__init__.py')
if os.path.exists(x):
+ pd = _package_data(x)
+ if pd.get('nested', False):
+ continue
self._split.append(self.full_package_name + '.' + d)
if sys.version_info < (3, ):
self._split = [(y.encode('utf-8') if isinstance(y, unicode) else y)
@@ -403,6 +426,23 @@ class NameSpacePackager(object):
fp.write('import pkg_resources\n'
'pkg_resources.declare_namespace(__name__)\n')
+ def python_version(self):
+ supported = self._pkg_data.get('supported')
+ if supported is None:
+ return
+ if len(supported) == 1:
+ minimum = supported[0]
+ else:
+ for x in supported:
+ if x[0] == sys.version_info[0]:
+ minimum = x
+ break
+ else:
+ return
+ if sys.version_info < minimum:
+ print('minimum python version(s): ' + str(supported))
+ sys.exit(1)
+
def check(self):
try:
from pip.exceptions import InstallationError
@@ -568,6 +608,8 @@ class NameSpacePackager(object):
to be installed explicitly as they are not on PyPI
install_requires should be dict, with keys 'any', 'py27' etc
or a list (which is as if only 'any' was defined
+
+ ToDo: update with: pep508 conditional dependencies
"""
if self._pkg[0] is None:
self._pkg[0] = []
@@ -606,6 +648,19 @@ class NameSpacePackager(object):
return self._pkg
@property
+ def extras_require(self):
+ """dict of conditions -> extra packages informaton required for installation
+ as of setuptools 33 doing `package ; python_version<=2.7' in install_requires
+ still doesn't work
+
+ https://www.python.org/dev/peps/pep-0508/
+ https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies
+ https://hynek.me/articles/conditional-python-dependencies/
+ """
+ ep = self._pkg_data.get('extras_require')
+ return ep
+
+ @property
def data_files(self):
df = self._pkg_data.get('data_files', [])
if self.has_mit_lic():
@@ -628,8 +683,16 @@ class NameSpacePackager(object):
@property
def ext_modules(self):
- """check if the C module can be build by trying to compile a small
- program against the libyaml development library"""
+ """check if all modules specified in the value for 'ext_modules' can be build
+ that value (if not None) is a list of dicts with 'name', 'src', 'lib'
+ Optional 'test' can be used to make sure trying to compile will work on the host
+
+ creates and return the external modules as Extensions, unless that
+ is not necessary at all for the action (like --version)
+
+ test existence of compiler by using export CC=nonexistent; export CXX=nonexistent
+ """
+
if hasattr(self, '_ext_modules'):
return self._ext_modules
if '--version' in sys.argv:
@@ -638,12 +701,32 @@ class NameSpacePackager(object):
return None
if sys.platform == "win32" and not self._pkg_data.get('win32bin'):
return None
+ if sys.platform == "win32":
+ if os.getenv("RUAMEL_FORCE_EXT_BUILD") is None:
+ return None
try:
plat = sys.argv.index('--plat-name')
if 'win' in sys.argv[plat + 1]:
return None
except ValueError:
pass
+ self._ext_modules = []
+ no_test_compile = False
+ if '--restructuredtext' in sys.argv:
+ no_test_compile = True
+ elif 'sdist' in sys.argv:
+ no_test_compile = True
+ if no_test_compile:
+ for target in self._pkg_data.get('ext_modules', []):
+ ext = Extension(
+ self.pn(target['name']),
+ sources=[self.pn(x) for x in target['src']],
+ libraries=[self.pn(x) for x in target.get('lib')],
+ )
+ self._ext_modules.append(ext)
+ return self._ext_modules
+
+ print('sys.argv', sys.argv)
import tempfile
import shutil
from textwrap import dedent
@@ -652,16 +735,13 @@ class NameSpacePackager(object):
import distutils.ccompiler
from distutils.errors import CompileError, LinkError
- self._ext_modules = []
for target in self._pkg_data.get('ext_modules', []): # list of dicts
- test_code = target.get('test')
- libraries = [self.pn(x) for x in target.get('lib')]
ext = Extension(
self.pn(target['name']),
sources=[self.pn(x) for x in target['src']],
- libraries=libraries,
+ libraries=[self.pn(x) for x in target.get('lib')],
)
- if not test_code:
+ if 'test' not in target: # no test just hope it works
self._ext_modules.append(ext)
continue
# write a temporary .c file to compile
@@ -669,24 +749,30 @@ class NameSpacePackager(object):
try:
tmp_dir = tempfile.mkdtemp(prefix='tmp_ruamel_')
bin_file_name = 'test' + self.pn(target['name'])
+ print('test compiling', bin_file_name)
file_name = os.path.join(tmp_dir, bin_file_name + '.c')
- with open(file_name, 'w') as fp:
+ with open(file_name, 'w') as fp: # write source
fp.write(c_code)
-
# and try to compile it
compiler = distutils.ccompiler.new_compiler()
assert isinstance(compiler, distutils.ccompiler.CCompiler)
+ # do any platform specific initialisations
distutils.sysconfig.customize_compiler(compiler)
-
+ # make sure you can reach header files because compile does change dir
+ compiler.add_include_dir(os.getcwd())
+ if sys.version_info < (3, ):
+ tmp_dir = tmp_dir.encode('utf-8')
+ # used to be a different directory, not necessary
+ compile_out_dir = tmp_dir
try:
compiler.link_executable(
compiler.compile(
[file_name],
- output_dir='/', # as file_name has absolute prefix
+ output_dir=compile_out_dir,
),
bin_file_name,
output_dir=tmp_dir,
- libraries=libraries,
+ libraries=ext.libraries,
)
except CompileError:
print('compile error:', file_name)
@@ -696,7 +782,7 @@ class NameSpacePackager(object):
continue
self._ext_modules.append(ext)
except Exception as e: # NOQA
- # print('Exception:', e)
+ print('Exception:', e)
pass
finally:
shutil.rmtree(tmp_dir)
@@ -733,12 +819,16 @@ def main():
if dump_kw in sys.argv:
import wheel
import distutils
- print('python: ', sys.version)
- print('distutils:', distutils.__version__)
- print('wheel: ', wheel.__version__)
+ import setuptools
+ print('python: ', sys.version)
+ print('setuptools:', setuptools.__version__)
+ print('distutils: ', distutils.__version__)
+ print('wheel: ', wheel.__version__)
nsp = NameSpacePackager(pkg_data)
nsp.check()
nsp.create_dirs()
+ MySdist.nsp = nsp
+ MyBdistWheel.nsp = nsp
kw = dict(
name=nsp.full_package_name,
namespace_packages=nsp.namespace_packages,
@@ -747,25 +837,34 @@ def main():
url=nsp.url,
author=nsp.author,
author_email=nsp.author_email,
- cmdclass={'install_lib': MyInstallLib},
+ cmdclass=dict(
+ install_lib=MyInstallLib,
+ sdist=MySdist,
+ bdist_wheel=MyBdistWheel,
+ ),
package_dir=nsp.package_dir,
entry_points=nsp.entry_points(),
description=nsp.description,
install_requires=nsp.install_requires,
+ extras_require=nsp.extras_require, # available since setuptools 18.0 / 2015-06
license=nsp.license,
classifiers=nsp.classifiers,
keywords=nsp.keywords,
package_data=nsp.package_data,
ext_modules=nsp.ext_modules,
)
+
if '--version' not in sys.argv and ('--verbose' in sys.argv or dump_kw in sys.argv):
for k in sorted(kw):
v = kw[k]
print(' "{0}": "{1}",'.format(k, v))
if dump_kw in sys.argv:
sys.argv.remove(dump_kw)
- with open('README.rst') as fp:
- kw['long_description'] = fp.read()
+ try:
+ with open('README.rst') as fp:
+ kw['long_description'] = fp.read()
+ except:
+ pass
if nsp.wheel(kw, setup):
return
for x in ['-c', 'egg_info', '--egg-base', 'pip-egg-info']:
@@ -791,7 +890,7 @@ def main():
try_dir = os.path.dirname(try_dir)
setup(**kw)
if nsp.nested and sys.argv[:2] == ['-c', 'bdist_wheel']:
- d = sys.argv[sys.argv.index('-d')+1]
+ d = sys.argv[sys.argv.index('-d') + 1]
for x in os.listdir(d):
if x.endswith('.whl'):
# remove .pth file from the wheel