From 3427e106ef5eaf41af67b71d187794950beea404 Mon Sep 17 00:00:00 2001 From: Philipp Rudiger Date: Sun, 3 Feb 2019 12:54:20 +0000 Subject: [PATCH] Ensure all tests pass without pandas, dask, xarray and scipy (#3453) --- holoviews/core/data/__init__.py | 4 ++- holoviews/core/data/dask.py | 2 +- holoviews/core/data/dictionary.py | 5 +++- holoviews/core/util.py | 14 ++++++++-- holoviews/element/raster.py | 2 +- holoviews/operation/element.py | 2 +- holoviews/plotting/bokeh/element.py | 7 +++-- holoviews/plotting/bokeh/stats.py | 2 +- holoviews/plotting/mpl/chart.py | 6 ++-- holoviews/plotting/util.py | 2 +- holoviews/tests/core/data/base.py | 15 +++++----- .../tests/core/data/testdaskinterface.py | 2 -- .../tests/core/data/testgridinterface.py | 12 ++++---- .../tests/core/data/testmultiinterface.py | 2 +- .../tests/core/data/testpandasinterface.py | 2 -- .../tests/core/data/testxarrayinterface.py | 6 ---- holoviews/tests/core/testndmapping.py | 2 +- holoviews/tests/core/testoptions.py | 18 ++++++++---- holoviews/tests/core/teststoreoptions.py | 13 ++++++--- holoviews/tests/core/testutils.py | 28 ++++++++++++++----- holoviews/tests/element/testgraphelement.py | 9 ++++-- holoviews/tests/element/teststatselements.py | 23 ++++++++++----- holoviews/tests/operation/testdatashader.py | 15 +++------- holoviews/tests/operation/testoperation.py | 25 +++++++++++------ .../operation/testtimeseriesoperations.py | 14 +++++++--- .../tests/plotting/bokeh/testcurveplot.py | 12 ++++---- .../tests/plotting/bokeh/testpointplot.py | 2 +- .../tests/plotting/bokeh/testrenderer.py | 2 -- .../tests/plotting/bokeh/testspikesplot.py | 4 +-- holoviews/tests/plotting/bokeh/testutils.py | 2 -- .../tests/plotting/bokeh/testviolinplot.py | 11 +++++++- .../plotting/matplotlib/testcurveplot.py | 14 +++++----- .../tests/plotting/matplotlib/testrenderer.py | 2 -- .../tests/plotting/matplotlib/testwidgets.py | 4 --- holoviews/tests/plotting/plotly/testplot.py | 21 +++++++------- holoviews/tests/plotting/testcomms.py | 2 -- holoviews/tests/plotting/testplotutils.py | 4 +-- holoviews/tests/teststreams.py | 15 ++++++---- 38 files changed, 191 insertions(+), 136 deletions(-) diff --git a/holoviews/core/data/__init__.py b/holoviews/core/data/__init__.py index 7665d2376d..adb7b0d57a 100644 --- a/holoviews/core/data/__init__.py +++ b/holoviews/core/data/__init__.py @@ -428,7 +428,9 @@ def reindex(self, kdims=None, vdims=None): data = self.interface.reindex(self, key_dims, val_dims) datatype = self.datatype if gridded and dropped: - datatype = [dt for dt in datatype if not self.interface.interfaces[dt].gridded] + interfaces = self.interface.interfaces + datatype = [dt for dt in datatype if not + getattr(interfaces.get(dt, None), 'gridded', True)] return self.clone(data, kdims=key_dims, vdims=val_dims, new_type=new_type, datatype=datatype) diff --git a/holoviews/core/data/dask.py b/holoviews/core/data/dask.py index 56519d7236..f1b03d8954 100644 --- a/holoviews/core/data/dask.py +++ b/holoviews/core/data/dask.py @@ -44,7 +44,7 @@ class DaskInterface(PandasInterface): @classmethod def loaded(cls): - return 'dask' in sys.modules + return 'dask' in sys.modules and 'pandas' in sys.modules @classmethod def applies(cls, obj): diff --git a/holoviews/core/data/dictionary.py b/holoviews/core/data/dictionary.py index b797e6c15e..d2ca0fa872 100644 --- a/holoviews/core/data/dictionary.py +++ b/holoviews/core/data/dictionary.py @@ -60,7 +60,10 @@ def init(cls, eltype, data, kdims, vdims): elif isinstance(data, list) and data == []: data = OrderedDict([(d, []) for d in dimensions]) elif isinstance(data, list) and isscalar(data[0]): - data = {dimensions[0]: np.arange(len(data)), dimensions[1]: data} + if eltype._auto_indexable_1d: + data = {dimensions[0]: np.arange(len(data)), dimensions[1]: data} + else: + data = {dimensions[0]: data} elif (isinstance(data, list) and isinstance(data[0], tuple) and len(data[0]) == 2 and any(isinstance(v, tuple) for v in data[0])): dict_data = zip(*((util.wrap_tuple(k)+util.wrap_tuple(v)) diff --git a/holoviews/core/util.py b/holoviews/core/util.py index 754c948470..610b3067db 100644 --- a/holoviews/core/util.py +++ b/holoviews/core/util.py @@ -812,7 +812,7 @@ def isscalar(val): """ Value is scalar or None """ - return val is None or np.isscalar(val) + return val is None or np.isscalar(val) or isinstance(val, datetime_types) def isnumeric(val): @@ -965,7 +965,12 @@ def range_pad(lower, upper, padding=None, log=False): center = (log_min+log_max) / 2.0 start, end = np.power(10, center-lspan/2.), np.power(10, center+uspan/2.) else: - span = (upper-lower) + if isinstance(lower, datetime_types) and not isinstance(lower, cftime_types): + # Ensure timedelta can be safely divided + lower, upper = np.datetime64(lower), np.datetime64(upper) + span = (upper-lower).astype('>m8[ns]') + else: + span = (upper-lower) lpad = span*(padding[0]) upad = span*(padding[1]) start, end = lower-lpad, upper+upad @@ -1391,7 +1396,7 @@ def is_dataframe(data): Checks whether the supplied data is of DataFrame type. """ dd = None - if 'dask' in sys.modules: + if 'dask' in sys.modules and 'pandas' in sys.modules: import dask.dataframe as dd return((pd is not None and isinstance(data, pd.DataFrame)) or (dd is not None and isinstance(data, dd.DataFrame))) @@ -1874,6 +1879,9 @@ def dt_to_int(value, time_unit='us'): elif isinstance(value, cftime_types): return cftime_to_timestamp(value, time_unit) + if isinstance(value, dt.date): + value = dt.datetime(*value.timetuple()[:6]) + # Handle datetime64 separately if isinstance(value, np.datetime64): try: diff --git a/holoviews/element/raster.py b/holoviews/element/raster.py index 3215de444f..9c10b93540 100644 --- a/holoviews/element/raster.py +++ b/holoviews/element/raster.py @@ -518,7 +518,7 @@ def sample(self, samples=[], **kwargs): (coords, type(self).__name__, self.bounds.lbrt())) data = self.interface.ndloc(self, (yidx, xidx)) - return self.clone(data, new_type=Table, datatype=['dataframe', 'dict']) + return self.clone(data, new_type=Table, datatype=['dataframe', 'dictionary']) def closest(self, coords=[], **kwargs): diff --git a/holoviews/operation/element.py b/holoviews/operation/element.py index c052609d7c..0caeb163fe 100644 --- a/holoviews/operation/element.py +++ b/holoviews/operation/element.py @@ -772,7 +772,7 @@ def _process_layer(self, element, key=None): dtype = x.dtype is_datetime = dtype.kind == 'M' or isinstance(x[0], datetime_types) if is_datetime: - dt_type = dtype if dtype.kind == 'M' else 'datetime64[ns]' + dt_type = 'datetime64[ns]' x = x.astype(dt_type).astype('int64') dvals = tuple(element.dimension_values(d) for d in element.dimensions()[1:]) xs, dvals = INTERPOLATE_FUNCS[self.p.interpolation](x.astype('f'), dvals) diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py index 0a1a2e4f9e..9c68deed88 100644 --- a/holoviews/plotting/bokeh/element.py +++ b/holoviews/plotting/bokeh/element.py @@ -217,8 +217,10 @@ def _get_hover_data(self, data, element, dimensions=None): dim = util.dimension_sanitizer(d.name) if dim not in data: data[dim] = element.dimension_values(d) - if isinstance(data[dim], np.ndarray) and data[dim].dtype.kind == 'M': - data[dim+'_dt_strings'] = [d.pprint_value(v) for v in data[dim]] + values = data[dim] + if (values.dtype.kind == 'M' or ( + len(values) and isinstance(values[0], util.datetime_types))): + data[dim+'_dt_strings'] = [d.pprint_value(v) for v in values] for k, v in self.overlay_dims.items(): dim = util.dimension_sanitizer(k.name) @@ -653,6 +655,7 @@ def _update_range(self, axis_range, low, high, factors, invert, shared, log, str elif (low == high and low is not None): if isinstance(low, util.datetime_types): offset = np.timedelta64(500, 'ms') + low, high = np.datetime64(low), np.datetime64(high) low -= offset high += offset else: diff --git a/holoviews/plotting/bokeh/stats.py b/holoviews/plotting/bokeh/stats.py index 967010a5b6..2b9719220a 100644 --- a/holoviews/plotting/bokeh/stats.py +++ b/holoviews/plotting/bokeh/stats.py @@ -106,7 +106,7 @@ def _apply_transforms(self, element, data, ranges, style, group=None): if isinstance(agg, Dimensioned): element = agg else: - element = element.clone([(element,)]) + element = element.clone([(agg,)]) return super(BoxWhiskerPlot, self)._apply_transforms(element, data, ranges, style, group) def _get_factors(self, element): diff --git a/holoviews/plotting/mpl/chart.py b/holoviews/plotting/mpl/chart.py index 09e31a42aa..47399479e5 100644 --- a/holoviews/plotting/mpl/chart.py +++ b/holoviews/plotting/mpl/chart.py @@ -82,7 +82,7 @@ def get_data(self, element, ranges, style): xs = element.dimension_values(0) ys = element.dimension_values(1) dims = element.dimensions() - if xs.dtype.kind == 'M': + if xs.dtype.kind == 'M' or (len(xs) and isinstance(xs[0], datetime_types)): dimtype = element.get_dimension_type(0) dt_format = Dimension.type_formatters.get(dimtype, '%Y-%m-%d %H:%M:%S') dims[0] = dims[0](value_format=DateFormatter(dt_format)) @@ -91,7 +91,7 @@ def get_data(self, element, ranges, style): def init_artists(self, ax, plot_args, plot_kwargs): xs, ys = plot_args - if xs.dtype.kind == 'M': + if xs.dtype.kind == 'M' or (len(xs) and isinstance(xs[0], datetime_types)): artist = ax.plot_date(xs, ys, '-', **plot_kwargs)[0] else: artist = ax.plot(xs, ys, **plot_kwargs)[0] @@ -1189,7 +1189,7 @@ def get_data(self, element, ranges, style): cols = [] for i, vs in enumerate((xs, ys)): vs = np.array(vs) - if vs.dtype.kind == 'M' and i < len(dims): + if (vs.dtype.kind == 'M' or (len(vs) and isinstance(vs[0], datetime_types))) and i < len(dims): dt_format = Dimension.type_formatters[np.datetime64] dims[i] = dims[i](value_format=DateFormatter(dt_format)) vs = np.array([dt_to_int(v, 'D') for v in vs]) diff --git a/holoviews/plotting/util.py b/holoviews/plotting/util.py index 3637d49327..6ef7291b52 100644 --- a/holoviews/plotting/util.py +++ b/holoviews/plotting/util.py @@ -736,7 +736,7 @@ def list_cmaps(provider=None, records=False, name=None, category=None, source=No # cmap_info stores only non-reversed info, so construct # suitable values for reversed version if appropriate r=r._replace(name=aname) - if aname.endswith('_r') and (r.category is not 'Diverging'): + if aname.endswith('_r') and (r.category != 'Diverging'): if r.bg=='light': r=r._replace(bg='dark') elif r.bg=='dark': diff --git a/holoviews/tests/core/data/base.py b/holoviews/tests/core/data/base.py index cb5c7b282b..55aa1c8b32 100644 --- a/holoviews/tests/core/data/base.py +++ b/holoviews/tests/core/data/base.py @@ -3,8 +3,7 @@ """ import datetime -from nose.plugins.attrib import attr -from unittest import SkipTest +from unittest import SkipTest, skipIf import numpy as np @@ -21,6 +20,8 @@ except: pd = None +pd_skip = skipIf(pd is None, "pandas is not available") + class DatatypeContext(object): @@ -384,11 +385,13 @@ def test_dataset_get_array_by_dimension(self): arr = self.dataset_hm.array(['x']) self.assertEqual(arr, self.xs[:, np.newaxis]) + @pd_skip def test_dataset_get_dframe(self): df = self.dataset_hm.dframe() self.assertEqual(df.x.values, self.xs) self.assertEqual(df.y.values, self.y_ints) + @pd_skip def test_dataset_get_dframe_by_dimension(self): df = self.dataset_hm.dframe(['x']) self.assertEqual(df, pd.DataFrame({'x': self.xs}, dtype=df.dtypes[0])) @@ -424,17 +427,15 @@ def init_column_data(self): # Test the constructor to be supported by all interfaces supporting # heterogeneous column types. + @pd_skip def test_dataset_dataframe_init_ht(self): "Tests support for heterogeneous DataFrames" - if pd is None: - raise SkipTest("Pandas not available") dataset = Dataset(pd.DataFrame({'x':self.xs, 'y':self.ys}), kdims=['x'], vdims=['y']) self.assertTrue(isinstance(dataset.data, self.data_type)) + @pd_skip def test_dataset_dataframe_init_ht_alias(self): "Tests support for heterogeneous DataFrames" - if pd is None: - raise SkipTest("Pandas not available") dataset = Dataset(pd.DataFrame({'x':self.xs, 'y':self.ys}), kdims=[('x', 'X')], vdims=[('y', 'Y')]) self.assertTrue(isinstance(dataset.data, self.data_type)) @@ -496,7 +497,7 @@ def test_dataset_range_with_dimension_range(self): # Operations - @attr(optional=1) # Uses pandas + @pd_skip def test_dataset_redim_with_alias_dframe(self): test_df = pd.DataFrame({'x': range(10), 'y': range(0,20,2)}) dataset = Dataset(test_df, kdims=[('x', 'X-label')], vdims=['y']) diff --git a/holoviews/tests/core/data/testdaskinterface.py b/holoviews/tests/core/data/testdaskinterface.py index 119a4fa667..dbfcf8542f 100644 --- a/holoviews/tests/core/data/testdaskinterface.py +++ b/holoviews/tests/core/data/testdaskinterface.py @@ -1,4 +1,3 @@ -from nose.plugins.attrib import attr from unittest import SkipTest import numpy as np @@ -14,7 +13,6 @@ from .testpandasinterface import PandasInterfaceTests -@attr(optional=1) class DaskDatasetTest(PandasInterfaceTests): """ Test of the pandas DaskDataset interface. diff --git a/holoviews/tests/core/data/testgridinterface.py b/holoviews/tests/core/data/testgridinterface.py index d8ec785ef6..867b09dce2 100644 --- a/holoviews/tests/core/data/testgridinterface.py +++ b/holoviews/tests/core/data/testgridinterface.py @@ -2,7 +2,7 @@ from collections import OrderedDict from itertools import product -from unittest import SkipTest +from unittest import SkipTest, skipIf import numpy as np from holoviews.core.data import Dataset @@ -14,6 +14,9 @@ except ImportError: da = None +pd_skip = skipIf(pd is None, "pandas is not available") + + from .base import ( GriddedInterfaceTests, InterfaceTests, HomogeneousColumnTests, DatatypeContext ) @@ -28,20 +31,18 @@ class GridInterfaceTests(GriddedInterfaceTests, HomogeneousColumnTests, Interfac data_type = (OrderedDict, dict) element = Dataset + @pd_skip def test_dataset_dataframe_init_hm(self): "Tests support for homogeneous DataFrames" - if pd is None: - raise SkipTest("Pandas not available") exception = "None of the available storage backends "\ "were able to support the supplied data format." with self.assertRaisesRegexp(Exception, exception): Dataset(pd.DataFrame({'x':self.xs, 'x2':self.xs_2}), kdims=['x'], vdims=['x2']) + @pd_skip def test_dataset_dataframe_init_hm_alias(self): "Tests support for homogeneous DataFrames" - if pd is None: - raise SkipTest("Pandas not available") exception = "None of the available storage backends "\ "were able to support the supplied data format." with self.assertRaisesRegexp(Exception, exception): @@ -432,6 +433,7 @@ def test_dataset_groupby_drop_dims_dynamic_with_vdim(self): partial = ds.to(Dataset, kdims=['Val'], vdims=['Val2'], groupby='y', dynamic=True) self.assertEqual(partial[19]['Val'], array[:, -1, :].T.flatten().compute()) + @pd_skip def test_dataset_get_dframe(self): df = self.dataset_hm.dframe() self.assertEqual(df.x.values, self.xs) diff --git a/holoviews/tests/core/data/testmultiinterface.py b/holoviews/tests/core/data/testmultiinterface.py index e3722a0a03..7516b545c3 100644 --- a/holoviews/tests/core/data/testmultiinterface.py +++ b/holoviews/tests/core/data/testmultiinterface.py @@ -129,7 +129,7 @@ def test_multi_array_redim(self): arrays = [np.column_stack([np.arange(i, i+2), np.arange(i, i+2)]) for i in range(2)] mds = Path(arrays, kdims=['x', 'y'], datatype=['multitabular']).redim(x='x2') for i, ds in enumerate(mds.split()): - self.assertEqual(ds, Path(arrays[i], kdims=['x2', 'y'], datatype=['dask'])) + self.assertEqual(ds, Path(arrays[i], kdims=['x2', 'y'])) def test_multi_mixed_interface_raises(self): arrays = [np.random.rand(10, 2) if j else {'x': range(10), 'y': range(10)} diff --git a/holoviews/tests/core/data/testpandasinterface.py b/holoviews/tests/core/data/testpandasinterface.py index 97c98b51c6..d18edf187d 100644 --- a/holoviews/tests/core/data/testpandasinterface.py +++ b/holoviews/tests/core/data/testpandasinterface.py @@ -1,4 +1,3 @@ -from nose.plugins.attrib import attr from unittest import SkipTest import numpy as np @@ -18,7 +17,6 @@ from .base import HeterogeneousColumnTests, InterfaceTests -@attr(optional=1) class PandasInterfaceTests(HeterogeneousColumnTests, InterfaceTests): """ Test for the PandasInterface. diff --git a/holoviews/tests/core/data/testxarrayinterface.py b/holoviews/tests/core/data/testxarrayinterface.py index 569ab86d60..9162422026 100644 --- a/holoviews/tests/core/data/testxarrayinterface.py +++ b/holoviews/tests/core/data/testxarrayinterface.py @@ -1,6 +1,5 @@ import datetime as dt from collections import OrderedDict -from nose.plugins.attrib import attr from unittest import SkipTest import numpy as np @@ -21,7 +20,6 @@ from .testgridinterface import GridInterfaceTests -@attr(optional=1) class XArrayInterfaceTests(GridInterfaceTests): """ Tests for xarray interface @@ -233,7 +231,6 @@ def test_dataset_sample_hm_alias(self): -@attr(optional=1) class DaskXArrayInterfaceTest(XArrayInterfaceTests): """ Tests for XArray interface wrapping dask arrays @@ -290,7 +287,6 @@ def test_xarray_dataset_with_scalar_dim_canonicalize(self): -@attr(optional=1) class Image_XArrayInterfaceTests(Image_ImageInterfaceTests): datatype = 'xarray' @@ -358,7 +354,6 @@ def test_dataarray_with_some_coords(self): Image(xrarr, kdims=['x', 'y']) -@attr(optional=1) class RGB_XArrayInterfaceTests(RGB_ImageInterfaceTests): datatype = 'xarray' @@ -369,7 +364,6 @@ def init_data(self): self.rgb_array[:, :, 1], self.rgb_array[:, :, 2])) -@attr(optional=1) class HSV_XArrayInterfaceTest(HSV_ImageInterfaceTests): datatype = 'xarray' diff --git a/holoviews/tests/core/testndmapping.py b/holoviews/tests/core/testndmapping.py index 69e4f15ad6..182fa3a74a 100644 --- a/holoviews/tests/core/testndmapping.py +++ b/holoviews/tests/core/testndmapping.py @@ -132,7 +132,7 @@ def test_idxmapping_unsorted_clone(self): def test_idxmapping_groupby_unsorted(self): data = [(('B', 2), 1), (('C', 2), 2), (('A', 1), 3)] - grouped = MultiDimensionalMapping(data, sort=False, kdims=['X', 'Y']).groupby('Y') + grouped = NdMapping(data, sort=False, kdims=['X', 'Y']).groupby('Y') self.assertEquals(grouped.keys(), [1, 2]) self.assertEquals(grouped.values()[0].keys(), ['A']) self.assertEquals(grouped.last.keys(), ['B', 'C']) diff --git a/holoviews/tests/core/testoptions.py b/holoviews/tests/core/testoptions.py index 29ef22ccd5..e4fb4b9773 100644 --- a/holoviews/tests/core/testoptions.py +++ b/holoviews/tests/core/testoptions.py @@ -1,5 +1,7 @@ import os import pickle +from unittest import SkipTest + import numpy as np from holoviews import Store, Histogram, Image, Curve, DynamicMap, opts from holoviews.core.options import ( @@ -7,8 +9,6 @@ ) from holoviews.element.comparison import ComparisonTestCase from holoviews import plotting # noqa Register backends -from unittest import SkipTest -from nose.plugins.attrib import attr Options.skip_invalid = False @@ -195,6 +195,8 @@ def test_options_property_disabled(self): class TestOptionTree(ComparisonTestCase): def setUp(self): + if 'matplotlib' not in Store.renderers: + raise SkipTest('Matplotlib backend not available.') Options._option_groups = ['group1', 'group2'] super(TestOptionTree, self).setUp() @@ -272,13 +274,14 @@ def test_optiontree_inheritance_flipped(self): {'kw2':'value2', 'kw4':'value4'}) -@attr(optional=1) # Requires matplotlib class TestStoreInheritanceDynamic(ComparisonTestCase): """ Tests to prevent regression after fix in PR #646 """ def setUp(self): + if 'matplotlib' not in Store.renderers: + raise SkipTest('Matplotlib backend not available.') self.store_copy = OptionTree(sorted(Store.options().items()), groups=['style', 'plot', 'norm']) self.backend = 'matplotlib' @@ -466,7 +469,6 @@ def test_custom_magic_to_default_inheritance(self): self.assertEqual(custom_obj_lookup.kwargs, expected_custom_obj) -@attr(optional=1) # Requires matplotlib class TestStoreInheritance(ComparisonTestCase): """ Tests to prevent regression after fix in 71c1f3a that resolves @@ -474,6 +476,8 @@ class TestStoreInheritance(ComparisonTestCase): """ def setUp(self): + if 'matplotlib' not in Store.renderers: + raise SkipTest('Matplotlib backend not available.') self.store_copy = OptionTree(sorted(Store.options().items()), groups=['style', 'plot', 'norm']) self.backend = 'matplotlib' @@ -559,6 +563,8 @@ def test_style_transfer(self): class TestOptionsMethod(ComparisonTestCase): def setUp(self): + if 'matplotlib' not in Store.renderers: + raise SkipTest('Matplotlib backend not available.') self.store_copy = OptionTree(sorted(Store.options().items()), groups=['style', 'plot', 'norm']) self.backend = 'matplotlib' @@ -610,6 +616,8 @@ def test_plot_options_object_list(self): class TestOptsMethod(ComparisonTestCase): def setUp(self): + if 'matplotlib' not in Store.renderers: + raise SkipTest('Matplotlib backend not available.') self.store_copy = OptionTree(sorted(Store.options().items()), groups=['style', 'plot', 'norm']) self.backend = 'matplotlib' @@ -720,7 +728,7 @@ def test_opts_clear_clone(self): self.assertEqual(not any(k in ['option1', 'option2'] for k in cleared_options.keys()), True) -@attr(optional=1) # Needs matplotlib + class TestOptionTreeFind(ComparisonTestCase): def setUp(self): diff --git a/holoviews/tests/core/teststoreoptions.py b/holoviews/tests/core/teststoreoptions.py index 022b9f6cc5..e508a06c24 100644 --- a/holoviews/tests/core/teststoreoptions.py +++ b/holoviews/tests/core/teststoreoptions.py @@ -2,13 +2,19 @@ Unit tests of the StoreOptions class used to control custom options on Store as used by the %opts magic. """ + +from unittest import SkipTest + import numpy as np + +try: + from holoviews.plotting import mpl # noqa Register backend +except: + raise SkipTest('Matplotlib backend not available.') + from holoviews import Overlay, Curve, Image, HoloMap from holoviews.core.options import Store, StoreOptions from holoviews.element.comparison import ComparisonTestCase -from holoviews import plotting # noqa Register backends -from holoviews.plotting import mpl # noqa Register backends -from nose.plugins.attrib import attr class TestStoreOptionsMerge(ComparisonTestCase): @@ -37,7 +43,6 @@ def test_partitioned_format(self): self.assertEqual(out, self.expected) -@attr(optional=1) # Requires matplotlib class TestStoreOptsMethod(ComparisonTestCase): """ The .opts method makes use of most of the functionality in diff --git a/holoviews/tests/core/testutils.py b/holoviews/tests/core/testutils.py index b1e2b37995..cc1c21971e 100644 --- a/holoviews/tests/core/testutils.py +++ b/holoviews/tests/core/testutils.py @@ -5,7 +5,7 @@ import sys, math import unittest import datetime -from unittest import SkipTest +from unittest import SkipTest, skipIf from itertools import product from collections import OrderedDict @@ -29,6 +29,8 @@ sanitize_identifier = sanitize_identifier_fn.instance() +pd_skip = skipIf(pd is None, "pandas is not available") + class TestDeepHash(ComparisonTestCase): """ @@ -74,23 +76,23 @@ def test_deephash_numpy_inequality(self): arr2 = np.array([1,2,4]) self.assertNotEqual(deephash(arr1), deephash(arr2)) + @pd_skip def test_deephash_dataframe_equality(self): - if pd is None: raise SkipTest self.assertEqual(deephash(pd.DataFrame({'a':[1,2,3],'b':[4,5,6]})), deephash(pd.DataFrame({'a':[1,2,3],'b':[4,5,6]}))) + @pd_skip def test_deephash_dataframe_inequality(self): - if pd is None: raise SkipTest self.assertNotEqual(deephash(pd.DataFrame({'a':[1,2,3],'b':[4,5,6]})), deephash(pd.DataFrame({'a':[1,2,3],'b':[4,5,8]}))) + @pd_skip def test_deephash_series_equality(self): - if pd is None: raise SkipTest self.assertEqual(deephash(pd.Series([1,2,3])), deephash(pd.Series([1,2,3]))) + @pd_skip def test_deephash_series_inequality(self): - if pd is None: raise SkipTest self.assertNotEqual(deephash(pd.Series([1,2,3])), deephash(pd.Series([1,2,7]))) @@ -114,8 +116,8 @@ def test_deephash_nested_native_inequality(self): obj2 = [[1,2], (3,6,7, [True]), 'a', 9.2, 42, {1:3,2:'c'}] self.assertNotEqual(deephash(obj1), deephash(obj2)) + @pd_skip def test_deephash_nested_mixed_equality(self): - if pd is None: raise SkipTest obj1 = [datetime.datetime(1,2,3), set([1,2,3]), pd.DataFrame({'a':[1,2],'b':[3,4]}), np.array([1,2,3]), {'a':'b', '1':True}, @@ -126,8 +128,8 @@ def test_deephash_nested_mixed_equality(self): OrderedDict([(1,'a'),(2,'b')]), np.int64(34)] self.assertEqual(deephash(obj1), deephash(obj2)) + @pd_skip def test_deephash_nested_mixed_inequality(self): - if pd is None: raise SkipTest obj1 = [datetime.datetime(1,2,3), set([1,2,3]), pd.DataFrame({'a':[1,2],'b':[3,4]}), np.array([1,2,3]), {'a':'b', '2':True}, @@ -618,6 +620,7 @@ def test_datetime64_s_to_us_int(self): dt = np.datetime64(datetime.datetime(2017, 1, 1), 's') self.assertEqual(dt_to_int(dt), 1483228800000000.0) + @pd_skip def test_timestamp_to_us_int(self): dt = pd.Timestamp(datetime.datetime(2017, 1, 1)) self.assertEqual(dt_to_int(dt), 1483228800000000.0) @@ -638,6 +641,7 @@ def test_datetime64_s_to_s_int(self): dt = np.datetime64(datetime.datetime(2017, 1, 1), 's') self.assertEqual(dt_to_int(dt, 's'), 1483228800.0) + @pd_skip def test_timestamp_to_s_int(self): dt = pd.Timestamp(datetime.datetime(2017, 1, 1)) self.assertEqual(dt_to_int(dt, 's'), 1483228800.0) @@ -695,45 +699,55 @@ def test_isfinite_timedelta64_nat(self): dt64 = np.timedelta64('NaT') self.assertFalse(isfinite(dt64)) + @pd_skip def test_isfinite_pandas_timestamp_nat(self): dt64 = pd.Timestamp('NaT') self.assertFalse(isfinite(dt64)) + @pd_skip def test_isfinite_pandas_period_nat(self): dt64 = pd.Period('NaT') self.assertFalse(isfinite(dt64)) + @pd_skip def test_isfinite_pandas_period_index(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D').to_period('D') self.assertEqual(isfinite(daily), np.array([True, True, True])) + @pd_skip def test_isfinite_pandas_period_series(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D').to_period('D').to_series() self.assertEqual(isfinite(daily), np.array([True, True, True])) + @pd_skip def test_isfinite_pandas_period_index_nat(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D').to_period('D') daily = pd.PeriodIndex(list(daily)+[pd.NaT]) self.assertEqual(isfinite(daily), np.array([True, True, True, False])) + @pd_skip def test_isfinite_pandas_period_series_nat(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D').to_period('D') daily = pd.Series(list(daily)+[pd.NaT]) self.assertEqual(isfinite(daily), np.array([True, True, True, False])) + @pd_skip def test_isfinite_pandas_timestamp_index(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D') self.assertEqual(isfinite(daily), np.array([True, True, True])) + @pd_skip def test_isfinite_pandas_timestamp_series(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D').to_series() self.assertEqual(isfinite(daily), np.array([True, True, True])) + @pd_skip def test_isfinite_pandas_timestamp_index_nat(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D') daily = pd.DatetimeIndex(list(daily)+[pd.NaT]) self.assertEqual(isfinite(daily), np.array([True, True, True, False])) + @pd_skip def test_isfinite_pandas_timestamp_series_nat(self): daily = pd.date_range('2017-1-1', '2017-1-3', freq='D') daily = pd.Series(list(daily)+[pd.NaT]) diff --git a/holoviews/tests/element/testgraphelement.py b/holoviews/tests/element/testgraphelement.py index cffa8952e1..a0b48ed896 100644 --- a/holoviews/tests/element/testgraphelement.py +++ b/holoviews/tests/element/testgraphelement.py @@ -1,9 +1,10 @@ """ Unit tests of Graph Element. """ -from unittest import SkipTest +from unittest import SkipTest, skipIf import numpy as np + from holoviews.core.data import Dataset from holoviews.core import util from holoviews.element.chart import Points @@ -12,6 +13,7 @@ connect_edges_pd) from holoviews.element.comparison import ComparisonTestCase +pd_skip = skipIf(util.pd is None, 'Pandas not available') class GraphTests(ComparisonTestCase): @@ -59,12 +61,14 @@ def test_graph_node_info_merge_on_index(self): self.assertEqual(graph.nodes.dimension_values(3), node_info.dimension_values(1)) + @pd_skip def test_graph_node_info_merge_on_index_partial(self): node_info = Dataset((np.arange(5), np.arange(1,6)), 'index', 'label') graph = Graph(((self.source, self.target), node_info)) expected = np.array([1., 2., 3., 4., 5., np.NaN, np.NaN, np.NaN]) self.assertEqual(graph.nodes.dimension_values(3), expected) + @pd_skip def test_graph_edge_segments_pd(self): segments = connect_edges_pd(self.graph) paths = [] @@ -264,9 +268,8 @@ def test_trimesh_constructor_tuple_nodes(self): self.assertEqual(trimesh.nodes.array([0, 1]), np.array(nodes).T) self.assertEqual(trimesh.nodes.dimension_values(2), np.arange(4)) + @pd_skip def test_trimesh_constructor_df_nodes(self): - if util.pd is None: - raise SkipTest('Test requires pandas') nodes_df = util.pd.DataFrame(self.nodes, columns=['x', 'y', 'z']) trimesh = TriMesh((self.simplices, nodes_df)) nodes = Nodes([(0, 0, 0, 0), (0.5, 1, 1, 1), diff --git a/holoviews/tests/element/teststatselements.py b/holoviews/tests/element/teststatselements.py index c122268779..8c54de468f 100644 --- a/holoviews/tests/element/teststatselements.py +++ b/holoviews/tests/element/teststatselements.py @@ -1,7 +1,8 @@ -from unittest import SkipTest +from unittest import SkipTest, skipIf import numpy as np import holoviews as hv + from holoviews.core.dimension import Dimension from holoviews.core.options import Compositor, Store from holoviews.core.util import pd @@ -9,6 +10,8 @@ Curve, Area, Contours, Polygons) from holoviews.element.comparison import ComparisonTestCase +pd_skip = skipIf(pd is None, 'Pandas not available') + class StatisticalElementTest(ComparisonTestCase): @@ -17,16 +20,14 @@ def test_distribution_array_constructor(self): self.assertEqual(dist.kdims, [Dimension('Value')]) self.assertEqual(dist.vdims, [Dimension('Density')]) + @pd_skip def test_distribution_dframe_constructor(self): - if pd is None: - raise SkipTest("Test requires pandas, skipping.") dist = Distribution(pd.DataFrame({'Value': [0, 1, 2]})) self.assertEqual(dist.kdims, [Dimension('Value')]) self.assertEqual(dist.vdims, [Dimension('Density')]) + @pd_skip def test_distribution_series_constructor(self): - if pd is None: - raise SkipTest("Test requires pandas") dist = Distribution(pd.Series([0, 1, 2], name='Value')) self.assertEqual(dist.kdims, [Dimension('Value')]) self.assertEqual(dist.vdims, [Dimension('Density')]) @@ -46,9 +47,8 @@ def test_bivariate_array_constructor(self): self.assertEqual(dist.kdims, [Dimension('x'), Dimension('y')]) self.assertEqual(dist.vdims, [Dimension('Density')]) + @pd_skip def test_bivariate_dframe_constructor(self): - if pd is None: - raise SkipTest("Test requires pandas, skipping.") dist = Bivariate(pd.DataFrame({'x': [0, 1, 2], 'y': [0, 1, 2]}, columns=['x', 'y'])) self.assertEqual(dist.kdims, [Dimension('x'), Dimension('y')]) self.assertEqual(dist.vdims, [Dimension('Density')]) @@ -115,8 +115,17 @@ def test_bivariate_from_points(self): class StatisticalCompositorTest(ComparisonTestCase): def setUp(self): + try: + import scipy # noqa + except: + raise SkipTest('SciPy not available') + try: + import matplotlib # noqa + except: + raise SkipTest('SciPy not available') self.renderer = hv.renderer('matplotlib') np.random.seed(42) + super(StatisticalCompositorTest, self).setUp() def test_distribution_composite(self): dist = Distribution(np.array([0, 1, 2])) diff --git a/holoviews/tests/operation/testdatashader.py b/holoviews/tests/operation/testdatashader.py index 1a872b9f28..8ef9ae97ab 100644 --- a/holoviews/tests/operation/testdatashader.py +++ b/holoviews/tests/operation/testdatashader.py @@ -1,5 +1,4 @@ from unittest import SkipTest -from nose.plugins.attrib import attr import numpy as np from holoviews import (Dimension, Curve, Points, Image, Dataset, RGB, Path, @@ -14,10 +13,9 @@ shade, rasterize ) except: - ds_version = None + raise SkipTest('Datashader not available') -@attr(optional=1) class DatashaderAggregateTests(ComparisonTestCase): """ Tests for datashader aggregation @@ -177,7 +175,6 @@ def test_aggregate_dframe_nan_path(self): self.assertEqual(img, expected) -@attr(optional=1) class DatashaderShadeTests(ComparisonTestCase): def test_shade_categorical_images_xarray(self): @@ -212,14 +209,13 @@ def test_shade_categorical_images_grid(self): -@attr(optional=1) class DatashaderRegridTests(ComparisonTestCase): """ Tests for datashader aggregation """ def setUp(self): - if ds_version is None or ds_version <= '0.5.0': + if ds_version <= '0.5.0': raise SkipTest('Regridding operations require datashader>=0.6.0') def test_regrid_mean(self): @@ -293,14 +289,13 @@ def test_regrid_zero_range(self): -@attr(optional=1) class DatashaderRasterizeTests(ComparisonTestCase): """ Tests for datashader aggregation """ def setUp(self): - if ds_version is None or ds_version <= '0.6.4': + if ds_version <= '0.6.4': raise SkipTest('Regridding operations require datashader>=0.7.0') def test_rasterize_trimesh_no_vdims(self): @@ -445,7 +440,6 @@ def test_rasterize_image_string_aggregator(self): -@attr(optional=1) class DatashaderStackTests(ComparisonTestCase): def setUp(self): @@ -482,11 +476,10 @@ def test_stack_saturate_compositor_reverse(self): self.assertEqual(combined, self.rgb2) -@attr(optional=1) class GraphBundlingTests(ComparisonTestCase): def setUp(self): - if ds_version is None or ds_version <= '0.7.0': + if ds_version <= '0.7.0': raise SkipTest('Regridding operations require datashader>=0.7.0') self.source = np.arange(8) self.target = np.zeros(8) diff --git a/holoviews/tests/operation/testoperation.py b/holoviews/tests/operation/testoperation.py index e76770f5e2..4d479d2e04 100644 --- a/holoviews/tests/operation/testoperation.py +++ b/holoviews/tests/operation/testoperation.py @@ -1,7 +1,12 @@ import datetime as dt +from unittest import skipIf import numpy as np -from nose.plugins.attrib import attr + +try: + import matplotlib as mpl +except: + mpl = None from holoviews import (HoloMap, NdOverlay, NdLayout, GridSpace, Image, Contours, Polygons, Points, Histogram, Curve, Area, @@ -13,6 +18,10 @@ gradient, contours, histogram, interpolate_curve) +pd_skip = skipIf(pd is None, "Pandas not available") +mpl_skip = skipIf(mpl is None, "Matplotlib is available") + + class OperationTests(ComparisonTestCase): """ Tests allowable data formats when constructing @@ -58,7 +67,7 @@ def test_image_gradient(self): op_img = gradient(img) self.assertEqual(op_img, img.clone(np.array([[3.162278, 3.162278], [3.162278, 3.162278]]), group='Gradient')) - @attr(optional=1) # Requires matplotlib + @mpl_skip def test_image_contours(self): img = Image(np.array([[0, 1, 0], [3, 4, 5.], [6, 7, 8]])) op_contours = contours(img, levels=[0.5]) @@ -68,14 +77,14 @@ def test_image_contours(self): vdims=img.vdims) self.assertEqual(op_contours, contour) - @attr(optional=1) # Requires matplotlib + @mpl_skip def test_image_contours_no_range(self): img = Image(np.zeros((2, 2))) op_contours = contours(img, levels=2) contour = Contours([], vdims=img.vdims) self.assertEqual(op_contours, contour) - @attr(optional=1) # Requires matplotlib + @mpl_skip def test_qmesh_contours(self): qmesh = QuadMesh(([0, 1, 2], [1, 2, 3], np.array([[0, 1, 0], [3, 4, 5.], [6, 7, 8]]))) op_contours = contours(qmesh, levels=[0.5]) @@ -85,7 +94,7 @@ def test_qmesh_contours(self): vdims=qmesh.vdims) self.assertEqual(op_contours, contour) - @attr(optional=1) # Requires matplotlib + @mpl_skip def test_qmesh_curvilinear_contours(self): x = y = np.arange(3) xs, ys = np.meshgrid(x, y) @@ -98,7 +107,7 @@ def test_qmesh_curvilinear_contours(self): vdims=qmesh.vdims) self.assertEqual(op_contours, contour) - @attr(optional=1) # Requires matplotlib + @mpl_skip def test_qmesh_curvilinear_edges_contours(self): x = y = np.arange(3) xs, ys = np.meshgrid(x, y) @@ -115,7 +124,7 @@ def test_qmesh_curvilinear_edges_contours(self): vdims=qmesh.vdims) self.assertEqual(op_contours, contour) - @attr(optional=1) # Requires matplotlib + @mpl_skip def test_image_contours_filled(self): img = Image(np.array([[0, 1, 0], [3, 4, 5.], [6, 7, 8]])) op_contours = contours(img, filled=True, levels=[2, 2.5]) @@ -195,7 +204,7 @@ def test_histogram_operation_datetime64(self): hist = Histogram(hist_data, kdims='Date', vdims=('Date_frequency', 'Frequency')) self.assertEqual(op_hist, hist) - @attr(optional=1) # Requires matplotlib + @pd_skip def test_histogram_operation_pd_period(self): dates = pd.date_range('2017-01-01', '2017-01-04', freq='D').to_period('D') op_hist = histogram(Dataset(dates, 'Date'), num_bins=4) diff --git a/holoviews/tests/operation/testtimeseriesoperations.py b/holoviews/tests/operation/testtimeseriesoperations.py index b816319376..faa1a6fb04 100644 --- a/holoviews/tests/operation/testtimeseriesoperations.py +++ b/holoviews/tests/operation/testtimeseriesoperations.py @@ -1,10 +1,16 @@ -from unittest import SkipTest -from nose.plugins.attrib import attr +from unittest import SkipTest, skipIf + try: import pandas as pd except: raise SkipTest('Pandas not available') +try: + import scipy # noqa +except: + scipy = None +scipy_skip = skipIf(scipy is None, "SciPy is not available.") + import numpy as np from holoviews import Curve, Scatter @@ -37,13 +43,13 @@ def test_roll_ints(self): rolled_vals = [np.NaN, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5] self.assertEqual(rolled, Curve(rolled_vals)) - @attr(optional=1) # Requires scipy + @scipy_skip def test_roll_date_with_window_type(self): rolled = rolling(self.date_curve, rolling_window=3, window_type='triang') rolled_vals = [np.NaN, 2, 3, 4, 5, 6, np.NaN] self.assertEqual(rolled, Curve((self.dates, rolled_vals))) - @attr(optional=1) # Requires scipy + @scipy_skip def test_roll_ints_with_window_type(self): rolled = rolling(self.int_curve, rolling_window=3, window_type='triang') rolled_vals = [np.NaN, 2, 3, 4, 5, 6, np.NaN] diff --git a/holoviews/tests/plotting/bokeh/testcurveplot.py b/holoviews/tests/plotting/bokeh/testcurveplot.py index 962c53423d..b9ed795c67 100644 --- a/holoviews/tests/plotting/bokeh/testcurveplot.py +++ b/holoviews/tests/plotting/bokeh/testcurveplot.py @@ -1,5 +1,5 @@ import datetime as dt -from unittest import SkipTest +from unittest import skipIf import numpy as np @@ -18,6 +18,8 @@ except: pass +pd_skip = skipIf(pd is None, 'Pandas not available') + class TestCurvePlot(TestBokehPlot): @@ -90,7 +92,7 @@ def test_batched_curve_line_width_and_color(self): self.assertEqual(plot.handles['source'].data['color'], color) def test_curve_overlay_datetime_hover(self): - obj = NdOverlay({i: Curve((list(pd.date_range('2016-01-01', '2016-01-31')), range(31))) for i in range(5)}, + obj = NdOverlay({i: Curve([(dt.datetime(2016, 1, j+1), j) for j in range(31)]) for i in range(5)}, kdims=['Test']) opts = {'Curve': {'tools': ['hover']}} obj = obj(plot=opts) @@ -132,9 +134,8 @@ def test_curve_datetime64(self): self.assertEqual(plot.handles['x_range'].start, np.datetime64(dt.datetime(2016, 1, 1))) self.assertEqual(plot.handles['x_range'].end, np.datetime64(dt.datetime(2016, 1, 10))) + @pd_skip def test_curve_pandas_timestamps(self): - if not pd: - raise SkipTest("Pandas not available") dates = pd.date_range('2016-01-01', '2016-01-10', freq='D') curve = Curve((dates, np.random.rand(10))) plot = bokeh_renderer.get_plot(curve) @@ -157,9 +158,8 @@ def test_curve_heterogeneous_datetime_types_overlay(self): self.assertEqual(plot.handles['x_range'].start, np.datetime64(dt.datetime(2016, 1, 1))) self.assertEqual(plot.handles['x_range'].end, np.datetime64(dt.datetime(2016, 1, 11))) + @pd_skip def test_curve_heterogeneous_datetime_types_with_pd_overlay(self): - if not pd: - raise SkipTest("Pandas not available") dates_pd = pd.date_range('2016-01-04', '2016-01-13', freq='D') dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)] dates = [dt.datetime(2016,1,i) for i in range(2, 12)] diff --git a/holoviews/tests/plotting/bokeh/testpointplot.py b/holoviews/tests/plotting/bokeh/testpointplot.py index d3c7245ffc..b5a21710dd 100644 --- a/holoviews/tests/plotting/bokeh/testpointplot.py +++ b/holoviews/tests/plotting/bokeh/testpointplot.py @@ -317,7 +317,7 @@ def test_points_datetime_hover(self): points = Points([(0, 1, dt.datetime(2017, 1, 1))], vdims='date').options(tools=['hover']) plot = bokeh_renderer.get_plot(points) cds = plot.handles['cds'] - self.assertEqual(cds.data['date'], np.array([1483228800000000000])) + self.assertEqual(cds.data['date'].astype('datetime64'), np.array([1483228800000000000])) self.assertEqual(cds.data['date_dt_strings'], ['2017-01-01 00:00:00']) hover = plot.handles['hover'] self.assertEqual(hover.tooltips, [('x', '@{x}'), ('y', '@{y}'), ('date', '@{date_dt_strings}')]) diff --git a/holoviews/tests/plotting/bokeh/testrenderer.py b/holoviews/tests/plotting/bokeh/testrenderer.py index 2061a000d0..37fe9893c5 100644 --- a/holoviews/tests/plotting/bokeh/testrenderer.py +++ b/holoviews/tests/plotting/bokeh/testrenderer.py @@ -2,7 +2,6 @@ from io import BytesIO from unittest import SkipTest -from nose.plugins.attrib import attr import numpy as np @@ -18,7 +17,6 @@ pass -@attr(optional=1) class BokehRendererTest(ComparisonTestCase): def setUp(self): diff --git a/holoviews/tests/plotting/bokeh/testspikesplot.py b/holoviews/tests/plotting/bokeh/testspikesplot.py index b1ebb6b475..084142efb4 100644 --- a/holoviews/tests/plotting/bokeh/testspikesplot.py +++ b/holoviews/tests/plotting/bokeh/testspikesplot.py @@ -117,7 +117,7 @@ def test_spikes_datetime_vdim_hover(self): points = Spikes([(0, 1, dt.datetime(2017, 1, 1))], vdims=['value', 'date']).options(tools=['hover']) plot = bokeh_renderer.get_plot(points) cds = plot.handles['cds'] - self.assertEqual(cds.data['date'], np.array([1483228800000000000])) + self.assertEqual(cds.data['date'].astype('datetime64'), np.array([1483228800000000000])) self.assertEqual(cds.data['date_dt_strings'], ['2017-01-01 00:00:00']) hover = plot.handles['hover'] self.assertEqual(hover.tooltips, [('x', '@{x}'), ('value', '@{value}'), ('date', '@{date_dt_strings}')]) @@ -126,7 +126,7 @@ def test_spikes_datetime_kdim_hover(self): points = Spikes([(dt.datetime(2017, 1, 1), 1)], 'x', 'y').options(tools=['hover']) plot = bokeh_renderer.get_plot(points) cds = plot.handles['cds'] - self.assertEqual(cds.data['x'], np.array([1483228800000000000])) + self.assertEqual(cds.data['x'].astype('datetime64'), np.array([1483228800000000000])) self.assertEqual(cds.data['x_dt_strings'], ['2017-01-01 00:00:00']) hover = plot.handles['hover'] self.assertEqual(hover.tooltips, [('x', '@{x_dt_strings}'), ('y', '@{y}')]) diff --git a/holoviews/tests/plotting/bokeh/testutils.py b/holoviews/tests/plotting/bokeh/testutils.py index b288ef3ce4..b420ad5a57 100644 --- a/holoviews/tests/plotting/bokeh/testutils.py +++ b/holoviews/tests/plotting/bokeh/testutils.py @@ -1,5 +1,4 @@ from unittest import SkipTest -from nose.plugins.attrib import attr from holoviews.core import Store from holoviews.element.comparison import ComparisonTestCase @@ -10,7 +9,6 @@ except: bokeh_renderer = None -@attr(optional=1) class TestBokehUtilsInstantiation(ComparisonTestCase): def setUp(self): diff --git a/holoviews/tests/plotting/bokeh/testviolinplot.py b/holoviews/tests/plotting/bokeh/testviolinplot.py index a2a1b8d55b..749b2912ad 100644 --- a/holoviews/tests/plotting/bokeh/testviolinplot.py +++ b/holoviews/tests/plotting/bokeh/testviolinplot.py @@ -1,5 +1,7 @@ from __future__ import absolute_import +from unittest import SkipTest + import numpy as np from holoviews.element import Violin @@ -15,6 +17,13 @@ class TestBokehViolinPlot(TestBokehPlot): + def setUp(self): + try: + import scipy # noqa + except: + raise SkipTest('Violin plot requires SciPy to compute kde') + super(TestBokehViolinPlot, self).setUp() + def test_violin_simple(self): values = np.random.rand(100) violin = Violin(values).opts(plot=dict(violin_width=0.7)) @@ -47,7 +56,7 @@ def test_violin_simple(self): self.assertEqual(patch_source.data['xs'], [kde['y']]) self.assertEqual(patch_source.data['ys'], [kde['x']]) - def test_box_whisker_multi_level(self): + def test_violin_multi_level(self): box= Violin((['A', 'B']*15, [3, 10, 1]*10, np.random.randn(30)), ['Group', 'Category'], 'Value') plot = bokeh_renderer.get_plot(box) diff --git a/holoviews/tests/plotting/matplotlib/testcurveplot.py b/holoviews/tests/plotting/matplotlib/testcurveplot.py index 918c8851fb..4a57a8c6fd 100644 --- a/holoviews/tests/plotting/matplotlib/testcurveplot.py +++ b/holoviews/tests/plotting/matplotlib/testcurveplot.py @@ -1,5 +1,5 @@ import datetime as dt -from unittest import SkipTest +from unittest import skipIf import numpy as np @@ -9,6 +9,8 @@ from .testplot import TestMPLPlot, mpl_renderer +pd_skip = skipIf(pd is None, 'Pandas is not available') + class TestCurvePlot(TestMPLPlot): @@ -18,9 +20,8 @@ def test_curve_datetime64(self): plot = mpl_renderer.get_plot(curve) self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735973.0)) + @pd_skip def test_curve_pandas_timestamps(self): - if not pd: - raise SkipTest("Pandas not available") dates = pd.date_range('2016-01-01', '2016-01-10', freq='D') curve = Curve((dates, np.random.rand(10))) plot = mpl_renderer.get_plot(curve) @@ -30,7 +31,7 @@ def test_curve_dt_datetime(self): dates = [dt.datetime(2016,1,i) for i in range(1, 11)] curve = Curve((dates, np.random.rand(10))) plot = mpl_renderer.get_plot(curve) - self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735973.0)) + self.assertEqual(tuple(map(round, plot.handles['axis'].get_xlim())), (735964.0, 735973.0)) def test_curve_heterogeneous_datetime_types_overlay(self): dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)] @@ -38,11 +39,10 @@ def test_curve_heterogeneous_datetime_types_overlay(self): curve_dt64 = Curve((dates64, np.random.rand(10))) curve_dt = Curve((dates, np.random.rand(10))) plot = mpl_renderer.get_plot(curve_dt*curve_dt64) - self.assertEqual(plot.handles['axis'].get_xlim(), (735964.0, 735974.0)) + self.assertEqual(tuple(map(round, plot.handles['axis'].get_xlim())), (735964.0, 735974.0)) + @pd_skip def test_curve_heterogeneous_datetime_types_with_pd_overlay(self): - if not pd: - raise SkipTest("Pandas not available") dates_pd = pd.date_range('2016-01-04', '2016-01-13', freq='D') dates64 = [np.datetime64(dt.datetime(2016,1,i)) for i in range(1, 11)] dates = [dt.datetime(2016,1,i) for i in range(2, 12)] diff --git a/holoviews/tests/plotting/matplotlib/testrenderer.py b/holoviews/tests/plotting/matplotlib/testrenderer.py index 56e8093bc6..78a304bccf 100644 --- a/holoviews/tests/plotting/matplotlib/testrenderer.py +++ b/holoviews/tests/plotting/matplotlib/testrenderer.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals from unittest import SkipTest -from nose.plugins.attrib import attr import numpy as np @@ -18,7 +17,6 @@ pass -@attr(optional=1) class MPLRendererTest(ComparisonTestCase): """ Note if not possible to compare the hashes of SVG and WebM formats diff --git a/holoviews/tests/plotting/matplotlib/testwidgets.py b/holoviews/tests/plotting/matplotlib/testwidgets.py index 4f91ed8a0e..4df7dc7af3 100644 --- a/holoviews/tests/plotting/matplotlib/testwidgets.py +++ b/holoviews/tests/plotting/matplotlib/testwidgets.py @@ -1,6 +1,5 @@ import json import datetime as dt -from nose.plugins.attrib import attr import numpy as np @@ -12,7 +11,6 @@ class TestSelectionWidget(TestMPLPlot): - @attr(optional=1) # Requires jinja2 def test_dynamic_nonoverlap(self): kdims = [Dimension('File', range=(0.01, 1)), Dimension('SliceDimension', range=(0.01, 1)), @@ -22,7 +20,6 @@ def test_dynamic_nonoverlap(self): kdims=kdims[:1]) mpl_renderer.get_widget(dmap1 + dmap2, 'selection') - @attr(optional=1) # Requires jinja2 def test_dynamic_values_partial_overlap(self): kdims = [Dimension('File', range=(0.01, 1)), Dimension('SliceDimension', values=['x', 'y', 'z']), @@ -32,7 +29,6 @@ def test_dynamic_values_partial_overlap(self): kdims=kdims[:1]) mpl_renderer.get_widget(dmap1 + dmap2, 'selection') - @attr(optional=1) # Requires jinja2 def test_holomap_datetime_widgets(self): hmap = HoloMap({np.datetime64(dt.datetime(2017, 1, i)): Curve([i]) for i in range(1, 3)}) widgets = mpl_renderer.get_widget(hmap, 'widgets') diff --git a/holoviews/tests/plotting/plotly/testplot.py b/holoviews/tests/plotting/plotly/testplot.py index 58e5067eb6..ad94d2af4f 100644 --- a/holoviews/tests/plotting/plotly/testplot.py +++ b/holoviews/tests/plotting/plotly/testplot.py @@ -1,5 +1,4 @@ from unittest import SkipTest -from nose.plugins.attrib import attr from holoviews.core import Store from holoviews.element.comparison import ComparisonTestCase @@ -16,14 +15,6 @@ from .. import option_intersections -class TestPlotDefinitions(ComparisonTestCase): - - known_clashes = [] - - def test_plotly_option_definitions(self): - # Check option definitions do not introduce new clashes - self.assertEqual(option_intersections('plotly'), self.known_clashes) - class TestPlotlyPlot(ComparisonTestCase): @@ -49,8 +40,16 @@ def _get_plot_state(self, element): return plot.state -@attr(optional=1) -class TestPlotlyFigureGrid(ComparisonTestCase): +class TestPlotDefinitions(TestPlotlyPlot): + + known_clashes = [] + + def test_plotly_option_definitions(self): + # Check option definitions do not introduce new clashes + self.assertEqual(option_intersections('plotly'), self.known_clashes) + + +class TestPlotlyFigureGrid(TestPlotlyPlot): def test_figure_grid_solo_traces(self): diff --git a/holoviews/tests/plotting/testcomms.py b/holoviews/tests/plotting/testcomms.py index dd7fa05d03..d001d570d4 100644 --- a/holoviews/tests/plotting/testcomms.py +++ b/holoviews/tests/plotting/testcomms.py @@ -1,4 +1,3 @@ -from nose.plugins.attrib import attr from holoviews.element.comparison import ComparisonTestCase from pyviz_comms import Comm, JupyterComm @@ -42,7 +41,6 @@ def assert_ready(msg=None, metadata=None): comm._handle_msg({'comm_id': 'Testing id'}) -@attr(optional=1) class TestJupyterComm(ComparisonTestCase): def test_init_comm(self): diff --git a/holoviews/tests/plotting/testplotutils.py b/holoviews/tests/plotting/testplotutils.py index 50dfbf508d..9d8054b533 100644 --- a/holoviews/tests/plotting/testplotutils.py +++ b/holoviews/tests/plotting/testplotutils.py @@ -1,7 +1,6 @@ from __future__ import absolute_import, unicode_literals from unittest import SkipTest -from nose.plugins.attrib import attr import numpy as np @@ -590,7 +589,7 @@ def test_get_min_distance_float32_type(self): np.arange(0, 2., .2, dtype='float32')) X, Y = np.meshgrid(xs, ys) dist = get_min_distance(Points((X.flatten(), Y.flatten()))) - self.assertEqual(round(dist, 5), 0.2) + self.assertEqual(float(round(dist, 5)), 0.2) def test_get_min_distance_int32_type(self): xs, ys = (np.arange(0, 10, dtype='int32'), @@ -647,7 +646,6 @@ def test_get_range_from_ranges(self): -@attr(optional=1) # Flexx is optional class TestBokehUtils(ComparisonTestCase): def setUp(self): diff --git a/holoviews/tests/teststreams.py b/holoviews/tests/teststreams.py index d9568c069a..6bd35bcfb3 100644 --- a/holoviews/tests/teststreams.py +++ b/holoviews/tests/teststreams.py @@ -611,9 +611,7 @@ def test_pipe_update(self): -class TestBufferStream(ComparisonTestCase): - - # Arrays +class TestBufferArrayStream(ComparisonTestCase): def test_init_buffer_array(self): arr = np.array([[0, 1]]) @@ -658,7 +656,8 @@ def test_buffer_array_send_verify_type_fail(self): with self.assertRaisesRegexp(TypeError, error): buff.send([1]) - # Dictionaries + +class TestBufferDictionaryStream(ComparisonTestCase): def test_init_buffer_dict(self): data = {'x': np.array([1]), 'y': np.array([2])} @@ -699,7 +698,13 @@ def test_buffer_dict_send_verify_shape_fail(self): with self.assertRaisesRegexp(ValueError, error): buff.send({'x': np.array([2]), 'y': np.array([3, 4])}) - # DataFrames + +class TestBufferDataFrameStream(ComparisonTestCase): + + def setUp(self): + if pd is None: + raise SkipTest('Pandas not available') + super(TestBufferDataFrameStream, self).setUp() def test_init_buffer_dframe(self): data = pd.DataFrame({'x': np.array([1]), 'y': np.array([2])})