[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