/usr/lib/python2.7/dist-packages/pyferret/feraggdset.py is in python-ferret 7.3-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | '''
Represents an aggregation of data sets
'''
from __future__ import print_function
import sys
import os
import tempfile
import pyferret
from pyferret.ferdset import _anonymous_dataset_qualifier
class FerAggDSet(pyferret.FerDSet):
'''
An aggregation of data sets and the variables they have in common
'''
def __init__(self, name, dsets, along='T', title='', warn=True, hide=False):
'''
Aggregates the given list of datasets along the given axis using the
Ferret "DEFINE DATA /AGGREGATE" command. Creates a FerVar for each data
variable in common among these datasets, and assigns it as an attribute
of this class instance using the variable name.
name (string): Ferret name for this aggregated dataset
dsets (sequence of strings and/or FerDSets): datasets to aggregate.
A string will be interpreted as a filename for creating a FerDSet.
along ('T', 'E', 'F'): axis along which to aggregate the datasets
title (string): title for the dataset for plots and listing;
if not given, the Ferret name for the dataset will be used
warn (bool): issue warning messages about variables not in common among
all member datasets (either not present or not using the same grid)
hide (bool): hide the member datasets in standard Ferret listings
such as with pyferret.showdata()
'''
# Create an empty dataset with the given Ferret name
super(FerAggDSet, self).__init__('', qual=_anonymous_dataset_qualifier)
if not isinstance(name, str):
raise ValueError('Ferret name for the aggregate dataset must be astring')
aggname = name.strip()
if not aggname:
raise ValueError('Ferret name for the aggregate dataset is blank')
self._filename = aggname
self._dsetname = aggname
# Need to keep the given order of component datasets
self._compdsetnames = [ ]
# But still use a dictionary with uppercase names for keys
self._compdsets = { }
if along not in ('T', 'E', 'F'):
raise ValueError("along must be one of 'T', 'E', or 'F'")
self._along = along
self._comphidden = bool(hide)
# Create a Ferret string variable containing all the dataset names to be aggregated
if not ( isinstance(dsets, tuple) or isinstance(dsets, list) ):
raise ValueError('dsets must be a tuple or list of strings and/or FerDSets')
filesfile = tempfile.NamedTemporaryFile(mode='w', delete=False,
prefix=aggname + '_', suffix='_agg.txt')
filesfilename = filesfile.name
deletefilesfile = True
try:
for myitem in dsets:
if isinstance(myitem, str):
mydset = pyferret.FerDSet(myitem)
elif isinstance(myitem, pyferret.FerDSet):
mydset = myitem
else:
raise ValueError('dsets must be a tuple or list of strings and/or FerDSets')
if mydset._dsetname.upper() in self._compdsets:
raise ValueError('duplicate dataset name ' + mydset._dsetname)
print(mydset._dsetname, file=filesfile)
self._compdsetnames.append(mydset._dsetname)
self._compdsets[mydset._dsetname.upper()] = mydset
deletefilesfile = False
finally:
filesfile.close()
if deletefilesfile:
os.unlink(filesfilename)
filesvarname = aggname + "_datafile_names"
cmdstr = 'LET ' + filesvarname + ' = SPAWN("cat \'' + filesfilename + '\'")'
(errval, errmsg) = pyferret.run(cmdstr)
if errval != pyferret.FERR_OK:
os.unlink(filesfilename)
raise ValueError(errmsg)
# filesfile not read (SPAWN command executed) until filesvarname is needed
# Create the DEFINE DATA /AGGREGATE Ferret command, creating
# and saving component FerDSets as needed
cmdstr = 'DEFINE DATA/AGGREGATE/' + self._along
if title:
cmdstr += '/TITLE="' + str(title) + '"'
if not warn:
cmdstr += '/QUIET'
if self._comphidden:
cmdstr += '/HIDE'
cmdstr += ' ' + aggname + ' = ' + filesvarname
(errval, errmsg) = pyferret.run(cmdstr)
# filesfile now read so can delete it
os.unlink(filesfilename)
if errval != pyferret.FERR_OK:
raise ValueError(errmsg)
# create a FerVar for each variable in this dataset
namesdict = pyferret.getstrdata('..varnames')
for varname in namesdict['data'].flatten():
if sys.version_info[0] > 2:
# For Python3.x, namesdict['data'] is a NumPy array of bytes; convert to unicode
varname = str(varname, 'UTF-8')
# create a FerVar representing this existing Ferret aggregated file variable
filevar = pyferret.FerVar()
filevar._markasknownvar(varname, self._dsetname, True)
# assign this FerVar - uppercase the variable name keys to make case-insensitive
self._fervars[varname.upper()] = filevar
# keep a original-case version of the name
self._fervarnames.add(varname)
def __repr__(self):
'''
Representation to of this FerAggDSet.
Includes the variable names as variables can be added after creation.
'''
infostr = "FerAggDSet(name='%s', dsets=%s, along='%s', hide=%s) with variables %s" % \
(self._dsetname, str(self._compdsetnames), self._along,
str(self._comphidden), str(self.fernames(sort=True)))
return infostr
def __eq__(self, other):
'''
Two FerAggDSets are equal if their Ferret names, lists of aggregated
dataset names, aggregation axis, component dataset hidden status, and
dictionary of FerVar are variables all equal. All string values are
compared case-insensitive.
'''
if not isinstance(other, pyferret.FerDSet):
return NotImplemented
if not isinstance(other, FerAggDSet):
return False
if not super(FerAggDSet, self).__eq__(other):
return False
if self._along != other._along:
return False
if self._comphidden != other._comphidden:
return False
if len(self._compdsetnames) != len(other._compdsetnames):
return False
for k in range(len(self._compdsetnames)):
if self._compdsetnames[k].upper() != other._compdsetnames[k].upper():
return False
return True
def __ne__(self, other):
'''
Two FerDSets are not equal if their Ferret names, lists of aggregated
dataset names, or dictionary of FerVar variables are not equal.
All string values are compared case-insensitive.
'''
if not isinstance(other, pyferret.FerDSet):
return NotImplemented
return not self.__eq__(other)
def getdsetnames(self):
'''
Returns a copy of the list of component dataset names (original-case)
in the order of their aggregation.
'''
return list(self._compdsetnames)
def getdsets(self):
'''
Returns a list of component FerDSet datasets
in the order of their aggregation.
'''
return [ self._compdsets[name.upper()] for name in self._compdsetnames ]
def close(self):
'''
Removes (cancels) all the variables in Ferret associated with this dataset,
then closes (cancels) this dataset in Ferret. If the aggregated dataset was
created with hide=True, this will close (cancel) all the component datasets
as well; otherwise the component datasets and dataset names will remain here
and in Ferret. Raises a ValueError if there is a problem.
'''
# if the dataset is already closed, ignore this command
if not self._dsetname:
return
# run the Ferret CANCEL commands in FerDSet.close
super(FerAggDSet, self).close()
# if component datasets were hidden, the above close also closed all the
# component datasets, so also clear the component dataset information
if self._comphidden:
self._compdsets.clear()
self._compdsetnames = [ ]
|