Skip to content
This repository has been archived by the owner on Oct 18, 2019. It is now read-only.

Commit

Permalink
Basic metaclass magic is working
Browse files Browse the repository at this point in the history
  • Loading branch information
David Stuebe committed Jun 5, 2013
1 parent 7a5ce5f commit fb2e096
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pyc
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
wicken
======

metadata companion library for paegan data model


description
============

Wicken is built on a Object Relational Mapper. It assumes a mapping exists between a flat namespace which will be used as properties in the object classes for ease of access and the schema for a particular data encoding. For instance the schema might be ISO 19115-2 and the data encoding XML, or the schema might be CF and the encoding NetCDF.

Concrete classes implement the _get and _set methods for a particular encoding, while
the class for a particular mapping is generated at run time from a mapping. Most of the magic happens in a few lines of meta programming...


29 changes: 29 additions & 0 deletions example_script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@


from wicken.dogma import NetCDFDogma
from netCDF4 import Dataset

rootGrp = Dataset('myfile.nc','w') # open a new file for read/write...


metadata_beliefs = {
'service_provider_name':'publisher_name',
'service_provider_contact_info':'publisher_email'}
# typically loaded from a file - a modified version of the IOOS Asset_SOS_MAP


# Make metadata object instance using the NetCDFDogma class to work with a NetCDF data objects metadata using CF conventions
metadata = NetCDFDogma('CF',metadata_beliefs, rootGrp)

print 'Class name: ', metadata.__class__.__name__


print metadata.service_provider_name

metadata.service_provider_name = 'ASA'

print metadata.service_provider_name

# Now use the netcdf method...

print metadata._dataObject.ncattrs()
Empty file added wicken/__init__.py
Empty file.
155 changes: 155 additions & 0 deletions wicken/dogma.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
#!/usr/bin/env python
'''
@author David Stuebe <dstuebe@asasscience.com>
@file dogma.py
@date 06/03/13
@description The dogma module provides a metaclass based approach to mapping a flat name
space for class properties to any storage format and metadata schema. Example classes are
implemented for a dictionary storage. A particular mapping from the flat namespace used for
the properties to the metadata schema must be provided at runtime.
'''

from lxml import etree
from netCDF4 import Dataset


class Tenants(object):
def __init__(self, belief, teaching, doc=None):
'''
belief is a string which will become a property of a particular dogma object
teaching is the string, collection or object that is used by the _set and
_get method of this Dogma to map a belieft about what a metadata element should be
called by IOOS to a particular schema, say ISO XML or NetCDF CF.
'''
self.belief = belief
self.teaching = teaching
if doc: self.__doc__ = doc

def __get__(self, dogma, objtype=None):
print '__get__:', self.belief
return dogma._get(self.teaching)

def __set__(self, dogma, value):
print '__set__:',self.belief
dogma._set(self.teaching,value)

def __delete__(self, dogma):
raise NotImplementedError('Can not delete the %s property!' % self.belief)

class MetaReligion(type):

def __call__(cls, religion, beliefs, *args, **kwargs):
'''
cls is the base class which new properties will be added to
religion is the unique prefix for that class and its beliefs (properties)
beliefs is a dictionary that maps property names (IOOS metadata) to a particular schema (ISO, CF, etc)
'''
print 'call: religion: ', religion
print 'call: beliefs: ', beliefs
clsName = religion + cls.__name__
clsDict={}
clsDict['_religion'] = religion
clsDict['_beliefs'] = beliefs


for belief, teaching in beliefs.iteritems():
clsDict[belief] = Tenants(belief, teaching)


clsType = MetaReligion.__new__(MetaReligion, clsName, (cls,), clsDict)


# Finally allow the instantiation to occur, but slip in our new class type
obj = super(MetaReligion, clsType).__call__(religion, beliefs, *args, **kwargs)

return obj



class Dogma(object):
__metaclass__ = MetaReligion

def __init__(self, religion, beliefs, dataObject):
print 'init: religion: ', religion
print 'init: beliefs: ', beliefs
print 'init: dataObect', dataObject

self._dataObject = dataObject



def _get(self, key):
raise NotImplementedError('_get Method is not implemented in the Dogma Base Class!')

def _set(self, key, value):
raise NotImplementedError('_set Method is not implemented in the Dogma Base Class!')


class DictionaryDogma(Dogma):

def __init__(self, religion, beliefs, dataObject=None):

if dataObject is None:
dataObject = {}

if not isinstance(dataObject, dict):
raise TypeError('DictionaryDogma only allows dictionary data objects!')

super(DictionaryDogma, self).__init__(religion, beliefs, dataObject)

def _get(self,key):
return self._dataObject.get(key)

def _set(self,key,value):
self._dataObject.__setitem__(key,value)


class XmlDogma(Dogma):

def __init__(self, religion, beliefs, dataObject=None):

if dataObject is None:
dataObject = etree.Element('root') # ???

if not isinstance(dataObject, etree._Element):
raise TypeError('XmlDogma only allows XML Element data objects!')

super(XmlDogma, self).__init__(religion, beliefs, dataObject)

def _get(self,xpath_args):
return self._dataObject.xpath(*xpath_args).text # Needs testing

def _set(self,key,value):
element = self._dataObject.xpath(*xpath_args)
element.text = value


class NetCDFDogma(Dogma):


def __init__(self, religion, beliefs, dataObject=None):

if dataObject is None: # allow none - what is the title?
dataObject = Dataset('junk_metadata.nc','w')

if not isinstance(dataObject, Dataset):
raise TypeError('NetCDFDogma only allows NetCDF4 Dataset data objects!')

super(NetCDFDogma, self).__init__(religion, beliefs, dataObject)

def _get(self,key):
try:
return getattr(self._dataObject,key)
except AttributeError:
return None

def _set(self,key,value):
setattr(self._dataObject,key,value)

def _write(self):

self._dataObject.close()




54 changes: 54 additions & 0 deletions wicken/etree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# =============================================================================
# OWSLib. Copyright (C) 2005 Sean C. Gillies
#
# Contact email: sgillies@frii.com
# =============================================================================

def patch_well_known_namespaces(etree_module):
"""Monkey patches the etree module to add some well-known namespaces."""
etree_module._namespace_map.update({
"http://www.w3.org/1999/02/22-rdf-syntax-ns#": "rdf",
"http://purl.org/rss/1.0/": "rss",
"http://purl.org/rss/1.0/modules/taxonomy/": "taxo",
"http://purl.org/dc/elements/1.1/": "dc",
"http://purl.org/rss/1.0/modules/syndication/": "syn",
"http://www.w3.org/2003/01/geo/wgs84_pos#": "geo",
"http://www.opengis.net/cat/csw/2.0.2": "csw",
"http://purl.org/dc/terms/": "dct",
"http://www.isotc211.org/2005/gco": "gco",
"http://www.isotc211.org/2005/gmd": "gmd",
"http://www.isotc211.org/2005/gts": "gts",
"http://www.isotc211.org/2005/srv": "srv",
"http://www.fgdc.gov": "fgdc",
"http://gcmd.gsfc.nasa.gov/Aboutus/xml/dif/": "dif",
"http://www.opengis.net/gml": "gml",
"http://www.opengis.net/ogc": "ogc",
"http://www.opengis.net/ows": "ows",
"http://www.opengis.net/ows/1.1": "ows",
"http://www.opengis.net/ows/2.0": "ows",
"http://www.opengis.net/wms": "wms",
"http://www.opengis.net/context": "wmc",
"http://www.opengis.net/wfs": "wfs",
"http://www.opengis.net/sos/1.0": "sos",
"urn:oasis:names:tc:ebxml-regrep:xsd:rim:3.0": "rim",
"http://www.w3.org/2001/XMLSchema": "xs",
"http://www.w3.org/XML/Schema": "xs2",
"http://www.w3.org/2001/XMLSchema-instance": "xsi",
"http://www.w3.org/1999/xlink": "xlink"})

# try to find lxml or elementtree
try:
from lxml import etree
except ImportError:
try:
# Python 2.5 with ElementTree included
import xml.etree.ElementTree as etree
patch_well_known_namespaces(etree)
except ImportError:
try:
# Python < 2.5 with ElementTree installed
import elementtree.ElementTree as etree
patch_well_known_namespaces(etree)
except ImportError:
raise RuntimeError('You need either lxml or ElementTree to use OWSLib!')

25 changes: 25 additions & 0 deletions wicken/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python
'''
@author David Stuebe <dstuebe@asasscience.com>
@file util.py
@date 06/03/13
@description Utility module for functions and helpers
'''



from pprint import pprint
import StringIO



def pretty_print(obj):

contents = "Pretty Print Failed :-("
try:
output = StringIO.StringIO()
pprint(obj, output)
contents = output.getvalue()
finally:
output.close()
return contents

0 comments on commit fb2e096

Please sign in to comment.