tokenizer.RowBuilder.c 6.3 KB
Newer Older
1
/*
Kipp Cannon's avatar
Kipp Cannon committed
2
 * Copyright (C) 2007-2009,2014,2017  Kipp C. Cannon
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
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */


/*
 * ============================================================================
 *
 *                         tokenizer.RowBuilder Class
 *
 * ============================================================================
 */


#include <Python.h>
#include <structmember.h>
#include <stdlib.h>
#include <tokenizer.h>


/*
 * ============================================================================
 *
 *                              Row Builder Type
 *
 * ============================================================================
 */


/*
 * Structure
 */


typedef struct {
	PyObject_HEAD
	/* class to be instantiated for new rows */
	PyTypeObject *rowtype;
	/* tuple of attribute names */
	PyObject *attributes;
	/* current row */
	PyObject *row;
	/* current attribute index */
	int i;
	/* the iterable passed to append() */
	PyObject *iter;
} ligolw_RowBuilder;


/*
 * append() method
 */


static PyObject *append(PyObject *self, PyObject *iter)
{
	ligolw_RowBuilder *rowbuilder = (ligolw_RowBuilder *) self;

kipp's avatar
kipp committed
73
	Py_XDECREF(rowbuilder->iter);
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
	rowbuilder->iter = PyObject_GetIter(iter);
	if(!rowbuilder->iter)
		return NULL;

	Py_INCREF(self);
	return self;
}


/*
 * __del__() method
 */


static void __del__(PyObject *self)
{
	ligolw_RowBuilder *rowbuilder = (ligolw_RowBuilder *) self;

92 93 94
	Py_XDECREF(rowbuilder->rowtype);
	Py_XDECREF(rowbuilder->attributes);
	Py_XDECREF(rowbuilder->row);
kipp's avatar
kipp committed
95
	Py_XDECREF(rowbuilder->iter);
96 97 98 99 100 101 102 103 104 105 106 107 108 109

	self->ob_type->tp_free(self);
}


/*
 * __init__() method
 */


static int __init__(PyObject *self, PyObject *args, PyObject *kwds)
{
	ligolw_RowBuilder *rowbuilder = (ligolw_RowBuilder *) self;

110
	if(!PyArg_ParseTuple(args, "OO", &rowbuilder->rowtype, &rowbuilder->attributes))
111 112
		return -1;

113 114
	Py_INCREF(rowbuilder->rowtype);

115
	rowbuilder->attributes = llwtokenizer_build_attributes(rowbuilder->attributes);
116

117
	if(!rowbuilder->attributes)
kipp's avatar
kipp committed
118 119
		return -1;

kipp's avatar
kipp committed
120 121
	rowbuilder->row = Py_None;
	Py_INCREF(rowbuilder->row);
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
	rowbuilder->i = 0;
	rowbuilder->iter = NULL;

	return 0;
}


/*
 * __iter__() method
 */


static PyObject *__iter__(PyObject *self)
{
	Py_INCREF(self);
	return self;
}


/*
 * next() method
 */


static PyObject *next(PyObject *self)
{
	ligolw_RowBuilder *rowbuilder = (ligolw_RowBuilder *) self;
	PyObject *item;

kipp's avatar
kipp committed
151 152 153 154 155
	if(!rowbuilder->iter) {
		PyErr_SetNone(PyExc_StopIteration);
		return NULL;
	}

156
	while((item = PyIter_Next(rowbuilder->iter))) {
157
		int result;
158 159 160 161 162 163 164 165
		if(rowbuilder->row == Py_None) {
			rowbuilder->row = PyType_GenericNew(rowbuilder->rowtype, NULL, NULL);
			if(!rowbuilder->row) {
				rowbuilder->row = Py_None;
				return NULL;
			}
			Py_DECREF(Py_None);
		}
166 167 168 169 170 171
		result = PyObject_SetAttr(rowbuilder->row, PyTuple_GET_ITEM(rowbuilder->attributes, rowbuilder->i), item);
		Py_DECREF(item);
		if(result < 0)
			return NULL;
		if(++rowbuilder->i >= PyTuple_GET_SIZE(rowbuilder->attributes)) {
			PyObject *row = rowbuilder->row;
kipp's avatar
kipp committed
172 173
			rowbuilder->row = Py_None;
			Py_INCREF(rowbuilder->row);
174 175 176 177 178
			rowbuilder->i = 0;
			return row;
		}
	}

kipp's avatar
kipp committed
179
	if(!PyErr_Occurred()) {
180
		PyErr_SetNone(PyExc_StopIteration);
kipp's avatar
kipp committed
181 182 183
		Py_DECREF(rowbuilder->iter);
		rowbuilder->iter = NULL;
	}
184

185 186 187 188 189 190 191 192 193 194 195
	return NULL;
}


/*
 * Type information
 */


static struct PyMemberDef members[] = {
	{"rowtype", T_OBJECT, offsetof(ligolw_RowBuilder, rowtype), 0, "row class"},
196
	{"attributes", T_OBJECT, offsetof(ligolw_RowBuilder, attributes), READONLY, "in-order tuple of attribute names"},
197 198 199 200 201 202 203 204 205 206 207 208
	{"row", T_OBJECT, offsetof(ligolw_RowBuilder, row), 0, "current row object"},
	{"i", T_INT, offsetof(ligolw_RowBuilder, i), 0, "current attribute index"},
	{NULL,}
};


static struct PyMethodDef methods[] = {
	{"append", append, METH_O,
"Append a sequence of tokens to the row builder, returning an iterator for\n"\
"generating a sequence of new row instances.  The tokens argument should be\n"\
"an iterable, producing a sequence of token objects.  If fewer tokens are\n"\
"yielded from the iterable than are required to construct a complete row,\n"\
kipp's avatar
kipp committed
209 210 211
"then the row is stored in its partially-populated state and its\n"\
"construction will continue upon the next invocation.  Note that it is\n"\
"possible that a call to this method will yield no new rows at all.\n"\
212 213 214
"\n"\
"Example:\n"\
"\n"\
Kipp Cannon's avatar
Kipp Cannon committed
215
">>> from ligo.lw import tokenizer\n"\
216 217 218 219
">>> class Row(object):\n"\
"...	pass\n"\
"...\n"\
">>> rows = tokenizer.RowBuilder(Row, [\"time\", \"snr\"])\n"\
220
">>> for row in rows.append([10, 6.8, 15, 29.1]):\n"\
221
"...     print(row.snr)\n"\
Kipp Cannon's avatar
Kipp Cannon committed
222 223 224
"...\n" \
"6.8\n" \
"29.1"
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	},
	{NULL,}
};


PyTypeObject ligolw_RowBuilder_Type = {
	PyObject_HEAD_INIT(NULL)
	.tp_basicsize = sizeof(ligolw_RowBuilder),
	.tp_dealloc = __del__,
	.tp_doc =
"This class provides the logic required to transform a sequence of of tokens\n"\
"parsed out of the delimited text of a Stream element into a sequence of row\n"\
"objects for insertion into a Table element.  An instance of this class is\n"\
"initialized with a Python class to be instantiated to form row objects,\n"\
"and an iterable providing the names of the row class' attributes to which\n"\
"tokens will be assigned in order.\n"\
"\n"\
"Example:\n"\
"\n"\
Kipp Cannon's avatar
Kipp Cannon committed
244
">>> from ligo.lw import tokenizer\n"\
245 246 247 248 249
">>> class Row(object):\n"\
"...     pass\n"\
"...\n"\
">>> t = tokenizer.Tokenizer(u\",\")\n"\
">>> t.set_types([int, float])\n"\
kipp's avatar
kipp committed
250
">>> rows = tokenizer.RowBuilder(Row, [\"time\", \"snr\"])\n"\
251 252
">>> l = list(rows.append(t.append(u\"10,6.8,15,29.1,\")))\n"\
">>> l[0].snr\n"\
253
"6.8\n"\
254
">>> l[1].time\n"\
255
"15",
256
	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
257 258 259 260 261 262 263 264
	.tp_init = __init__,
	.tp_iter = __iter__,
	.tp_iternext = next,
	.tp_members = members,
	.tp_methods = methods,
	.tp_name = MODULE_NAME ".RowBuilder",
	.tp_new = PyType_GenericNew,
};