diff options
Diffstat (limited to 'setup.py')
-rw-r--r-- | setup.py | 155 |
1 files changed, 127 insertions, 28 deletions
@@ -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 |