[PEAK] The basics of peak.schema
Phillip J. Eby
pje at telecommunity.com
Tue Dec 7 00:30:55 EST 2004
So, what will peak.schema look like to start with? I previously posted
about constraints, but for now I'm going to punt on the larger constraint
framework by simply ignoring constraints altogether.
As I see it, a schema class will simply be a regular Python class, with
attribute descriptors, not unlike those of peak.model. Well, actually,
they'll be completely unlike peak.model; more like:
class Something(schema.Entity):
foo = schema.Link(OtherType, inverse="otherEnd")
bar = schema.Sequence(int) # sequence of integers
baz = schema.Field(str) # string, unique key
spam = ping = schema.Field(int) # two integer fields
schema.Unique("spam","ping") # declare a unique key (spam+ping)
So, really, they're more like binding.Attributes than
model.Attributes. Unlike the latter, they also won't be method
exporters. In order to trap the equivalent of link/unlink events, you'll
have to use custom sequence or mapping types.
The descriptors will essentially delegate all their behavior to a workspace
object, which will be accessible as an attribute on individual objects
(with a default "null workspace" for instances or classes not bound to a
workspace).
There are really only three behaviors anyway: get an unknown attribute
value, verify a change before making the change, and notify after a
successful change. All of these operations will be delegated to the
workspace, which will implement them using generic functions.
The default implementations of these functions will do semi-useful things,
like raise an error to indicate that the attribute is missing, supply the
default value, etc.
This is an extremely narrow definition and set of features, but really this
is nearly all of what I currently use in peak.model, if you ignore the
crufty syntax-management parts, and the ZODB-based
persistence. peak.schema will use a different persistence mechanism, which
will not use ghosts. Instead, objects will only be loaded if they exist in
the underlying DB, and only when you attempt to reach them via an attribute
of a loaded object. This approach does away with lots of annoying bits in
the current implementation of DM's, where you have to implement 'get()' or
'__contains__' on the DM to ensure that the object you're retrieving in
fact exists.
The initial workspace implementation will be supremely trivial, as it will
essentially just emulate the normal state of Python objects. That is, when
you set attributes they'll be set, and when you read them you'll find
them. However, over time we'll beef it up to support a flexible
constraint-checking facility, after we first figure out how to implement
the simpler constraints.
Initially, MOF alignment/compliance won't be a goal for peak.schema; the
main idea is just to get a dumb prototype up and running that can be used
with workspaces and metadata. Our first workspace implementations will
probably be a simple in-memory test workspace, and a *simple* SQL mapper
(with fixed-per-backend mapping patterns; no custom/legacy DB support).
Part of the prototype layer will be introspection APIs to let you examine
the metadata for a type -- the equivalents of e.g. mdl_featureNames and
such in peak.model. The difference is that these APIs will be external
functions, rather than built in to the classes or descriptors, so there
will be none of that awkward
'someThing.__class__.someFeature.doSomething()' stuff. Also, it means that
there's not a need for junk like 'model.Integer' and 'model.String', which
were there for the benefit of MOF and CORBA metadata that will now be
available via functions *even for non-PEAK types*. So, with peak.schema
you'll be able to declare a feature as a 'datetime.datetime' (for example)
without having to wrap it in a bunch of typecode fluff.
Indeed, peak.schema probably won't need equivalents of the model.Immutable
or model.Primitive base types, because if you have a type that's one of
these, it's probably a non-PEAK type anyway. You'll just declare metadata
for the non-PEAK type and be done with it, assuming you need any metadata
at all. So, really, you'll just have schema.Entity and schema.Value,
corresponding to model.Element and model.Struct, respectively, with the
only real difference being that schema.Value objects will be immutable, and
will disallow inverse relationships, and fields with non-Value types.
Anyway, at least to begin with, peak.schema will do a *lot* less validation
on its attributes than peak.model does, and less management of persistence
issues like in-place modification of mutable sequences or mappings. A lot
of these capabilities will come back later as it becomes clearer how to
layer in validation. Right now, with so many things up in the air, I think
it's better to solidify the foundation structure before moving up to more
advanced features.
Questions, anyone? Issues?
More information about the PEAK
mailing list