 |
Python
The Python generator in Umple generates Python 3 classes from Umple models, and lets you embed Python methods in Umple. It is chosen with generate Python; in a model, -g Python on the command line or Python Code in UmpleOnline. The generated classes follow the public API of the Java generator's classes, with the Python behaviour described below.
Changed in Umple 1.38: As of Umple 1.38, the Python generator described here replaces the earlier one, which translated the generated Java code into Python. It generates Python from the model directly, so the generated code differs from what earlier versions of Umple produced. If you relied on the earlier Python generator, earlier versions of Umple are available from the Umple releases on GitHub.
Embedding Python methods: To insert a Python method in Umple, you specify the method signature followed by the keyword Python, an open curly bracket, any number of lines of Python code, and a closing curly bracket. The code is used as written, indented to fit the generated method. A method can have a Java body and a Python body side by side; each generator uses its own. A body without a language tag is taken to be Python. A method that has bodies only for other languages is left out of the Python with warning W9212, and so are actions, activities and code injections written only for other languages. A derived attribute written only for other languages would have no value, so it is reported with error E9211.
Umple finds the closing curly bracket with Java's comment rules. A curly bracket in a Python # comment therefore counts, so keep curly brackets in comments balanced. The rest of a line after Python's // operator is skipped as a comment, so put the closing curly bracket on a line of its own after such a line.
To create a main Python function, use the same signature as for Java with the code tagged as Python: public static void main(String [ ] args) Python {. Running the generated module calls main with the full sys.argv. From the folder Umple generated into, run python3 -m shop.Main for a class Main in namespace shop, or python3 Main.py for a class without a namespace. Other modules that import the main class get the running one.
Python code can use the classes of its own namespace, and those listed with depend (depend shop.Item; or depend shop.*;), without importing them: Umple imports such a class at the start of each method that names it, as Java sees these classes without an import, unless the method binds that name itself (as a parameter, a local variable or its own import). Other classes are imported as in any Python code, for example from shop.Item import Item, where shop is the class's namespace.
Untagged code in actions, injections and defaults: Actions of state machines, entry, exit and do activities, code injections, derived attributes and initial values written without a language tag are Java. For Python, Umple translates such code when it keeps to a small subset of Java: literals, local variables, assignments, conditions and loops, calls to the model's own methods, new for model classes, the String methods equals, contains, startsWith, endsWith, length and isEmpty, Thread.sleep (which in a do activity also ends the activity once it is cancelled, as Java's interrupt does), System.currentTimeMillis, Math's abs, max, min, sqrt, pow, floor, ceil, round and random, System.out.println and throw new RuntimeException. Other code is reported with error E9211, which shows how that kind of code is written in Python. Actions, activities, injections and derived attributes can have a Python version instead, which is used as written; an initial value can call a method written in Python. In text, booleans, the null literal and a missing model object read true, false and null, as in Java.
The generated Python:
- Each class is a module
ClassName.py in the package given by its namespace. Files are written in UTF-8.
- Attribute setters and the methods that set, add or remove links return
True, or False when the change is refused (for example by a constraint, a multiplicity bound or a key that can no longer change). An add method that creates the linked object from constructor arguments returns it, or None when the association is full.
- Getters of association ends with many objects return tuples; getters of list attributes return copies.
- An
autounique attribute, like a unique one, gets the class methods getWith and hasWith followed by its name, which find an object by its value.
- Links between objects are compared by identity. Classes with a key also get
__eq__ and __hash__ based on the key.
str() of an object has the layout of Java's toString, with Python's spelling of values (True, None) except that a missing date or linked object prints null as in Java. A toString method written in the model replaces it.
- Comments on classes, attributes, associations and methods, and the requirements they implement, become docstrings.
- Parameters named like Python keywords are renamed:
in becomes input, and other keywords get a trailing underscore.
- Overloaded methods become one method that calls the most specific overload matching the arguments, judged by their types when the program runs (Java judges by the declared types of the expressions passed).
None matches any reference type, boxed numbers such as Integer included; when several overloads take it, the most specific is called, then the first declared, where Java may report the call as ambiguous.
- A method written in the model with the same parameter types as a method Python generates (for example a Python
delete()) replaces that method; other overloads of the name stay. int and Integer count as one type.
- A subclass's methods compete with the inherited methods of their name that they do not override: the most specific one is called, wherever it is declared. A subclass method reaches the parent's methods through
super() (calling self would call its own method again). A static method a subclass declares hides the inherited methods of its name.
- Guards, preconditions and invariants can use Java's
equals, contains and a String's length(), and the constants of other classes (Limit.MAX, shop.Limit.MAX, Outer.Inner.MAX, also through a subclass of Outer), which the method imports. A String's length counts UTF-16 code units, as in Java.
- A class constant whose value is made of literals and operators alone, such as
60 * 24, is set in the class body. Any other is computed once, when it is first read, and then kept, so it can use any class of any module, whichever is loaded first; a branch of a conditional that is not taken is never run. A value whose computation needs the value itself raises RuntimeError naming it, where Java would read a default such as 0.
- A synchronized method holds a reentrant lock of its object while it runs, contracts and injections included, as Java's holds the object's monitor; the object's class and its subclasses share that lock. A static synchronized method holds its class's lock.
- Translated code computes with Python's numbers: integers do not overflow at 32 or 64 bits,
Float has double precision, and a floating division by zero raises ZeroDivisionError where Java gives NaN or infinity. Math's functions give Java's results, halves, NaN, infinities and the sign of zero included; as Float is a double, Math.round of a Float gives a long, of an integer an int.
- Queued and pooled state machines and queued methods take events or calls on worker threads, as in Java: each class of an object has one for its events and one for its queued methods. A worker runs its calls one at a time in the order they were made, and the event's or method's own call returns at once. A pooled machine first runs an event its current state can take, leaving the others waiting. Automatic transitions run at once. Deleting the object drops what is still waiting. Unlike Java's, a worker with nothing to run ends once the main thread has finished and every other thread left is an idle worker, so a program ends without deleting its objects; a worker starts again if work arrives.
- Timers and do activities of state machines use Python threads. Leaving a state or deleting the object cancels its timers and asks its do activity to stop; an activity that runs for long checks
thread.cancelled.is_set(), where thread is the worker it runs in, and returns when it is set, or pauses with thread.sleep(milliseconds), which returns True as soon as the activity is cancelled. An event on a deleted object does nothing and returns False; a queued event returns at once, as always.
Python in UmpleOnline: Select Python Code from the Generate menu, then click Execute It. The model needs a main method written in Python. An error in Python code you wrote names its line in your model, except in a method body a trait composes with superCall; an error there, or in code Umple translated or generated, names the line of the generated Python.
Command line use: Generating Python needs only Umple (java -jar umple.jar -g Python model.ump). Checking the generated Python for syntax errors (the -c option) needs Python 3: Umple uses the interpreter named by the environment variable UMPLE_PYTHON, or else python3, or else python. The check never runs the generated code.
Currently unsupported features, reported with error E9210 (the class concerned is then not generated):
- Tracing.
- Distributed classes.
- Static queued methods.
- Custom constructors and
emit template methods.
- Around injections and injections at code labels.
- Association specialization.
- An inner class whose superclass is an inner class declared elsewhere in the same outer class, or is that outer class (a superclass declared beside it works).
- JSON generation (the genJson suboption).
- A guard testing a state with
is in state.
- A guard, precondition or invariant that calls a Java library method other than
equals, contains and a String's length(), or that names something the model does not define or a member of another class other than a constant.
- A method named like another that is static where the other is not, including a method Python generates for the class.
If any of the features that are supported appear to function incorrectly, please submit a new issue here.
|