Re: [Modeling-users] Pythonic, and non-XML, Model description
Status: Abandoned
Brought to you by:
sbigaret
|
From: Sebastien B. <sbi...@us...> - 2003-02-28 00:16:18
|
Hi Mario,
> following comments about the XML model (on and off the list) and
> how it can be improved or redone altogether, i started thinking about=
=20
> it...
> And (to be able to get it out of my mind and get to some other work ;=
-)
> here is a proposal for a pure python description of the model. It=20
> follows
> the XML closely, and in fact may always retain compatibility (at least
> generation of XML from the python model, which will be trivial).
I agree: the pymodel must have the same power of expression than the
existing xml-file, i.e. every properties for Entities, Attributes
etc. should be settable in the py-model just like they are in the xml.=
=20=20
Your proposal holds the complete kick-off material.
> The behaviour in general would stay the same as the XML way of
> doing things, namely form this model you would generate the classes
> and the db schemas.
These features are available for any Modeling.Model object, so the "onl=
y"
thing to do is build it from the py-model, just like it goes for the xm=
l.
(same for generating an xml-model, thus mapping a py-model to an xml-mo=
del
will be straightforward --cf. ModelSet.getXMLDOMForModelNamed() and
getXMLStreamForModelNamed())
> Some differences are choice of default values, and that key and locki=
ng
> attributes are defined on attributes and relations rather than entiti=
es=20
> ;)
Ok, I guess we won't argue any further on this by now ;)
> As an exercise, I have taken the sample model in the distribution:
> testPackages/StoreEmployees/model_StoreEmployees.xml and re-expressed=
it
> in this pythonic way.
Thanks, this made things even clearer.
> Apart from readability and losing of some verbosity, other gains are
> "executability" and dynamicity -- it could be very easy to modify a m=
odel
> at runtime, if you would ever want to do that.
Oh oh, I can't believe you said that! Models' mutability at runtime is =
an
other subject we'd better discuss apart from this thread. It *is* possi=
ble,
under some conditions I certainly need to gather before answering. If y=
ou
need this sort of feature in short-term, you'd better picked me on wild=
ly!!
> Also, given that a model now becomes a module in and of itself, it g=
ains
> from what modules have to offer, such as self-tests.
Ok.
> And, speed of course, as i see no reason why this model object would =
also
> not serve as the model object in memory at runtime (but that's for
> Sebastien to confirm) -- thus loading the model is equivalent to "from
> MyModel import model".
Well, it will need a few more lines of code to actually load the model =
into
the so-called defaultModelSet (cf. Modeling.ModelSet and the generated
__init__.py), but that's it.
> Can you please take a look at the 2 linked files below (as temporary
> URLs, as to attach they are too big);
> - PyModel.py -- defines the classes (signatures for) for, and
> documents the rules for, a PyModel instance
> - sample_PyModel.py -- re-expresses the StoreEmployees model
Ok, now let's take a look at the big stuff ;)
Your python code is sound and clear. My first comments are:
- maybe we'll gain more readability if relationships' multiplicity lo=
wer-
and upper bounds where encoded in strings, such as: '0-1', '1-1', '=
0-*'
or '2-16'.
=20=20
- Same for external type's width, precision and scale, such as in:
'NUMERIC(12,2)' or 'VARCHAR(200)'
- Again, same for an entity's parent which could be specified along w=
ith
the entity's name: 'Executive(Employee)'
- What about the possibility to add a '*' to an attribute's name when=
it's
required? (may be same for a relationship, equivalent to lower boun=
d=3D=3D1)
- Allow litterals instead of the equivalent integers in the xml: 'CAS=
CADE'
for the delete rule is more explicit than int(2)!
- I think I would have made 'name' instead 'columnName' the default f=
or
displayLabel :)
Now that I get used to the idea of a python-model, I'm also thinking of=
some
extents to your proposal:
- We could have subclasses for your Attribute: PrimaryKey, ForeignKey
(defaults for both would be: int, not class property, etc.), String
(with a default external size/width), Integer, Numeric, ... You get=
the
idea.
- Relation can also be sub-classed to 'ToOne' and 'ToMany' (default w=
ould
be '0-*' for the latter)
Last, I'm thinking of some automatic processing which is already coded =
in
the zmodeler and that could be done at model-time to reduce verbosity i=
n a
significant manner:
- have a primary key 'id' automatically declared if not set,
- have foreign keys automatically set for relationships, using the sa=
me
defaults the zmodeler already uses (e.g. FKEmployeeId for a to-many
relationship pointing to the entity Employee). It would need some
additional checks but it's definitely possible.
This could be as handy as the feature you submitted in your proposal:
automatic definition parent properties which are not overriden in
sub-entities.
I wrote all these items with something in mind, actually. You know, I'm
basically lazing, most of the time I do not take about DB-Schemas detai=
ls,
and I will be delighted if it was possible to write the same StoreEmplo=
yee
model really simply. This is a good illustration of the automatic proce=
ssing
I described above because this model (like every test models) were desi=
gned
using the zmodeler and its functionalities.
In fact, I'm thinking that something simple like that could be writte=
n:
(this would imply some changes to your proposed API, such as making
'destinationEntity' the second argument for the Relationship's initial=
izer).
-----------------------------------------------------------------------=
-----
from PyModel import Attribute,Relation,Entity,Model
_connDict =3D {}
model =3D Model('StoreEmployees',connDict=3D_connDict)
model.entities =3D [
Entity('Store',
attributes=3D[ String('corporateName *', width=3D30) ],
relations=3D[ ToMany('employees', 'Employee', delete=3D'deny') ])
# Employee and its subclasses SalesClerk and Executive
Entity('Employee',
attributes=3D[ String('lastName *', width=3D20, isUsedForLocking=
=3D1 ],=20
String['firstName *', width=3D50, isUsedForLocking=
=3D1 ], ],
relations=3D[ ToMany('toAddresses', 'Address', delete=3D'cascad=
e' ],=20
ToOne('toStore', 'Store') ])
Entity('SalesClerk(Employee)',=20
attributes=3D[ String('storeArea', width=3D20) ]),
Entity('Executive(Employee)',
## width declared in external=
Type
attributes=3D[ String('officeLocation', externalType=3D'VARCHAR(=
5)') ],
relations=3D[ ToMany('marks', 'Mark', delete=3D'cascade' ]),
#
Entity('Address',
attributes=3D[ String('street', width=3D80),=20
String('zipCode', width=3D80),=20
String('town', width=3D80), ],
relations=3D[ ToMany('toEmployee', 'Employee', delete=3D'deny') ]=
),
#
Entity('Mark',
attributes=3D[ Integer('month *'),=20
Integer('mark *'), ],
relations=3D[ ToOne('executive', 'Executive' ] ])
]
if __name__ =3D=3D '__main__':
print model.validate()
print model.toXML()
-----------------------------------------------------------------------=
-----
(this example was written with the intention of being strictly equiva=
lent
to the original one)=20
Of course this would need some additional cpu-time to load a model, but=
I
bet it would be far quicker than parsing the xml!
This of course still needs to be discussed and refined. I did not hav=
e any
time to try & implement my proposal, but I guess that at some point of =
the
discussion we'll need to see the words take shape --at this point this =
could
naturally be made in a dev-branch if several of us are on this.
I really have the feeling that we will succeed in designing a very ni=
ce
python model. Let's go for it now that Mario brought some light on the
path!
Cheers,
-- S=E9bastien.
|