Register a new entity with parameters

Now, since we have one entity. Let’s spice things up with more complicate entity by creating a Report class at app/report.py:

class Report(object):
    def __init__(self,
                 calculator,
                 assignment_scores:list,
                 final_exam_score:int):
        self.calculator        = calculator
        self.assignment_scores = assignment_scores  # max score = 10
        self.final_exam_score  = final_exam_score   # max score = 100

    def grade(self):
        total_scores     = sum(self.assignment_scores)
        total_max_scores = (10 * len(self.assignment_scores))
        assignment_part  = total_scores / total_max_scores
        final_exam_part  = final_exam_score / 100

        grade_ratio = self.calculator.add(
            assignment_part * 0.7,
            final_exam_part * 0.3
        )

        return grade_ratio * 100

At this point, again, Imagination does not know about the report. To do so, let’s register an entity of an instance of app.report.Report in containers.xml:

<imagination>
    <!-- ... (omitted) ... -->
    <entity id="report.bob" class="app.report.Report">

        <!-- Pass [2, 0, 1, 8, 6, 9, 7, 5] (list of integers)
             as "assignment_scores" -->
        <param type="list" name="assignment_scores">
            <item type="int">2</item>
            <item type="int">0</item>
            <item type="int">1</item>
            <item type="int">8</item>
            <item type="int">6</item>
            <item type="int">9</item>
            <item type="int">7</item>
            <item type="int">5</item>
        </param>

        <!-- Pass 89 (integer)
             as "final_exam_score" -->
        <param type="int" name="final_exam_score">89</param>

        <!-- Pass the reference of the "calc" entity
             as "calculator" -->
        <param type="entity" name="calculator">calc</param>
    </entity>
</imagination>

where report.bob is the entity ID.

Note

In case you are confused, here is the equivalent code.

# From the previous page...
from app.util import Calculator

calc = Calculator()

# Now, to work with the report class.
from app.report import Report

report = Report(calc, [2, 0, 1, 8, 6, 9, 7, 5], 89)

The key differences at this point are:

  • neither the calc entity and the report.bob entity are not instantiated immediately until the report.bob entity is requested/activated,
  • the calc is always activated before the report.bob entity as calc is a dependency of report.bob.
  • the objects are still living only in the scope of the container.

How to work with the report entity

To refer the report entity, for example, in main.py, simply use report_bob = assembler.core.get('report.bob')

Now, to actually use the entity, let’s add something to the end of main.py.

# Omitted the code for main.py already shown above
report_bob = assembler.core.get('report.bob')
print(report_bob.grade())  # STDOUT: 59.94999...

So, as you can see, the entity works pretty much like a normal object, except the key differences mentioned earlier.

What can you define as parameters or items?

Type Name Data Type Example PCDATA, child nodes
str Unicode (default) bamboo
bool Boolean (bool) [1] true, false
float Float (float) 1.2, 2.0
int Integer (int) 123
class Class reference [2] argparser.ArgumentParser
entity An Imagination entity [3] report.bob (Entity ID)
list Python’s List (list) (See an example below)
dict Python’s Dictionary (dict) (See an example below)

Here is an example. From:

<imagination>
    <entity class="foo.Bar" id="panda">
        <param type="bool" name="enabled">false</param>
        <param type="dict" name="data">
            <item type="list" key="collection">
                <item type="str">shiroyuki</item>
                <item type="str">is</item>
                <item type="str">happy</item>
            </item>
            <item type="str" key="code">1234</item>
        </param>
    </entity>
</imagination>

The equivalence to the Python code used to instantiate this entity will be:

panda = foo.Bar(enabled = False, data = {
        'collection': ['shiroyuki', 'is', 'happy'],
        'code': 1234,
    })

Note

How to define parameters and items can be used with a factorized entity, which will be mentioned in the next step.

Tip

For more information about the DTD of the configuration file, please check out the DTD on GitHub.

Footnotes

[1]Only any variations (letter case) of the word ‘true’ or ‘false’ are considered as a valid boolean value.
[2]An import path of a class, as known as a fully-qualified class name, e.g., argparser.ArgumentParser
[3]Any Imagination entity (see Definitions used in this documentation)

Next step? Dynamically define an entity with a factory entity.