From d4d34f7fd41da846ed098a6386a28e43efe6e5e7 2014-02-05 01:39:12 From: Thomas Kluyver <takowl@gmail.com> Date: 2014-02-05 01:39:12 Subject: [PATCH] Merge pull request #4975 from minrk/t2pp setup.py changes for 2.0 --- diff --git a/MANIFEST.in b/MANIFEST.in index 7a26f03..d34b8e9 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -35,3 +35,4 @@ global-exclude *.pyc global-exclude *.pyo global-exclude .dircopy.log global-exclude .git +global-exclude .ipynb_checkpoints diff --git a/setup.py b/setup.py index 5c65400..587a6e3 100755 --- a/setup.py +++ b/setup.py @@ -67,6 +67,7 @@ from setupbase import ( update_submodules, require_submodules, UpdateSubmodules, + get_bdist_wheel, CompileCSS, JavascriptVersion, install_symlinked, @@ -242,8 +243,8 @@ setup_args['cmdclass'] = { # For some commands, use setuptools. Note that we do NOT list install here! # If you want a setuptools-enhanced install, just run 'setupegg.py install' needs_setuptools = set(('develop', 'release', 'bdist_egg', 'bdist_rpm', - 'bdist', 'bdist_dumb', 'bdist_wininst', 'install_egg_info', - 'egg_info', 'easy_install', 'upload', + 'bdist', 'bdist_dumb', 'bdist_wininst', 'bdist_wheel', + 'egg_info', 'easy_install', 'upload', 'install_egg_info', )) if sys.platform == 'win32': # Depend on setuptools for install on *Windows only* @@ -259,43 +260,38 @@ if len(needs_setuptools.intersection(sys.argv)) > 0: # specific to setup setuptools_extra_args = {} +# setuptools requirements + +extras_require = dict( + parallel = ['pyzmq>=2.1.11'], + qtconsole = ['pyzmq>=2.1.11', 'pygments'], + zmq = ['pyzmq>=2.1.11'], + doc = ['Sphinx>=1.1', 'numpydoc'], + test = ['nose>=0.10.1'], + notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2'], + nbconvert = ['pygments', 'jinja2', 'Sphinx>=0.3'] +) +everything = set() +for deps in extras_require.values(): + everything.update(deps) +extras_require['all'] = everything +install_requires = [] +if sys.platform == 'darwin': + install_requires.append('readline') +elif sys.platform.startswith('win'): + # Pyreadline has unicode and Python 3 fixes in 2.0 + install_requires.append('pyreadline>=2.0') + if 'setuptools' in sys.modules: # setup.py develop should check for submodules from setuptools.command.develop import develop setup_args['cmdclass']['develop'] = require_submodules(develop) + setup_args['cmdclass']['bdist_wheel'] = get_bdist_wheel() setuptools_extra_args['zip_safe'] = False setuptools_extra_args['entry_points'] = {'console_scripts':find_entry_points()} - setup_args['extras_require'] = dict( - parallel = 'pyzmq>=2.1.11', - qtconsole = ['pyzmq>=2.1.11', 'pygments'], - zmq = 'pyzmq>=2.1.11', - doc = ['Sphinx>=1.1', 'numpydoc'], - test = 'nose>=0.10.1', - notebook = ['tornado>=3.1', 'pyzmq>=2.1.11', 'jinja2'], - nbconvert = ['pygments', 'jinja2', 'Sphinx>=0.3'] - ) - everything = set() - for deps in setup_args['extras_require'].values(): - if not isinstance(deps, list): - deps = [deps] - for dep in deps: - everything.add(dep) - setup_args['extras_require']['all'] = everything - - requires = setup_args.setdefault('install_requires', []) - setupext.display_status = False - if not setupext.check_for_readline(): - if sys.platform == 'darwin': - requires.append('readline') - elif sys.platform.startswith('win'): - # Pyreadline 64 bit windows issue solved in versions >=1.7.1 - # Also solves issues with some older versions of pyreadline that - # satisfy the unconstrained depdendency. - requires.append('pyreadline>=1.7.1') - else: - pass - # do we want to install readline here? + setup_args['extras_require'] = extras_require + requires = setup_args['install_requires'] = install_requires # Script to be run by the windows binary installer after the default setup # routine, to add shortcuts and similar windows-only things. Windows @@ -314,10 +310,13 @@ if 'setuptools' in sys.modules: "ipython_win_post_install.py"}} else: - # If we are running without setuptools, call this function which will + # If we are installing without setuptools, call this function which will # check for dependencies an inform the user what is needed. This is # just to make life easy for users. - check_for_dependencies() + for install_cmd in ('install', 'symlink'): + if install_cmd in sys.argv: + check_for_dependencies() + break # scripts has to be a non-empty list, or install_scripts isn't called setup_args['scripts'] = [e.split('=')[0].strip() for e in find_entry_points()] diff --git a/setupbase.py b/setupbase.py index b5c9b20..c15e9ab 100644 --- a/setupbase.py +++ b/setupbase.py @@ -127,23 +127,44 @@ def find_package_data(): # This is not enough for these things to appear in an sdist. # We need to muck with the MANIFEST to get this to work - # exclude static things that we don't ship (e.g. mathjax) - excludes = ['mathjax'] + # exclude components from the walk, + # we will build the components separately + excludes = ['components'] # add 'static/' prefix to exclusions, and tuplify for use in startswith - excludes = tuple([os.path.join('static', ex) for ex in excludes]) + excludes = tuple([pjoin('static', ex) for ex in excludes]) # walk notebook resources: cwd = os.getcwd() os.chdir(os.path.join('IPython', 'html')) - static_walk = list(os.walk('static')) static_data = [] - for parent, dirs, files in static_walk: + for parent, dirs, files in os.walk('static'): if parent.startswith(excludes): continue for f in files: - static_data.append(os.path.join(parent, f)) - + static_data.append(pjoin(parent, f)) + components = pjoin("static", "components") + # select the components we actually need to install + # (there are lots of resources we bundle for sdist-reasons that we don't actually use) + static_data.extend([ + pjoin(components, "backbone", "backbone-min.js"), + pjoin(components, "bootstrap", "bootstrap", "js", "bootstrap.min.js"), + pjoin(components, "font-awesome", "font", "*.*"), + pjoin(components, "highlight.js", "build", "highlight.pack.js"), + pjoin(components, "jquery", "jquery.min.js"), + pjoin(components, "jquery-ui", "ui", "minified", "jquery-ui.min.js"), + pjoin(components, "jquery-ui", "themes", "smoothness", "jquery-ui.min.css"), + pjoin(components, "marked", "lib", "marked.js"), + pjoin(components, "requirejs", "require.js"), + pjoin(components, "underscore", "underscore-min.js"), + ]) + + # Ship all of Codemirror's CSS and JS + for parent, dirs, files in os.walk(pjoin(components, 'codemirror')): + for f in files: + if f.endswith(('.js', '.css')): + static_data.append(pjoin(parent, f)) + os.chdir(os.path.join('tests',)) js_tests = glob('casperjs/*.*') + glob('casperjs/*/*') @@ -157,7 +178,6 @@ def find_package_data(): 'IPython.config.profile' : ['README*', '*/*.py'], 'IPython.core.tests' : ['*.png', '*.jpg'], 'IPython.lib.tests' : ['*.wav'], - 'IPython.testing' : ['*.txt'], 'IPython.testing.plugin' : ['*.txt'], 'IPython.html' : ['templates/*'] + static_data, 'IPython.html.tests' : js_tests, @@ -167,6 +187,17 @@ def find_package_data(): 'IPython.nbconvert.filters' : ['marked.js'], 'IPython.nbformat' : ['tests/*.ipynb'] } + + # verify that package_data makes sense + for pkg, data in package_data.items(): + pkg_root = pjoin(*pkg.split('.')) + for d in data: + path = pjoin(pkg_root, d) + if '*' in path: + assert len(glob(path)) > 0, "No files match pattern %s" % path + else: + assert os.path.exists(path), "Missing package data: %s" % path + return package_data @@ -215,10 +246,9 @@ def find_data_files(): """ Find IPython's data_files. - Most of these are docs. + Just man pages at this point. """ - docdirbase = pjoin('share', 'doc', 'ipython') manpagebase = pjoin('share', 'man', 'man1') # Simple file lists can be made by hand @@ -227,24 +257,8 @@ def find_data_files(): # When running from a source tree, the manpages aren't gzipped manpages = [f for f in glob(pjoin('docs','man','*.1')) if isfile(f)] - igridhelpfiles = [f for f in glob(pjoin('IPython','extensions','igrid_help.*')) if isfile(f)] - - # For nested structures, use the utility above - example_files = make_dir_struct( - 'data', - pjoin('docs','examples'), - pjoin(docdirbase,'examples') - ) - manual_files = make_dir_struct( - 'data', - pjoin('docs','html'), - pjoin(docdirbase,'manual') - ) - # And assemble the entire output list - data_files = [ (manpagebase, manpages), - (pjoin(docdirbase, 'extensions'), igridhelpfiles), - ] + manual_files + example_files + data_files = [ (manpagebase, manpages) ] return data_files @@ -452,7 +466,8 @@ def check_for_dependencies(): check_for_sphinx() check_for_pygments() check_for_nose() - check_for_pexpect() + if os.name == 'posix': + check_for_pexpect() check_for_pyzmq() check_for_tornado() check_for_readline() @@ -556,6 +571,70 @@ def require_submodules(command): return DecoratedCommand #--------------------------------------------------------------------------- +# bdist related +#--------------------------------------------------------------------------- + +def get_bdist_wheel(): + """Construct bdist_wheel command for building wheels + + Constructs py2-none-any tag, instead of py2.7-none-any + """ + class RequiresWheel(Command): + description = "Dummy command for missing bdist_wheel" + user_options = [] + + def initialize_options(self): + pass + + def finalize_options(self): + pass + + def run(self): + print("bdist_wheel requires the wheel package") + sys.exit(1) + + if 'setuptools' not in sys.modules: + return RequiresWheel + else: + try: + from wheel.bdist_wheel import bdist_wheel, read_pkg_info, write_pkg_info + except ImportError: + return RequiresWheel + + class bdist_wheel_tag(bdist_wheel): + + def get_tag(self): + return ('py%i' % sys.version_info[0], 'none', 'any') + + def add_requirements(self, metadata_path): + """transform platform-dependent requirements""" + pkg_info = read_pkg_info(metadata_path) + # pkg_info is an email.Message object (?!) + # we have to remove the unconditional 'readline' and/or 'pyreadline' entries + # and transform them to conditionals + requires = pkg_info.get_all('Requires-Dist') + del pkg_info['Requires-Dist'] + def _remove_startswith(lis, prefix): + """like list.remove, but with startswith instead of ==""" + found = False + for idx, item in enumerate(lis): + if item.startswith(prefix): + found = True + break + if found: + lis.pop(idx) + + for pkg in ("readline", "pyreadline"): + _remove_startswith(requires, pkg) + requires.append("readline; sys.platform == 'darwin'") + requires.append("pyreadline (>=2.0); sys.platform == 'win32'") + for r in requires: + pkg_info['Requires-Dist'] = r + write_pkg_info(metadata_path, pkg_info) + + return bdist_wheel_tag + +#--------------------------------------------------------------------------- # Notebook related #--------------------------------------------------------------------------- diff --git a/setupext/setupext.py b/setupext/setupext.py index 468c457..38f6c43 100644 --- a/setupext/setupext.py +++ b/setupext/setupext.py @@ -107,7 +107,7 @@ def check_for_pexpect(): try: import pexpect except ImportError: - print_status("pexpect", "no (required for running standalone doctests)") + print_status("pexpect", "no (will use bundled version in IPython.external)") return False else: print_status("pexpect", pexpect.__version__)