Skip to main content

How-to: Use classes

There are two key things to keep in mind if you want to work with classes in a ArupCompute Python library:

  1. ArupCompute uses JSON to represent user-defined objects, including Python class objects.
  2. ArupCompute parses JSON objects into Python dictionaries, not to Python class objects.

This means:

  1. To pass a Python object to an ArupCompute Python calculation, you need to pass a JSON string representing the object.
  2. ArupCompute will take the JSON string representation of an object and convert it to a Python dictionary. Therefore, to work with the object, you can work directly with the dictionary representation of your object (ie. use its key/value data) or you can convert the dictionary to a class object and work directly with the object. Similarly, if your calculation returns a Python class object, ArupCompute will represent this object either as a JSON string (via ArupCompute website and API) or a Python dictionary (via arupcomputepy).

The snippet below demonstrates how to work with a Python class object as an input:

import math

# User-defined Python class
class Circle:
def __init__(self, name: str, radius: float):
self.name = name
self.radius = radius

def __str__(self):
return f"Hello, from circle {self.name}!"

def diameter(self):
return self.radius * 2

def area(self):
return math.pi * math.pow(self.radius, 2)

# Here's a Python calculation which takes a user-defined object as input.
# We've added a type hint for the input parameter, to indicate that the intended
# type of our input is the Circle type (based on our user-defined class).

# Note that type hints don't make Python check and enforce use of a type.

# ArupCompute uses JSON to represent user-defined objects. If we want to use this
# Python calculation via ArupCompute, to pass our Circle input, we need to pass a
# JSON object representing the circle (ie. {"name":"Circle A","radius":32}).
def summarise(c: Circle) -> ArupComputeResult:

# ArupCompute parses a JSON object (ie. JSON representation of your class object)
# to a Python dictionary. As such, we can add a check of whether the provided input
# is of the desired type (Circle) and create a new instance of the Circle object based
# on dictionary data if it is not. We can do this by mapping the dictionary kvp pairs to
# the required init arguments using the **-operator (if c is {"name":"Circle A","radius":32}
# Circle(**c) is equivalent to Circle(name = "Circle A", radius = 32))
circle = c if isinstance(c, Circle) else Circle(**c)

d = ArupComputeResultItem()

# Now that we are working with our Circle object, we can access the methods we defined
# in our Circle class (ex. our diameter, area and __str__ methods)
d.value = circle.diameter()
d.symbol = "diameter"

a = ArupComputeResultItem()
a.value = circle.area()
a.symbol = "area"

acr = ArupComputeResult()
acr.arupComputeResultItems.append(d)
acr.arupComputeResultItems.append(a)

acr.arupComputeReport_HTML = f'<p>{circle.__str__()}</p>'

return acr

# We can use our class as a type hint for the method's return data type. Again, this is only
# something we add as a hint, for readability. Python is not a statically typed language, it
# will not check that the type of the output is "correct".
def double_radius(c: Circle) -> Circle:
new_circle = c if isinstance(c, Circle) else Circle(**c)

new_circle.radius = new_circle.radius * 2

# Our object will be returned as JSON (via AC frontend, via API) or as a Python dictionary
# (via arupcomputepy)
return new_circle