text: from __future__ import absolute_import, division, print_function
  
  import numpy as np
  
  from .. import Variable
  from ..core import indexing
  from ..core.utils import Frozen, FrozenOrderedDict
  from .common import AbstractDataStore, BackendArray
  from .locks import SerializableLock, ensure_lock
  
  # FIXME: Add a dedicated lock, even if ecCodes is supposed to be thread-safe
  #   in most circumstances. See:
  #       https://confluence.ecmwf.int/display/ECC/Frequently+Asked+Questions
  ECCODES_LOCK = SerializableLock()
  
  
  class CfGribArrayWrapper(BackendArray):
      def __init__(self, datastore, array):
          self.datastore = datastore
          self.shape = array.shape
          self.dtype = array.dtype
          self.array = array
  
      def __getitem__(self, key):
          return indexing.explicit_indexing_adapter(
              key, self.shape, indexing.IndexingSupport.OUTER, self._getitem)
  
      def _getitem(self, key):
          with self.datastore.lock:
              return self.array[key]
  
  
  class CfGribDataStore(AbstractDataStore):
      """
      Implements the ``xr.AbstractDataStore`` read-only API for a GRIB file.
      """
      def __init__(self, filename, lock=None, **backend_kwargs):
          import cfgrib
          if lock is None:
              lock = ECCODES_LOCK
          self.lock = ensure_lock(lock)
          self.ds = cfgrib.open_file(filename, **backend_kwargs)
  
      def open_store_variable(self, name, var):
          if isinstance(var.data, np.ndarray):
              data = var.data
          else:
              wrapped_array = CfGribArrayWrapper(self, var.data)
              data = indexing.LazilyOuterIndexedArray(wrapped_array)
  
          encoding = self.ds.encoding.copy()
          encoding['original_shape'] = var.data.shape
  
          return Variable(var.dimensions, data, var.attributes, encoding)
  
      def get_variables(self):
          return FrozenOrderedDict((k, self.open_store_variable(k, v))
                                   for k, v in self.ds.variables.items())
  
      def get_attrs(self):
          return Frozen(self.ds.attributes)
  
      def get_dimensions(self):
          return Frozen(self.ds.dimensions)
  
      def get_encoding(self):
          dims = self.get_dimensions()
          encoding = {
              'unlimited_dims': {k for k, v in dims.items() if v is None},
          }
          return encoding
  