Toward a Better Python Feature API
Previously, I asserted that the Python Cartographic Library feature API was superior to anything generated trivially from C++ code (even excellent C++) by SWIG. Of course, even PCL's API can be improved. I've been inspired by Django's database abstraction API to experiment with something even easier to use. Friday night I hacked on PCL's GeoRSS module, and tied up loose ends this afternoon. See branches/PCL-newfeatureapi/PCL-GeoRSS.
Feature sources are absent from the new API. A feature type class has a query manager attribute, features, and methods of this object provide iterators over features. For example, let's find items of a GeoRSS in a region of interest using a bounding box filter:
>>> url = 'http://pleiades.stoa.org/places/settlement.atom' >>> store = GeoRSSFeatureStore(url) >>> Entry = store.featuretype('entry') >>> Entry.features.count 230 # Filter for intersection with a # (29dE, 36dN, 30dE, 37dN) bounding box >>> features = [f for f in Entry.features.filter( ... bbox=(29.0, 36.0, 30.0, 37.0) ... ) ... ] >>> len(features) 62 # Inspect the first feature >>> f = features >>> f.id 'http://pleiades.stoa.org/places/638749' >>> f.properties.title u'Antiphellos/Habesos' >>> f.properties.the_geom.toWKT() 'POINT (29.6370000000000005 36.1931999999999974)' >>> type(f.context) <class 'feedparser.FeedParserDict'>
A GeoRSS feature's context is a reference to that item's parsed data structure. Everything feedparser can glean about the item (and that's nearly everything) is thereby available to a programmer.
Here's an example, using a better feed, of using a Python filter expression to obtain an iterator over only certain items tagged "web":
>>> url = 'http://sgillies.net/blog/feeds/entries/' >>> store = GeoRSSFeatureStore(url) >>> Entry = store.featuretype('entry') >>> Entry.features.count 31 >>> features = [f for f in Entry.features.filter( ... properties="'web' in f.tags" ... ) ... ] >>> len(features) 12 >>> f = features >>> f.id 'http://sgillies.net/blog/entries/412' >>> f.properties.title u'GeoRSS and Validation' >>> f.properties.tags [u'web'] >>> f.properties.the_geom.toWKT() 'POINT (-105.0958300000000065 40.5869900000000001)' # More detail about the tags, via the feature context >>> tag = f.context.tags >>> tag.term u'web' >>> tag.scheme u'http://sgillies.net/blog/categories/' >>> tag.label u'Web'
That's dirt simple. Following the Django lead, creating and saving new features ought to be as straightforward as:
>>> new_georss_entry = Entry(title=u'GeoRSS Everywhere', ...) >>> new_georss_entry.save() >>> Entries.features.count 32