Source code for sofa.access.proxy

# Copyright (c) 2019 Jannika Lossner
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

"""Classes for accessing arrays and data in the underlying :class:`netCDF4.Dataset`.
"""

[docs]class ProxyObject: """Proxy object that provides access to variables and attributes of a name group in the netCDF4 dataset""" def __init__(self, database, name): self._database = database self._name = name self.standard_dimensions = dict() return @property def database(self): return self._database @property def name(self): return self._name @property def dataset(self): try: return self._dataset except: if self.database is None: return None return self.database.dataset @dataset.setter def dataset(self, value): try: self._dataset = value except: raise @staticmethod def _valid_data_name(name): if "_" in name: return False if name in ["name", "database", "dataset", "Metadata", "Variables", "Type", "Units"]: return False return True def _get_dataset_value_or_none(self, name): if self.dataset is None: raise Exception("No dataset open!") if not ProxyObject._valid_data_name(name): raise Exception("{0} is not a valid name for a dataset value.") container_name = self.name + name if container_name in self.database.Variables.list_variables(): # attribute is a variable, return proper access class var = self.database.Variables.get_variable(container_name) if "S" not in var.dimensions(): return var else: return self.database.Variables.get_string_array(container_name) elif container_name in self.database.Metadata.list_attributes(): # attribute is an attribute in the netcdf-4 dataset return self.database.Metadata.get_attribute(container_name) else: return None def __getattribute__(self, name): try: return super().__getattribute__(name) except AttributeError: if not ProxyObject._valid_data_name(name): raise value = self._get_dataset_value_or_none(name) if value is None: print(self.name+name, "not part of .SOFA dataset") raise return value def __setattr__(self, name, value): if not ProxyObject._valid_data_name(name) or self.dataset is None: super().__setattr__(name, value) return existing = self._get_dataset_value_or_none(name) if existing is None: if type(value) == str: # attempting to set an attribute print("Adding attribute {0} to .SOFA dataset".format(self.name+name)) self.create_attribute(name, value) return raise AttributeError("{0} not part of {1}, use create_... instead.".format(name, self.name)) # we don't know what or where it should be container_name = self.name + name if type(value) == str: self.database.Metadata.set_attribute(container_name, value) return try: existing.set_values(value) except: print("Failed to set values on", container_name, "directly, use set_values instead.") raise
[docs] def create_attribute(self, name, value=""): """Creates the attribute in the netCDF4 dataset with its full name self.name+name Parameters ---------- name : str Name of the variable value : str, optional Initial value of the attribute """ self.database.Metadata.create_attribute(self.name + name, value=value)
[docs] def create_variable(self, name, dims, data_type="d", fill_value=0): """Creates the variable in the netCDF4 dataset with its full name self.name+name Parameters ---------- name : str Name of the variable dims : tuple(str) Dimensions of the variable Returns ------- value : `sofa.access.Variable` Access object for the variable """ if name in self.standard_dimensions: std_dims = self.standard_dimensions[name] if dims not in std_dims: raise ValueError("Dimensions {0} not standard: {1}".format(dims, std_dims)) return self.database.Variables.create_variable(self.name + name, dims, data_type=data_type, fill_value=fill_value)
[docs] def create_string_array(self, name, dims): """Creates the string array in the netCDF4 dataset with its full name self.name+name Parameters ---------- name : str Name of the variable dims : tuple(str) Dimensions of the variable Returns ------- value : `sofa.access.StringArray` Access object for the string array """ if name in self.standard_dimensions: std_dims = self.standard_dimensions[name] if dims not in std_dims: raise ValueError("Dimensions {0} not standard: {1}".format(dims, std_dims)) return self.database.Variables.create_string_array(self.name + name, dims)
# @property # def Description(self): # """Informal description of the object""" # return self.database.__getattribute__(self.name + "Description") # @Description.setter # def Description(self, value): # self.database.__setattr__(self.name + "Description", value)