MetaEdit API to create models |
Post Reply |
Author | ||
edward22243
Major Contributor Joined: 19.Apr.2019 Points: 41 |
Post Options
Thanks(0)
Posted: 11.Nov.2022 at 10:59 |
|
I want to be able to generate models using the API (connect to WSDL-server). I read the https://www.metacase.com/papers/importing_API.pdf paper and I have it working partly. I can generate graphs, and objects and relations.
However I have problems with objects that have as a property a collection of other objects. The errormessage does not really explain too much. I just post the python code here since it is self-explanatory. (I use Python Zeep btw, https://docs.python-zeep.org/) def createMEOop(meany): areaID, objectID = meany.meValue.split('_') result = factory.MEOop(areaID=int(areaID), objectID=int(objectID)) return result materialdef = factory.METype(name = "MaterialDef") n = factory.MEAny( meType = "String", meValue = "'my_matdef'") creat_mat_role = factory.MEAny( meType = "Boolean", meValue = "true") # collections physintout = factory.METype(name = "PhysicalInterfaceOut") n = factory.MEAny( meType = "String", meValue = "'eerste'") creat_lib = factory.MEAny( meType = "Boolean", meValue = "true") p1 = c.service.instProps(physintout, factory.MEAnyArray([nullAny, nullAny]), factory.MEAnyArray([n, creat_lib]) , nullAny,nullAny) #c.service.addToGraph(createMEOop(p1), createMEOop(newGraphAny)) #? physin2 = factory.METype(name = "PhysicalInterfaceOut") n = factory.MEAny( meType = "String", meValue = "'tweede'") creat_lib = factory.MEAny( meType = "Boolean", meValue = "false") p2 = c.service.instProps(physin2, factory.MEAnyArray([nullAny, nullAny]), factory.MEAnyArray([n, creat_lib]) , nullAny,nullAny) # p1 en p2 geen AnyArray ?? collectionout = factory.MEAnyArray([p1,p2]) #c.service.addToGraph(createMEOop(p1), createMEOop(newGraphAny)) #? physio = factory.METype(name = "PhysicalInterfaceIO") n = factory.MEAny( meType = "String", meValue = "'derde'") creat_lib = factory.MEAny( meType = "Boolean", meValue = "false") p3 = c.service.instProps(physio, factory.MEAnyArray([nullAny, nullAny]), factory.MEAnyArray([n, creat_lib]) , nullAny,nullAny) collectionio = factory.MEAnyArray([p3]) physin = factory.METype(name = "PhysicalInterfaceIn") n = factory.MEAny( meType = "String", meValue = "'vierde'") creat_lib = factory.MEAny( meType = "Boolean", meValue = "false") p4 = c.service.instProps(physin, factory.MEAnyArray([nullAny, nullAny]), factory.MEAnyArray([n, creat_lib]) , nullAny,nullAny) collectionin = factory.MEAnyArray([p4]) props_mat_def = factory.MEAnyArray([n, creat_mat_role, collectionout, collectionio, collectionin]) matdef_done = c.service.instProps(materialdef, factory.MEAnyArray([nullAny, nullAny, nullAny, nullAny, nullAny]), props_mat_def , nullAny,nullAny) The matdef_done line fails, what I did is instantiate every object (the PhysicalInterfaceIn) and because they are a collection I put the in a MEAnyArray. Basically they look like: >>> p4 { 'meType': 'MEOop', 'meValue': '3_7397' } The error I get is: TypeError: Any element received object of type 'MEAnyArray', expected lxml.etree._Element or builtins.dict or zeep.objects.MEAny But everything in the MEAnyArray is already an MEAny? The metamodel is here: Furthermore: Could I receive some more (elaborate) examples of using the API to generate more elaborate models (the paper is really basic), thanks.
Edited by edward22243 - 11.Nov.2022 at 11:14 |
||
stevek
MetaCase Joined: 11.Mar.2008 Points: 641 |
Post Options
Thanks(1)
|
|
I love your "the Python code is self-explanatory"
Without knowing the details of Zeep, I'd suggest looking at the red lines for collectionout/io/in, where you create a property value that is a collection of objects. That value is an MEAny (it's going to be put in an MEAnyArray - cf. the Zeep error message saying you've put an MEAnyArray in an MEAnyArray). The format for a collection of MEOops in an MEAny is shown in the list of types used by the API:
An MEAny's meValue is only a string, hence the need for a simple format rather than actual MEOop objects. So you're probably going to need to replace those three lines to look more like this:
where 3_111 is replaced with p1's areaID and objectID, and 3_222 similarly for p2. (I generally write little helper routines to map such strings to MEOops and back, or to wrap and unwrap things in MEAny's.) For more documentation and examples of the API, have you looked at the manual's API chapter? |
||
edward22243
Major Contributor Joined: 19.Apr.2019 Points: 41 |
Post Options
Thanks(0)
|
|
About the Python-code, just started working with it yesterday and it seems quit straightforward, and you clearly understood it About helper-functions, I think it should be possible to generate API-access code (don't know any better name) from any metamodel to create models via the API. What I mean: what I am doing by hand now to be able to make graphs, and it contents (objects, etc) could be generated. We are in the modelling business to avoid having to handcode this, aren't we The only access to the metamodel I have via an exported mxt-model. Probably, you have made this years ago already (I would be disappointed if you did not make it already ). Would you be willing to share this? |
||
stevek
MetaCase Joined: 11.Mar.2008 Points: 641 |
Post Options
Thanks(0)
|
|
While it would be possible to generate an API at the level of the metamodel, rather than the metametamodel, there just don't seem enough API programs for a given metamodel and given programming language to make that worthwhile. Even if we just limit it to the space of programming languages, the last API questions I've answered have been on Python, Node.js, Java, C, and C#. Each of these tends to have more than one possible SOAP library, all with their own peculiarities. There just isn't the critical mass for one choice, nor any particularly clear choices, to make it feasible for us.
Any API built in that way would be very fragile with respect to metamodel evolution. And metamodel evolution is one of the main use cases for the API. Most evolution just works - expanding the metamodel with new object types or relationship types, renaming things - with no need for the API, but where you change the language in a less common way and want existing models to update automatically, the API is your best bet. You'd have to have two versions of the API working simultaneously to be able to do that, and the code would be nearly unreadable, since both ends of the transformation would look so similar. For importing models from some other format, we tend to ingest that format and create MXM files. Often the source is simple enough that it can be parsed with MERL, which then gives you a familiar environment for processing and outputting the necessary XML. You can build a small hand-made model and export it to MXM to give you an initial example for how things should look (and there are lots of things you can omit - see the XML chapter in the Workbench User's Guide). As always, the best approach depends on the task, source, target, processing, programming language and existing familiarity. Any of the approaches can work, including building a metamodel-level API level. I think I've only seen that once, although bits of low-hanging fruit are often picked from that area. That's the normal approach to coding: do it with the existing system for the first 2-3 occurrences, but if you have to write similar code often, make a function. Using the API is just programming after all, so the work gets optimized as you go along in building something to meet your particular needs - it's just hard for us to provide a once-and-for-all generic solution that meets each user's needs. Of course the users have all the familiar programmer tools on their side of the API, so if they want a metamodel-level API wrapper, they can build it - in a way that's appropriate to them. That will generally be a much simpler metamodel-level API than one made by a generic process (where it would have to support e.g. n-ary relationships with dynamic ports and complex properties in roles and relationships, whereas most use cases would just have simple binary relationships with maybe a single property).
Having seen the maintainability problems of metamodel-level APIs and XML schemas, we went with the metametamodel level. I don't think there's a right and wrong answer, but I do still feel that the right level for a metamodelling tool is the metametamodel level. The functions or schema are then the same for everybody, and we can sensibly document them and provide examples. The metamodel-specific parts are in data, not hard-coded in function names or element names - and from the point of view of a metamodelling tool, metamodels are data, so that seems a good fit. Edited by stevek - 11.Nov.2022 at 15:04 |
||
edward22243
Major Contributor Joined: 19.Apr.2019 Points: 41 |
Post Options
Thanks(0)
|
|
Thank you for the reply.
I could define the "MaterialDef" when I use the OrderedCollection as you described. The materialdef (matdef_done) is succesfully generated ( matdef_done = { 'meType': 'MEOop', 'meValue': '3_7458' } Furthermore, I want to be able to generate a Material. The picture of my previous post (Screenshot) shows that the Material has two properties. A name (string) and the MaterialDef I just generated. So I define a material: product = factory.METype(name = "Material") n = factory.MEAny( meType = "String", meValue = "'my_product'") prod_props = factory.MEAnyArray([n, matdef_done]) So prod_props: [{ 'meType': 'String', 'meValue': "'my_product'" }, { 'meType': 'MEOop', 'meValue': '3_7458' }] However, generating a Material leads to error: Number of values does not match number of properties. Did a bit of fiddling, and turns out a Material can be generated when I just use the string property, so when I omit the matdef-property. I can not add this generated material to the graph though ( error: Bad receiver type for addToGraph ). Maybe not strange, since it is still missing the MaterialDef property. Things get stranger though, I am able to add the generated MaterialDef to the graph! While I only have defined the MaterialDef as a property of Material, and not in the graph itself. So I can do things programmatically that I would not be able to do in the diagram. To summarise: below in the pic you see a OperationsDefintion3-graph with contens object (Material, NOT MaterialDef) and I can generate a MaterialDef in the graph. Question: I would like to define the MaterialDef as a property of Material programmatically and be able to add that Material to the graph (as I do noramlly when using the Diagram GUI). How to continue? Edited by edward22243 - 14.Nov.2022 at 10:58 |
||
stevek
MetaCase Joined: 11.Mar.2008 Points: 641 |
Post Options
Thanks(0)
|
|
Since Material is only expecting one property, it's probably a different type than the one you intended: i.e. you have more than one type called Material. From the picture you have a Graph type called Material too, and that will be found first. See the entry for METype, and as mentioned there either use the internal name (check from an MXT export) or use subTypeNamed(). With only 4 types in the API (MEOop, MEAny, METype, MENull), it's well worth reading that page of the manual.
That explains your next question: you created a Graph, not an object, and you can't add a Graph into a Graph.
A Graph is fine with containing instances of object types that wouldn't now be allowed by the UI - you could have removed an old object type to sunset it, so users can't add new instances to the graph, but any existing instances there would still be fine (any generators for them would still work, so having them isn't a problem). The API can work with these cases too: since API programs are generally written by the metamodeller not the modeller, we trust that he knows well enough what he's doing. |
||
edward22243
Major Contributor Joined: 19.Apr.2019 Points: 41 |
Post Options
Thanks(0)
|
|
Changing the METype name to the name used in the mxm-file worked. Now able to add the Material to the graph.
I quess being able to add a type to the graph that cannot be done in the GUI (by modelers, rather metamodellers) can be considered a feature and usefull for metaprogrammers. Thanks again.
|
||
Post Reply | |
Tweet |
Forum Jump | Forum Permissions You cannot post new topics in this forum You cannot reply to topics in this forum You cannot delete your posts in this forum You cannot edit your posts in this forum You cannot create polls in this forum You cannot vote in polls in this forum |