Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

Changeset 12

Show
Ignore:
Timestamp:
02/17/07 03:16:03
Author:
fumanchu
Message:

Added AttributeDocstrings? metaclass.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/geniusql/__init__.py

    r11 r12  
    1616 
    1717__version__ = "1.0alpha" 
     18 
     19 
     20class _AttributeDocstrings(type): 
     21    """Metaclass for declaring docstrings for class attributes.""" 
     22    # The full docstring for this type is down in the __init__ method so 
     23    # that it doesn't show up in help() for every consumer class. 
     24     
     25    def __init__(cls, name, bases, dct): 
     26        '''Metaclass for declaring docstrings for class attributes. 
     27         
     28        Base Python doesn't provide any syntax for setting docstrings on 
     29        'data attributes' (non-callables). This metaclass allows class 
     30        definitions to follow the declaration of a data attribute with 
     31        a docstring for that attribute; the attribute docstring will be 
     32        popped from the class dict and folded into the class docstring. 
     33         
     34        The naming convention for attribute docstrings is: <attrname> + "__doc". 
     35        For example: 
     36         
     37            class Thing(object): 
     38                """A thing and its properties.""" 
     39                 
     40                __metaclass__ = cherrypy._AttributeDocstrings 
     41                 
     42                height = 50 
     43                height__doc = """The height of the Thing in inches.""" 
     44         
     45        In which case, help(Thing) starts like this: 
     46         
     47            >>> help(mod.Thing) 
     48            Help on class Thing in module pkg.mod: 
     49             
     50            class Thing(__builtin__.object) 
     51             |  A thing and its properties. 
     52             |   
     53             |  height [= 50]: 
     54             |      The height of the Thing in inches. 
     55             |  
     56         
     57        The benefits of this approach over hand-edited class docstrings: 
     58            1. Places the docstring nearer to the attribute declaration. 
     59            2. Makes attribute docs more uniform ("name (default): doc"). 
     60            3. Reduces mismatches of attribute _names_ between 
     61               the declaration and the documentation. 
     62            4. Reduces mismatches of attribute default _values_ between 
     63               the declaration and the documentation. 
     64         
     65        The benefits of a metaclass approach over other approaches: 
     66            1. Simpler ("less magic") than interface-based solutions. 
     67            2. __metaclass__ can be specified at the module global level 
     68               for classic classes. 
     69         
     70        The type of the attribute is intentionally not included, because 
     71        that's not How Python Works. Quack. 
     72        ''' 
     73         
     74        newdoc = [cls.__doc__ or ""] 
     75         
     76        dctnames = dct.keys() 
     77        dctnames.sort() 
     78         
     79        for name in dctnames: 
     80            if name.endswith("__doc"): 
     81                # Remove the magic doc attribute. 
     82                if hasattr(cls, name): 
     83                    delattr(cls, name) 
     84                 
     85                # Get an inspect-style docstring if possible (usually so). 
     86                val = dct[name] 
     87                try: 
     88                    import inspect 
     89                    val = inspect.getdoc(property(doc=val)).strip() 
     90                except: 
     91                    pass 
     92                 
     93                # Indent the docstring. 
     94                val = '\n'.join(['    ' + line.rstrip() 
     95                                 for line in val.split('\n')]) 
     96                 
     97                # Get the default value. 
     98                attrname = name[:-5] 
     99                try: 
     100                    attrval = getattr(cls, attrname) 
     101                except AttributeError: 
     102                    attrval = "missing" 
     103                 
     104                # Add the complete attribute docstring to our list. 
     105                newdoc.append("%s [= %r]:\n%s" % (attrname, attrval, val)) 
     106         
     107        # Add our list of new docstrings to the class docstring. 
     108        cls.__doc__ = "\n\n".join(newdoc) 
     109 
    18110 
    19111import threading 
     
    738830 
    739831class Database(object): 
     832     
     833    __metaclass__ = _AttributeDocstrings 
    740834     
    741835    adaptertosql = AdapterToSQL()