Package gavo :: Package votable :: Module enc_tabledata
[frames] | no frames]

Source Code for Module gavo.votable.enc_tabledata

  1  """ 
  2  Encoding to tabledata. 
  3  """ 
  4   
  5  #c Copyright 2008-2019, the GAVO project 
  6  #c 
  7  #c This program is free software, covered by the GNU GPL.  See the 
  8  #c COPYING file in the source distribution. 
  9   
 10   
 11  import datetime #noflake: used in generated code 
 12   
 13  from gavo import utils #noflake: used in generated code 
 14  from gavo.utils import stanxml 
 15  from gavo.utils import pgsphere #noflake: used in generated code 
 16  from gavo.votable import coding 
 17  from gavo.votable import common 
 18   
 19   
20 -def _getArrayShapingCode(field, padder):
21 """returns common code for almost all array serialization. 22 23 Field must describe an array (as opposed to a single value). 24 25 padder must be python-source for whatever is used to pad 26 arrays that are too short. 27 """ 28 base = [ 29 "if val is None: val = []"] 30 if field.isMultiDim(): 31 # it's an nD array (n>1): flatten out all values 32 base.append("val = coding.ravel(val)") 33 if field.hasVarLength(): 34 return base 35 else: 36 return base+["val = coding.trim(val, %s, %s)"%( 37 field.getLength(), padder)]
38 39
40 -def _addNullvalueCode(field, src, validator, defaultNullValue=None):
41 """adds code handle null values where not default representation exists. 42 """ 43 nullvalue = coding.getNullvalue(field, validator) 44 if nullvalue is None: 45 if defaultNullValue is None: 46 action = (" raise common.BadVOTableData('None passed for field" 47 " that has no NULL value', None, '%s', hint='Integers in VOTable" 48 " have no natural serializations for missing values. You need to" 49 " define one using values null to allow for NULL in integer columns')" 50 )%field.getDesignation() 51 else: 52 action = (" tokens.append(%r)"%stanxml.escapePCDATA(defaultNullValue)) 53 else: 54 action = " tokens.append(%r)"%stanxml.escapePCDATA(nullvalue) 55 return [ 56 'if val is None:', 57 action, 58 'else:']+common.indentList(src, " ")
59 60
61 -def _makeFloatEncoder(field):
62 return [ 63 "if val is None or val!=val:", # NaN is a null value, too 64 " tokens.append('NaN')", 65 "else:", 66 " tokens.append(repr(float(val)))"]
67 68
69 -def _makeComplexEncoder(field):
70 return [ 71 "if val is None:", 72 " tokens.append('NaN NaN')", 73 "else:", 74 " try:", 75 " tokens.append('%s %s'%(repr(val.real), repr(val.imag)))", 76 " except AttributeError:", 77 " tokens.append(repr(val))",]
78 79
80 -def _makeBooleanEncoder(field):
81 return [ 82 "if val is None:", 83 " tokens.append('?')", 84 "elif val:", 85 " tokens.append('1')", 86 "else:", 87 " tokens.append('0')",]
88 89
90 -def _makeUByteEncoder(field):
91 return _addNullvalueCode(field, [ 92 "if isinstance(val, int):", 93 ' tokens.append(str(val))', 94 "else:", 95 ' tokens.append(str(ord(val[:1])))',], 96 common.validateVOTInt, "")
97 98
99 -def _makeIntEncoder(field):
100 return _addNullvalueCode(field, [ 101 "tokens.append(str(val))"], 102 common.validateVOTInt)
103 104
105 -def _makeCharEncoder(field):
106 src = [] 107 108 src.extend(common.getXtypeEncoderCode(field)) 109 src.append("val = coding.trimString(val, %s)"%repr(field.arraysize)) 110 111 if field.datatype=="char": 112 src.extend([ 113 'if isinstance(val, unicode):', 114 ' val = val.encode("ascii", "replace")']) 115 116 src.extend([ 117 "tokens.append(stanxml.escapePCDATA(val))"]) 118 119 return _addNullvalueCode(field, src, lambda _: True, "")
120 121 122 _encoders = { 123 'boolean': _makeBooleanEncoder, 124 'bit': _makeIntEncoder, 125 'unsignedByte': _makeUByteEncoder, 126 'short': _makeIntEncoder, 127 'int': _makeIntEncoder, 128 'long': _makeIntEncoder, 129 'char': _makeCharEncoder, 130 'unicodeChar': _makeCharEncoder, 131 'float': _makeFloatEncoder, 132 'double': _makeFloatEncoder, 133 'floatComplex': _makeComplexEncoder, 134 'doubleComplex': _makeComplexEncoder, 135 } 136 137
138 -def _getArrayEncoderLinesNotNULL(field):
139 """returns python lines to encode array values of field. 140 141 Again, the specs are a bit nuts, so we end up special casing almost 142 everything. 143 144 For fixed-length arrays we enforce the given length by 145 cropping or adding nulls (except, currently, for bit and char arrays). 146 """ 147 type = field.datatype 148 # bit array literals are integers, real special handling 149 if type=="bit": 150 return ['tokens.append(utils.toBinary(val))'] 151 # char array literals are strings, real special handling 152 if type=='char' or type=='unicodeChar': 153 return _makeCharEncoder(field) 154 155 src = common.getXtypeEncoderCode(field) 156 src.extend(_getArrayShapingCode(field, '[None]')) 157 src.extend([ # Painful name juggling to avoid functions 158 'fullTokens = tokens', 159 'tokens = []', 160 'arr = val']) 161 162 src.extend(['for val in coding.ravel(arr):']+common.indentList( 163 _encoders[type](field), " ")) 164 src.append("fullTokens.append(' '.join(tokens))") 165 src.append("tokens = fullTokens") 166 return src
167 168
169 -def _getArrayEncoderLines(field):
170 """returns python lines to encode array values of field. 171 172 This will encode NULL array as empty strings. 173 """ 174 return [ 175 "if val is None:", 176 " tokens.append('')", 177 "else:",]+common.indentList(_getArrayEncoderLinesNotNULL(field), " ")
178 179
180 -def getLinesFor(field):
181 """returns a sequence of python source lines to encode values described 182 by field into tabledata. 183 """ 184 if field.isScalar(): 185 return _encoders[field.datatype](field) 186 else: 187 return _getArrayEncoderLines(field)
188 189
190 -def getPostamble(tableDefinition):
191 return [ 192 "return '<TR>%s</TR>'%(''.join('<TD>%s</TD>'%v for v in tokens))"]
193 194
195 -def getGlobals(tableDefinition):
196 return globals()
197