Roundtrip¶
This tutorial covers some of the basic features of MCL. We will create a simple information model for books that can then be used to describe a certain collection of books.
Creating an information model¶
The building blocks for creating information models are in the pnb.mcl.metamodel.standard module.
Note
pnb.mcl.metamodel is a namespace package that is meant to include alternative metamodel implementations in future (which may be available as, e.g., add-ons to MCL). Alternative implementations will provide additional functionality such as undo-redo support for model changes. As such functionality typically has an impact on performance, it is not provided by the standard implementation. In short: use the standard implementation except if additional functionality is required.
A Model is a container for related information. We create a Model that will hold our information model for books:
1from pnb.mcl.metamodel import standard as mm
2BookML = mm.Model(name='BookML', uri='http://www.plants-and-bytes.de/BookML')
3print(BookML)
↳ <Model 'BookML' (http://www.plants-and-bytes.de/BookML)>
The name a the Model should give a hint of what the Model is about. Our model will describe
the Book Modeling Language, or 'BookML'. Most building blocks (i.e., those derived from NamedElement) can have a name, and for most of them, the name is required.
The uri of the Model serves as an identifier that should be globally unique. As we (pnb plants & bytes) own the http://www.plants-and-bytes.de domain, there is no risk that some other organization will use the same URI by mistake.
Warning
The uri of a Model is not necessarily a valid web address.
In general, a URI (Uniform Resource Identifier) is just an identifier. In certain settings, it may be useful to actually publish a Model under its URI – which would then be a URL (Uniform Resource Locator). For instance, see Wikipedia for the distinction between URIs and URLs.
As our information model will cover books, it is straightforward to create a corresponding Class. In our simple model, a ConcreteClass shall suffice:
4Book = mm.ConcreteClass(name='Book')
5print(Book)
↳ <ConcreteClass 'Book'>
We can now add the new class to the model:
6BookML.add(Book)
7print(Book)
↳ <ConcreteClass 'BookML.Book'>
Note that the string representation of Book has changed: it knows that it is now part of the model. Vice versa, we can get the Book class from the model via its name:
8print(BookML.Book)
↳ <ConcreteClass 'BookML.Book'>
9print(Book is BookML.Book)
↳ True
Thus, there is in general no need to keep local names for the elements added to a model.
Note
This namespace concept applies to most classes in the metamodel. For example, also the ConcreteClass BookML.Book is a namespace that provides access to its sub-elements by name.
To cover the title of a book, we add the following DataProperty to Book:
10BookML.Book.add(mm.DataProperty(
11 name='Title', type_=str, lower=1, upper=1))
12print(BookML.Book.Title)
↳ <DataProperty 'BookML.Book.Title'>
The type_ of the new Property is str, the standard Python type for strings. If we give a title for a book, it must be a string; anything else would not be acceptable.
lower and upper are the lower and upper limit of the multiplicity of the Title DataProperty:
lowermeans that aBookmust have at least 1 value forTitle;uppermeans that aBookmust have at most 1 value forTitle.
In consequence, a Book must have exactly 1 value for Title.
A DataProperty is suitable if the type of the code:Property is a DataType, including Python’s built-in str, int, and float.