diff --git a/.travis.yml b/.travis.yml index c42ff764417..43d8069d763 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ # Based on https://github.com/Jorge-C/ordination/blob/master/.travis.yml language: python python: + - "2.6" - "2.7" - "3.3" notifications: @@ -28,11 +29,15 @@ matrix: env: UPDATE_PYENV='pip install pydap' - python: "2.7" env: UPDATE_PYENV='' + - python: "2.6" + env: UPDATE_PYENV='' # Install packages install: - conda create --yes -n test_env python=$TRAVIS_PYTHON_VERSION pip nose mock numpy pandas scipy netCDF4 - source activate test_env + # install unittest2 ONLY if running 2.6 + - if [ ${TRAVIS_PYTHON_VERSION:0:3} == "2.6" ]; then pip install unittest2; fi - echo $UPDATE_PYENV; $UPDATE_PYENV - python setup.py install # Run test diff --git a/setup.py b/setup.py index 3c86702bd19..abdadd53762 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ 'Intended Audience :: Science/Research', 'Programming Language :: Python', 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', @@ -37,6 +38,8 @@ INSTALL_REQUIRES = ['numpy >= 1.7', 'pandas >= 0.13.1'] TESTS_REQUIRE = ['nose >= 1.0'] +if sys.version_info[:2] < (2, 7): + TESTS_REQUIRE += ["unittest2 == 0.5.1"] DESCRIPTION = "Extended arrays for working with scientific datasets in Python" LONG_DESCRIPTION = """ diff --git a/test/__init__.py b/test/__init__.py index 2ea6479d20c..ddc295b5009 100644 --- a/test/__init__.py +++ b/test/__init__.py @@ -1,5 +1,3 @@ -import unittest - import numpy as np from numpy.testing import assert_array_equal @@ -7,6 +5,11 @@ from xray.variable import as_variable from xray.pycompat import PY3 +try: + import unittest2 as unittest +except ImportError: + import unittest + try: import scipy has_scipy = True diff --git a/test/test_backends.py b/test/test_backends.py index efbf811c0be..d72d137f008 100644 --- a/test/test_backends.py +++ b/test/test_backends.py @@ -239,8 +239,8 @@ def test_open_encodings(self): actual = open_dataset(tmp_file) self.assertVariableEqual(actual['time'], expected['time']) - actual_encoding = {k: v for k, v in iteritems(actual['time'].encoding) - if k in expected['time'].encoding} + actual_encoding = dict((k, v) for k, v in iteritems(actual['time'].encoding) + if k in expected['time'].encoding) self.assertDictEqual(actual_encoding, expected['time'].encoding) def test_open_group(self): diff --git a/test/test_data_array.py b/test/test_data_array.py index d05483fb1cf..55ea3cde625 100644 --- a/test/test_data_array.py +++ b/test/test_data_array.py @@ -2,10 +2,9 @@ import pandas as pd from copy import deepcopy from textwrap import dedent -from collections import OrderedDict from xray import Dataset, DataArray, Index, Variable, align -from xray.pycompat import iteritems +from xray.pycompat import iteritems, OrderedDict from . import TestCase, ReturnItem, source_ndarray diff --git a/test/test_dataset.py b/test/test_dataset.py index 9f669134705..15c6104bee5 100644 --- a/test/test_dataset.py +++ b/test/test_dataset.py @@ -1,4 +1,3 @@ -from collections import OrderedDict from copy import copy, deepcopy from textwrap import dedent try: @@ -11,7 +10,7 @@ from xray import (Dataset, DataArray, Index, Variable, backends, utils, align, indexing) -from xray.pycompat import iteritems +from xray.pycompat import iteritems, OrderedDict from . import TestCase @@ -164,7 +163,7 @@ def test_indexes_properties(self): self.assertEquals(2, len(data.indexes)) - self.assertEquals({'x', 'y'}, set(data.indexes)) + self.assertEquals(set(['x', 'y']), set(data.indexes)) self.assertVariableIdentical(data.indexes['x'], data['x'].variable) self.assertVariableIdentical(data.indexes['y'], data['y'].variable) @@ -367,11 +366,11 @@ def test_drop_vars(self): self.assertEqual(data, data.drop_vars()) - expected = Dataset({k: data[k] for k in data if k != 'time'}) + expected = Dataset(dict((k, data[k]) for k in data if k != 'time')) actual = data.drop_vars('time') self.assertEqual(expected, actual) - expected = Dataset({k: data[k] for k in ['dim2', 'dim3', 'time']}) + expected = Dataset(dict((k, data[k]) for k in ['dim2', 'dim3', 'time'])) actual = data.drop_vars('dim1') self.assertEqual(expected, actual) @@ -510,20 +509,20 @@ def test_setitem(self): def test_delitem(self): data = create_test_data() - all_items = {'time', 'dim1', 'dim2', 'dim3', 'var1', 'var2', 'var3'} + all_items = set(['time', 'dim1', 'dim2', 'dim3', 'var1', 'var2', 'var3']) self.assertItemsEqual(data, all_items) del data['var1'] - self.assertItemsEqual(data, all_items - {'var1'}) + self.assertItemsEqual(data, all_items - set(['var1'])) del data['dim1'] - self.assertItemsEqual(data, {'time', 'dim2', 'dim3'}) + self.assertItemsEqual(data, set(['time', 'dim2', 'dim3'])) def test_squeeze(self): data = Dataset({'foo': (['x', 'y', 'z'], [[[1], [2]]])}) for args in [[], [['x']], [['x', 'z']]]: def get_args(v): return [set(args[0]) & set(v.dimensions)] if args else [] - expected = Dataset({k: v.squeeze(*get_args(v)) - for k, v in iteritems(data.variables)}) + expected = Dataset(dict((k, v.squeeze(*get_args(v))) + for k, v in iteritems(data.variables))) self.assertDatasetIdentical(expected, data.squeeze(*args)) # invalid squeeze with self.assertRaisesRegexp(ValueError, 'cannot select a dimension'): @@ -595,8 +594,8 @@ def test_concat(self): def rectify_dim_order(dataset): # return a new dataset with all variable dimensions tranposed into # the order in which they are found in `data` - return Dataset({k: v.transpose(*data[k].dimensions) - for k, v in iteritems(dataset.variables)}, + return Dataset(dict((k, v.transpose(*data[k].dimensions)) + for k, v in iteritems(dataset.variables)), dataset.attrs) for dim in ['dim1', 'dim2', 'dim3']: diff --git a/test/test_utils.py b/test/test_utils.py index f70775bca3f..7d385fce966 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -1,8 +1,8 @@ -from collections import OrderedDict import numpy as np import pandas as pd from xray import utils +from xray.pycompat import OrderedDict from . import TestCase diff --git a/test/test_variable.py b/test/test_variable.py index 520e890b016..c10b7f571cb 100644 --- a/test/test_variable.py +++ b/test/test_variable.py @@ -1,4 +1,4 @@ -from collections import namedtuple, OrderedDict +from collections import namedtuple from copy import copy, deepcopy from datetime import datetime from textwrap import dedent @@ -9,7 +9,7 @@ from xray import Variable, Dataset, DataArray, indexing from xray.variable import (Index, as_variable, NumpyArrayAdapter, PandasIndexAdapter, _as_compatible_data) -from xray.pycompat import PY3 +from xray.pycompat import PY3, OrderedDict from . import TestCase, source_ndarray diff --git a/xray/backends/memory.py b/xray/backends/memory.py index 1a180b21c6a..00cc21e5159 100644 --- a/xray/backends/memory.py +++ b/xray/backends/memory.py @@ -1,4 +1,4 @@ -from collections import OrderedDict +from xray.pycompat import OrderedDict from .common import AbstractWritableDataStore diff --git a/xray/backends/netCDF4_.py b/xray/backends/netCDF4_.py index 1a39e310d1e..0421a33cd28 100644 --- a/xray/backends/netCDF4_.py +++ b/xray/backends/netCDF4_.py @@ -1,4 +1,3 @@ -from collections import OrderedDict import warnings import numpy as np @@ -9,7 +8,7 @@ from xray.conventions import encode_cf_variable from xray.utils import FrozenOrderedDict, NDArrayMixin from xray import indexing -from xray.pycompat import iteritems, basestring, bytes_type +from xray.pycompat import iteritems, basestring, bytes_type, OrderedDict class NetCDF4ArrayWrapper(NDArrayMixin): diff --git a/xray/backends/scipy_.py b/xray/backends/scipy_.py index 0162fc93f9b..ed63217fc36 100644 --- a/xray/backends/scipy_.py +++ b/xray/backends/scipy_.py @@ -1,4 +1,3 @@ -from collections import OrderedDict try: # Python 2 from cStringIO import StringIO as BytesIO except ImportError: # Python 3 @@ -9,7 +8,7 @@ import xray from xray.backends.common import AbstractWritableDataStore from xray.utils import Frozen -from xray.pycompat import iteritems, basestring, unicode_type +from xray.pycompat import iteritems, basestring, unicode_type, OrderedDict from .. import conventions from .netcdf3 import is_valid_nc3_name, coerce_nc3_dtype, encode_nc3_variable diff --git a/xray/conventions.py b/xray/conventions.py index b36025d4466..1e1a78d2f07 100644 --- a/xray/conventions.py +++ b/xray/conventions.py @@ -1,16 +1,16 @@ import numpy as np import pandas as pd import warnings -from collections import defaultdict, OrderedDict +from collections import defaultdict from datetime import datetime from . import indexing from . import utils -from .pycompat import iteritems, bytes_type, unicode_type +from .pycompat import iteritems, bytes_type, unicode_type, OrderedDict import xray # standard calendars recognized by netcdftime -_STANDARD_CALENDARS = {'standard', 'gregorian', 'proleptic_gregorian'} +_STANDARD_CALENDARS = set(['standard', 'gregorian', 'proleptic_gregorian']) def mask_and_scale(array, fill_value=None, scale_factor=None, add_offset=None, diff --git a/xray/data_array.py b/xray/data_array.py index cf1b7da83d5..2d2cc760dc1 100644 --- a/xray/data_array.py +++ b/xray/data_array.py @@ -1,7 +1,7 @@ import functools import operator import warnings -from collections import defaultdict, OrderedDict +from collections import defaultdict import numpy as np import pandas as pd @@ -14,7 +14,7 @@ from . import variable from .common import AbstractArray, AbstractIndexes from .utils import multi_index_from_product -from .pycompat import iteritems, basestring +from .pycompat import iteritems, basestring, OrderedDict def _is_dict_like(value): @@ -639,8 +639,8 @@ def reduce(self, func, dimension=None, axis=None, keep_attrs=False, # For now, take an aggressive strategy of removing all variables # associated with any dropped dimensions # TODO: save some summary (mean? bounds?) of dropped variables - drop |= {k for k, v in iteritems(self.dataset.variables) - if any(dim in drop for dim in v.dimensions)} + drop |= set(k for k, v in iteritems(self.dataset.variables) + if any(dim in drop for dim in v.dimensions)) ds = self.dataset.drop_vars(*drop) ds[self.name] = var @@ -702,7 +702,9 @@ def concat(cls, arrays, dimension='concat_dimension', indexers=None, datasets.append(arr.dataset) if concat_over is None: concat_over = set() - concat_over = set(concat_over) | {name} + elif isinstance(concat_over, basestring): + concat_over = set([concat_over]) + concat_over = set(concat_over) | set([name]) ds = xray.Dataset.concat(datasets, dimension, indexers, concat_over=concat_over) return ds[name] @@ -897,7 +899,7 @@ def align(*objects, **kwargs): # Exclude dimensions with all equal indices to avoid unnecessary reindexing # work. - joined_indexes = {k: join_indices(v) for k, v in iteritems(all_indexes) - if any(not v[0].equals(idx) for idx in v[1:])} + joined_indexes = dict((k, join_indices(v)) for k, v in iteritems(all_indexes) + if any(not v[0].equals(idx) for idx in v[1:])) return tuple(obj.reindex(copy=copy, **joined_indexes) for obj in objects) diff --git a/xray/dataset.py b/xray/dataset.py index e6f96308ac3..cbb4832f5b4 100644 --- a/xray/dataset.py +++ b/xray/dataset.py @@ -5,7 +5,7 @@ from cStringIO import StringIO as BytesIO except ImportError: # Python 3 from io import BytesIO -from collections import OrderedDict, Mapping +from collections import Mapping from . import backends from . import conventions @@ -18,7 +18,7 @@ from . import ops from .utils import (FrozenOrderedDict, Frozen, SortedKeysDict, ChainMap, multi_index_from_product) -from .pycompat import iteritems, itervalues, basestring +from .pycompat import iteritems, itervalues, basestring, OrderedDict def open_dataset(nc, decode_cf=True, mask_and_scale=True, decode_times=True, @@ -623,13 +623,12 @@ def isel(self, **indexers): raise ValueError("dimensions %r do not exist" % invalid) # all indexers should be int, slice or np.ndarrays - indexers = {k: np.asarray(v) if not isinstance(v, (int, np.integer, slice)) else v - for k, v in iteritems(indexers)} + indexers = dict((k, np.asarray(v) if not isinstance(v, (int, np.integer, slice)) else v) + for k, v in iteritems(indexers)) variables = OrderedDict() for name, var in iteritems(self.variables): - var_indexers = {k: v for k, v in iteritems(indexers) - if k in var.dimensions} + var_indexers = dict((k, v) for k, v in iteritems(indexers) if k in var.dimensions) variables[name] = var.isel(**var_indexers) return type(self)(variables, self.attrs) @@ -923,11 +922,11 @@ def merge(self, other, inplace=False, overwrite_vars=set(), potential_conflicts = self.variables else: if isinstance(overwrite_vars, basestring): - overwrite_vars = {overwrite_vars} + overwrite_vars = set([overwrite_vars]) else: overwrite_vars = set(overwrite_vars) - potential_conflicts = {k: v for k, v in iteritems(self.variables) - if k not in overwrite_vars} + potential_conflicts = dict((k, v) for k, v in iteritems(self.variables) + if k not in overwrite_vars) # update variables new_variables = _expand_variables(other_variables, potential_conflicts, @@ -975,8 +974,8 @@ def drop_vars(self, *names): raise ValueError('One or more of the specified variable ' 'names does not exist in this dataset') drop = set(names) - drop |= {k for k, v in iteritems(self.variables) - if any(name in v.dimensions for name in names)} + drop |= set(k for k, v in iteritems(self.variables) + if any(name in v.dimensions for name in names)) variables = OrderedDict((k, v) for k, v in iteritems(self.variables) if k not in drop) return type(self)(variables, self.attrs) @@ -1150,7 +1149,7 @@ def concat(cls, datasets, dimension='concat_dimension', indexers=None, if concat_over is None: concat_over = set() elif isinstance(concat_over, basestring): - concat_over = {concat_over} + concat_over = set([concat_over]) else: concat_over = set(concat_over) @@ -1180,7 +1179,7 @@ def differs(vname, v): % (concat_over, datasets[0])) # automatically concatenate over variables along the dimension - auto_concat_dims = {dim_name} + auto_concat_dims = set([dim_name]) if hasattr(dimension, 'dimensions'): auto_concat_dims |= set(dimension.dimensions) for k, v in iteritems(datasets[0]): diff --git a/xray/indexing.py b/xray/indexing.py index 454f191e71e..7cdbc259f2e 100644 --- a/xray/indexing.py +++ b/xray/indexing.py @@ -129,9 +129,8 @@ def remap_label_indexers(data_obj, indexers): """Given an xray data object and label based indexers, return a mapping of equivalent location based indexers. """ - return {dim: convert_label_indexer(data_obj.indexes[dim], label, dim) - for dim, label in iteritems(indexers)} - + return dict((dim, convert_label_indexer(data_obj.indexes[dim], label, dim)) + for dim, label in iteritems(indexers)) def _expand_slice(slice_, size): return np.arange(*slice_.indices(size)) diff --git a/xray/pycompat.py b/xray/pycompat.py index fda76b5b206..811ca4a513f 100644 --- a/xray/pycompat.py +++ b/xray/pycompat.py @@ -11,6 +11,7 @@ def iteritems(d): def itervalues(d): return iter(d.values()) xrange = range + from collections import OrderedDict else: # Python 2 basestring = basestring @@ -21,3 +22,7 @@ def iteritems(d): def itervalues(d): return d.itervalues() xrange = xrange + try: + from collections import OrderedDict + except ImportError: + from ordereddict import OrderedDict diff --git a/xray/utils.py b/xray/utils.py index 51cbbf18819..08b9387d0da 100644 --- a/xray/utils.py +++ b/xray/utils.py @@ -2,13 +2,13 @@ """ import functools import warnings -from collections import OrderedDict, Mapping, MutableMapping +from collections import Mapping, MutableMapping import numpy as np import pandas as pd import xray -from .pycompat import basestring, iteritems, PY3 +from .pycompat import basestring, iteritems, PY3, OrderedDict def alias_warning(old_name, new_name, stacklevel=3): @@ -44,7 +44,7 @@ def squeeze(xray_obj, dimensions, dimension=None): if any(dimensions[k] > 1 for k in dimension): raise ValueError('cannot select a dimension to squeeze out ' 'which has length greater than one') - return xray_obj.isel(**{dim: 0 for dim in dimension}) + return xray_obj.isel(**dict((dim, 0) for dim in dimension)) def allclose_or_equiv(arr1, arr2, rtol=1e-5, atol=1e-8): diff --git a/xray/variable.py b/xray/variable.py index 97ec9fd25f7..0b3bd591204 100644 --- a/xray/variable.py +++ b/xray/variable.py @@ -6,11 +6,10 @@ from itertools import izip except ImportError: # Python 3 izip = zip -from collections import OrderedDict from . import indexing from . import ops -from .pycompat import basestring +from .pycompat import basestring, OrderedDict from . import utils import xray