4 Exceptions
Contents
Welcome to the PyXMI tutorial. This is a good place to start if you are new to PyXMI. If you already have the PyXMI module and would like a quick reference, you might find the API document more helpful than this tutorial.
In this tutorial I hope to cover all that the PyXMI module is capable of. In the current version of PyXMI, there are only activity diagrams to worry about. I will also go over some basic usage of Poseidon, the UML modeling tool PyXMI should be used with.
Contents
PyXMI is a Python module that is used to parse XMI documents created with Poseidon. XMI is an XML format used the save model data that can then be used by other tools. The PyXMI module is not very functional on its own. It is meant to be used within other Python modules to incorperate the functionality of your diagram. You could also write an entire program within a single activity diagram. Throughout this tutorial you will be shown the various ways you can use the state machine objects created with PyXMI within your Python applications.
Contents
The purpose of the PyXMI module is to create
executable models. The way this is accomplished is by parsing an XMI document created by Poseidon. You create activity diagrams with Poseidon that contain Python statements. A Python statement is a line of executeable Python code. An example of a Python statement would be
var = 2+2 or a function call like
sys.exit(). The models you create contain Python statements in action nodes controlled by decision nodes and activity flows. There are a number of activity diagram elements defined by the UML that PyXMI currently does not support: merge, fork, and join nodes.
Each activity diagram that is used with PyXMI must contain an initial and a final node. These nodes indicate where the code execution begins and ends. Without them, your diagram will either never start or never end. Every activity diagram node supported by PyXMI is represented by a Python class in the PyXMI module. The classes currently defined by PyXMI are:
initialNode,
finalNode,
actionNode,
decisionNode,
stateMachine.
The state machine class contains all the methods used to parse the XMI document. The file name of the XMI document is pased to the constructor. The constructor then calls all the methods needed to construct the state machine object from the document. First, the
diagram id is found and assigned to the id attribute of the state machine object. Next, the
diagram name is found and assigned to the name attribute of the statemachine object. Next, all
guard conditions are found.
guard conditions are Python expressions that must evaluate to
true or
false. For each guard element that is found, it is added to the guards dictionary attribute of the state machine object, using the
id attribute of the guard condition as the dictionary key. Next, the
initial node is found. An initial object is created once the element is found and assigned to the initial attribute of the state machine object. The initial node must have an outgoing id. This is statement executed by PyXMI and can be an
action node or a
decision node. Next, the
final node is found. A final object is created once the element is found and assigned to the final attribute of the state machine object. The final node must have an incomming id. This indicates that the diagram is finished executing and can come from an
action node or a
decision node. Next, all
action nodes are found. For each element found, an action object is created. Action nodes may have 1 or more incomming ids. They may be other action nodes or decision nodes. Each action node may have only one outgoing id. Finally, all
decision nodes are found. For each element found, a decision object is created. Decision nodes are the opposite of action nodes; they may have only one incomming id and 1 or more outgoing ids. Once all decision nodes are found, the state machine object is ready to be executed.
State machine objects are executed by invoking the
run() method. Starting with version 0.2, the run method takes any number of arguments. These arguments can be accessed within activity diagrams using args[index]. This method enters an infinate loop. The first condition that is check is if the current node is a final node. This is the only way the loop may be exited. Starting with version 0.2, once the main loop is exited, the run method will return the value of the
return_value attribute.
return_value defaults to
None. The next condition checked is if the current node is an action node. If true, the statement is executed. The next node becomes the current node's outgoing id. Finally, if the current node is a decision node, all guard conditions associated with all the node's outgoing ids are evaluted. If one of the guard conditions contains the word
else, this id becomes the default action. All other guard conditions are evaluted in no preset order. The next action becomes the first one to evalute to true. For this reason, it is a good idea to have no more than 2 guard conditions per decision node. However, each outgoing id must have a guard condition.
Contents
You should use PyXMI if you are writing Python applications and want to visualize complex control flow with a Poseidon activity diagram. Instead of creating an activity diagram and then having to interpret it manually to write Python code, PyXMI can be used to
run your diagram. If your Python applications require more complex activity diagram features like forking (multi-threaded applications), you could still use PyXMI state machine objects
within your application. This would require more effort from the programmer to divide state machine objects to different parts of Python modules. This is really a design decision. The more activity diagrams that are used within your Python modules, less time is needed to spend changing your Python modules and more time working with activity diagrams. So if you enjoy visually designing your logic for Python applications, PyXMI is for you.
Starting with version 0.2, you can use class diagrams to create a society of classes using the new
classSociety class. This tutorial contains new examples that cover using this new class.
Contents
The PyXMI module is a regular Python module that can be imported just like any other Python module. It is a
stand-alone module; there are no other
third-party modules required for PyXMI to function. In this section of the of the tutorial, I will mention the current
builtin modules that PyXMI uses. Then, a simple example of how to use the the module
Contents
The current version of PyXMI requires two builtin Python modules;
sys, and
xml.dom.minidom. The sys module is currently only needed to exit the Python interpreter. The xml.dom.minidom module is needed to parse the XMI documents and created a Python
dom object. These modules are included with any Python 2.4 distribution.
Contents
In the PyXMI folder, there are some example XMI files that you can use as a reference. There should be a file named
hello_world.xmi. You can run this model like this:
>>> import PyXMI
>>> hello_world_model = PyXMI.stateMachine("C:\Python24\PyXMI\hello_world.xmi")
>>> hello_world_model.run()
Hello World!
>>>
As you can see, you import PyXMI just you you would any other module. The next line constructs the state machine object. The parameter to the constructor is the file name of the xmi document. You may have to change this line to where you PyXMI folder is located. Then the
run method is called. If all goes well, you should get the same output as above.
Contents
This section introduces using Poseidon. It is a very incomplete introduction to Poseidon. There are many features that PyXMI does not use. If you want to use Poseidon for modeling purposes other than PyXMI, I would suggest finding a complete Poseidon tutorial.
Contents
Poseidon is written in Java so it is portable accross most platforms. In order to run Poseidon, you must have a Java Virtual Machine installed. If you are using Windows, there is an installer available. For detailed installation instructions, refer to the
Gentleware site.
Contents
Once Poseidon is installed, you can start creating activity diagrams. From the
Create Diagram menu, select
activity diagram. After you do this, you should see somthing similar to:
As you can see, the default name given to the diagram is
Activity diagram_1. You should change this name to somthing more descriptive, especially if you have many diagrams.
Note:PyXMI can only parse one activity diagram per XMI file.
Contents
When you are ready to save your diagram, from the
file menu, select
Export Project to XMI.... A standard file save dialog box will appear.
Contents
Starting with version 0.4 PyXMI includes PyXMI defined exceptions. With these exceptions raised by PyXMI, you can be sure that PyXMI was the source of the error and not your own code. In this section, I will describe each of these exceptions and what causes them to be raised.
Contents
The
PyXMIFileNotFound exception is raised when a file cannot be found. This is true for any
IOError raised by the interpreter when a PyXMI funtion causes the error. Possible causes could be an invalid path, or invalid file system permissions.
Contents
The
PyXMIBadXML exception is raised when an XMI document cannot be parsed. This is because XML within the document is not well-formed. This problem can usually be fixed by re-exporting the XMI file from Poseidon or PyXMI.
Contents
The
PyXMINoInitialNode exception is raised when there is no initial node found in an activity diagram. Initial nodes are required for every activity diagram.
Contents
The
PyXMINoFinalNode exception is raised when there is no final node found in an activity diagram. Final nodes are required for every activity diagram.
Contents
The
PyXMINoIncommingFlow exception is raised when there is no incomming flow for an action node or a decision node. This exception ensures that no broken flows exist in the activity diagram.
Contents
The
PyXMINoClassDefined exception is raised when the
getClass method is invoked on a classSociety instance and class does not exist.
Contents
In this section I will give some basic examples of how to use PyXMI. They are fairly basic examples that can be modified or just used as a reference. Each XMI file for the diagrams explained in this section are located in the PyXMI package.
Contents
In this first example, we have an activity diagram wich holds the logic for an input loop. The file name is
example1.xmi and if you open it with Poseidon, you should see somthing similar to:
In this diagram, the control flow starts at the initial node at the top of the diagram. It then gets to the action node which asks the user to enter some text and assign it to a variable. Then, the decision node is reached. You will notice that the decision node has two outgoing flows, each with a guard condition. The first condition only contains the statement
else. This is required for PyXMI if there is a default path to take if no other conditions evaluate to true. The other condition checks if the user entered "q". If this condition evaluates to true, the final node is reached and the diagram is finished executing. You can test this diagram like this:
>>> import PyXMI
>>> example1_model = PyXMI.stateMachine("C:\Python24\PyXMI\example1.xmi")
>>> example1_model.run()
Enter some text:Hello from PyXMI
Hello from PyXMI
Enter some text:q
>>>
Contents
In this example the user is asked for two numbers and operation. Then, depending on what operation the user entered, the two numbers are either added, subtracted, multiplied, or divided. If text other then + or - or * or / is entered when asked for an operation, the error is displayed. You can test the diagram like the first example, but change the filename accordingly (example2.xmi).
Contents
Starting with version 0.2 of PyXMI, there is a new
classSociety class that can be used to construct an object which holds a society of classes. You use a class diagram to create the classes. The classSociety instance can then parse the XMI document containing the diagram and create the classes. You can model the attributes and operations of your classes in your diagram. However, this will have no effect on the classes created with the classSociety object. Since Python is a
dynamically-typed language, this is no problem as you will see in the next example.
There should be an XMI document named example3.xmi in your PyXMI folder. If you open the document with Poseidon, it should look similar to:
As you can see, this diagram defines two classes. These classes don't define any attributes or methods which is fine because the classSociety class would not recognize them. You can construct instances of these classes like this:
>>> import PyXMI
>>> classes = PyXMI.classSociety(file_name="C:\Python24\PyXMI\example3.xmi")
>>> obj1 = classes.test_class1()
>>> obj2 = classes.test_class2()
>>> print obj1, obj2
>>>
Contents
The classSociety class provides an
addMethod method which allows you to add methods to your classes. These new methods are created using activity diagrams. In this example we will add a constructor to one of the classes created in the previous example. In the PyXMI folder there should be an XMI document named example4.xmi. This is an activity diagram which represents our constructor. If you open the document with Poseidon, it should look like:
You can add the constructor to the test class like this:
>>> import PyXMI
>>> classes = PyXMI.classSociety(file_name="C:\Python24\PyXMI\example3.xmi")
>>> classes.addMethod("__init__", "test_class1", "C:\Python24\PyXMI\example4.xmi")
>>> obj = classes.test_class1()
>>> obj.name
'Test Class'
>>>
In the constructor diagram, the attribute
name is assigned some text. The instance name has a name attribute with some text.
Contents
Starting with PyXMI 0.3 state machine objects have two new methods:
exportPyxmi and
importPyxmi.
exportPyxmi creates an XMI document containing all attributes of the instance that calls the method. The format created with this method is similar to that used by Poseidon but contains less elements.
exportPyxmi exports only those elements that are required to re-create the state machine instance. Poseidon XMI documents contain many elements that are used to create a graphical representation of the diagram. These elements are of no use to PyXMI and are therefore wasted file space. Use this method if you need smaller file sizes. The file created with this method cannot be used with Poseidon. You can export an XMI document like this:
>>> import PyXMI
>>> example2_model = PyXMI.stateMachine(file_name="C:\Python24\PyXMI\example2.xmi")
>>> example2_model.exportPyxmi("example2_export.xmi")
You now have a new XMI document that is much smaller in size compered to the document generated by Poseidon. You can use this object again like this:
>>> example2_import = PyXMI.stateMachine()
>>> example2_import.importPyxmi("example2_export.xmi")
>>> example2_import.name
'Activity_1'
>>>
To use the import method, you need a state machine instance. You can construct an instance with no arguments in the constructor to create an
empty state machine and then call the import method to
create the state machine. You can also call this method on a state machine object that has already parsed an XMI document. This will change the instance completely.