Skip to content

Commit

Permalink
Merge pull request astropy#11903 from nstarman/dependency-pyyaml
Browse files Browse the repository at this point in the history
make PyYaml a runtime dependency
  • Loading branch information
mhvk authored Jun 30, 2021
2 parents d4f3216 + 4fcf758 commit 4654cde
Show file tree
Hide file tree
Showing 24 changed files with 51 additions and 285 deletions.
20 changes: 1 addition & 19 deletions astropy/coordinates/tests/test_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from astropy.table import Table

from astropy.tests.helper import assert_quantity_allclose
from astropy.utils.compat.optional_deps import HAS_SCIPY, HAS_YAML # noqa
from astropy.utils.compat.optional_deps import HAS_SCIPY # noqa
from astropy.units import allclose as quantity_allclose


Expand Down Expand Up @@ -519,7 +519,6 @@ def test_gcrs_itrs_cartesian_repr():
gcrs.transform_to(ITRS())


@pytest.mark.skipif('not HAS_YAML')
def test_regression_6446():
# this succeeds even before 6446:
sc1 = SkyCoord([1, 2], [3, 4], unit='deg')
Expand All @@ -538,23 +537,6 @@ def test_regression_6446():
assert sio1.getvalue() == sio2.getvalue()


def test_regression_6448():
"""
This tests the more narrow problem reported in 6446 that 6448 is meant to
fix. `test_regression_6446` also covers this, but this test is provided
so that this is still tested even if YAML isn't installed.
"""
sc1 = SkyCoord([1, 2], [3, 4], unit='deg')
# this should always succeed even prior to 6448
assert sc1.galcen_v_sun is None

c1 = SkyCoord(1, 3, unit='deg')
c2 = SkyCoord(2, 4, unit='deg')
sc2 = SkyCoord([c1, c2])
# without 6448 this fails
assert sc2.galcen_v_sun is None


def test_regression_6597():
frame_name = 'galactic'
c1 = SkyCoord(1, 3, unit='deg', frame=frame_name)
Expand Down
3 changes: 0 additions & 3 deletions astropy/coordinates/tests/test_spectral_coordinate.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,9 +840,6 @@ def test_spectral_coord_from_sky_coord_without_distance():
@pytest.mark.parametrize('specsys', list(EXPECTED_VELOCITY_FRAMES))
def test_spectralcoord_accuracy(specsys):

# PyYAML is needed to read in the ecsv table
pytest.importorskip('yaml')

# This is a test to check the numerical results of transformations between
# different velocity frames in SpectralCoord. This compares the velocity
# shifts determined with SpectralCoord to those determined from the rv
Expand Down
11 changes: 1 addition & 10 deletions astropy/io/ascii/ecsv.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
from . import core, basic
from astropy.table import meta, serialize
from astropy.utils.data_info import serialize_context_as
from astropy.utils.exceptions import AstropyUserWarning, AstropyWarning
from astropy.utils.exceptions import AstropyUserWarning
from astropy.io.ascii.core import convert_numpy

__doctest_requires__ = {'Ecsv': ['yaml']}

ECSV_VERSION = '1.0'
DELIMITERS = (' ', ',')
ECSV_DATATYPES = (
Expand Down Expand Up @@ -135,13 +133,6 @@ def get_cols(self, lines):

try:
header = meta.get_header_from_yaml(lines)
except ImportError as exc:
if 'PyYAML package is required' in str(exc):
warnings.warn("file looks like ECSV format but PyYAML is not installed "
"so it cannot be parsed as ECSV",
AstropyWarning)
raise core.InconsistentTableError('unable to parse yaml in meta header'
' (PyYAML package is required)')
except meta.YamlParseError:
raise core.InconsistentTableError('unable to parse yaml in meta header')

Expand Down
3 changes: 1 addition & 2 deletions astropy/io/ascii/tests/test_connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from astropy.table.table_helpers import simple_table
from astropy.utils.data import get_pkg_data_filename
from astropy.utils.compat.optional_deps import HAS_BS4, HAS_YAML # noqa
from astropy.utils.compat.optional_deps import HAS_BS4 # noqa

import numpy as np

Expand Down Expand Up @@ -136,7 +136,6 @@ def test_write_csv(tmpdir):
t.write(path)


@pytest.mark.skipif('not HAS_YAML')
def test_auto_identify_ecsv(tmpdir):
tbl = simple_table()
tmpfile = str(tmpdir.join('/tmpFile.ecsv'))
Expand Down
32 changes: 2 additions & 30 deletions astropy/io/ascii/tests/test_ecsv.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
"""
This module tests some of the methods related to the ``ECSV``
reader/writer.
Requires `pyyaml <https://pyyaml.org/>`_ to be installed.
"""
from astropy.table.column import MaskedColumn
import os
Expand All @@ -15,6 +13,7 @@

import pytest
import numpy as np
import yaml

from astropy.table import Table, Column, QTable, NdarrayMixin
from astropy.table.table_helpers import simple_table
Expand All @@ -25,17 +24,14 @@
from astropy.units import allclose as quantity_allclose
from astropy.units import QuantityInfo

from astropy.utils.exceptions import AstropyUserWarning, AstropyWarning
from astropy.utils.exceptions import AstropyUserWarning

from astropy.io.ascii.ecsv import DELIMITERS
from astropy.io import ascii
from astropy import units as u
from astropy.utils.compat.optional_deps import HAS_YAML # noqa

from .common import TEST_DIR

pytestmark = pytest.mark.skipif(not HAS_YAML, reason='YAML required')

DTYPES = ['bool', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32',
'uint64', 'float16', 'float32', 'float64', 'float128',
'str']
Expand Down Expand Up @@ -370,7 +366,6 @@ def assert_objects_equal(obj1, obj2, attrs, compare_class=True):
}


@pytest.mark.skipif('not HAS_YAML')
def test_ecsv_mixins_ascii_read_class():
"""Ensure that ascii.read(ecsv_file) returns the correct class
(QTable if any Quantity subclasses, Table otherwise).
Expand All @@ -392,7 +387,6 @@ def test_ecsv_mixins_ascii_read_class():
assert type(t2) is QTable


@pytest.mark.skipif('not HAS_YAML')
def test_ecsv_mixins_qtable_to_table():
"""Test writing as QTable and reading as Table. Ensure correct classes
come out.
Expand Down Expand Up @@ -423,7 +417,6 @@ def test_ecsv_mixins_qtable_to_table():
assert_objects_equal(col, col2, attrs, compare_class)


@pytest.mark.skipif('not HAS_YAML')
@pytest.mark.parametrize('table_cls', (Table, QTable))
def test_ecsv_mixins_as_one(table_cls):
"""Test write/read all cols at once and validate intermediate column names"""
Expand Down Expand Up @@ -493,7 +486,6 @@ def make_multidim(col, ndim):
return col


@pytest.mark.skipif('not HAS_YAML')
@pytest.mark.parametrize('name_col', list(mixin_cols.items()))
@pytest.mark.parametrize('table_cls', (Table, QTable))
@pytest.mark.parametrize('ndim', (1, 2, 3))
Expand Down Expand Up @@ -524,23 +516,6 @@ def test_ecsv_mixins_per_column(table_cls, name_col, ndim):
assert t2[name]._time.jd2.__class__ is np.ndarray


def test_ecsv_but_no_yaml_warning(monkeypatch):
"""
Test that trying to read an ECSV without PyYAML installed when guessing
emits a warning, but reading with guess=False gives an exception.
"""
monkeypatch.setitem(sys.modules, 'yaml', None)

with pytest.warns(AstropyWarning, match=r'file looks like ECSV format but '
'PyYAML is not installed') as w:
ascii.read(SIMPLE_LINES)
assert len(w) == 1

with pytest.raises(ascii.InconsistentTableError, match='unable to parse yaml'), \
pytest.warns(AstropyWarning, match=r'PyYAML is not installed'):
ascii.read(SIMPLE_LINES, format='ecsv')


def test_round_trip_masked_table_default(tmpdir):
"""Test (mostly) round-trip of MaskedColumn through ECSV using default serialization
that uses an empty string "" to mark NULL values. Note:
Expand Down Expand Up @@ -574,7 +549,6 @@ def test_round_trip_masked_table_default(tmpdir):
assert not np.all(t2[name] == t[name]) # Expected diff


@pytest.mark.skipif('not HAS_YAML')
def test_round_trip_masked_table_serialize_mask(tmpdir):
"""Same as prev but set the serialize_method to 'data_mask' so mask is written out"""
filename = str(tmpdir.join('test.ecsv'))
Expand All @@ -601,7 +575,6 @@ def test_round_trip_masked_table_serialize_mask(tmpdir):
assert np.all(t2[name] == t[name])


@pytest.mark.skipif('not HAS_YAML')
@pytest.mark.parametrize('table_cls', (Table, QTable))
def test_ecsv_round_trip_user_defined_unit(table_cls, tmpdir):
"""Ensure that we can read-back enabled user-defined units."""
Expand Down Expand Up @@ -822,7 +795,6 @@ def test_full_repr_roundtrip():

# First here is some helper code used to make the expected outputs code.
def _get_ecsv_header_dict(text):
import yaml
lines = [line.strip() for line in text.splitlines()]
lines = [line[2:] for line in lines if line.startswith('#')]
lines = lines[2:] # Get rid of the header
Expand Down
2 changes: 1 addition & 1 deletion astropy/io/ascii/tests/test_write.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ def test_roundtrip_masked(fmt_name_class):
fast = fmt_name in ascii.core.FAST_CLASSES
try:
ascii.write(t, out, format=fmt_name, fast_writer=fast)
except ImportError: # Some failed dependency, e.g. PyYAML, skip test
except ImportError: # Some failed dependency, skip test
return

# No-header formats need to be told the column names
Expand Down
42 changes: 2 additions & 40 deletions astropy/io/fits/connect.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@
from astropy.io import registry as io_registry
from astropy import units as u
from astropy.table import Table, serialize, meta, Column, MaskedColumn
from astropy.table.table import has_info_class
from astropy.time import Time
from astropy.utils.data_info import MixinInfo, serialize_context_as
from astropy.utils.data_info import serialize_context_as
from astropy.utils.exceptions import (AstropyUserWarning,
AstropyDeprecationWarning)
from . import HDUList, TableHDU, BinTableHDU, GroupsHDU, append as fits_append
Expand Down Expand Up @@ -92,20 +91,7 @@ def _decode_mixins(tbl):
if not tbl.meta['comments']:
del tbl.meta['comments']

try:
info = meta.get_header_from_yaml(lines)
except ImportError as exc:
if 'PyYAML package is required' in str(exc):
warnings.warn(
"the file contains information about Astropy native objects "
"(mixin columns) that have been serialized when writing it, "
"but the PyYAML package is required to read those. Without "
"this package some information will be missing in the table",
AstropyUserWarning
)
return tbl
else:
raise
info = meta.get_header_from_yaml(lines)

# Add serialized column information to table meta for use in constructing mixins
tbl.meta['__serialized_columns__'] = info['meta']['__serialized_columns__']
Expand Down Expand Up @@ -324,30 +310,6 @@ def _encode_mixins(tbl):
for attr in ('description', 'meta'))
for col in tbl.itercols())

# If PyYAML is not available then check to see if there are any mixin cols
# that *require* YAML serialization. FITS already has support for Time,
# Quantity, so if those are the only mixins the proceed without doing the
# YAML bit, for backward compatibility (i.e. not requiring YAML to write
# Time or Quantity). In this case other mixin column meta (e.g.
# description or meta) will be silently dropped, consistent with astropy <=
# 2.0 behavior.
try:
import yaml # noqa
except ImportError:
for col in tbl.itercols():
if (has_info_class(col, MixinInfo) and
col.__class__ not in (u.Quantity, Time)):
raise TypeError("cannot write type {} column '{}' "
"to FITS without PyYAML installed."
.format(col.__class__.__name__, col.info.name))
else:
if info_lost:
warnings.warn("table contains column(s) with defined 'format',"
" 'description', or 'meta' info attributes. These"
" will be dropped unless you install PyYAML.",
AstropyUserWarning)
return tbl

# Convert the table to one with no mixins, only Column objects. This adds
# meta data which is extracted with meta.get_yaml_from_table. This ignores
# Time-subclass columns and leave them in the table so that the downstream
Expand Down
7 changes: 3 additions & 4 deletions astropy/io/fits/convenience.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,10 +551,9 @@ def table_to_hdu(table, character_as_bytes=False):
"though one has to enable the unit before reading.")
else:
warning += (
"and cannot be recovered in reading. If pyyaml is "
"installed, it can roundtrip within astropy by "
"using QTable both to write and read back, "
"though one has to enable the unit before reading.")
"and cannot be recovered in reading. It can roundtrip "
"within astropy by using QTable both to write and read "
"back, though one has to enable the unit before reading.")
warnings.warn(warning, AstropyUserWarning)

else:
Expand Down
Loading

0 comments on commit 4654cde

Please sign in to comment.