From eecdabbd7605d922591217822289ba25401b31a4 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Tue, 23 May 2017 10:33:25 +0200 Subject: [PATCH 1/7] as_variable now part of the public API --- doc/api.rst | 1 + doc/whats-new.rst | 4 ++++ xarray/__init__.py | 2 +- xarray/core/variable.py | 30 +++++++++++++++++++++--------- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index 055ec733641..0a0082375f2 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -22,6 +22,7 @@ Top-level functions full_like zeros_like ones_like + as_variable Dataset ======= diff --git a/doc/whats-new.rst b/doc/whats-new.rst index ff16c133591..e9359a514b5 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -38,6 +38,10 @@ Enhancements to ``py.test`` (:issue:`1393`). By `Matthew Gidden `_. +- ``xarray.core.variable.as_variable`` is now part of the public API and + can be accessed using :py:meth:`~xarray.as_variable` (:issue:`1303`). + By `Benoit Bovy `_. + Bug fixes ~~~~~~~~~ diff --git a/xarray/__init__.py b/xarray/__init__.py index c88a0176616..e3d4a60ac46 100644 --- a/xarray/__init__.py +++ b/xarray/__init__.py @@ -7,7 +7,7 @@ from .core.combine import concat, auto_combine from .core.extensions import (register_dataarray_accessor, register_dataset_accessor) -from .core.variable import Variable, IndexVariable, Coordinate +from .core.variable import as_variable, Variable, IndexVariable, Coordinate from .core.dataset import Dataset from .core.dataarray import DataArray from .core.merge import merge, MergeError diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 34b86275374..b7daeb8c353 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -28,14 +28,26 @@ pass -def as_variable(obj, name=None, copy=False): - """Convert an object into an Variable. - - - If the object is already an `Variable`, return a shallow copy. - - Otherwise, if the object has 'dims' and 'data' attributes, convert - it into a new `Variable`. - - If all else fails, attempt to convert the object into an `Variable` by - unpacking it into the arguments for `Variable.__init__`. +def as_variable(obj, name=None): + """Convert an object into a Variable. + + Parameters + ---------- + obj : object + Object to convert into a Variable. + If the object is already a Variable, return a shallow copy. + Otherwise, if the object has 'dims' and 'data' attributes, convert + it into a new Variable. + If all else fails, attempt to convert the object into a Variable by + unpacking it into the arguments for creating a new Variable. + name : str, optional + Dimension name (only if data in `obj` is 1-dimensional). + + Returns + ------- + var : Variable + The newly created variable. + """ # TODO: consider extending this method to automatically handle Iris and # pandas objects. @@ -75,7 +87,7 @@ def as_variable(obj, name=None, copy=False): 'explicit list of dimensions: %r' % obj) if name is not None and name in obj.dims: - # convert the into an Index + # convert the Variable into an Index if obj.ndim != 1: raise ValueError( '%r has more than 1-dimension and the same name as one of its ' From f2976492befebd190330f15647d726aeadb399d8 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 24 May 2017 07:26:20 +0200 Subject: [PATCH 2/7] fully remove copy kwarg of as_variable --- xarray/core/groupby.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/groupby.py b/xarray/core/groupby.py index 3c3ed7dcc12..2e31ae5bc2a 100644 --- a/xarray/core/groupby.py +++ b/xarray/core/groupby.py @@ -539,7 +539,7 @@ def _combine(self, applied, shortcut=False): combined = self._restore_dim_order(combined) if coord is not None: if shortcut: - combined._coords[coord.name] = as_variable(coord, copy=True) + combined._coords[coord.name] = as_variable(coord) else: combined.coords[coord.name] = coord combined = self._maybe_restore_empty_groups(combined) From cdd3cbcc725754737d9eac77eb52c9b78623690c Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 24 May 2017 07:51:55 +0200 Subject: [PATCH 3/7] as_variable docstring changes --- xarray/core/variable.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index b7daeb8c353..c836b74c396 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -35,13 +35,19 @@ def as_variable(obj, name=None): ---------- obj : object Object to convert into a Variable. - If the object is already a Variable, return a shallow copy. - Otherwise, if the object has 'dims' and 'data' attributes, convert - it into a new Variable. - If all else fails, attempt to convert the object into a Variable by - unpacking it into the arguments for creating a new Variable. + + - If the object is already a Variable, return a shallow copy. + - Otherwise, if the object has 'dims' and 'data' attributes, convert + it into a new Variable. + - If all else fails, attempt to convert the object into a Variable by + unpacking it into the arguments for creating a new Variable. name : str, optional - Dimension name (only if data in `obj` is 1-dimensional). + If provided + + - `obj` can be a 1D array, which is assumed to label coordinate values + along a dimension of this given name. + - Variables with name matching one of their dimensions are converted + into `IndexVariable` objects. Returns ------- From 227b0e98bf1a1cfe72ba7d6d6a230c90a1626f42 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 24 May 2017 07:52:27 +0200 Subject: [PATCH 4/7] move as_variable to advanced API section --- doc/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api.rst b/doc/api.rst index 0a0082375f2..08d04ec2005 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -22,7 +22,6 @@ Top-level functions full_like zeros_like ones_like - as_variable Dataset ======= @@ -490,6 +489,7 @@ Advanced API Variable IndexVariable + as_variable register_dataset_accessor register_dataarray_accessor From c089d35c2ed0b6dce71ff80b38c31b1e53be0819 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 24 May 2017 09:01:19 +0200 Subject: [PATCH 5/7] fix typo --- xarray/core/variable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index c836b74c396..9982da9a9b8 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -42,7 +42,7 @@ def as_variable(obj, name=None): - If all else fails, attempt to convert the object into a Variable by unpacking it into the arguments for creating a new Variable. name : str, optional - If provided + If provided: - `obj` can be a 1D array, which is assumed to label coordinate values along a dimension of this given name. From 6b43b6e91bdd2d06e9429d39ab132106560d372b Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 24 May 2017 13:28:01 +0200 Subject: [PATCH 6/7] add more tests for as_variable Also allow passing to `as_variable` objects that have a `data` attribute but no `values` attribute. --- xarray/core/variable.py | 5 ++++- xarray/tests/test_variable.py | 30 +++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 9982da9a9b8..ad4836b930f 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -65,7 +65,10 @@ def as_variable(obj, name=None): obj = obj.copy(deep=False) elif hasattr(obj, 'dims') and (hasattr(obj, 'data') or hasattr(obj, 'values')): - obj = Variable(obj.dims, getattr(obj, 'data', obj.values), + obj_data = getattr(obj, 'data', None) + if obj_data is None: + obj_data = getattr(obj, 'values') + obj = Variable(obj.dims, obj_data, getattr(obj, 'attrs', None), getattr(obj, 'encoding', None)) elif isinstance(obj, tuple): diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index aa061516949..caa021b311e 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -609,11 +609,14 @@ def test_no_conflicts(self): def test_as_variable(self): data = np.arange(10) expected = Variable('x', data) + expected_extra = Variable('x', data, attrs={'myattr': 'val'}, + encoding={'scale_factor': 1}) self.assertVariableIdentical(expected, as_variable(expected)) ds = Dataset({'x': expected}) - self.assertVariableIdentical(expected, as_variable(ds['x']).to_base_variable()) + var = as_variable(ds['x']).to_base_variable() + self.assertVariableIdentical(expected, var) self.assertNotIsInstance(ds['x'], Variable) self.assertIsInstance(as_variable(ds['x']), Variable) @@ -621,8 +624,20 @@ def test_as_variable(self): fake_xarray = FakeVariable(expected.values, expected.dims) self.assertVariableIdentical(expected, as_variable(fake_xarray)) - xarray_tuple = (expected.dims, expected.values) - self.assertVariableIdentical(expected, as_variable(xarray_tuple)) + FakeVariable = namedtuple('FakeVariable', 'data dims') + fake_xarray = FakeVariable(expected.data, expected.dims) + self.assertVariableIdentical(expected, as_variable(fake_xarray)) + + FakeVariable = namedtuple('FakeVariable', + 'data values dims attrs encoding') + fake_xarray = FakeVariable(expected_extra.data, expected_extra.values, + expected_extra.dims, expected_extra.attrs, + expected_extra.encoding) + self.assertVariableIdentical(expected_extra, as_variable(fake_xarray)) + + xarray_tuple = (expected_extra.dims, expected_extra.values, + expected_extra.attrs, expected_extra.encoding) + self.assertVariableIdentical(expected_extra, as_variable(xarray_tuple)) with self.assertRaisesRegexp(TypeError, 'tuples to convert'): as_variable(tuple(data)) @@ -637,6 +652,15 @@ def test_as_variable(self): expected = Variable([], 0) self.assertVariableIdentical(expected, actual) + data = np.arange(9).reshape((3, 3)) + expected = Variable(('x', 'y'), data) + with self.assertRaisesRegex( + ValueError, 'without explicit dimension names'): + as_variable(data, name='x') + with self.assertRaisesRegex( + ValueError, 'has more than 1-dimension'): + as_variable(expected, name='x') + def test_repr(self): v = Variable(['time', 'x'], [[1, 2, 3], [4, 5, 6]], {'foo': 'bar'}) expected = dedent(""" From 6a6394013bf572d7424af6da73758e9f1bcf87d7 Mon Sep 17 00:00:00 2001 From: Benoit Bovy Date: Wed, 24 May 2017 14:34:14 +0200 Subject: [PATCH 7/7] fix py27 test --- xarray/tests/test_variable.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/tests/test_variable.py b/xarray/tests/test_variable.py index caa021b311e..f5d207d0978 100644 --- a/xarray/tests/test_variable.py +++ b/xarray/tests/test_variable.py @@ -654,10 +654,10 @@ def test_as_variable(self): data = np.arange(9).reshape((3, 3)) expected = Variable(('x', 'y'), data) - with self.assertRaisesRegex( + with self.assertRaisesRegexp( ValueError, 'without explicit dimension names'): as_variable(data, name='x') - with self.assertRaisesRegex( + with self.assertRaisesRegexp( ValueError, 'has more than 1-dimension'): as_variable(expected, name='x')