Simplified Analysis Integration Example

In this example we will add an ExponentCalculator class and integrate it into django_analyses.

Interface Creation

By default, interfaces are expected to be classes and expose a run() method which returns a dictionary of output keys and values. Therefore, an ExponentCalculator class might look something like this:

exponent_calculator.py
class ExponentCalculator:
    def __init__(self, base: float, exponent: float):
        self.base = base
        self.exponent = exponent

    def run(self) -> dict:
        return {"result": self.base ** self.exponent}

Analysis Creation

The ExponentCalculator class is one possible implementation of exponentiation. Let’s define this procedure as a new available analysis:

>>> from django_analyses.models import Analysis
>>> definition = {
>>>     "title": "Exponentiation",
>>>     "description": "Calculate <base> in the power of <exponent>.",
>>> }
>>> analysis = Analysis.objects.create(**definition)

Analysis Version Creation

Now, we can create an AnalysisVersion instance to represent the ExponentCalculator class we’ve created:

>>> from django_analyses.models import AnalysisVersion
>>> definition = {
>>>     "title": "built-in",
>>>     "description": "Calculate the exponent of a number using Python's built-in power operator.",
>>> }
>>> analysis_version = AnalysisVersion.objects.create(**definition)

Input Specification

The ExponentCalculator class expects two float type input values which are assigned in its initialization: base and exponent.

InputSpecification instances are created with an association to a specific Analysis (this prevents name clashes between input or output definitions for different analyses) and may be used for a number of its AnalysisVersion instances.

>>> from django_analyses.models import FloatInputDefinition, InputSpecification
>>> definition = {
>>>     "base": {
>>>         "type": FloatInputDefinition,
>>>         "required": True,
>>>         "description": "Floating point number to be raised by <exponent>.",
>>>     },
>>>     "exponent": {
>>>         "type": FloatInputDefinition,
>>>         "required": True,
>>>         "description": "Floating point number to raise <base> by.",
>>>     },
>>> }
>>> analysis = Analysis.objects.get(title="Exponentiation")
>>> input_specification, created = InputSpecification.objects.from_dict(analysis, definition)
>>> input_specification
<InputSpecification:
[Exponentiation]
    base                                    Float
    exponent                                Float
>
>>> created
True

Output Specification

The OutputSpecification may be created very similarly:

>>> from django_analyses.models import FloatOutputDefinition, OutputSpecification
>>> definition = {
>>>     "result": {
>>>         "type": FloatOutputDefinition,
>>>         "description": "Product of <base> multiplied <exponent> times.",
>>>     }
>>> }
>>> analysis = Analysis.objects.get(title="Exponentiation")
>>> output_specification, created = OutputSpecification.objects.from_dict(analysis, definition)
>>> output_specification
<OutputSpecification
[Exponentiation]
    result                                  Float
>
>>> created
True

Interface Integration

At this stage our new analysis is ready to be “plugged-in”. Interfaces are queried from the ANALYSIS_INTERFACES dictionary in the project’s settings.py. Analyses are expected to be registered as ANALYSIS_INTERFACES["analysis_title"]["analysis_version_title"], so in our case:

settings.py
from exponent_calculator import ExponentCalculator

...

ANALYSIS_INTERFACES = {"Exponentiation": {"built-in": ExponentCalculator}}