1 """
2 A simplified API to single-table VOTables.
3
4 The basic idea is: open(...) -> (table, metadata),
5
6 where table is a numpy array.
7 """
8
9
10
11
12
13
14
15 from cStringIO import StringIO
16
17 try:
18 import numpy
19
20
21 numpyType = {
22 "short": numpy.int16,
23 "int": numpy.int32,
24 "long": numpy.int64,
25 "float": numpy.float32,
26 "double": numpy.float64,
27 "boolean": numpy.bool,
28 "char": numpy.str_,
29 "floatComplex": numpy.complex64,
30 "doubleComplex": numpy.complex128,
31 "unsignedByte": numpy.uint8,
32 "unicodeChar": numpy.unicode_
33 }
34 except ImportError:
35
36 pass
37
38 from gavo.votable import votparse
39 from gavo.votable import tablewriter
40 from gavo.votable.model import VOTable as V
41
42
43
76
77
78 -def makeDtype(tableMetadata, defaultStringLength=20):
79 """returns an record array datatype for a given table metadata.
80
81 defaultStringLength lets you specify a length for char(*) fields;
82 since makeDtype has no access to the tabular data and numpy insists on
83 having string length, DaCHS needs to guess here.
84
85 If this isn't fine-grained enough for you, you can always path tableMetadata,
86 replacing * arraysizes with more appropriate values in individual
87 cases.
88 """
89 dtypes = []
90 seen = set()
91 for f in tableMetadata:
92 name = f.getDesignation().encode('ascii', 'ignore')
93 while name in seen:
94 name = name+"_"
95 seen.add(name)
96 shape = f.getShape()
97 if shape is None:
98
99
100
101 if f.datatype=="char":
102
103 if f.arraysize=="*":
104 dtypes.append((name, "a", defaultStringLength))
105 elif f.arraysize is None:
106 dtypes.append((name, "a", 1))
107 else:
108
109 dtypes.append((name, "a", int(f.arraysize)))
110
111 else:
112 dtypes.append((name, numpyType[f.datatype]))
113
114 else:
115 dtypes.append((
116 name,
117 numpyType[f.datatype],
118 shape))
119 return dtypes
120
121
122 -def load(source, raiseOnInvalid=True):
123 """returns (data, metadata) from the first table of a VOTable.
124
125 data is a list of records (as a list), metadata a TableMetadata instance.
126
127 source can be a string that is then interpreted as a local file name,
128 or it can be a file-like object.
129 """
130 if isinstance(source, basestring):
131 source = file(source)
132 infos = {}
133
134
135
136
137 rows = None
138 for element in votparse.parse(source, [V.INFO], raiseOnInvalid):
139 if isinstance(element, V.INFO):
140 infos.setdefault(element.name, []).append(element)
141 else:
142 if rows is not None:
143 break
144 fields = TableMetadata(element.tableDefinition, infos)
145 rows = list(element)
146 if rows is None:
147 return None, None
148 return rows, fields
149
150
151 -def loads(stuff, raiseOnInvalid=True):
152 """returns data,metadata for a VOTable literal in stuff.
153 """
154 return load(StringIO(stuff), raiseOnInvalid)
155
156
157 -def save(data, tableDef, destF):
158 """saves (data, tableDef) in VOTable format to destF.
159
160 data is a sequence of tuples, tableDef V.TABLE instance as, for example,
161 obtainable from metadata.votTable as returned by load. data must contain
162 type-right python values that match the table definition.
163
164 A load-save cycle loses all top-level and resource level metadata in the
165 simplified interface. Use the full interface if that hurts you.
166 """
167 root = V.VOTABLE[
168 V.RESOURCE[
169 tablewriter.DelayedTable(tableDef, data, V.BINARY)]]
170 tablewriter.write(root, destF)
171