diff options
author | Anthon van der Neut <anthon@mnt.org> | 2015-08-28 22:53:27 +0200 |
---|---|---|
committer | Anthon van der Neut <anthon@mnt.org> | 2015-08-28 22:53:27 +0200 |
commit | 5ecff93774763a96442af70e38043f3e9d1b7335 (patch) | |
tree | c63551460b569a3d8025eb61ec195dc1e08e1302 /setup.py | |
parent | 386029ed647ca7fd0209506285f02365c347eef9 (diff) | |
download | ruamel.yaml-5ecff93774763a96442af70e38043f3e9d1b7335.tar.gz |
split
Diffstat (limited to 'setup.py')
-rw-r--r-- | setup.py | 210 |
1 files changed, 169 insertions, 41 deletions
@@ -11,39 +11,71 @@ if __name__ != '__main__': full_package_name = None +# parses python ( "= dict( )" ) or json ( "= { # JSON" ) def _package_data(fn): data = {} with open(fn) as fp: parsing = False + lines = [] for line in fp.readlines(): if line.startswith('_package_data'): - parsing = True + if 'dict(' in line: + parsing = 'python' + elif '# JSON' in line: + parsing = 'json' + lines.append('{\n') + else: + raise NotImplementedError continue if not parsing: continue - if line.startswith(')'): - break - if '# NOQA' in line: - line = line.split('# NOQA', 1)[0].rstrip() - k, v = [x.strip() for x in line.split('=', 1)] - if v[-1] == ',': - v = v[:-1] - if v[0] in '\'"' and v[0] == v[-1]: - data[k] = v[1:-1] - elif v == 'None': - data[k] = None - elif v == 'True': - data[k] = True - elif v == 'False': - data[k] = False - elif v[0] == '(' and v[-1] == ')': - data[k] = tuple([x.strip()[1:-1] if x[0] in '\'"' else int(x) - for x in v[1:-1].split(', ')]) - elif v[0] == '[' and v[-1] == ']': - data[k] = [x.strip()[1:-1] if x[0] in '\'"' else int(x) - for x in v[1:-1].split(', ')] + if parsing == 'json': + x = line.rsplit("# ", 1) + if len(x) > 1: + if x[1].startswith('JSON'): + lines.append(x[0]+'\n') + import json + try: + data = json.loads(''.join(lines)) + except ValueError: + w = len(str(len(lines))) + for i, line in enumerate(lines): + print('{0:{1}}: {2}'.format( + i+1, w, line), end='') + raise + break + elif not x[0].strip(): + continue # empty line can have any comment + elif '"' not in x[1] and "'" not in x[1]: + # can't deal with quotes might be # in string + line = x[0] + '\n' + lines.append(line) + elif parsing == 'python': + if line.startswith(')'): + break + if '# NOQA' in line: + line = line.split('# NOQA', 1)[0].rstrip() + k, v = [x.strip() for x in line.split('=', 1)] + if v[-1] == ',': + v = v[:-1] + if v[0] in '\'"' and v[0] == v[-1]: + data[k] = v[1:-1] + elif v == 'None': + data[k] = None + elif v == 'True': + data[k] = True + elif v == 'False': + data[k] = False + elif v[0] == '(' and v[-1] == ')': + data[k] = tuple([x.strip()[1:-1] if x[0] in '\'"' else + int(x) for x in v[1:-1].split(', ')]) + elif v[0] == '[' and v[-1] == ']': + data[k] = [x.strip()[1:-1] if x[0] in '\'"' else int(x) + for x in v[1:-1].split(', ')] + else: + print('Unknown: >>>>> {0!r} {1!r}'.format(k, v)) else: - print('Unknown: >>>>> {0!r} {1!r}'.format(k, v)) + raise NotImplementedError return data pkg_data = _package_data('__init__.py') @@ -55,8 +87,9 @@ exclude_files = [ # # imports import os import sys +import platform -from setuptools import setup +from setuptools import setup, Extension, Distribution # NOQA from setuptools.command import install_lib @@ -117,7 +150,7 @@ class NameSpacePackager(object): def __init__(self, pkg_data): assert isinstance(pkg_data, dict) self._pkg_data = pkg_data - self.full_package_name = self._pkg_data['full_package_name'] + self.full_package_name = self.pn(self._pkg_data['full_package_name']) self._split = None self.depth = self.full_package_name.count('.') self.command = None @@ -125,12 +158,24 @@ class NameSpacePackager(object): '--single-version-externally-managed' not in sys.argv: print('error: 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 + if self._pkg_data.get('universal'): + Distribution.is_pure = lambda *args: True + else: + Distribution.is_pure = lambda *args: False for x in sys.argv: if x[0] == '-' or x == 'setup.py': continue self.command = x break + def pn(self, s): + if sys.version_info < (3, ) and isinstance(s, unicode): + return s.encode('utf-8') + return s + @property def split(self): """split the full package name in list of compontents""" @@ -143,7 +188,8 @@ class NameSpacePackager(object): for d in os.listdir('.'): if not os.path.isdir(d) or d == self._split[0] or d[0] == '_': continue - x = os.path.join(d, 'setup.py') # prevent sub-packages in namespace from being included + # 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' @@ -175,12 +221,14 @@ class NameSpacePackager(object): with open(os.path.join(d, '__init__.py'), 'w') as fp: fp.write('import pkg_resources\n' 'pkg_resources.declare_namespace(__name__)\n') - os.symlink( - # a.b gives a/b -> .. - # a.b.c gives a/b/c -> ../.. - os.path.join(*['..'] * self.depth), - os.path.join(*self.split[self.depth].split('.')) - ) + # not necessary if not using find_packages, recursive links + # are horrible anyway, slowing down pip + # os.symlink( + # # a.b gives a/b -> .. + # # a.b.c gives a/b/c -> ../.. + # os.path.join(*['..'] * self.depth), + # os.path.join(*self.split[self.depth].split('.')) + # ) def check(self): try: @@ -239,7 +287,7 @@ class NameSpacePackager(object): ep = self._pkg_data.get('entry_points', True) if ep is None: return None - if ep is not True: + if ep not in [True, 1]: return {'console_scripts': [ep]} if package_name is None: package_name = self.full_package_name @@ -278,12 +326,12 @@ class NameSpacePackager(object): @property def status(self): # αβ - status = self._pkg_data.get('status', 'β') - if status == 'α': + status = self._pkg_data.get('status', u'β') + if status == u'α': return (3, 'Alpha') - elif status == 'β': + elif status == u'β': return (4, 'Beta') - elif 'stable' in status.lower(): + elif u'stable' in status.lower(): return (5, 'Production/Stable') raise NotImplementedError @@ -293,15 +341,26 @@ class NameSpacePackager(object): 'Development Status :: {0} - {1}'.format(*self.status), 'Intended Audience :: Developers', 'License :: ' + ('Other/Proprietary License' - if self._pkg_data.get('license') else + if self.pn(self._pkg_data.get('license')) else 'OSI Approved :: MIT License'), 'Operating System :: OS Independent', 'Programming Language :: Python', - ] + ] + [self.pn(x) for x in self._pkg_data.get('classifiers', [])] @property def install_requires(self): - return pkg_data.get('install_requires', []) + ir = self._pkg_data.get('install_requires', []) + if isinstance(ir, list): + return ir + # 'any' for all builds, 'py27' etc for specifics versions + res = ir.get('any', []) + implementation = platform.python_implementation() + if implementation == 'CPython': + pyver = 'py{0}{1}'.format(*sys.version_info) + elif implementation == 'PyPy': + pyver = 'pypy' if sys.version_info < (3, ) else 'pypy3' + res.extend(ir.get(pyver, [])) + return res @property def data_files(self): @@ -324,6 +383,74 @@ class NameSpacePackager(object): return {} return {self.full_package_name: df} + @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""" + if hasattr(self, '_ext_modules'): + return self._ext_modules + if '--version' in sys.argv: + return None + # if sys.platform == "win32": + # return None + import tempfile + import shutil + from textwrap import dedent + + import distutils.sysconfig + 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, + ) + if not test_code: + self._ext_modules.append(ext) + continue + # write a temporary .c file to compile + c_code = dedent(target['test']) + try: + tmp_dir = tempfile.mkdtemp(prefix='tmp_ruamel_') + bin_file_name = 'test' + self.pn(target['name']) + file_name = os.path.join(tmp_dir, bin_file_name + '.c') + with open(file_name, 'w') as fp: + fp.write(c_code) + + # and try to compile it + compiler = distutils.ccompiler.new_compiler() + assert isinstance(compiler, distutils.ccompiler.CCompiler) + distutils.sysconfig.customize_compiler(compiler) + + try: + compiler.link_executable( + compiler.compile( + [file_name], + output_dir='/', # as file_name has absolute prefix + ), + bin_file_name, + output_dir=tmp_dir, + libraries=libraries, + ) + except CompileError: + print('compile error:', file_name) + continue + except LinkError: + print('libyaml link error', file_name) + continue + self._ext_modules.append(ext) + except Exception as e: # NOQA + # print('Exception:', e) + pass + finally: + shutil.rmtree(tmp_dir) + return self._ext_modules + def wheel(self, kw, setup): """temporary add setup.cfg if creating a wheel to include LICENSE file https://bitbucket.org/pypa/wheel/issues/47 @@ -367,8 +494,9 @@ def main(): license=nsp.license, classifiers=nsp.classifiers, package_data=nsp.package_data, + ext_modules=nsp.ext_modules, ) - if '--version' not in sys.argv: + if '--version' not in sys.argv or '--verbose' in sys.argv: for k in sorted(kw): v = kw[k] print(k, '->', v) |