From a89b7668ac3b6be7f0b39fdd0bb50aa72f339585 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:35:19 +0200 Subject: [PATCH 01/53] add a dict-like checker --- xarray/core/utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index a139d2ef10a..bee5646069e 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -95,6 +95,12 @@ def maybe_coerce_to_str(index, original_coords): return index +def maybe_coerce_to_dict(dict_like): + is_dict_like = True + if is_dict_like: + return dict_like + else: + return dict(dict_like) def safe_cast_to_index(array: Any) -> pd.Index: """Given an array, safely cast it to a pandas.Index. From 8912de4349d29d80fc3170f8b9431d963fdcb8a8 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:39:01 +0200 Subject: [PATCH 02/53] Update dataset.py --- xarray/core/dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 5f5c01ad4c9..b87d4ce883a 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -755,7 +755,7 @@ def __init__( data_vars, coords, compat="broadcast_equals" ) - self._attrs = dict(attrs) if attrs is not None else None + self._attrs = maybe_coerce_to_dict(attrs) if attrs is not None else None self._close = None self._encoding = None self._variables = variables From 70c39e0a58421dd4e1ec44877f3d9e396f73f618 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:40:44 +0200 Subject: [PATCH 03/53] Update merge.py --- xarray/core/merge.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/core/merge.py b/xarray/core/merge.py index db5b95fd415..021de44c0d6 100644 --- a/xarray/core/merge.py +++ b/xarray/core/merge.py @@ -520,9 +520,9 @@ def merge_attrs(variable_attrs, combine_attrs, context=None): elif combine_attrs == "drop": return {} elif combine_attrs == "override": - return dict(variable_attrs[0]) + return variable_attrs[0] elif combine_attrs == "no_conflicts": - result = dict(variable_attrs[0]) + result = variable_attrs[0] for attrs in variable_attrs[1:]: try: result = compat_dict_union(result, attrs) @@ -551,7 +551,7 @@ def merge_attrs(variable_attrs, combine_attrs, context=None): dropped_keys |= {key for key in attrs if key not in result} return result elif combine_attrs == "identical": - result = dict(variable_attrs[0]) + result = variable_attrs[0] for attrs in variable_attrs[1:]: if not dict_equiv(result, attrs): raise MergeError( From 9f46ea98f34d20971ff562ab7dbb59950238d557 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:42:05 +0200 Subject: [PATCH 04/53] Update variable.py --- xarray/core/variable.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index f69951580c7..c03c1ca7041 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -46,6 +46,7 @@ ensure_us_time_resolution, infix_dims, is_duck_array, + maybe_coerce_to_dict, maybe_coerce_to_str, ) @@ -862,7 +863,7 @@ def attrs(self) -> Dict[Hashable, Any]: @attrs.setter def attrs(self, value: Mapping[Hashable, Any]) -> None: - self._attrs = dict(value) + self._attrs = maybe_coerce_to_dict(value) @property def encoding(self): From cf11be768acc7fb9fdecfbe5aae6c82c72e539cc Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:44:27 +0200 Subject: [PATCH 05/53] Update dataset.py --- xarray/core/dataset.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index b87d4ce883a..379f7c8da4e 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -96,6 +96,7 @@ infix_dims, is_dict_like, is_scalar, + maybe_coerce_to_dict, maybe_wrap_array, ) from .variable import ( From 4b5b51919ec323fcbffbeef85fcc71cfa992d528 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:45:39 +0200 Subject: [PATCH 06/53] Update utils.py --- xarray/core/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index bee5646069e..6d688aefd31 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -95,6 +95,7 @@ def maybe_coerce_to_str(index, original_coords): return index + def maybe_coerce_to_dict(dict_like): is_dict_like = True if is_dict_like: @@ -102,6 +103,7 @@ def maybe_coerce_to_dict(dict_like): else: return dict(dict_like) + def safe_cast_to_index(array: Any) -> pd.Index: """Given an array, safely cast it to a pandas.Index. From 043e7b6c3da553427de115fdcba9efd09b517f52 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 11:21:03 +0200 Subject: [PATCH 07/53] Update utils.py --- xarray/core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 6d688aefd31..2446ad52b14 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -97,7 +97,7 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(dict_like): - is_dict_like = True + is_dict_like = False if is_dict_like: return dict_like else: From 1bb3327d270e0b8a18f0f7588d4c9088bf396f48 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Tue, 3 Aug 2021 15:45:09 +0200 Subject: [PATCH 08/53] Use a shallow .copy() like dict(result) did. --- xarray/core/merge.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/core/merge.py b/xarray/core/merge.py index 021de44c0d6..c97a17716d0 100644 --- a/xarray/core/merge.py +++ b/xarray/core/merge.py @@ -520,9 +520,9 @@ def merge_attrs(variable_attrs, combine_attrs, context=None): elif combine_attrs == "drop": return {} elif combine_attrs == "override": - return variable_attrs[0] + return variable_attrs[0].copy() elif combine_attrs == "no_conflicts": - result = variable_attrs[0] + result = variable_attrs[0].copy() for attrs in variable_attrs[1:]: try: result = compat_dict_union(result, attrs) @@ -551,7 +551,7 @@ def merge_attrs(variable_attrs, combine_attrs, context=None): dropped_keys |= {key for key in attrs if key not in result} return result elif combine_attrs == "identical": - result = variable_attrs[0] + result = variable_attrs[0].copy() for attrs in variable_attrs[1:]: if not dict_equiv(result, attrs): raise MergeError( From e4fc98965e6cf12ad25a8ec571389067378e432c Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 4 Aug 2021 22:36:14 +0200 Subject: [PATCH 09/53] use copy() instead --- xarray/core/dataarray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index cb2c4d30a69..79cdd1173ab 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -580,7 +580,7 @@ def to_dataset( result = self._to_dataset_whole(name) if promote_attrs: - result.attrs = dict(self.attrs) + result.attrs = self.attrs.copy() return result From de21491bae01fc71850d1ed37cab99fe2afc95a2 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 4 Aug 2021 23:03:55 +0200 Subject: [PATCH 10/53] Update utils.py --- xarray/core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 2446ad52b14..34a85ecb4a4 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -448,7 +448,7 @@ def compat_dict_union( union : dict union of the contents. """ - new_dict = dict(first_dict) + new_dict = first_dict.copy() update_safety_check(first_dict, second_dict, compat) new_dict.update(second_dict) return new_dict From 68ac983f331f62164ff302d1df79dc33c047fbf0 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 4 Aug 2021 23:43:31 +0200 Subject: [PATCH 11/53] Update utils.py --- xarray/core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 34a85ecb4a4..e3da69ff347 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -426,7 +426,7 @@ def compat_dict_intersection( def compat_dict_union( - first_dict: Mapping[K, V], + first_dict: Dict[K, V], second_dict: Mapping[K, V], compat: Callable[[V, V], bool] = equivalent, ) -> MutableMapping[K, V]: From a4a1c3d8fc662bb057224cd7b89b638e41dfc64b Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 5 Aug 2021 10:30:02 +0200 Subject: [PATCH 12/53] Initialize ds attrs the same way as in Variable --- xarray/core/dataset.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 379f7c8da4e..4f58128bffb 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -756,7 +756,9 @@ def __init__( data_vars, coords, compat="broadcast_equals" ) - self._attrs = maybe_coerce_to_dict(attrs) if attrs is not None else None + self._attrs = None + if attrs is not None: + self.attrs = attrs self._close = None self._encoding = None self._variables = variables @@ -796,7 +798,7 @@ def attrs(self) -> Dict[Hashable, Any]: @attrs.setter def attrs(self, value: Mapping[Hashable, Any]) -> None: - self._attrs = dict(value) + self._attrs = maybe_coerce_to_dict(value) @property def encoding(self) -> Dict: From 93510c534031fed430cc274058a7c45f9d9d71ce Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 5 Aug 2021 10:43:30 +0200 Subject: [PATCH 13/53] change typing --- xarray/core/dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 4f58128bffb..f6c34ebbd42 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -797,7 +797,7 @@ def attrs(self) -> Dict[Hashable, Any]: return self._attrs @attrs.setter - def attrs(self, value: Mapping[Hashable, Any]) -> None: + def attrs(self, value: Dict[Hashable, Any]) -> None: self._attrs = maybe_coerce_to_dict(value) @property From 0369166c36a29ac5fab7f098fa5f6733d6314f06 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Thu, 5 Aug 2021 10:48:33 +0200 Subject: [PATCH 14/53] more typing --- xarray/core/dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index f6c34ebbd42..1caa8af769d 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -734,7 +734,7 @@ def __init__( # categories data_vars: Mapping[Hashable, Any] = None, coords: Mapping[Hashable, Any] = None, - attrs: Mapping[Hashable, Any] = None, + attrs: Dict[Hashable, Any] = None, ): # TODO(shoyer): expose indexes as a public argument in __init__ From 40891c65edf261de5d3ad62ae8c9154e6d178436 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 6 Aug 2021 15:44:31 +0200 Subject: [PATCH 15/53] Update utils.py --- xarray/core/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index e3da69ff347..4a77387804f 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -96,12 +96,12 @@ def maybe_coerce_to_str(index, original_coords): return index -def maybe_coerce_to_dict(dict_like): - is_dict_like = False - if is_dict_like: - return dict_like +def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: + """Convert to dict if the object is not a valid dict-like.""" + if isinstance(obj, MutableMapping) and hasattr(obj, "copy"): + return obj else: - return dict(dict_like) + return dict(obj) def safe_cast_to_index(array: Any) -> pd.Index: From 475cb0cace814f3163d5e9b202f6e095cc7add90 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 6 Aug 2021 15:48:49 +0200 Subject: [PATCH 16/53] shallow copy here just like with the dict --- xarray/core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 4a77387804f..57135057575 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -99,7 +99,7 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" if isinstance(obj, MutableMapping) and hasattr(obj, "copy"): - return obj + return obj.copy() else: return dict(obj) From 100731bc36847af5a7501e4ea4b1868e2333e1b9 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 6 Aug 2021 15:59:02 +0200 Subject: [PATCH 17/53] Update utils.py --- xarray/core/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 57135057575..f6f80773117 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -8,6 +8,7 @@ import re import sys import warnings +from copy import copy from enum import Enum from typing import ( TYPE_CHECKING, @@ -99,7 +100,7 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" if isinstance(obj, MutableMapping) and hasattr(obj, "copy"): - return obj.copy() + return copy(obj) else: return dict(obj) From 252faf4ee54b8060b50c71cce0bb8c6432b43f91 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 6 Aug 2021 16:14:54 +0200 Subject: [PATCH 18/53] Update utils.py --- xarray/core/utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index f6f80773117..6dc3cd8d4b1 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -8,7 +8,6 @@ import re import sys import warnings -from copy import copy from enum import Enum from typing import ( TYPE_CHECKING, @@ -99,8 +98,8 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" - if isinstance(obj, MutableMapping) and hasattr(obj, "copy"): - return copy(obj) + if isinstance(obj, dict): + return obj.copy() else: return dict(obj) From f8fb503efc1ec745b1c99da4d6d9123bfd9d1cb9 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 09:44:14 +0200 Subject: [PATCH 19/53] Update conventions.py --- xarray/conventions.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xarray/conventions.py b/xarray/conventions.py index c3a05e42f82..03d478c387b 100644 --- a/xarray/conventions.py +++ b/xarray/conventions.py @@ -1,5 +1,6 @@ import warnings from collections import defaultdict +from copy import copy import numpy as np import pandas as pd @@ -95,7 +96,7 @@ def __getitem__(self, key): def _var_as_tuple(var): - return var.dims, var.data, var.attrs.copy(), var.encoding.copy() + return var.dims, var.data, copy(var.attrs), var.encoding.copy() def maybe_encode_nonstring_dtype(var, name=None): @@ -562,7 +563,7 @@ def stackable(dim): del var_attrs[attr_name] if decode_coords and "coordinates" in attributes: - attributes = dict(attributes) + attributes = copy(attributes) coord_names.update(attributes.pop("coordinates").split()) return new_vars, attributes, coord_names @@ -786,7 +787,7 @@ def _encode_coordinates(variables, attributes, non_dim_coord_names): # http://mailman.cgd.ucar.edu/pipermail/cf-metadata/2014/007571.html global_coordinates.difference_update(written_coords) if global_coordinates: - attributes = dict(attributes) + attributes = copy(attributes) if "coordinates" in attributes: warnings.warn( f"cannot serialize global coordinates {global_coordinates!r} because the global " From 6021e1214e29b9ef7004d2b272d60a9c1b5d3e6f Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 09:56:38 +0200 Subject: [PATCH 20/53] Update utils.py --- xarray/core/utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 6dc3cd8d4b1..78f361d4019 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -8,6 +8,7 @@ import re import sys import warnings +from copy import copy from enum import Enum from typing import ( TYPE_CHECKING, @@ -99,7 +100,7 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" if isinstance(obj, dict): - return obj.copy() + return copy(obj) else: return dict(obj) @@ -426,7 +427,7 @@ def compat_dict_intersection( def compat_dict_union( - first_dict: Dict[K, V], + first_dict: MutableMapping[K, V], second_dict: Mapping[K, V], compat: Callable[[V, V], bool] = equivalent, ) -> MutableMapping[K, V]: @@ -448,7 +449,7 @@ def compat_dict_union( union : dict union of the contents. """ - new_dict = first_dict.copy() + new_dict = copy(first_dict) update_safety_check(first_dict, second_dict, compat) new_dict.update(second_dict) return new_dict From ccae97fc7e5490e14452b3d8045fad1a0bffae8a Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 09:59:05 +0200 Subject: [PATCH 21/53] Update dataarray.py --- xarray/core/dataarray.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index 79cdd1173ab..4cf3f1b680d 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -1,5 +1,6 @@ import datetime import warnings +from copy import copy from typing import ( TYPE_CHECKING, Any, @@ -580,7 +581,7 @@ def to_dataset( result = self._to_dataset_whole(name) if promote_attrs: - result.attrs = self.attrs.copy() + result.attrs = copy(self.attrs) return result From 9391de6fa805a699dcedbaf63eb9f64c14d9add3 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:07:56 +0200 Subject: [PATCH 22/53] Update merge.py --- xarray/core/merge.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xarray/core/merge.py b/xarray/core/merge.py index c97a17716d0..471266cdf71 100644 --- a/xarray/core/merge.py +++ b/xarray/core/merge.py @@ -1,3 +1,4 @@ +from copy import copy from typing import ( TYPE_CHECKING, AbstractSet, @@ -520,9 +521,9 @@ def merge_attrs(variable_attrs, combine_attrs, context=None): elif combine_attrs == "drop": return {} elif combine_attrs == "override": - return variable_attrs[0].copy() + return copy(variable_attrs[0]) elif combine_attrs == "no_conflicts": - result = variable_attrs[0].copy() + result = copy(variable_attrs[0]) for attrs in variable_attrs[1:]: try: result = compat_dict_union(result, attrs) @@ -551,7 +552,7 @@ def merge_attrs(variable_attrs, combine_attrs, context=None): dropped_keys |= {key for key in attrs if key not in result} return result elif combine_attrs == "identical": - result = variable_attrs[0].copy() + result = copy(variable_attrs[0]) for attrs in variable_attrs[1:]: if not dict_equiv(result, attrs): raise MergeError( From bbf4916078d6dcbbaecb79ed596ee5d247c64e5c Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:14:33 +0200 Subject: [PATCH 23/53] typing --- xarray/core/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 78f361d4019..a86bd0f002c 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -97,9 +97,9 @@ def maybe_coerce_to_str(index, original_coords): return index -def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> Dict[Hashable, Any]: +def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> MutableMapping[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" - if isinstance(obj, dict): + if isinstance(obj, MutableMapping): return copy(obj) else: return dict(obj) From 1164f3d4bb408796c631cd9401523824ccf28a24 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:20:48 +0200 Subject: [PATCH 24/53] Update dataset.py --- xarray/core/dataset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 1caa8af769d..03b474e1c1d 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -701,7 +701,7 @@ class Dataset(DataWithCoords, DatasetArithmetic, Mapping): description: Weather related data. """ - _attrs: Optional[Dict[Hashable, Any]] + _attrs: Optional[MutableMapping[Hashable, Any]] _cache: Dict[str, Any] _coord_names: Set[Hashable] _dims: Dict[Hashable, int] @@ -790,14 +790,14 @@ def variables(self) -> Mapping[Hashable, Variable]: return Frozen(self._variables) @property - def attrs(self) -> Dict[Hashable, Any]: + def attrs(self) -> MutableMapping[Hashable, Any]: """Dictionary of global attributes on this dataset""" if self._attrs is None: self._attrs = {} return self._attrs @attrs.setter - def attrs(self, value: Dict[Hashable, Any]) -> None: + def attrs(self, value: MutableMapping[Hashable, Any]) -> None: self._attrs = maybe_coerce_to_dict(value) @property From c5a842e7ad639c7f49de99122e0b7019db49bc1e Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:22:43 +0200 Subject: [PATCH 25/53] Update dataset.py --- xarray/core/dataset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 03b474e1c1d..3007a122e2a 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -734,7 +734,7 @@ def __init__( # categories data_vars: Mapping[Hashable, Any] = None, coords: Mapping[Hashable, Any] = None, - attrs: Dict[Hashable, Any] = None, + attrs: MutableMapping[Hashable, Any] = None, ): # TODO(shoyer): expose indexes as a public argument in __init__ From badc69acf1b0622f810a4823374c5e909cf2e199 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:33:42 +0200 Subject: [PATCH 26/53] Update dataset.py --- xarray/core/dataset.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 3007a122e2a..2f675942bb7 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -1102,7 +1102,7 @@ def _replace( variables: Dict[Hashable, Variable] = None, coord_names: Set[Hashable] = None, dims: Dict[Any, int] = None, - attrs: Union[Dict[Hashable, Any], None, Default] = _default, + attrs: Union[MutableMapping[Hashable, Any], None, Default] = _default, indexes: Union[Dict[Any, Index], None, Default] = _default, encoding: Union[dict, None, Default] = _default, inplace: bool = False, @@ -1151,7 +1151,7 @@ def _replace_with_new_dims( self, variables: Dict[Hashable, Variable], coord_names: set = None, - attrs: Union[Dict[Hashable, Any], None, Default] = _default, + attrs: Union[MutableMapping[Hashable, Any], None, Default] = _default, indexes: Union[Dict[Hashable, Index], None, Default] = _default, inplace: bool = False, ) -> "Dataset": @@ -1166,7 +1166,7 @@ def _replace_vars_and_dims( variables: Dict[Hashable, Variable], coord_names: set = None, dims: Dict[Hashable, int] = None, - attrs: Union[Dict[Hashable, Any], None, Default] = _default, + attrs: Union[MutableMapping[Hashable, Any], None, Default] = _default, inplace: bool = False, ) -> "Dataset": """Deprecated version of _replace_with_new_dims(). @@ -6907,7 +6907,7 @@ def polyfit( covariance = xr.DataArray(Vbase, dims=("cov_i", "cov_j")) * fac variables[name + "polyfit_covariance"] = covariance - return Dataset(data_vars=variables, attrs=self.attrs.copy()) + return Dataset(data_vars=variables, attrs=copy.copy(self.attrs)) def pad( self, @@ -7641,6 +7641,6 @@ def _wrapper(Y, *coords_, **kwargs): result = result.assign_coords( {"param": params, "cov_i": params, "cov_j": params} ) - result.attrs = self.attrs.copy() + result.attrs = copy.copy(self.attrs) return result From a721f4dddd25ee7ccb43079b8b001e1eaa00ecfa Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:44:09 +0200 Subject: [PATCH 27/53] Update dataarray.py --- xarray/core/dataarray.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index 4cf3f1b680d..02a3dbb841b 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -795,7 +795,7 @@ def loc(self) -> _LocIndexer: return _LocIndexer(self) @property - def attrs(self) -> Dict[Hashable, Any]: + def attrs(self) -> MutableMapping[Hashable, Any]: """Dictionary storing arbitrary metadata with this array.""" return self.variable.attrs From 2515a8efe821fd4703d5d7526888849fcf26cd67 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:45:45 +0200 Subject: [PATCH 28/53] Update dataarray.py --- xarray/core/dataarray.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py index 02a3dbb841b..20890366e0d 100644 --- a/xarray/core/dataarray.py +++ b/xarray/core/dataarray.py @@ -10,6 +10,7 @@ Iterable, List, Mapping, + MutableMapping, Optional, Sequence, Tuple, From 653327cdd203943da0453eb8abeaf24bfeb7fa91 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 10:50:54 +0200 Subject: [PATCH 29/53] Update dataset.py --- xarray/core/dataset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 2f675942bb7..782ef7d42cd 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -734,7 +734,7 @@ def __init__( # categories data_vars: Mapping[Hashable, Any] = None, coords: Mapping[Hashable, Any] = None, - attrs: MutableMapping[Hashable, Any] = None, + attrs: Mapping[Hashable, Any] = None, ): # TODO(shoyer): expose indexes as a public argument in __init__ @@ -797,7 +797,7 @@ def attrs(self) -> MutableMapping[Hashable, Any]: return self._attrs @attrs.setter - def attrs(self, value: MutableMapping[Hashable, Any]) -> None: + def attrs(self, value: Mapping[Hashable, Any]) -> None: self._attrs = maybe_coerce_to_dict(value) @property From 3ad419301218ed809d4990eec8507b3d363a5f76 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 11:00:06 +0200 Subject: [PATCH 30/53] Update dataset.py --- xarray/core/dataset.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 782ef7d42cd..a074bbd42fd 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -798,7 +798,8 @@ def attrs(self) -> MutableMapping[Hashable, Any]: @attrs.setter def attrs(self, value: Mapping[Hashable, Any]) -> None: - self._attrs = maybe_coerce_to_dict(value) + # Disable type checking to work around mypy bug - see mypy#4167 + self._attrs = maybe_coerce_to_dict(value) # type: ignore[assignment] @property def encoding(self) -> Dict: From a088b16d978fc5879b8101f0a94fa19ed1f6d858 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 18:09:19 +0200 Subject: [PATCH 31/53] try coercing to dict --- xarray/conventions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/conventions.py b/xarray/conventions.py index 03d478c387b..21145a8858b 100644 --- a/xarray/conventions.py +++ b/xarray/conventions.py @@ -11,6 +11,7 @@ from .core.common import contains_cftime_datetimes from .core.pycompat import is_duck_dask_array from .core.variable import IndexVariable, Variable, as_variable +from .core.utils import maybe_coerce_to_dict CF_RELATED_DATA = ( "bounds", @@ -563,7 +564,7 @@ def stackable(dim): del var_attrs[attr_name] if decode_coords and "coordinates" in attributes: - attributes = copy(attributes) + attributes = maybe_coerce_to_dict(attributes) coord_names.update(attributes.pop("coordinates").split()) return new_vars, attributes, coord_names From a798f8e82c9344199b1247f8451e81f9cc2436ac Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 23:35:52 +0200 Subject: [PATCH 32/53] Update dataset.py --- xarray/core/dataset.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index a074bbd42fd..e79af3add68 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -758,7 +758,7 @@ def __init__( self._attrs = None if attrs is not None: - self.attrs = attrs + self.attrs = attrs # type: ignore[assignment] # https://github.com/python/mypy/issues/3004 self._close = None self._encoding = None self._variables = variables @@ -798,8 +798,7 @@ def attrs(self) -> MutableMapping[Hashable, Any]: @attrs.setter def attrs(self, value: Mapping[Hashable, Any]) -> None: - # Disable type checking to work around mypy bug - see mypy#4167 - self._attrs = maybe_coerce_to_dict(value) # type: ignore[assignment] + self._attrs = maybe_coerce_to_dict(value) @property def encoding(self) -> Dict: From 3391ac335d3fadffb19119f53199605606974e63 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 7 Aug 2021 23:50:04 +0200 Subject: [PATCH 33/53] Update conventions.py --- xarray/conventions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/conventions.py b/xarray/conventions.py index 21145a8858b..8bd25776762 100644 --- a/xarray/conventions.py +++ b/xarray/conventions.py @@ -10,8 +10,8 @@ from .core import duck_array_ops, indexing from .core.common import contains_cftime_datetimes from .core.pycompat import is_duck_dask_array -from .core.variable import IndexVariable, Variable, as_variable from .core.utils import maybe_coerce_to_dict +from .core.variable import IndexVariable, Variable, as_variable CF_RELATED_DATA = ( "bounds", From 68459de3bdeac71abbd588c7f914185c2fe6d55c Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 14 Aug 2021 14:58:34 +0200 Subject: [PATCH 34/53] issubclass seems slightly faster --- xarray/core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index a86bd0f002c..e5298493388 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -99,7 +99,7 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> MutableMapping[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" - if isinstance(obj, MutableMapping): + if issubclass(type(obj), MutableMapping): return copy(obj) else: return dict(obj) From 894b6eaa6c12cacd477805f3163f7f0b8efc34f0 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sat, 14 Aug 2021 15:27:34 +0200 Subject: [PATCH 35/53] Update utils.py --- xarray/core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index e5298493388..cf2bd4d1074 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -99,7 +99,7 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> MutableMapping[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" - if issubclass(type(obj), MutableMapping): + if issubclass(obj.__class__, MutableMapping): return copy(obj) else: return dict(obj) From 6f5b372401751d67d595211449d65e71f53c195f Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 20 Aug 2021 07:47:34 +0200 Subject: [PATCH 36/53] Try out TypeGuard to avoid the slow isinstance check --- xarray/core/utils.py | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index cf2bd4d1074..791d4abd0bd 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -38,6 +38,38 @@ V = TypeVar("V") T = TypeVar("T") +# TODO: Remove this check once python 3.9 is not supported: +if sys.version_info >= (3, 9): + from typing import TypeGuard + + def _is_MutableMapping( + obj: Mapping[Hashable, Any] + ) -> TypeGuard[MutableMapping[Hashable, Any]]: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") + + +else: + # See GH5624, this is a convoluted way to allow type-checking to use + # `TypeGuard` without requiring typing_extensions as a required dependency + # to _run_ the code (it is required to type-check). + try: + from typing_extensions import TypeGuard + + def _is_MutableMapping( + obj: Mapping[Hashable, Any] + ) -> TypeGuard[MutableMapping[Hashable, Any]]: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") + + except ImportError: + from typing import TYPE_CHECKING, Any + + if TYPE_CHECKING: + raise + else: + TypeGuard = Any + def alias_message(old_name: str, new_name: str) -> str: return f"{old_name} has been deprecated. Use {new_name} instead." @@ -99,8 +131,12 @@ def maybe_coerce_to_str(index, original_coords): def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> MutableMapping[Hashable, Any]: """Convert to dict if the object is not a valid dict-like.""" - if issubclass(obj.__class__, MutableMapping): - return copy(obj) + # if isinstance(obj, MutableMapping): + if _is_MutableMapping(obj): + # if hasattr(obj, "update"): + # return obj.copy() + # return copy(obj) + return obj else: return dict(obj) From e479c5c93248cd5d54d397ac9b05f866cee5ef9b Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 20 Aug 2021 07:54:57 +0200 Subject: [PATCH 37/53] Update utils.py --- xarray/core/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 791d4abd0bd..35b5f2aa1ed 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -63,8 +63,6 @@ def _is_MutableMapping( return hasattr(obj, "__setitem__") except ImportError: - from typing import TYPE_CHECKING, Any - if TYPE_CHECKING: raise else: From 41fd3b93f2dbf6f9d361aba11e7aaac0897d934d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Fri, 20 Aug 2021 08:08:07 +0200 Subject: [PATCH 38/53] Update utils.py --- xarray/core/utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 5c148164bdd..d06fc1e94a6 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -38,8 +38,8 @@ V = TypeVar("V") T = TypeVar("T") -# TODO: Remove this check once python 3.9 is not supported: -if sys.version_info >= (3, 9): +# TODO: Remove this check once python 3.10 is not supported: +if sys.version_info >= (3, 10): from typing import TypeGuard def _is_MutableMapping( @@ -127,7 +127,7 @@ def maybe_coerce_to_str(index, original_coords): return index -def maybe_coerce_to_dict(obj: Mapping[Hashable, Any]) -> MutableMapping[Hashable, Any]: +def maybe_coerce_to_dict(obj: Mapping[Any, Any]) -> MutableMapping[Any, Any]: """Convert to dict if the object is not a valid dict-like.""" # if isinstance(obj, MutableMapping): if _is_MutableMapping(obj): From c728006117f1734dfe4defed8fa747843d3cf2fe Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:45:08 +0200 Subject: [PATCH 39/53] add typing in variable --- xarray/core/dataset.py | 6 +++--- xarray/core/variable.py | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index e1416ade690..7f43a6599be 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -698,7 +698,7 @@ class Dataset(DataWithCoords, DatasetArithmetic, Mapping): description: Weather related data. """ - _attrs: Optional[MutableMapping[Hashable, Any]] + _attrs: Optional[MutableMapping[Any, Any]] _cache: Dict[str, Any] _coord_names: Set[Hashable] _dims: Dict[Hashable, int] @@ -787,7 +787,7 @@ def variables(self) -> Mapping[Hashable, Variable]: return Frozen(self._variables) @property - def attrs(self) -> MutableMapping[Hashable, Any]: + def attrs(self) -> MutableMapping[Any, Any]: """Dictionary of global attributes on this dataset""" if self._attrs is None: self._attrs = {} @@ -1099,7 +1099,7 @@ def _replace( variables: Dict[Hashable, Variable] = None, coord_names: Set[Hashable] = None, dims: Dict[Any, int] = None, - attrs: Union[MutableMapping[Hashable, Any], None, Default] = _default, + attrs: Union[MutableMapping[Any, Any], None, Default] = _default, indexes: Union[Dict[Any, Index], None, Default] = _default, encoding: Union[dict, None, Default] = _default, inplace: bool = False, diff --git a/xarray/core/variable.py b/xarray/core/variable.py index ddda4f8b49a..34aafb045a4 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -13,6 +13,7 @@ Hashable, List, Mapping, + MutableMapping, Optional, Sequence, Tuple, @@ -285,10 +286,18 @@ class Variable(AbstractArray, NdimSizeLenMixin, VariableArithmetic): form of a Dataset or DataArray should almost always be preferred, because they can use more complete metadata in context of coordinate labels. """ + _attrs: Optional[MutableMapping[Any, Any]] __slots__ = ("_dims", "_data", "_attrs", "_encoding") - def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False): + def __init__( + self, + dims, + data, + attrs: Optional[Mapping[Any, Any]] = None, + encoding=None, + fastpath=False + ): """ Parameters ---------- @@ -313,7 +322,7 @@ def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False): self._attrs = None self._encoding = None if attrs is not None: - self.attrs = attrs + self.attrs = attrs # type: ignore[assignment] # https://github.com/python/mypy/issues/3004 if encoding is not None: self.encoding = encoding @@ -863,7 +872,7 @@ def __setitem__(self, key, value): indexable[index_tuple] = value @property - def attrs(self) -> Dict[Hashable, Any]: + def attrs(self) -> MutableMapping[Any, Any]: """Dictionary of local attributes on this variable.""" if self._attrs is None: self._attrs = {} From 0558996d939476a2f2c72f6fb99c948157fca4f0 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 1 Sep 2021 22:55:04 +0200 Subject: [PATCH 40/53] lint --- xarray/core/variable.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 34aafb045a4..9145293ca3c 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -286,6 +286,7 @@ class Variable(AbstractArray, NdimSizeLenMixin, VariableArithmetic): form of a Dataset or DataArray should almost always be preferred, because they can use more complete metadata in context of coordinate labels. """ + _attrs: Optional[MutableMapping[Any, Any]] __slots__ = ("_dims", "_data", "_attrs", "_encoding") @@ -296,7 +297,7 @@ def __init__( data, attrs: Optional[Mapping[Any, Any]] = None, encoding=None, - fastpath=False + fastpath=False, ): """ Parameters From 320debb55e7cec8b866dee44ac064f692241e573 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 1 Sep 2021 23:00:18 +0200 Subject: [PATCH 41/53] hashable -> any --- xarray/core/dataset.py | 4 ++-- xarray/core/utils.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py index 7f43a6599be..bcc9f9f34c8 100644 --- a/xarray/core/dataset.py +++ b/xarray/core/dataset.py @@ -1148,7 +1148,7 @@ def _replace_with_new_dims( self, variables: Dict[Hashable, Variable], coord_names: set = None, - attrs: Union[MutableMapping[Hashable, Any], None, Default] = _default, + attrs: Union[MutableMapping[Any, Any], None, Default] = _default, indexes: Union[Dict[Hashable, Index], None, Default] = _default, inplace: bool = False, ) -> "Dataset": @@ -1163,7 +1163,7 @@ def _replace_vars_and_dims( variables: Dict[Hashable, Variable], coord_names: set = None, dims: Dict[Hashable, int] = None, - attrs: Union[MutableMapping[Hashable, Any], None, Default] = _default, + attrs: Union[MutableMapping[Any, Any], None, Default] = _default, inplace: bool = False, ) -> "Dataset": """Deprecated version of _replace_with_new_dims(). diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 4bbc88230df..441eb4eeb18 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -43,8 +43,8 @@ from typing import TypeGuard def _is_MutableMapping( - obj: Mapping[Hashable, Any] - ) -> TypeGuard[MutableMapping[Hashable, Any]]: + obj: Mapping[Any, Any] + ) -> TypeGuard[MutableMapping[Any, Any]]: """Check if the object is a mutable mapping.""" return hasattr(obj, "__setitem__") @@ -57,8 +57,8 @@ def _is_MutableMapping( from typing_extensions import TypeGuard def _is_MutableMapping( - obj: Mapping[Hashable, Any] - ) -> TypeGuard[MutableMapping[Hashable, Any]]: + obj: Mapping[Any, Any] + ) -> TypeGuard[MutableMapping[Any, Any]]: """Check if the object is a mutable mapping.""" return hasattr(obj, "__setitem__") From 596c661f6d4b38a50a7dd947f689bd2c09fddc6d Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 1 Sep 2021 23:10:41 +0200 Subject: [PATCH 42/53] add typing to indexvariable --- xarray/core/variable.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index 9145293ca3c..bf33a805f99 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -2583,10 +2583,18 @@ class IndexVariable(Variable): They also have a name property, which is the name of their sole dimension unless another name is given. """ + _attrs: Optional[MutableMapping[Any, Any]] __slots__ = () - def __init__(self, dims, data, attrs=None, encoding=None, fastpath=False): + def __init__( + self, + dims, + data, + attrs: Optional[Mapping[Any, Any]] = None, + encoding=None, + fastpath=False, + ): super().__init__(dims, data, attrs, encoding, fastpath) if self.ndim != 1: raise ValueError(f"{type(self).__name__} objects must be 1-dimensional") From 4e5b2620d950f1819e92933ed2410ee4ce0233b8 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Wed, 1 Sep 2021 23:13:16 +0200 Subject: [PATCH 43/53] Update variable.py --- xarray/core/variable.py | 1 + 1 file changed, 1 insertion(+) diff --git a/xarray/core/variable.py b/xarray/core/variable.py index bf33a805f99..3468d5b5884 100644 --- a/xarray/core/variable.py +++ b/xarray/core/variable.py @@ -2583,6 +2583,7 @@ class IndexVariable(Variable): They also have a name property, which is the name of their sole dimension unless another name is given. """ + _attrs: Optional[MutableMapping[Any, Any]] __slots__ = () From 84b494f5100d35c3093f4de4883639293b456790 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:08:41 +0100 Subject: [PATCH 44/53] Update utils.py --- xarray/core/utils.py | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 1a7c1315f18..6ceb622198c 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -40,32 +40,8 @@ # TODO: Remove this check once python 3.10 is not supported: if sys.version_info >= (3, 10): from typing import TypeGuard - - def _is_MutableMapping( - obj: Mapping[Any, Any] - ) -> TypeGuard[MutableMapping[Any, Any]]: - """Check if the object is a mutable mapping.""" - return hasattr(obj, "__setitem__") - - else: - # See GH5624, this is a convoluted way to allow type-checking to use - # `TypeGuard` without requiring typing_extensions as a required dependency - # to _run_ the code (it is required to type-check). - try: - from typing_extensions import TypeGuard - - def _is_MutableMapping( - obj: Mapping[Any, Any] - ) -> TypeGuard[MutableMapping[Any, Any]]: - """Check if the object is a mutable mapping.""" - return hasattr(obj, "__setitem__") - - except ImportError: - if TYPE_CHECKING: - raise - else: - TypeGuard = Any + from typing_extensions import TypeGuard def alias_message(old_name: str, new_name: str) -> str: @@ -126,6 +102,11 @@ def maybe_coerce_to_str(index, original_coords): return index +def _is_MutableMapping(obj: Mapping[Any, Any]) -> TypeGuard[MutableMapping[Any, Any]]: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") + + def maybe_coerce_to_dict(obj: Mapping[Any, Any]) -> MutableMapping[Any, Any]: """Convert to dict if the object is not a valid dict-like.""" # if isinstance(obj, MutableMapping): From 8c09d4a32a89e53237c4179949028d11989a9c59 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:23:54 +0100 Subject: [PATCH 45/53] TypeGuard not in typing_extensions 3.7 --- xarray/core/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 6ceb622198c..33e32a4a61e 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -40,6 +40,8 @@ # TODO: Remove this check once python 3.10 is not supported: if sys.version_info >= (3, 10): from typing import TypeGuard +elif sys.version_info == (3, 7): + TypeGuard = Any else: from typing_extensions import TypeGuard From 9758348ee5415f665fe47f97cd1130fe4d4e0f77 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:34:06 +0100 Subject: [PATCH 46/53] Update utils.py --- xarray/core/utils.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 33e32a4a61e..ab3292ea6a6 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -37,14 +37,6 @@ V = TypeVar("V") T = TypeVar("T") -# TODO: Remove this check once python 3.10 is not supported: -if sys.version_info >= (3, 10): - from typing import TypeGuard -elif sys.version_info == (3, 7): - TypeGuard = Any -else: - from typing_extensions import TypeGuard - def alias_message(old_name: str, new_name: str) -> str: return f"{old_name} has been deprecated. Use {new_name} instead." @@ -104,9 +96,31 @@ def maybe_coerce_to_str(index, original_coords): return index -def _is_MutableMapping(obj: Mapping[Any, Any]) -> TypeGuard[MutableMapping[Any, Any]]: - """Check if the object is a mutable mapping.""" - return hasattr(obj, "__setitem__") +# See GH5624, this is a convoluted way to allow type-checking to use `TypeGuard` without +# requiring typing_extensions as a required dependency to _run_ the code (it is required +# to type-check). +try: + if sys.version_info >= (3, 10): + from typing import TypeGuard + else: + from typing_extensions import TypeGuard +except ImportError: + if TYPE_CHECKING: + raise + else: + + def _is_MutableMapping( + obj: Mapping[Any, Any] + ) -> TypeGuard[MutableMapping[Any, Any]]: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") + + +else: + + def _is_MutableMapping(obj: Mapping[Any, Any]) -> bool: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") def maybe_coerce_to_dict(obj: Mapping[Any, Any]) -> MutableMapping[Any, Any]: From 2192835e79cdb0bcabf777092f253e2c5b3179e7 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:41:11 +0100 Subject: [PATCH 47/53] Update utils.py --- xarray/core/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index ab3292ea6a6..65343909c14 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -104,7 +104,7 @@ def maybe_coerce_to_str(index, original_coords): from typing import TypeGuard else: from typing_extensions import TypeGuard -except ImportError: +except NameError: if TYPE_CHECKING: raise else: From b995c4a3b4ba688444450c817b52f65d81a6831b Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:48:39 +0100 Subject: [PATCH 48/53] Update utils.py --- xarray/core/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index 65343909c14..f453f675740 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -104,9 +104,9 @@ def maybe_coerce_to_str(index, original_coords): from typing import TypeGuard else: from typing_extensions import TypeGuard -except NameError: +except (ImportError, NameError) as e: if TYPE_CHECKING: - raise + raise e else: def _is_MutableMapping( From 650ce2294cdfb7b999aa5e1efbf5139909e1c132 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:54:10 +0100 Subject: [PATCH 49/53] Update utils.py --- xarray/core/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index f453f675740..ad2531a525b 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -109,16 +109,16 @@ def maybe_coerce_to_str(index, original_coords): raise e else: - def _is_MutableMapping( - obj: Mapping[Any, Any] - ) -> TypeGuard[MutableMapping[Any, Any]]: + def _is_MutableMapping(obj: Mapping[Any, Any]) -> bool: """Check if the object is a mutable mapping.""" return hasattr(obj, "__setitem__") else: - def _is_MutableMapping(obj: Mapping[Any, Any]) -> bool: + def _is_MutableMapping( + obj: Mapping[Any, Any] + ) -> TypeGuard[MutableMapping[Any, Any]]: """Check if the object is a mutable mapping.""" return hasattr(obj, "__setitem__") From 1f0d41bfeb7fd4412d638c39b920fb3b3ba8bfcb Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 14 Nov 2021 16:40:49 +0100 Subject: [PATCH 50/53] typing_extensions now a required package --- xarray/core/utils.py | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index ad2531a525b..cb96a006636 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -33,6 +33,11 @@ import numpy as np import pandas as pd +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: + from typing_extensions import TypeGuard + K = TypeVar("K") V = TypeVar("V") T = TypeVar("T") @@ -96,31 +101,11 @@ def maybe_coerce_to_str(index, original_coords): return index -# See GH5624, this is a convoluted way to allow type-checking to use `TypeGuard` without -# requiring typing_extensions as a required dependency to _run_ the code (it is required -# to type-check). -try: - if sys.version_info >= (3, 10): - from typing import TypeGuard - else: - from typing_extensions import TypeGuard -except (ImportError, NameError) as e: - if TYPE_CHECKING: - raise e - else: - - def _is_MutableMapping(obj: Mapping[Any, Any]) -> bool: - """Check if the object is a mutable mapping.""" - return hasattr(obj, "__setitem__") - - -else: - - def _is_MutableMapping( - obj: Mapping[Any, Any] - ) -> TypeGuard[MutableMapping[Any, Any]]: - """Check if the object is a mutable mapping.""" - return hasattr(obj, "__setitem__") +def _is_MutableMapping( + obj: Mapping[Any, Any] +) -> TypeGuard[MutableMapping[Any, Any]]: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") def maybe_coerce_to_dict(obj: Mapping[Any, Any]) -> MutableMapping[Any, Any]: From 3661d43945abfb14013e4245acf10a456d0a1719 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 14 Nov 2021 15:42:52 +0000 Subject: [PATCH 51/53] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- xarray/core/utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index cb96a006636..acb76d3003a 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -101,9 +101,7 @@ def maybe_coerce_to_str(index, original_coords): return index -def _is_MutableMapping( - obj: Mapping[Any, Any] -) -> TypeGuard[MutableMapping[Any, Any]]: +def _is_MutableMapping(obj: Mapping[Any, Any]) -> TypeGuard[MutableMapping[Any, Any]]: """Check if the object is a mutable mapping.""" return hasattr(obj, "__setitem__") From a494fd7e52a1f04b10beae48b5557922350986fd Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 14 Nov 2021 16:50:07 +0100 Subject: [PATCH 52/53] TypeGuard still not in typing_extensions 3.7 --- xarray/core/utils.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index acb76d3003a..ad2531a525b 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -33,11 +33,6 @@ import numpy as np import pandas as pd -if sys.version_info >= (3, 10): - from typing import TypeGuard -else: - from typing_extensions import TypeGuard - K = TypeVar("K") V = TypeVar("V") T = TypeVar("T") @@ -101,9 +96,31 @@ def maybe_coerce_to_str(index, original_coords): return index -def _is_MutableMapping(obj: Mapping[Any, Any]) -> TypeGuard[MutableMapping[Any, Any]]: - """Check if the object is a mutable mapping.""" - return hasattr(obj, "__setitem__") +# See GH5624, this is a convoluted way to allow type-checking to use `TypeGuard` without +# requiring typing_extensions as a required dependency to _run_ the code (it is required +# to type-check). +try: + if sys.version_info >= (3, 10): + from typing import TypeGuard + else: + from typing_extensions import TypeGuard +except (ImportError, NameError) as e: + if TYPE_CHECKING: + raise e + else: + + def _is_MutableMapping(obj: Mapping[Any, Any]) -> bool: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") + + +else: + + def _is_MutableMapping( + obj: Mapping[Any, Any] + ) -> TypeGuard[MutableMapping[Any, Any]]: + """Check if the object is a mutable mapping.""" + return hasattr(obj, "__setitem__") def maybe_coerce_to_dict(obj: Mapping[Any, Any]) -> MutableMapping[Any, Any]: From 0e6036f383614ba3795a9ad9035349c42d38c2c9 Mon Sep 17 00:00:00 2001 From: Illviljan <14371165+Illviljan@users.noreply.github.com> Date: Sun, 14 Nov 2021 17:03:50 +0100 Subject: [PATCH 53/53] Update utils.py --- xarray/core/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xarray/core/utils.py b/xarray/core/utils.py index ad2531a525b..1f66a4c6928 100644 --- a/xarray/core/utils.py +++ b/xarray/core/utils.py @@ -129,8 +129,8 @@ def maybe_coerce_to_dict(obj: Mapping[Any, Any]) -> MutableMapping[Any, Any]: if _is_MutableMapping(obj): # if hasattr(obj, "update"): # return obj.copy() - # return copy(obj) - return obj + return copy(obj) + # return obj else: return dict(obj)