diff --git a/.travis.yml b/.travis.yml index b9afed96..5b71b589 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,36 +1,57 @@ language: python python: - - "2.7" - - "3.5" - - "3.6" + - 2.7 + - 3.4 + - 3.5 + - 3.6 + # also includes 3.7 (see below) env: - - NUMPY_VERSION="" WITH_COVERAGE=1 # environment to test with the latest version of NumPy + - NUMPY_VERSION="" # environment to test with the latest version of NumPy - NUMPY_VERSION="<1.13" + +matrix: + # support for python 3.7 is rather awkward via Travis CI + # https://github.com/travis-ci/travis-ci/issues/9815 + include: + - python: 3.7 + dist: xenial + sudo: true + env: NUMPY_VERSION="" + - python: 3.7 + dist: xenial + sudo: true + env: NUMPY_VERSION="<1.13" + exclude: + # for older python versions only test the latest versions of NumPy + - python: 2.7 + env: NUMPY_VERSION="<1.13" + - python: 3.4 + env: NUMPY_VERSION="<1.13" + - python: 3.5 + env: NUMPY_VERSION="<1.13" + before_install: - - phantomjs --version - - wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh - - chmod +x miniconda.sh + - wget https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh -O miniconda.sh && chmod +x miniconda.sh - ./miniconda.sh -b - export PATH=/home/travis/miniconda2/bin:$PATH # Update conda itself - conda update --yes conda + install: - - conda create --yes -n env_name python=$TRAVIS_PYTHON_VERSION pip numpy${NUMPY_VERSION} 'scipy>=0.17.0' matplotlib pandas nose flake8 pep8 jupyter - - source activate env_name - - pip install https://github.com/google/closure-linter/archive/master.zip - - pip install 'sphinx<1.6' sphinx-bootstrap-theme coverage coveralls - # install lockfile before to prevent a failure in travis - - pip install 'lockfile>=0.10.2' + - conda create --yes -n travis python=$TRAVIS_PYTHON_VERSION pip numpy${NUMPY_VERSION} 'scipy>=0.17.0' matplotlib pandas flake8 pep8 jupyter coverage cython + - source activate travis + - conda install -c conda-forge phantomjs --yes + # scikit-learn has to be pinned down due to a bug: https://github.com/scikit-learn/scikit-learn/issues/12671 + - pip install https://github.com/google/closure-linter/archive/master.zip 'sphinx<1.6' sphinx-bootstrap-theme coveralls 'scikit-learn==0.19.2' --no-binary scikit-learn - pip install -e '.[all]' --verbose - npm install -g jsdoc + script: - flake8 emperor/*.py tests/*.py scripts/*.py setup.py # we can only run gjslint in a python 2.7.x environment - if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then gjslint --custom_jsdoc_tags 'module,function,constructs,alias,default' 'emperor/support_files/js/*.js' 'tests/javascript_tests/*.js'; fi - # execute the full test suite - - python tests/all_tests.py # we just check coverage in the latest version of NumPy - - if [ ${WITH_COVERAGE} ]; then nosetests emperor --with-coverage --cover-package=emperor --cover-inclusive tests; fi + - coverage run tests/all_tests.py; coverage report - make -C doc html after_success: - coveralls diff --git a/README.md b/README.md index 648be855..6e5149a4 100644 --- a/README.md +++ b/README.md @@ -11,4 +11,10 @@ Before contributing code to Emperor, please familiarize yourself with the [contr ## Usage -You can start using Emperor through [QIIME2](https://qiime2.org)'s [interfaces](https://docs.qiime2.org/2.0.6/interfaces/) (the command line interface or the graphical user interface), or alternatively using the Python interface (compatible with the Jupyter notebook, see [this example](http://nbviewer.jupyter.org/github/biocore/emperor/blob/new-api/examples/keyboard.ipynb)). For more detalis, refer to our [online documentation](http://emperor.microbio.me/uno/). +You can start using Emperor through [QIIME2](https://qiime2.org)'s [interfaces](https://docs.qiime2.org/2018.8/interfaces/) (the command line interface or the graphical user interface), or alternatively using the Python interface (compatible with the Jupyter notebook, see [this example](http://nbviewer.jupyter.org/github/biocore/emperor/blob/new-api/examples/keyboard.ipynb)). For more detalis, refer to our [online documentation](http://emperor.microbio.me/uno/). + +## Publications + +- [EMPeror: a tool for visualizing high-throughput microbial community data](https://www.ncbi.nlm.nih.gov/pubmed/24280061). GigaScience, 2013. + +- [Bringing the Dynamic Microbiome to Life with Animations](https://www.ncbi.nlm.nih.gov/pubmed/28081445). Cell Host & Microbe, 2016. diff --git a/setup.py b/setup.py index d02e4fce..2d610440 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,7 @@ import sys -from distutils.core import setup -from glob import glob +from setuptools import setup, find_packages __version__ = "1.0.0beta18-dev" __maintainer__ = "Emperor development team" @@ -25,6 +24,9 @@ Programming Language :: Python Programming Language :: Python :: 2.7 Programming Language :: Python :: 3.4 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 Programming Language :: Python :: Implementation :: CPython Operating System :: OS Independent Operating System :: POSIX @@ -33,19 +35,15 @@ classifiers = [s.strip() for s in classes.split('\n') if s] -long_description = """Emperor: a tool for visualizing high-throughput microbial community data - -EMPeror: a tool for visualizing high-throughput microbial community data. -Vazquez-Baeza Y, Pirrung M, Gonzalez A, Knight R. -Gigascience. 2013 Nov 26;2(1):16. -""" +with open('README.md') as f: + long_description = f.read() skbio_2 = "scikit-bio >= 0.4.1, < 0.5.0" skbio_3 = "scikit-bio >= 0.4.1" base = ["numpy >= 1.7", "scipy >= 0.17.0", "click", "pandas", skbio_2, "jinja2 >= 2.9", "future"] doc = ["Sphinx < 1.6", "sphinx-bootstrap-theme"] -test = ["nose >= 0.10.1", "pep8", "flake8"] +test = ["pep8", "flake8"] all_deps = base + doc + test # prevent python2 from trying to install skbio >= 0.5.0 (which only works in @@ -63,8 +61,8 @@ maintainer=__maintainer__, maintainer_email=__email__, url='http://github.com/biocore/emperor', - packages=['emperor', 'emperor.qiime_backports'], - scripts=glob('scripts/*py'), + packages=find_packages(), + scripts=['scripts/make_emperor.py'], package_data={ 'emperor': ['support_files/vendor/js/three.js-plugins/*.js', 'support_files/vendor/js/*.js', @@ -84,5 +82,6 @@ install_requires=base, extras_require={'doc': doc, 'test': test, 'all': all_deps}, long_description=long_description, + long_description_content_type='text/markdown', license='BSD-3-Clause', classifiers=classifiers) diff --git a/tests/all_tests.py b/tests/all_tests.py index ec390bf6..b4289cbc 100755 --- a/tests/all_tests.py +++ b/tests/all_tests.py @@ -14,14 +14,12 @@ dde2a06f2d990db8b09da65764cd27fc047db788 """ -import re import sys import click import subprocess -from os import walk -from glob import glob -from os.path import join, abspath, dirname, split +from os.path import join, abspath, dirname +from unittest import TestLoader, TextTestRunner from emperor import __version__ @@ -66,43 +64,15 @@ def test(suppress_unit_tests, suppress_javascript_unit_tests, unittest_glob): "run.") test_dir = abspath(dirname(__file__)) - - unittest_good_pattern = re.compile(r'OK\s*$') - application_not_found_pattern = re.compile(b'ApplicationNotFoundError') - python_name = 'python' bad_tests = [] - missing_application_tests = [] # Run through all of Emperor's unit tests, and keep track of any files # which fail unit tests, note that these are the unit tests only if not suppress_unit_tests: - unittest_names = [] - if not unittest_glob: - for root, dirs, files in walk(test_dir): - for name in files: - if name.startswith('test_') and name.endswith('.py'): - unittest_names.append(join(root, name)) - else: - for fp in glob(unittest_glob): - fn = split(fp)[1] - if fn.startswith('test_') and fn.endswith('.py'): - unittest_names.append(abspath(fp)) - - unittest_names.sort() - - for unittest_name in unittest_names: - print("Testing %s:\n" % unittest_name) - command = '%s %s -v' % (python_name, unittest_name) - stdout, stderr, return_value = console(command) - print(stderr.decode("utf-8")) - if not unittest_good_pattern.search(stderr.decode("utf-8")): - if application_not_found_pattern.search(stderr): - missing_application_tests.append(unittest_name) - else: - bad_tests.append(unittest_name) + res = TextTestRunner().run(TestLoader().discover(start_dir=test_dir)) if not suppress_javascript_unit_tests: - print("JavaScript Test Suite") + click.echo("JavaScript Test Suite") runner = join(test_dir, 'javascript_tests', 'runner.js') index = join(test_dir, 'javascript_tests', 'index.html') @@ -117,35 +87,29 @@ def test(suppress_unit_tests, suppress_javascript_unit_tests, unittest_glob): else: javascript_tests_passed = True - print("==============\nResult summary\n==============") + click.echo("==============\nResult summary\n==============") if not suppress_unit_tests: - print("\nUnit test result summary\n------------------------\n") - if bad_tests: - print("\nThe following unit tests failed.\n%s" - % '\n'.join(bad_tests)) - - if missing_application_tests: - print("\nThe following unit tests failed, in part or whole due " - "to missing external applications.\nDepending on the " - "Emperor features you plan to use, this may not be " - "critical.\n%s" % '\n'.join(missing_application_tests)) - - if not(missing_application_tests or bad_tests): - print("\nAll unit tests passed.\n") + click.echo("\nUnit test result summary\n------------------------\n") + if not res.wasSuccessful(): + bad_tests = [i[0].id() for i in res.failures + res.errors] + click.echo("\nThe following unit tests failed:\n%s" + % '\n'.join(bad_tests)) + else: + click.echo("\nAll unit tests passed.\n") if not suppress_javascript_unit_tests: - print('\nJavaScript unit tests result summary\n' - '------------------------------------\n') + click.echo('\nJavaScript unit tests result summary\n' + '------------------------------------\n') if javascript_tests_passed: - print('All JavaScript unit tests passed.\n') + click.echo('All JavaScript unit tests passed.\n') else: - print('JavaScript unit tests failed, check the summary above.') + click.echo('JavaScript unit tests failed, check the summary ' + 'above.') # In case there were no failures of any type, exit with a return code of 0 return_code = 1 - if (len(bad_tests) == 0 and len(missing_application_tests) == 0 and - javascript_tests_passed): + if (len(bad_tests) == 0 and javascript_tests_passed): return_code = 0 exit(return_code)