[Thuban-commits] r2741 - branches/WIP-pyshapelib-bramz/libraries/pyshapelib
scm-commit@wald.intevation.org
scm-commit at wald.intevation.org
Wed Mar 14 00:30:42 CET 2007
Author: bramz
Date: 2007-03-14 00:30:41 +0100 (Wed, 14 Mar 2007)
New Revision: 2741
Modified:
branches/WIP-pyshapelib-bramz/libraries/pyshapelib/ChangeLog
branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pyshapelib_common.h
branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pytest.py
branches/WIP-pyshapelib-bramz/libraries/pyshapelib/shapelib.c
Log:
Added part_types() to SHPObject to return tuple of part types. Added __repr__ operators to return a string that can reconstruct the object using eval()
Modified: branches/WIP-pyshapelib-bramz/libraries/pyshapelib/ChangeLog
===================================================================
--- branches/WIP-pyshapelib-bramz/libraries/pyshapelib/ChangeLog 2007-03-13 23:17:33 UTC (rev 2740)
+++ branches/WIP-pyshapelib-bramz/libraries/pyshapelib/ChangeLog 2007-03-13 23:30:41 UTC (rev 2741)
@@ -1,5 +1,14 @@
2007-03-12 Bram de Greve <bram.degreve at gmail.com>
+ * shapelib.c, shapelib_common.h: Added part_types() to SHPObject to
+ return tuple of part types. Added __repr__ operators to return a
+ string that can reconstruct the object using eval()
+
+ * pytest.py: Added tests for part_types() and __repr__.
+ Humanized the output a bit.
+
+2007-03-12 Bram de Greve <bram.degreve at gmail.com>
+
* shapelib.c, shapelib.i: replaced shapelib.i by shapelib.c to use
hand-crafted Python bindings instead of SWIG generated ones.
Modified: branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pyshapelib_common.h
===================================================================
--- branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pyshapelib_common.h 2007-03-13 23:17:33 UTC (rev 2740)
+++ branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pyshapelib_common.h 2007-03-13 23:30:41 UTC (rev 2741)
@@ -4,8 +4,17 @@
#include <Python.h>
#include <structmember.h>
+/* helper to export constants (macros) to Python.
+ * The constant in Python will have the same name as in C
+ */
#define PYSHAPELIB_ADD_CONSTANT(constant) PyModule_AddIntConstant(module, #constant, constant)
+/* helper to define the type object.
+ *
+ * This assumes quite a few things about different things being available and their name.
+ * For example, if type = Foo, then there should be a deallocation function called Foo_dealloc.
+ * See the macro itself for other examples.
+ */
#define PYSHAPELIB_DEFINE_TYPE(type, name, doc) \
{ \
PyObject_HEAD_INIT(NULL) \
@@ -18,7 +27,7 @@
0, /*tp_getattr*/ \
0, /*tp_setattr*/ \
0, /*tp_compare*/ \
- 0, /*tp_repr*/ \
+ (reprfunc) type ## _repr, /*tp_repr*/ \
0, /*tp_as_number*/ \
0, /*tp_as_sequence*/ \
0, /*tp_as_mapping*/ \
@@ -50,6 +59,9 @@
} \
/**/
+/* helper to add type to module.
+ * Does a bit of the tedious bookkeeping for us
+ */
#define PYSHAPELIB_ADD_TYPE(type, name) \
type.ob_type = &PyType_Type; \
if (PyType_Ready(&type) >= 0) \
@@ -58,6 +70,4 @@
PyModule_AddObject(module, name, (PyObject*)&type); \
}
-
-
#endif
\ No newline at end of file
Modified: branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pytest.py
===================================================================
--- branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pytest.py 2007-03-13 23:17:33 UTC (rev 2740)
+++ branches/WIP-pyshapelib-bramz/libraries/pyshapelib/pytest.py 2007-03-13 23:30:41 UTC (rev 2741)
@@ -4,17 +4,53 @@
# The the shapefile module
#
+print "--- testing shapelib ---"
+
+def test_shpobject(obj):
+ # The vertices method returns the shape as a list of lists of tuples.
+ print "vertices:", obj.vertices()
+
+ # The part_types method returns a tuple with the types of every part
+ print "part_types:", obj.part_types()
+
+ # The extents returns a tuple with two 4-element lists with the min.
+ # and max. values of the vertices.
+ print "extents:", obj.extents()
+
+ # The type attribute is the type code (one of the SHPT* constants
+ # defined in the shapelib module)
+ print "type:", obj.type
+
+ # The id attribute is the shape id
+ print "id:", obj.id
+
+ # the __repr__ method returns a string that can be eval()'ed to
+ # recreate the object. This __repr__ is also used by __str__
+ # and print
+ print "obj:", obj
+ print "reconstruction using __repr__:",
+ obj_repr = repr(obj)
+ obj_copy = eval(obj_repr)
+ if repr(obj_copy) == obj_repr:
+ print "ok"
+ else:
+ print "failed"
+
+
+
def make_shapefile(filename):
+ print "\n* Creating a ShapeFile"
+
# Create a shapefile with polygons
outfile = shapelib.create(filename, shapelib.SHPT_POLYGON)
# Create one very simple polygon and write it to the shapefile. The
# vertices should be given in clockwise order to comply with the
# shapefile specification.
+ print "\nA very simple polygon"
obj = shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
[[(10, 10), (10, 20), (20, 20), (10, 10)]])
- print obj.extents()
- print obj.vertices()
+ test_shpobject(obj)
outfile.write_object(-1, obj)
# Create a polygon with a hole. Note that according to the
@@ -26,18 +62,20 @@
# list of part types, one for each part of the shape. For polygons,
# the part type is always shapelib.SHPP_RING, though. The part
# types are only relevant for SHPT_MULTIPATCH shapefiles.
+ print "\nPolygon with a hole"
obj = shapelib.SHPObject(shapelib.SHPT_POLYGON, 1,
[[(0, 0), (0, 40), (40, 40), (40, 0), (0, 0)],
[(10, 10), (20, 10), (20, 20), (10, 20),(10, 10)],
])
- print obj.extents()
- print obj.vertices()
+ test_shpobject(obj)
outfile.write_object(-1, obj)
# close the file.
outfile.close()
def read_shapefile(filename):
+ print "\n* Reading a ShapeFile"
+
# open the shapefile
shp = shapelib.ShapeFile(filename)
@@ -46,30 +84,21 @@
# the SHPT* constants defined in the shapelib module) and min and
# max are 4-element lists with the min. and max. values of the
# vertices.
- print shp.info()
+ print "info:", shp.info()
- # read_object reads a shape
- obj = shp.read_object(0)
-
- # The vertices method returns the shape as a list of lists of tuples.
- print obj.vertices()[0][:10]
-
- # The extents returns a tuple with two 4-element lists with the min.
- # and max. values of the vertices.
- print obj.extents()
-
- # The type attribute is the type code (one of the SHPT* constants
- # defined in the shapelib module)
- print obj.type
-
- # The id attribute is the shape id
- print obj.id
-
# the cobject method returns a PyCObject containing the shapelib
# SHPHandle. This is useful for passing shapefile objects to
# C-Python extensions.
- print shp.cobject()
+ print "cobject:", shp.cobject()
+
+ n = shp.info()[0]
+ for i in range(n):
+ obj = shp.read_object(i)
+ print "\nread_object(%i):" % i
+ test_shpobject(obj)
+ print "\n* SHPTree:"
+
# build a quad tree from the shapefile. The first argument must be
# the return value of the shape file object's cobject method (this
# is currently needed to access the shape file at the C-level). The
@@ -90,6 +119,8 @@
# Test the DBF file module.
#
+print "\n\n--- testing dbflib ---"
+
def make_dbf(file):
# create a new dbf file and add three fields.
dbf = dbflib.create(file)
Modified: branches/WIP-pyshapelib-bramz/libraries/pyshapelib/shapelib.c
===================================================================
--- branches/WIP-pyshapelib-bramz/libraries/pyshapelib/shapelib.c 2007-03-13 23:17:33 UTC (rev 2740)
+++ branches/WIP-pyshapelib-bramz/libraries/pyshapelib/shapelib.c 2007-03-13 23:30:41 UTC (rev 2741)
@@ -11,6 +11,8 @@
}
PySHPObject;
+/* allocator
+ */
static PyObject* PySHPObject_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
PySHPObject* self;
@@ -19,6 +21,8 @@
return (PyObject*) self;
}
+/* deallocator
+ */
static void PySHPObject_dealloc(PySHPObject* self)
{
SHPDestroyObject(self->shpObject);
@@ -72,6 +76,11 @@
}
/* parts and part_types have to have the same lengths */
+ if (part_type_list == Py_None)
+ {
+ Py_DECREF(part_type_list);
+ part_type_list = NULL;
+ }
if (part_type_list)
{
if (!PySequence_Check(parts))
@@ -203,32 +212,31 @@
/* A multipart shape. Usual for SHPT_ARC and SHPT_POLYGON */
result = PyList_New(object->nParts);
- if (!result)
- return NULL;
+ if (!result)
+ return NULL;
- for (part_idx = 0, vertex_idx = 0; part_idx < object->nParts;
- part_idx++)
- {
- if (part_idx < object->nParts - 1)
- length = (object->panPartStart[part_idx + 1]
- - object->panPartStart[part_idx]);
- else
- length = object->nVertices - object->panPartStart[part_idx];
-
- part = build_vertex_list(object, vertex_idx, length);
- if (!part)
- goto fail;
+ for (part_idx = 0, vertex_idx = 0; part_idx < object->nParts; part_idx++)
+ {
+ if (part_idx < object->nParts - 1)
+ length = (object->panPartStart[part_idx + 1]
+ - object->panPartStart[part_idx]);
+ else
+ length = object->nVertices - object->panPartStart[part_idx];
+
+ part = build_vertex_list(object, vertex_idx, length);
+ if (!part)
+ goto fail;
- if (PyList_SetItem(result, part_idx, part) < 0)
- goto fail;
+ if (PyList_SetItem(result, part_idx, part) < 0)
+ goto fail;
- vertex_idx += length;
+ vertex_idx += length;
+ }
}
- }
else
{
- /* only one part. usual for SHPT_POINT */
- result = build_vertex_list(object, 0, object->nVertices);
+ /* only one part. usual for SHPT_POINT */
+ result = build_vertex_list(object, 0, object->nVertices);
}
return result;
@@ -252,16 +260,16 @@
list = PyList_New(length);
if (!list)
- return NULL;
+ return NULL;
for (i = 0; i < length; i++, index++)
{
- vertex = Py_BuildValue("dd", object->padfX[index],
- object->padfY[index]);
- if (!vertex)
- goto fail;
- if (PyList_SetItem(list, i, vertex) < 0)
- goto fail;
+ vertex = Py_BuildValue("dd", object->padfX[index],
+ object->padfY[index]);
+ if (!vertex)
+ goto fail;
+ if (PyList_SetItem(list, i, vertex) < 0)
+ goto fail;
}
return list;
@@ -272,20 +280,87 @@
return NULL;
}
+
+
+static PyObject* PySHPObject_part_types(PySHPObject* self)
+{
+ int i;
+ PyObject* result = NULL;
+ SHPObject* object = self->shpObject;
+
+ if (object->nParts == 0 || object->panPartType == 0)
+ {
+ Py_RETURN_NONE;
+ }
+
+ result = PyTuple_New(object->nParts);
+ if (!result) return NULL;
+
+ for (i = 0; i < object->nParts; ++i)
+ {
+ /* PyTuple_SetItem steals a reference */
+ PyObject* part_type = PyInt_FromLong((long)object->panPartType[i]);
+ if (!part_type || PyTuple_SetItem(result, i, part_type) < 0) goto fail;
+ }
+ return result;
+
+fail:
+ Py_DECREF(result);
+ return NULL;
+}
+
+
+
static PyObject* PySHPObject_type(PySHPObject* self, void* closure)
{
return PyInt_FromLong(self->shpObject->nSHPType);
}
+
+
static PyObject* PySHPObject_id(PySHPObject* self, void* closure)
{
return PyInt_FromLong(self->shpObject->nShapeId);
}
+
+
+/* return a string that can be feeded to eval() to reconstruct the object,
+ * assuming a proper context
+ */
+static PyObject* PySHPObject_repr(PySHPObject* self)
+{
+ PyObject* format = NULL;
+ PyObject* args = NULL;
+ PyObject* result = NULL;
+
+ format = PyString_FromString("shapelib.SHPObject(%i, %i, %s, %s)");
+ if (!format) return NULL;
+
+ args = Py_BuildValue("iiNN",
+ self->shpObject->nSHPType,
+ self->shpObject->nShapeId,
+ PySHPObject_vertices(self),
+ PySHPObject_part_types(self));
+ if (!args)
+ {
+ Py_DECREF(format);
+ return NULL;
+ }
+
+ result = PyString_Format(format, args);
+ Py_DECREF(args);
+ Py_DECREF(format);
+ return result;
+}
+
+
+
static PyMethodDef PySHPObject_methods[] =
{
{"extents", (PyCFunction)PySHPObject_extents, METH_NOARGS, NULL},
{"vertices", (PyCFunction)PySHPObject_vertices, METH_NOARGS, NULL},
+ {"part_types", (PyCFunction)PySHPObject_part_types, METH_NOARGS, NULL},
{NULL}
};
@@ -308,6 +383,8 @@
}
PyShapeFile;
+/* allocator
+ */
static PyObject* PyShapeFile_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
PyShapeFile* self;
@@ -316,6 +393,8 @@
return (PyObject*) self;
}
+/* constructor
+ */
static int PyShapeFile_init(PyShapeFile* self, PyObject* args, PyObject* kwds)
{
char* file;
@@ -338,6 +417,8 @@
Py_RETURN_NONE;
}
+/* destructor
+ */
static void PyShapeFile_dealloc(PyShapeFile* self)
{
PyShapeFile_close(self);
@@ -405,6 +486,12 @@
return PyCObject_FromVoidPtr(self->handle, NULL);
}
+static PyObject* PyShapeFile_repr(PyShapeFile* self)
+{
+ /* TODO: it would be nice to do something like "shapelib.ShapeFile(filename, mode)" instead */
+ return PyString_FromFormat("<shapelib.ShapeFile object at %p>", self->handle);
+}
+
static PyMethodDef PyShapeFile_methods[] =
{
{"close", (PyCFunction)PyShapeFile_close, METH_NOARGS, "close the shape file" },
More information about the Thuban-commits
mailing list