Meta-data
Reference
Before going into specifics here is a full example for context:
def pythagoras(a: float, b: float) -> object:
"""Pythagoras theorem
Uses pythagoras theorem to calculate the hypotenuse length of a right-angled triangle.
Args:
a: The first side length
:units: mm
:latex: \\\\Delta_A
b: The second side length
:units: mm
:latex: \\\\Delta_B
Returns:
h: The hypotenuse length of the triangle
:units: mm
:latex: h
.. codeauthor:: Hugh Groves <[email protected]>
.. codeauthor:: George Aggrey <[email protected]>
.. levelofreview:: Complete
.. assumption:: Triangle is right-angled
.. assumption:: Triangle is planar
.. versionchanged:: 1.0.0
Changed to the power of 2, instead of 3 as in original version
.. versionchanged:: 1.0.1
Fixed typo in input argument descriptions
.. additionalinformationlink:: https://en.wikipedia.org/wiki/Pythagorean_theorem
Wikipedia article on pythagoras theorem
.. persistentcalcid:: e4b77e3d-562c-4bc1-bdde-bdc1e76f5ae2
"""
h = math.sqrt(a ** 2 + b ** 2)
return h
Parameters (inputs and outputs)
The following meta-data can be extracted from parameters and used within the ArupCompute system:
- Symbol
- Type
- Description
- Units (optional)
- LaTeX (optional)
The majority of the information is extracted from the docstring, although some is also taken from the function definition.
Example:
Args:
a: The first side length
:units: mm
:latex: \\\\Delta_A
b: The second side length
:units: mm
:latex: \\\\Delta_B
Returns:
h: The hypotenuse length of the triangle
:units: mm
:latex: h
Docstring format for inputs / output meta-data:
Args:
<input_1>: <description_i1>
:units: <units_i1>
:latex: <latex_i1>
<input_2>: <description_i2>
:units: <units_i2>
:latex: <latex_i2>
Returns:
<result_1>: <description_r1>
:units: <units_r1>
:latex: <latex_r1>
<result_2>: <description_r2>
:units: <units_r2>
:latex: <latex_r2>
Symbol
The symbol of your input is extracted from the function signature. The symbol from the function inputs will be used to correlate with the data in the docstrings, so make sure they match!
Type
Types are extracted using PEP484 style annotations.
Including type annotations will help ensure the ArupCompute system works as expected, as well as helping users provide the correct information to your functions.
This article from RealPython explain the python type system in great detail.
Type hints by themselves don't cause Python to enforce types. Type hints simply suggest types to whoever or whatever (ie. the ArupCompute frontend) is reading your code, which is helpful for improving the documentation and usability of what you write. Python will not stop you from using the wrong type for an argument (it won't throw an error for the wrong type).
Common options will be:
- Text
-> str
- Number
-> float
or-> int
- True / false
-> bool
ArupCompute supports use of more "complex" type hints as well, including for collections-based types like:
- Lists (ex. list of numbers)
-> List[float]
or-> List[int]
- Dictionary
-> Dict[str, int]
(the types of both keys and values are needed)
Collections-based type hints will be shown as JSON input fields in the AC frontend:
If you want to use these types as hints, you'll need to import the typing
module.
from typing import Dict, List, Optional, Tuple
a: Dict[str, str] = {"colour": "blue"}
b: List[int] = [5]
c: Tuple[int, str, float] = (3, "yes", 7.5)
This type hints cheat sheet is a useful reference.
ArupCompute also supports type hints for numpy
types:
- Numpy array
-> numpy.ndarray
or-> numpy.typing.ArrayLike
Type hints for user defined classes are supported as well. Refer to this section of the docs for notes on working with Python classes and class instances as inputs. As with collections-based inputs, object inputs will be shown as JSON input fields in the AC frontend.
ArupCompute Python calculations can also use other collections-based and functions-based type hints, but these type hints are not currently supported by ArupCompute or on the ArupCompute frontend:
- Union
-> Union[int, str, float]
(an object of either int, str or float type) - Optional
-> Optional[int]
(either an object of the given type or None, note that AC does not currently support optional inputs) - Type alias (ie. assigning a type to an alias, so you can use the type or the alias interchangeably)
- Callable (ie. functions)
- Generics (ie. arbitrary types)
Description
The description of the input will be extracted from the Args
section of the docstrings.
This will usually be presented to users as a tooltip.
LaTeX
LaTeX notation can be used to typeset inputs. An exhaustive guide can be found here, but for example this notation \gamma_{max}
would appear as below in the web interface.
You can preview what the typesetting will look like in this interactive editor.
The backslash in a LaTeX symbol needs to be escaped 3 times (ex. \gamma specified as \\\\gamma) to be parsed properly by ArupCompute.
Units (optional)
Units are declared by using the :units:
annotation. LaTeX notation can be used to typeset the units, for example mm^2
would appear as below in the web interface.
Version(s)
For function revisions the Sphinx ‘versionchanged’ directive will be reused.
Semver 2.0 format is to be used for version numbering.
If no versionchanged
directives are present the function will assume the version 0.0.0 - Initial revision
.
It is best-practice to leave all prior versionchanged
tags in the docstring to allow a version history to be generated and shown to end users.
.. versionchanged:: <semver>
<description>
.. versionchanged:: 1.2.3
Fixed divide by 0 error in certain circumstances
Author(s)
For capturing code author(s) we will reuse the Sphinx 'codeauthor' directive. The first instance of 'codeauthor' will be used as the main author, subsequent ones will be 'additional' authors.
.. codeauthor:: <Name> <<email>>
.. codeauthor:: Hugh Groves <[email protected]>
Level of review
An indication of the level of review that the function has undertaken.
Options are:
- Work in progress
- Complete
If no levelofreview
directive is present the default value assumed will be 'Complete'.
.. levelofreview:: <level>
.. levelofreview:: Work in progress
Assumption
Assumptions that the user may need to know about for using the function correctly.
.. assumption:: <text>
.. assumption:: Triangle is planar
Additional information link
This directive is used to provide external links, for example to guidance on how to use the function.
.. additionalinformationlink:: <url>
<link text>
.. additionalinformationlink:: https://en.wikipedia.org/wiki/Pythagorean_theorem
Wikipedia article on pythagoras theorem
Persistent calculation identifier
This meta-data is used to track functions across multiple library versions, even if the functions name, folder, inputs, description etc. change.
UUIDv4 format is required. This website can be used to generate UUIDv4.
.. persistentcalcid:: <UUIDv4>
.. persistentcalcid:: a4889bcf-d2bb-41eb-8b06-ac87ac80a6b3
Explanation
For the ArupCompute system to work meta-data about the functions within a library need to be scraped.
In the C# backend this is achieved using Attributes. A full list of supported Attributes can be found in the arupcompute-sdk-dotnet repo.
For the python backend an alternative system must be found.
Reasoning behind chosen solution
As is reasonably common in the python ecosystem docstrings and annotations will be used to encode the meta-data.
PEP287 states that reStructuredText should be used in docstrings.
PEP3107 and PEP484 show how type annotations can be used.
reStructuredText contains the concept of ‘directives’ and ‘field lists’ for encapsulating additional meta-data. We will reuse this in our system. Popular documentation generator Sphinx utilises these features of reStructuredText to capture meta-data. There are a number of directives used within Sphinx that capture data we are interested in, so we will reuse the same syntax so that the same docstrings can inform ArupCompute as well as auto-generated documentation.
Directives
Directives follow this format:
.. <directive_name>:: <argument>
<block>
As a tangible example here is one from the Sphinx documentation
.. deprecated:: 3.1
Use function 'spam' instead
Field lists
Field lists follow the format
:fieldname: Field content
These are limited to single arguments, and can appear as supplements to directives.
Directives vs. field lists
Although much of the ArupCompute meta-data is simple key-value pairs, for consistency with more complicated instructions and to allow for future extensibility all top-level meta-data constructs will be implemented as directives.