| 1 |
"""Geniusql, a Python database library.""" |
|---|
| 2 |
|
|---|
| 3 |
__version__ = "1.0alpha" |
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
class _AttributeDocstrings(type): |
|---|
| 7 |
"""Metaclass for declaring docstrings for class attributes.""" |
|---|
| 8 |
|
|---|
| 9 |
|
|---|
| 10 |
|
|---|
| 11 |
def __init__(cls, name, bases, dct): |
|---|
| 12 |
'''Metaclass for declaring docstrings for class attributes. |
|---|
| 13 |
|
|---|
| 14 |
Base Python doesn't provide any syntax for setting docstrings on |
|---|
| 15 |
'data attributes' (non-callables). This metaclass allows class |
|---|
| 16 |
definitions to follow the declaration of a data attribute with |
|---|
| 17 |
a docstring for that attribute; the attribute docstring will be |
|---|
| 18 |
popped from the class dict and folded into the class docstring. |
|---|
| 19 |
|
|---|
| 20 |
The naming convention for attribute docstrings is: <attrname> + "__doc". |
|---|
| 21 |
For example: |
|---|
| 22 |
|
|---|
| 23 |
class Thing(object): |
|---|
| 24 |
"""A thing and its properties.""" |
|---|
| 25 |
|
|---|
| 26 |
__metaclass__ = geniusql._AttributeDocstrings |
|---|
| 27 |
|
|---|
| 28 |
height = 50 |
|---|
| 29 |
height__doc = """The height of the Thing in inches.""" |
|---|
| 30 |
|
|---|
| 31 |
In which case, help(Thing) starts like this: |
|---|
| 32 |
|
|---|
| 33 |
>>> help(mod.Thing) |
|---|
| 34 |
Help on class Thing in module pkg.mod: |
|---|
| 35 |
|
|---|
| 36 |
class Thing(__builtin__.object) |
|---|
| 37 |
| A thing and its properties. |
|---|
| 38 |
| |
|---|
| 39 |
| height [= 50]: |
|---|
| 40 |
| The height of the Thing in inches. |
|---|
| 41 |
| |
|---|
| 42 |
|
|---|
| 43 |
The benefits of this approach over hand-edited class docstrings: |
|---|
| 44 |
1. Places the docstring nearer to the attribute declaration. |
|---|
| 45 |
2. Makes attribute docs more uniform ("name (default): doc"). |
|---|
| 46 |
3. Reduces mismatches of attribute _names_ between |
|---|
| 47 |
the declaration and the documentation. |
|---|
| 48 |
4. Reduces mismatches of attribute default _values_ between |
|---|
| 49 |
the declaration and the documentation. |
|---|
| 50 |
|
|---|
| 51 |
The benefits of a metaclass approach over other approaches: |
|---|
| 52 |
1. Simpler ("less magic") than interface-based solutions. |
|---|
| 53 |
2. __metaclass__ can be specified at the module global level |
|---|
| 54 |
for classic classes. |
|---|
| 55 |
|
|---|
| 56 |
For various formatting reasons, you should write multiline docs |
|---|
| 57 |
with a leading newline and not a trailing one: |
|---|
| 58 |
|
|---|
| 59 |
response__doc = """ |
|---|
| 60 |
The response object for the current thread. In the main thread, |
|---|
| 61 |
and any threads which are not HTTP requests, this is None.""" |
|---|
| 62 |
|
|---|
| 63 |
The type of the attribute is intentionally not included, because |
|---|
| 64 |
that's not How Python Works. Quack. |
|---|
| 65 |
''' |
|---|
| 66 |
type.__init__(cls, name, bases, dct) |
|---|
| 67 |
|
|---|
| 68 |
newdoc = [cls.__doc__ or ""] |
|---|
| 69 |
|
|---|
| 70 |
dctnames = dct.keys() |
|---|
| 71 |
dctnames.sort() |
|---|
| 72 |
|
|---|
| 73 |
for name in dctnames: |
|---|
| 74 |
if name.endswith("__doc"): |
|---|
| 75 |
|
|---|
| 76 |
if hasattr(cls, name): |
|---|
| 77 |
delattr(cls, name) |
|---|
| 78 |
|
|---|
| 79 |
|
|---|
| 80 |
val = dct[name] |
|---|
| 81 |
try: |
|---|
| 82 |
import inspect |
|---|
| 83 |
val = inspect.getdoc(property(doc=val)).strip() |
|---|
| 84 |
except: |
|---|
| 85 |
pass |
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 |
val = '\n'.join([' ' + line.rstrip() |
|---|
| 89 |
for line in val.split('\n')]) |
|---|
| 90 |
|
|---|
| 91 |
|
|---|
| 92 |
attrname = name[:-5] |
|---|
| 93 |
try: |
|---|
| 94 |
attrval = getattr(cls, attrname) |
|---|
| 95 |
except AttributeError: |
|---|
| 96 |
attrval = "missing" |
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
newdoc.append("%s [= %r]:\n%s" % (attrname, attrval, val)) |
|---|
| 100 |
|
|---|
| 101 |
|
|---|
| 102 |
cls.__doc__ = "\n\n".join(newdoc) |
|---|
| 103 |
|
|---|
| 104 |
|
|---|
| 105 |
from geniusql import errors, typerefs |
|---|
| 106 |
from geniusql import adapters |
|---|
| 107 |
from geniusql import conns |
|---|
| 108 |
from geniusql import deparse |
|---|
| 109 |
from geniusql import isolation |
|---|
| 110 |
from geniusql.queries import * |
|---|
| 111 |
from geniusql import sqlwriters |
|---|
| 112 |
from geniusql import providers |
|---|
| 113 |
from geniusql.objects import * |
|---|
| 114 |
|
|---|
| 115 |
|
|---|
| 116 |
def db(provider, **options): |
|---|
| 117 |
"""Return a Database and Schema object for the given provider. |
|---|
| 118 |
|
|---|
| 119 |
provider: A 'shortcut name' registered in geniusql.providers.registry. |
|---|
| 120 |
|
|---|
| 121 |
This function does not call CREATE DATABASE (although it may open a |
|---|
| 122 |
database connection). |
|---|
| 123 |
""" |
|---|
| 124 |
return providers.registry.open(provider, **options) |
|---|
| 125 |
|
|---|