Commit 08d784fb authored by Ole Streicher's avatar Ole Streicher

New upstream release candidate 1.0rc1

parent 1cc8ef5f
This diff is collapsed.
Metadata-Version: 1.1
Name: astropy
Version: 0.4.4
Version: 1.0rc1
Summary: Community-developed python astronomy tools
Author: The Astropy Developers
License: BSD
Astropy is a package intended to contain core functionality and some
common tools needed for performing astronomy and astrophysics research with
......@@ -26,20 +26,22 @@ For system packagers: Please install Astropy with the command::
This will prevent the astropy_helpers bootstrap script from attempting to
reach out to PyPI.
Project Status
Travis Build Status
.. image::
Test Coverage Status
.. image::
.. image::
For an overview of the testing and build status of all packages associated
with the Astropy Project, see
Astropy is licensed under a 3-clause BSD style license - see the
``licenses/LICENSE.rst`` file.
\ No newline at end of file
``licenses/LICENSE.rst`` file.
This diff is collapsed.
......@@ -6,6 +6,8 @@ Python. It also provides an index for other astronomy packages and tools for
managing them.
from __future__ import absolute_import
# this indicates whether or not we are in astropy's
......@@ -31,7 +33,7 @@ except ImportError:
__githash__ = ''
__minimum_numpy_version__ = '1.5.1'
__minimum_numpy_version__ = '1.6.0'
# The location of the online documentation for astropy
......@@ -174,14 +176,13 @@ def test(package=None, test_path=None, args=None, plugins=None,
open_files : bool, optional
Fail when any tests leave files open. Off by default, because
this adds extra run time to the test suite. Works only on
platforms with a working `lsof` command.
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
is installed.
the cores on the machine. Requires the `pytest-xdist` plugin.
docs_path : str, optional
The path to the documentation .rst files.
......@@ -217,8 +218,10 @@ def _initialize_astropy():
from warnings import warn
# If this file is in ./astropy/ then import is within a source dir
is_astropy_source_dir = (os.path.abspath(os.path.dirname(__file__)) ==
os.path.abspath('astropy') and os.path.exists(''))
source_dir = os.path.abspath(os.path.dirname(__file__))
is_astropy_source_dir = (
os.path.exists(os.path.join(source_dir, os.pardir, '.git')) and
os.path.isfile(os.path.join(source_dir, os.pardir, '')))
def _rollback_import(message):
......@@ -238,11 +241,21 @@ def _initialize_astropy():
from .utils import _compiler
except ImportError:
if is_astropy_source_dir:
'You appear to be trying to import astropy from within a '
'source checkout; please run `./ develop` or '
'`./ build_ext --inplace` first so that extension '
'modules can be compiled and made importable.')
log.warn('You appear to be trying to import astropy from '
'within a source checkout without building the '
'extension modules first. Attempting to (re)build '
'extension modules:')
'An error occurred while attempting to rebuild the '
'extension modules. Please try manually running '
'`./ develop` or `./ build_ext '
'--inplace` to see what the issue was. Extension '
'modules must be successfully compiled and importable '
'in order to import astropy.')
# Outright broken installation; don't be nice.
......@@ -258,6 +271,36 @@ def _initialize_astropy():
def _rebuild_extensions():
import os
import subprocess
import sys
import time
from .utils.console import Spinner
from .extern.six import next
devnull = open(os.devnull, 'w')
old_cwd = os.getcwd()
os.chdir(os.path.join(os.path.dirname(__file__), os.pardir))
sp = subprocess.Popen([sys.executable, '', 'build_ext',
'--inplace'], stdout=devnull,
with Spinner('Rebuilding extension modules') as spinner:
while sp.poll() is None:
if sp.returncode != 0:
raise OSError('Running build_ext --inplace failed '
'with error code {0}: try rerunning this command '
'manually to check what the error was.'.format(
import logging
# Use the root logger as a dummy log before initilizing Astropy's logger
# Licensed under a 3-clause BSD style license - see LICENSE.rst
# The ERFA wrappers are not guaranteed available at setup time
from .core import *
except ImportError:
This diff is collapsed.
This diff is collapsed.
# Licensed under a 3-clause BSD style license - see LICENSE.rst
# "" is auto-generated by from the template
# "". Do *not* edit "" directly, instead edit
# "" and run from the source directory to
# update it.
This module uses Cython to wrap the ERFA library in numpy-vectorized
This is currently *not* part of the public Astropy API, and may change in
the future.
The key idea is that any function can be called with inputs that are arrays,
and the wrappers will automatically vectorize and call the ERFA functions for
each item using broadcasting rules for numpy. So the return values are always
numpy arrays of some sort.
For ERFA functions that take/return vectors or matricies, the vector/matrix
dimension(s) are always the *last* dimension(s). For example, if you
want to give ten matricies (i.e., the ERFA input type is double[3][3]),
you would pass in a (10, 3, 3) numpy array. If the output of the ERFA
function is scalar, you'll get back a length-10 1D array.
Note that the Cython part of these functions are implemented in a separate
module (compiled as ``_core``), derived from the ``core.pyx`` file. Splitting
the wrappers into separate pure-python and Cython portions dramatically reduces
compilation time without notably impacting performance. (See issue [#3063] on the
github repository for more about this.)
from __future__ import absolute_import, division, print_function
import warnings
from distutils.version import LooseVersion
from ..utils.exceptions import AstropyUserWarning
import numpy
from . import _core
NPYLT18 = LooseVersion(numpy.__version__) < LooseVersion('1.8')
# TODO: remove the above variable and the code using it and make_outputs_scalar when numpy < 1.8 is no longer supported
__all__ = ['ErfaError', 'ErfaWarning',
{{ funcs|map(attribute='pyname')|surround("'","'")|join(", ") }},
{{ constants|map(attribute='name')|surround("'","'")|join(", ") }},
'dt_eraASTROM', 'dt_eraLDBODY']
class ErfaError(ValueError):
A class for errors triggered by ERFA functions (status codes < 0)
class ErfaWarning(AstropyUserWarning):
A class for warnings triggered by ERFA functions (status codes > 0)
STATUS_CODES = {} # populated below before each function that returns an int
# This is a hard-coded list of status codes that need to be remapped,
# such as to turn errors into warnings.
'cal2jd': {-3: 3}
def check_errwarn(statcodes, func_name):
# Remap any errors into warnings in the STATUS_CODES_REMAP dict.
if func_name in STATUS_CODES_REMAP:
for before, after in STATUS_CODES_REMAP[func_name].items():
statcodes[statcodes == before] = after
STATUS_CODES[func_name][after] = STATUS_CODES[func_name][before]
if numpy.any(statcodes<0):
# errors present - only report the errors.
if statcodes.shape:
statcodes = statcodes[statcodes<0]
errcodes = numpy.unique(statcodes)
errcounts = dict([(e, numpy.sum(statcodes==e)) for e in errcodes])
elsemsg = STATUS_CODES[func_name].get('else', None)
if elsemsg is None:
errmsgs = dict([(e, STATUS_CODES[func_name].get(e, 'Return code ' + str(e))) for e in errcodes])
errmsgs = dict([(e, STATUS_CODES[func_name].get(e, elsemsg)) for e in errcodes])
emsg = ', '.join(['{0} of "{1}"'.format(errcounts[e], errmsgs[e]) for e in errcodes])
raise ErfaError('ERFA function "' + func_name + '" yielded ' + emsg)
elif numpy.any(statcodes>0):
#only warnings present
if statcodes.shape:
statcodes = statcodes[statcodes>0]
warncodes = numpy.unique(statcodes)
warncounts = dict([(w, numpy.sum(statcodes==w)) for w in warncodes])
elsemsg = STATUS_CODES[func_name].get('else', None)
if elsemsg is None:
warnmsgs = dict([(w, STATUS_CODES[func_name].get(w, 'Return code ' + str(w))) for w in warncodes])
warnmsgs = dict([(w, STATUS_CODES[func_name].get(w, elsemsg)) for w in warncodes])
wmsg = ', '.join(['{0} of "{1}"'.format(warncounts[w], warnmsgs[w]) for w in warncodes])
warnings.warn('ERFA function "' + func_name + '" yielded ' + wmsg, ErfaWarning)
#<-------------------------trailing shape verification------------------------>
def check_trailing_shape(arr, shape, name):
if arr.shape[-len(shape):] != shape:
raise Exception()
raise ValueError("{0} must be of trailing dimensions {1}".format(name, shape))
#<--------------------------Actual ERFA-wrapping code------------------------->
dt_eraASTROM = numpy.dtype([('pmt','d'),
('refb','d')], align=True)
dt_eraLDBODY = numpy.dtype([('bm','d'),
('pv','d',(2,3))], align=True)
{% for constant in constants %}
{{ }} = {{ constant.value }}
"""{{ constant.doc|join(' ') }}"""
{%- endfor %}
{% for func in funcs %}
def {{ func.pyname }}({{ func.args_by_inout('in|inout')|map(attribute='name')|join(', ') }}):
Wrapper for ERFA function ``{{ }}``.
{%- for arg in func.args_by_inout('in|inout') %}
{{ }} : {{ arg.ctype }} array
{%- endfor %}
{%- for arg in func.args_by_inout('inout|out|ret') %}
{{ }} : {{ arg.ctype }} array
{%- endfor %}
The ERFA documentation is below.
{{ func.doc }}
#Turn all inputs into arrays
{%- for arg in func.args_by_inout('in|inout') %}
{{ }}_in = numpy.array({{ }}, dtype={{ arg.dtype }}, order="C", copy=False, subok=True)
{%- endfor %}
{%- for arg in func.args_by_inout('in|inout') %}
{%- if arg.ndim > 0 %}
check_trailing_shape({{ }}_in, {{ arg.shape }}, "{{}}")
{%- endif %}
{%- endfor %}
{%- if func.args_by_inout('in|inout') %}
make_outputs_scalar = False
if NPYLT18:
# in numpy < 1.8, the iterator used below doesn't work with 0d/scalar arrays
# so we replace all scalars with 1d arrays
make_outputs_scalar = True
{%- for arg in func.args_by_inout('in|inout') %}
if {{ arg.name_in_broadcast }}.shape == tuple():