diff --git a/MANIFEST.in b/MANIFEST.in index 88236be8e..87279a5c8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,7 +1,6 @@ include README.rst include CHANGES.rst -include ez_setup.py include ah_bootstrap.py include setup.cfg include pycraf/tests/coveragerc @@ -26,7 +25,6 @@ include astropy_helpers/CHANGES.rst include astropy_helpers/LICENSE.rst recursive-include astropy_helpers/licenses * -include astropy_helpers/ez_setup.py include astropy_helpers/ah_bootstrap.py recursive-include astropy_helpers/astropy_helpers *.py *.pyx *.c *.h *.rst diff --git a/ah_bootstrap.py b/ah_bootstrap.py index ece5aa98f..8a0e8a1f0 100644 --- a/ah_bootstrap.py +++ b/ah_bootstrap.py @@ -58,7 +58,14 @@ from configparser import ConfigParser, RawConfigParser -_str_types = (str, bytes) +if sys.version_info[0] < 3: + _str_types = (str, unicode) + _text_type = unicode + PY3 = False +else: + _str_types = (str, bytes) + _text_type = str + PY3 = True # What follows are several import statements meant to deal with install-time @@ -129,7 +136,11 @@ # TODO: Maybe enable checking for a specific version of astropy_helpers? DIST_NAME = 'astropy-helpers' PACKAGE_NAME = 'astropy_helpers' -UPPER_VERSION_EXCLUSIVE = None + +if PY3: + UPPER_VERSION_EXCLUSIVE = None +else: + UPPER_VERSION_EXCLUSIVE = '3' # Defaults for other options DOWNLOAD_IF_NEEDED = True @@ -161,7 +172,7 @@ def __init__(self, path=None, index_url=None, use_git=None, offline=None, if not (isinstance(path, _str_types) or path is False): raise TypeError('path must be a string or False') - if not isinstance(path, str): + if PY3 and not isinstance(path, _text_type): fs_encoding = sys.getfilesystemencoding() path = path.decode(fs_encoding) # path to unicode @@ -804,9 +815,9 @@ def run_cmd(cmd): stdio_encoding = 'latin1' # Unlikely to fail at this point but even then let's be flexible - if not isinstance(stdout, str): + if not isinstance(stdout, _text_type): stdout = stdout.decode(stdio_encoding, 'replace') - if not isinstance(stderr, str): + if not isinstance(stderr, _text_type): stderr = stderr.decode(stdio_encoding, 'replace') return (p.returncode, stdout, stderr) diff --git a/docs/conf.py b/docs/conf.py index ed9cc3948..f9fca73d3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -30,17 +30,7 @@ import sys try: - import astropy_helpers -except ImportError: - # Building from inside the docs/ directory? - if os.path.basename(os.getcwd()) == 'docs': - a_h_path = os.path.abspath(os.path.join('..', 'astropy_helpers')) - if os.path.isdir(a_h_path): - sys.path.insert(1, a_h_path) - -# Load all of the global Astropy configuration -try: - from sphinx_astropy.conf import * + from sphinx_astropy.conf.v1 import * # noqa except ImportError: print('ERROR: the documentation requires the sphinx-astropy package to be installed') sys.exit(1) @@ -180,7 +170,7 @@ # -- Options for the edit_on_github extension --------------------------------- if eval(setup_cfg.get('edit_on_github')): - extensions += ['astropy_helpers.sphinx.ext.edit_on_github'] + extensions += ['sphinx_astropy.ext.edit_on_github'] versionmod = __import__(setup_cfg['package_name'] + '.version') edit_on_github_project = setup_cfg['github_project'] @@ -195,6 +185,32 @@ # -- Resolving issue number to links in changelog ----------------------------- github_issues_url = 'https://github.com/{0}/issues/'.format(setup_cfg['github_project']) +# -- Turn on nitpicky mode for sphinx (to warn about references not found) ---- +# +# nitpicky = True +# nitpick_ignore = [] +# +# Some warnings are impossible to suppress, and you can list specific references +# that should be ignored in a nitpick-exceptions file which should be inside +# the docs/ directory. The format of the file should be: +# +# +# +# for example: +# +# py:class astropy.io.votable.tree.Element +# py:class astropy.io.votable.tree.SimpleElement +# py:class astropy.io.votable.tree.SimpleElementWithContent +# +# Uncomment the following lines to enable the exceptions: +# +# for line in open('nitpick-exceptions'): +# if line.strip() == "" or line.startswith("#"): +# continue +# dtype, target = line.split(None, 1) +# target = target.strip() +# nitpick_ignore.append((dtype, six.u(target))) + # -- Inline Plotting ---------------------------------------------------------- diff --git a/docs/make.bat b/docs/make.bat index 93dfe92b9..aa930134b 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -37,6 +37,8 @@ if "%1" == "help" ( if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* + del /q /s api + del /q /s generated goto end ) diff --git a/pycraf/__init__.py b/pycraf/__init__.py index 5ed26005c..b363904bd 100644 --- a/pycraf/__init__.py +++ b/pycraf/__init__.py @@ -5,12 +5,25 @@ Top-level functionality: ''' -# Affiliated packages may add whatever they like to this file, but +# Packages may add whatever they like to this file, but # should keep this content at the top. # ---------------------------------------------------------------------------- from ._astropy_init import * # ---------------------------------------------------------------------------- +# Enforce Python version check during package import. +# This is the same check as the one at the top of setup.py +import sys + +__minimum_python_version__ = "3.5" + +class UnsupportedPythonError(Exception): + pass + +if sys.version_info < tuple((int(val) for val in __minimum_python_version__.split('.'))): + raise UnsupportedPythonError("pycraf does not support Python < {}".format(__minimum_python_version__)) + + if not _ASTROPY_SETUP_: # For egg_info test builds to pass, put package imports here. diff --git a/pycraf/_astropy_init.py b/pycraf/_astropy_init.py index 73a52fb3c..1e229e193 100644 --- a/pycraf/_astropy_init.py +++ b/pycraf/_astropy_init.py @@ -1,6 +1,6 @@ # Licensed under a 3-clause BSD style license - see LICENSE.rst -__all__ = ['__version__', '__githash__', 'test'] +__all__ = ['__version__', '__githash__'] # this indicates whether or not we are in the package's setup.py try: @@ -23,95 +23,6 @@ __githash__ = '' -# set up the test command -def _get_test_runner(): - import os - from astropy.tests.helper import TestRunner - return TestRunner(os.path.dirname(__file__)) - - -def test(package=None, test_path=None, args=None, plugins=None, - verbose=False, pastebin=None, remote_data=False, pep8=False, - pdb=False, coverage=False, open_files=False, **kwargs): - """ - Run the tests using `py.test `__. A proper set - of arguments is constructed and passed to `pytest.main`_. - - .. _py.test: http://pytest.org/latest/ - .. _pytest.main: http://pytest.org/latest/builtin.html#pytest.main - - Parameters - ---------- - package : str, optional - The name of a specific package to test, e.g. 'io.fits' or 'utils'. - If nothing is specified all default tests are run. - - test_path : str, optional - Specify location to test by path. May be a single file or - directory. Must be specified absolutely or relative to the - calling directory. - - args : str, optional - Additional arguments to be passed to pytest.main_ in the ``args`` - keyword argument. - - plugins : list, optional - Plugins to be passed to pytest.main_ in the ``plugins`` keyword - argument. - - verbose : bool, optional - Convenience option to turn on verbose output from py.test_. Passing - True is the same as specifying ``'-v'`` in ``args``. - - pastebin : {'failed','all',None}, optional - Convenience option for turning on py.test_ pastebin output. Set to - ``'failed'`` to upload info for failed tests, or ``'all'`` to upload - info for all tests. - - remote_data : bool, optional - Controls whether to run tests marked with @remote_data. These - tests use online data and are not run by default. Set to True to - run these tests. - - pep8 : bool, optional - Turn on PEP8 checking via the `pytest-pep8 plugin - `_ and disable normal - tests. Same as specifying ``'--pep8 -k pep8'`` in ``args``. - - pdb : bool, optional - Turn on PDB post-mortem analysis for failing tests. Same as - specifying ``'--pdb'`` in ``args``. - - coverage : bool, optional - Generate a test coverage report. The result will be placed in - the directory htmlcov. - - open_files : bool, optional - Fail when any tests leave files open. Off by default, because - this adds extra run time to the test suite. Requires the - `psutil `_ package. - - parallel : int, optional - When provided, run the tests in parallel on the specified - number of CPUs. If parallel is negative, it will use the all - the cores on the machine. Requires the - `pytest-xdist `_ plugin - installed. Only available when using Astropy 0.3 or later. - - kwargs - Any additional keywords passed into this function will be passed - on to the astropy test runner. This allows use of test-related - functionality implemented in later versions of astropy without - explicitly updating the package template. - - """ - test_runner = _get_test_runner() - return test_runner.run_tests( - package=package, test_path=test_path, args=args, - plugins=plugins, verbose=verbose, pastebin=pastebin, - remote_data=remote_data, pep8=pep8, pdb=pdb, - coverage=coverage, open_files=open_files, **kwargs) - if not _ASTROPY_SETUP_: # noqa import os from warnings import warn @@ -120,6 +31,12 @@ def test(package=None, test_path=None, args=None, plugins=None, ConfigurationDefaultMissingError, ConfigurationDefaultMissingWarning) + # Create the test function for self test + from astropy.tests.runner import TestRunner + test = TestRunner.make_test_runner_in(os.path.dirname(__file__)) + test.__test__ = False + __all__ += ['test'] + # add these here so we only need to cleanup the namespace at the end config_dir = None diff --git a/pycraf/conftest.py b/pycraf/conftest.py index a1a623892..ae44fa078 100644 --- a/pycraf/conftest.py +++ b/pycraf/conftest.py @@ -1,8 +1,19 @@ -# this contains imports plugins that configure py.test for astropy tests. -# by importing them here in conftest.py they are discoverable by py.test -# no matter how it is invoked within the source tree. +# This file is used to configure the behavior of pytest when using the Astropy +# test infrastructure. -from astropy.tests.pytest_plugins import * +from astropy.version import version as astropy_version +if astropy_version < '3.0': + # With older versions of Astropy, we actually need to import the pytest + # plugins themselves in order to make them discoverable by pytest. + from astropy.tests.pytest_plugins import * +else: + # As of Astropy 3.0, the pytest plugins provided by Astropy are + # automatically made available when Astropy is installed. This means it's + # not necessary to import them here, but we still need to import global + # variables that are used for configuration. + from astropy.tests.plugins.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS + +from astropy.tests.helper import enable_deprecations_as_exceptions ## Uncomment the following line to treat all DeprecationWarnings as ## exceptions. For Astropy v2.0 or later, there are 2 additional keywords, @@ -32,7 +43,7 @@ # running the tests. import os -# This is to figure out the affiliated package version, rather than +# This is to figure out the package version, rather than # using Astropy's try: from .version import version diff --git a/setup.cfg b/setup.cfg index d38ba97e1..1c70147a6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -21,6 +21,9 @@ addopts = -p no:warnings [ah_bootstrap] auto_use = True +[flake8] +exclude = extern,sphinx,*parsetab.py + [pycodestyle] # E101 - mix of tabs and spaces # W191 - use of tabs @@ -50,8 +53,9 @@ github_project = bwinkel/pycraf # install_requires should be formatted as a comma-separated list, e.g.: # install_requires = astropy, scipy, matplotlib install_requires = astropy, scipy, matplotlib -# version should be PEP386 compatible (http://www.python.org/dev/peps/pep-0386) +# version should be PEP440 compatible (https://www.python.org/dev/peps/pep-0440/) version = 0.25.8dev +minimum_python_version = 3.5 [entry_points] diff --git a/setup.py b/setup.py index 9dbcb1720..22993db95 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,7 @@ #!/usr/bin/env python # Licensed under a 3-clause BSD style license - see LICENSE.rst +# Note: This file needs to be Python 2 / <3.6 compatible, so that the nice +# "This package only supports Python 3.x+" error prints without syntax errors etc. ''' @@ -17,6 +19,31 @@ import glob import os import sys +try: + from configparser import ConfigParser +except ImportError: + from ConfigParser import ConfigParser + +# Get some values from the setup.cfg +conf = ConfigParser() +conf.read(['setup.cfg']) +metadata = dict(conf.items('metadata')) + +PACKAGENAME = metadata.get('package_name', 'pycraf') +DESCRIPTION = metadata.get('description', 'pycraf') +AUTHOR = metadata.get('author', 'Benjamin Winkel') +AUTHOR_EMAIL = metadata.get('author_email', 'bwinkel@mpifr.de') +LICENSE = metadata.get('license', 'GPLv3') +URL = metadata.get('url', 'https://github.com/bwinkel/pycraf') +__minimum_python_version__ = metadata.get("minimum_python_version", "2.7") + +# Enforce Python version check - this is the same check as in __init__.py but +# this one has to happen before importing ah_bootstrap. +if sys.version_info < tuple((int(val) for val in __minimum_python_version__.split('.'))): + sys.stderr.write("ERROR: cygrid requires Python {} or later\n".format(__minimum_python_version__)) + sys.exit(1) + +# Import ah_bootstrap after the python version validation import ah_bootstrap from setuptools import setup @@ -28,28 +55,11 @@ import __builtin__ as builtins builtins._ASTROPY_SETUP_ = True -from astropy_helpers.setup_helpers import ( - register_commands, get_debug_option, get_package_info - ) +from astropy_helpers.setup_helpers import (register_commands, get_debug_option, + get_package_info) from astropy_helpers.git_helpers import get_git_devstr from astropy_helpers.version_helpers import generate_version_py -# Get some values from the setup.cfg -try: - from ConfigParser import ConfigParser -except ImportError: - from configparser import ConfigParser - -conf = ConfigParser() -conf.read(['setup.cfg']) -metadata = dict(conf.items('metadata')) - -PACKAGENAME = metadata.get('package_name', 'pycraf') -DESCRIPTION = metadata.get('description', 'pycraf') -AUTHOR = metadata.get('author', 'Benjamin Winkel') -AUTHOR_EMAIL = metadata.get('author_email', 'bwinkel@mpifr.de') -LICENSE = metadata.get('license', 'GPLv3') -URL = metadata.get('url', 'https://github.com/bwinkel/pycraf') # order of priority for long_description: # (1) set in setup.cfg, @@ -156,5 +166,6 @@ zip_safe=False, use_2to3=False, entry_points=entry_points, + python_requires='>={}'.format(__minimum_python_version__), **package_info )