0

I'm writing a parser for an internal xml-based metadata format in python. I need to provide different classes for handling different tags. There will be a need for a rather big collection of handlers, so I've envisioned it as a simple plugin system. What I want to do is simply load every class in a package, and register it with my parser. My current attempt looks like this:
(Handlers is the package containing the handlers, each handler has a static member tags, which is a tuple of strings)

class MetadataParser:
    def __init__(self):
        #...
        self.handlers={}
        self.currentHandler=None
        for handler in dir(Handlers): # Make a list of all symbols exported by Handlers
            if handler[-7:] == 'Handler': # and for each of those ending in "Handler"
                handlerMod=my_import('MetadataLoader.Handlers.' + handler)
                self.registerHandler(handlerMod, handlerMod.tags) # register them for their tags

    # ...

    def registerHandler(self, handler, tags):
        """ Register a handler class for each xml tag in a given list of tags """
        if not isSequenceType(tags): 
            tags=(tags,) # Sanity check, make sure the tag-list is indeed a list
        for tag in tags:
            self.handlers[tag]=handler

However, this does not work. I get the error AttributeError: 'module' object has no attribute 'tags' What am I doing wrong?

carlpett
  • 12,203
  • 5
  • 48
  • 82
  • 1
    You don't really give much information. The error message would probably say *in which line* the error occurs, which obviously would help to pinpoint the problem. Also your code has syntax errors (missing colon after class name, indentation), so what you posted here wouldn't run at all. Also the error might well be in some part of the code that you didn't post... – sth Jun 17 '09 at 12:13

4 Answers4

0

Probably one of your handlerMod modules does not contain any tags variable.

sth
  • 222,467
  • 53
  • 283
  • 367
0

I suggest you read the example and explanation on this page where how to write a plug-in architecture is explained.

Asclepius
  • 57,944
  • 17
  • 167
  • 143
Sushant
  • 1,013
  • 1
  • 11
  • 20
0

First off, apologies for poorly formated/incorrect code.
Also thanks for looking at it. However, the culprit was, as so often, between the chair and the keyboard. I confused myself by having classes and modules of the same name. The result of my_import (which I now realize I didn't even mention where it comes from... It's from SO: link) is a module named for instance areaHandler. I want the class, also named areaHandler. So I merely had to pick out the class by eval('Handlers.' + handler + '.' + handler).
Again, thanks for your time, and sorry about the bandwidth

Community
  • 1
  • 1
carlpett
  • 12,203
  • 5
  • 48
  • 82
  • `eval` is not a great way to dynamically get attributes. The normal way to do it would be `getattr(getattr(Handlers, handler), handler)`. – Ben Jan 04 '12 at 22:07
0

Simple and completly extensible implementation via extend_me library.

Code could look like

from extend_me import ExtensibleByHash

# create meta class
tagMeta = ExtensibleByHash._('Tag', hashattr='name')

# create base class for all tags
class BaseTag(object):
    __metaclass__ = tagMeta

    def __init__(self, tag):
        self.tag = tag

    def process(self, *args, **kwargs):
        raise NotImeplemntedError()

# create classes for all required tags
class BodyTag(BaseTag):
    class Meta:
        name = 'body'

    def process(self, *args, **kwargs):
        pass  # do processing

class HeadTag(BaseTag):
    class Meta:
        name = 'head'

    def process(self, *args, **kwargs):
        pass  # do some processing here

# implement other tags in this way
# ...

# process tags
def process_tags(tags):
    res_tags = []
    for tag in tags:
        cls = tagMeta.get_class(tag)  # get correct class for each tag
        res_tags.append(cls(tag))  # and add its instance to result
    return res_tags

For more information look at documentation or code. This lib is used in OpenERP / Odoo RPC lib

FireMage
  • 121
  • 1
  • 3