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. |