4 # STORES DICTIONARY OF ATTRIBUTE-BOUND GRAPHS
5 # AND LIST OF UNBOUND GRAPHS
6 class SchemaDict(dict):
7 """ Container for schema rules bound to a class or object. Rules are stored in
8 two indexes for fast access, indexed by graph, and indexed by attrname.
9 Use += and -= to add or remove rules.
11 def __init__(self
,newlist
=(),baselist
=()):
12 "Initialize schema list from list of base classes and newlist of rules"
15 # COMBINE SCHEMAS FROM PARENTS WITH NEW SCHEMA LIST
17 if hasattr(b
,'__class_schema__'):
18 self
.update(b
.__class
_schema
__)
19 self
.attrs
.update(b
.__class
_schema
__.attrs
)
20 for i
in newlist
: # newlist OVERRIDES OLD DEFS FROM baselist
24 "Add a schema rule to this SchemaDict"
27 if isinstance(i
[1],types
.StringType
):
28 if i
[1] in self
.attrs
: # REMOVE OLD ENTRY
29 self
-= self
.attrs
[i
[1]]
30 self
.attrs
[i
[1]]=i
# SAVE IN INDEX ACCORDING TO ATTR NAME
32 raise TypeError('Attribute name must be a string')
35 self
[g
].append(i
) # SAVE IN GRAPH INDEX
36 return self
# REQUIRED FROM iadd()!!
39 "Remove a schema rule from this SchemaDict"
42 raise KeyError('graph not found in SchemaDict!')
43 self
[g
].remove(i
) # REMOVE OLD ENTRY
44 if len(self
[g
])==0: # REMOVE EMPTY LIST
47 if isinstance(i
[1],types
.StringType
):
48 if i
[1] not in self
.attrs
:
49 raise KeyError('attribute not found in SchemaDict!')
50 del self
.attrs
[i
[1]] # REMOVE OLD ENTRY
52 raise TypeError('Attribute name must be a string')
53 return self
# REQUIRED FROM iadd()!!
55 def initInstance(self
,obj
):
56 "Add obj as new node to all graphs referenced by this SchemaDict."
57 for g
,l
in self
.items(): # GET ALL OUR RULES
60 g
.__iadd
__(obj
,(s
,)) # ADD OBJECT TO GRAPH USING RULE s
62 def getschema(self
,attr
=None,graph
=None):
63 "Return list of schema rules that match attr / graph arguments."
65 if attr
in self
.attrs
:
66 return [self
.attrs
[attr
]]
71 raise ValueError('You must specify an attribute or graph.')
72 return [] # DIDN'T FIND ANYTHING
77 class SchemaList(list):
78 "Temporary container for returned schema list, with attached methods"
79 def __init__(self
,obj
):
80 self
.obj
=obj
# OBJECT THAT WE'RE DESCRIBING SCHEMA OF
81 list.__init
__(self
) # CALL SUPERCLASS CONSTRUCTOR
83 def __iadd__(self
,rule
):
84 "Add a new schema rule to object described by this SchemaList"
85 if not hasattr(self
.obj
,'__schema__'):
86 self
.obj
.__schema
__=SchemaDict()
87 self
.obj
.__schema
__ += rule
88 return self
# REQUIRED FROM iadd()!!
90 # PROBABLY NEED AN __isub__() TOO??
94 ######################
95 # getschema, getnodes, getedges
96 # these functions are analogous to getattr, except they get graph information
99 def getschema(o
,attr
=None,graph
=None):
100 "Get list of schema rules for object o that match attr / graph arguments."
103 if hasattr(o
,'__schema__'):
104 for s
in o
.__schema
__.getschema(attr
,graph
):
106 if isinstance(s
[1],types
.StringType
):
108 if attr
and len(found
)>0: # DON'T PROCEED
110 if hasattr(o
,'__class_schema__'):
111 for s
in o
.__class
_schema
__.getschema(attr
,graph
):
112 if not isinstance(s
[1],types
.StringType
) or s
[1] not in attrs
:
113 found
.append(s
) # DON'T OVERWRITE OBJECT __schema__ BINDINGS
119 def setschema(o
,attr
,graph
):
120 "Bind object to graph, and if attr not None, also bind graph to this attribute."
121 if not hasattr(o
,'__schema__'):
122 o
.__schema
__=SchemaDict()
123 o
.__schema
__ += (graph
,attr
)
127 def getnodes(o
,attr
=None,graph
=None):
128 """Get destination nodes from graph bindings of o, limited to the
129 specific attribute or graph if specified"""
131 if hasattr(o
,'__schema__') and attr
in o
.__schema
__:
132 return getattr(o
,o
.__schema
__[attr
][2]) # RETURN THE PRODUCT
134 if hasattr(o
,'__class_schema__') and attr
in o
.__class
_schema
__:
135 return getattr(o
,o
.__class
_schema
__[attr
][2]) # RETURN THE PRODUCT
136 raise AttributeError('No attribute named %s in object %s' % (attr
,o
))
137 elif graph
: # JUST LOOK UP THE GRAPH TRIVIALLY
139 else: # SHOULD WE GET ALL NODES FROM ALL SCHEMA ENTRIES? HOW??
140 raise ValueError('You must pass an attribute name or graph')
144 def getedges(o
,attr
=None,graph
=None):
145 """Get edges from graph bindings of o, limited to the specific attribute
146 or graph if specified"""
147 g
=getnodes(o
,attr
,graph
) # CAN JUST REUSE THE LOGIC OF getnodes
148 if g
and hasattr(g
,'edges'):