Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

#!/usr/bin/env python 

 

""" 

@file ion/services/dm/ingestion/cdm_attribute_methods.py 

@author David Stuebe 

 

@Brief Methods for merging CDM Dataset attributes 

 

Loosely based on Porter-Duff Image Compositing rules 

""" 

 

# Get the object decorator used on wrapper methods! 

from ion.core.object.object_utils import _gpb_source 

 

import ion.util.ionlog 

log = ion.util.ionlog.getLogger(__name__) 

 

import time, calendar 

from ion.core.object.gpb_wrapper import OOIObjectError 

from ion.util import procutils as pu 

 

@_gpb_source 

def MergeAttSrc(self, attname, src): 

    """ 

    The Source overwrites the destination 

 

    @param self - the destination Variable or Group to be modified 

    @param attname - the name of the attribute to merge 

    @param src - the source Variable or Group to be applied to the destination 

     

    """ 

    # @raise OOIObjectError: When the named attribute in src and the named attribute in dst have mismatched types 

    # @note: Check if MyId of src att is the same as MyId of dst att - a shortcut for equality! 

    # @todo: Type checking -- ensure src and dest are groups or variables 

 

 

    # Grap the attribute objects from both sources 

    (src_att, dst_att) = _get_attribs(src, self, attname) 

 

    if src_att is None: 

        log.info('Source attribute is None and cannot be merged into Dest.  Attributes will remain unchanged') 

        return None 

 

    if dst_att is None: 

        # Add the attribute anew 

        log.debug('Adding new attribute into destination') 

        self.AddAttribute(attname, src_att.GetDataType(), src_att.GetValues()) 

        return None 

 

    if src_att.MyId == dst_att.MyId: 

        log.debug('Src and Dst attributes are the same.  Attributes will remain unchanged') 

        return None 

 

 

    # Replace the existing attribute 

    # @todo: Should we manually remove the old attribute first?  If we do 

    #        we need not be concerned with the matching of attribute types 

#        if not dst_att.IsSameType(src_att): 

#            raise OOIObjectError('Attributes have mismatched types according to "Attribute.IsSameType(...)"') 

    log.debug('Copying src attribute into destination') 

    self.SetAttribute(attname, src_att.GetValues(), src_att.GetDataType()) 

 

 

    return None 

 

@_gpb_source 

def MergeAttDst(self, attname, src): 

    """ 

    The Destination is unchanged - ignore the source - a NoOp! 

 

    @param self - the destination Variable or Group to be modified 

    @param attname - the name of the attribute to merge 

    @param src - the source Variable or Group to be applied to the destination 

 

    """ 

    # NO-OP 

    return None 

 

@_gpb_source 

def MergeAttGreater(self, attname, src): 

    """ 

    Keep the greater of the two attribute values 

 

    @param self - the destination Variable or Group to be modified 

    @param attname - the name of the attribute to merge 

    @param src - the source Variable or Group to be applied to the destination 

 

    """ 

    # @note: Check if MyId of src att is the same as MyId of dst att - a shortcut for equality! 

    # @todo: Type checking -- ensure src and dest are groups or variables 

 

 

    # Grap the attribute objects from both sources 

    (src_att, dst_att) = _get_attribs(src, self, attname) 

 

    if src_att is None: 

        log.info('Source attribute is None and cannot be merged into Dest.  Attributes will remain unchanged') 

        return None 

 

    if dst_att is None: 

        log.info('Dest attribute is None and will be disregarded.  Source will replace Dest') 

        self.AddAttribute(attname, src_att.GetDataType(), src_att.GetValues()) 

        return None 

 

    # @todo: Ensure the length of the attribute list is exactly ONE 

 

 

    src_val = self._GetNumericValue(src_att.GetDataType(), src_att.GetValue()) 

    dst_val = self._GetNumericValue(dst_att.GetDataType(), dst_att.GetValue()) 

 

    if pu.isnan(src_val) or pu.isnan(dst_val): 

        raise ValueError('Cannot merge valid attributes with NaN values for attribute "%s". SRC: %s.   DST: %s' % (attname, str(src_val), str(dst_val))) 

 

    if src_val > dst_val: 

        self.SetAttribute(attname, src_att.GetValues(), src_att.GetDataType()) 

    elif dst_val > src_val: 

        pass # NO-OP (dst_val is already set in the destination) 

    else: 

        log.info('Src and Dst attribute values are the same.  Attributes will remain unchanged') 

 

 

    return None 

 

@_gpb_source 

def MergeAttLesser(self, attname, src): 

    """ 

    Keep the lesser of the two attribute values 

 

    @param self - the destination Variable or Group to be modified 

    @param attname - the name of the attribute to merge 

    @param src - the source Variable or Group to be applied to the destination 

 

    """ 

    # @note: Check if MyId of src att is the same as MyId of dst att - a shortcut for equality! 

    # @todo: Type checking -- ensure src and dest are groups or variables 

 

 

    # Grap the attribute objects from both sources 

    (src_att, dst_att) = _get_attribs(src, self, attname) 

 

    if src_att is None: 

        log.info('Source attribute is None and cannot be merged into Dest.  Attributes will remain unchanged') 

        return None 

 

    if dst_att is None: 

        log.info('Dest attribute is None and will be disregarded.  Source will replace Dest') 

        self.AddAttribute(attname, src_att.GetDataType(), src_att.GetValues()) 

        return None 

 

    # @todo: Ensure the length of the attribute list is exactly ONE 

 

 

    src_val = self._GetNumericValue(src_att.GetDataType(), src_att.GetValue()) 

    dst_val = self._GetNumericValue(dst_att.GetDataType(), dst_att.GetValue()) 

 

 

    if pu.isnan(src_val) or pu.isnan(dst_val): 

        raise ValueError('Cannot merge valid attributes with NaN values for attribute "%s". SRC: %s.   DST: %s' % (attname, str(src_val), str(dst_val))) 

 

    if src_val < dst_val: 

        self.SetAttribute(attname, src_att.GetValues(), src_att.GetDataType()) 

    elif dst_val < src_val: 

        pass # NO-OP (dst_val is already set in the destination) 

    else: 

        log.info('Src and Dst attribute values are the same.  Attributes will remain unchanged') 

 

 

    return None 

 

@_gpb_source 

def MergeAttDstOver(self, attname, src): 

    """ 

    Merge the Destination over the Source. Use case: Global Att - history 

    Deduplicate the list of attrs and append the dest. 

 

    Add more examples! 

 

    @param self - the destination Variable or Group to be modified 

    @param attname - the name of the attribute to merge 

    @param src - the source Variable or Group to be applied to the destination 

 

    """ 

 

    # - Check if MyId of src att is the same as MyId of dst att - a shortcut for equality! 

 

 

    return None 

 

 

def _get_attribs(src, dst, attname): 

    src_att = None 

    dst_att = None 

    if src.HasAttribute(attname): 

        try: 

            src_att = src.FindAttributeByName(attname) 

        except OOIObjectError, ex: 

            log.warn("Error finding attribute by name.  Cause: %s" % str(ex)) 

 

    if dst.HasAttribute(attname): 

        try: 

            dst_att = dst.FindAttributeByName(attname) 

        except OOIObjectError, ex: 

            log.warn("Error finding attribute by name.  Cause: %s" % str(ex)) 

 

    return (src_att, dst_att) 

 

@_gpb_source 

def _GetNumericValue(self, data_type, value): 

 

    def _norm_string(val): 

        result = 0 

        if ':' in val: 

            result = calendar.timegm(time.strptime(val, '%Y-%m-%dT%H:%M:%SZ')) 

        elif '.' in val: 

            result = float(val) 

        else: 

            result = int(val) # int() method will  upcast to long if necessary! 

        return result 

 

    _get_numeric_value = { 

                            self.DataType.BYTE        : lambda val: val, 

                            self.DataType.SHORT       : lambda val: val, 

                            self.DataType.INT         : lambda val: val, 

                            self.DataType.LONG        : lambda val: val, 

                            self.DataType.FLOAT       : lambda val: val, 

                            self.DataType.DOUBLE      : lambda val: val, 

                            self.DataType.CHAR        : lambda val: ord(val), 

                            self.DataType.STRING      : lambda val: _norm_string(val), 

                            # self.DataType.STRUCTURE -- recursive merge not supported 

                            # self.DataType.SEQUENCE  -- recursive merge not supported 

                            self.DataType.ENUM        : lambda val: int(val) 

                            # self.DataType.OPAQUE 

                      } 

    return _get_numeric_value[data_type](value) 

 

 

''' 

 

#----------------------------# 

# Application Startup 

#----------------------------# 

:: bash :: 

bin/twistd -n cc -h localhost -a sysname=cdmtest,register=demodata res/apps/resource.app 

 

 

#------------------------------------# 

# Prepare Dataset Groups for Testing 

#------------------------------------# 

from datetime import datetime 

from ion.services.coi.datastore_bootstrap.ion_preload_config import SAMPLE_TRAJ_DATASET_ID, SAMPLE_PROFILE_DATASET_ID, SAMPLE_TRAJ_DATA_SOURCE_ID, SAMPLE_PROFILE_DATA_SOURCE_ID 

from ion.services.coi.resource_registry.resource_client import ResourceClient, ResourceInstance 

rc = ResourceClient(proc=sup) 

ds_deferred = rc.get_instance(SAMPLE_PROFILE_DATASET_ID) 

 

ds = ds_deferred.result 

group1 = ds.root_group 

title1 = group1.FindAttributeByName('title') 

group2 = group1.AddGroup('new_group') 

title2 = group2.AddAttribute('title', group2.DataType.STRING, '!! Brand New Title !!') 

min_lat1 = group1.FindAttributeByName('ion_geospatial_lat_min') 

min_lat2 = group2.AddAttribute('ion_geospatial_lat_min', group2.DataType.DOUBLE, 45.352) 

time_start1 = group1.FindAttributeByName('ion_time_coverage_end') 

time_start2 = group2.AddAttribute('ion_time_coverage_end', group2.DataType.STRING, datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')) 

 

min_lat1.IsSameType(min_lat2) 

title1.IsSameType(title2) 

 

title1.GetValue() 

title2.GetValue() 

 

 

#-----------------------------# 

# Start testing merge methods 

#-----------------------------# 

from ion.services.dm.ingestion.cdm_attribute_methods import * 

 

group1.FindAttributeByName('ion_time_coverage_end').GetValue() 

group2.FindAttributeByName('ion_time_coverage_end').GetValue() 

MergeAttGreater(group1, 'ion_time_coverage_end', group2) 

group1.FindAttributeByName('ion_time_coverage_end').GetValue() 

group2.FindAttributeByName('ion_time_coverage_end').GetValue() 

 

 

group2.HasAttribute('blamo') 

MergeAttDst(group2, 'blamo', group1) 

group2.HasAttribute('blamo') 

 

group2.HasAttribute('history') 

MergeAttSrc(group2, 'history', group1) 

group2.FindAttributeByName('history').GetValues() 

 

 

 

 

'''