@James suggested that I should file a blog post about my recent findings/results.
Background
I just recently started with Canvas because Uppsala University has decided to use it as its upcoming LMS platform after a failed attempt with another product. Therefore I had already spent some time with Blackboard and was quite fond of the calculated questions type in quizzes. I quickly found out that Canvas offers essentially the same functionality but a bit less comfortable.
Problem
A calculated question or Formula Question as it is called in the interface of Canvas is based on a table of pre-generated variable values and corresponding results. In the general case the variables are defined and the target function is entered using the web interface, then Canvas calculates random number values for the variables and the resulting answer value. However, as the designer you have no possibility to influence the variable values afterwards (unlike in Blackboard where you have a spreadsheet-like interface). Also, in Canvas, the equation cannot be altered once it has been entered - and the supported syntax is not very convenient for more complex problems.
I was also missing the ability to give a relative tolerance for the correct answers in a question, however, I found out that entering a percentage-sign exactly gives this behavior even though it does not seem documented anywhere.
Solution or problems?
My hope was then for the API, since it seemed to support the creation of questions. But even though there is a Python library for the purpose of controlling Canvas, many of the functions are not very well documented. My first tries failed miserably but finally I was on the right track.
The cause of my problems was that the Canvas API uses different field identifiers and structures when creating a calculated question as when you retrieve the contents of an already existing question, as I of course did in my attempts to reverse-engineer the interface.
Working solution
Here is now an example for a working solution to give you full control over the generation of Formula Qeustions using Python and the canvasapi library. The example is in Python 3 and creates a question from the field of electronics - the voltage in a voltage divider. The Python script generates the variables, fills the variables with random numbers from a set of predefined, commonly used values. I tried to write the script more for readability than any pythonic optimization.
<SPAN class="keyword token">from</SPAN> canvasapi <SPAN class="keyword token">import</SPAN> Canvas<BR /><SPAN class="keyword token">import</SPAN> itertools<BR /><SPAN class="keyword token">import</SPAN> random<BR /><BR />API_URL <SPAN class="operator token">=</SPAN> <SPAN class="string token">"https://canvas.instructure.com"</SPAN><BR />API_KEY <SPAN class="operator token">=</SPAN> <SPAN class="operator token"><</SPAN>your api key here<SPAN class="operator token">></SPAN><BR /><BR />canvas <SPAN class="operator token">=</SPAN> Canvas<SPAN class="punctuation token">(</SPAN>API_URL<SPAN class="punctuation token">,</SPAN> API_KEY<SPAN class="punctuation token">)</SPAN><BR /><BR /><SPAN class="comment token"># create a calculated_question</SPAN><BR /><SPAN class="comment token"># example of a potential divider</SPAN><BR /><SPAN class="comment token">#</SPAN><BR /><SPAN class="comment token"># U2 = U0 * R2 / ( R1 + R2 )</SPAN><BR /><SPAN class="comment token">#</SPAN><BR /><BR />E3 <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="number token">1</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">2</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">5</SPAN><SPAN class="punctuation token">]</SPAN><BR />E6 <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="number token">1.0</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1.5</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">2.2</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">3.3</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">4.7</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">6.8</SPAN><SPAN class="punctuation token">]</SPAN><BR />E12 <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="number token">1.0</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1.2</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1.5</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1.8</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">2.2</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">2.7</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">3.3</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">3.9</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">4.7</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">5.6</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">6.8</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">8.2</SPAN><SPAN class="punctuation token">]</SPAN><BR /><BR />coursename <SPAN class="operator token">=</SPAN> <SPAN class="string token">'test'</SPAN><BR />quizname <SPAN class="operator token">=</SPAN> <SPAN class="string token">'test'</SPAN><BR /><BR /><SPAN class="comment token"># define the input variable names</SPAN><BR /><SPAN class="comment token"># each variable has its own range, format and scale</SPAN><BR /><SPAN class="comment token"># </SPAN><BR />variables <SPAN class="operator token">=</SPAN> \<BR /> <SPAN class="punctuation token">[</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'U0'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'unit'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'V'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'format'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'{:.1f}'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'scale'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'1'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'range'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="number token">1.2</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1.5</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">4.5</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">9</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">12</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">24</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">48</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">110</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">220</SPAN><SPAN class="punctuation token">]</SPAN><BR /> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'R1'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'unit'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'ohm'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'format'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'{:.1f}'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'scale'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'1'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'range'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN> i<SPAN class="operator token">*</SPAN>j <SPAN class="keyword token">for</SPAN> i<SPAN class="punctuation token">,</SPAN> j <SPAN class="keyword token">in</SPAN> itertools<SPAN class="punctuation token">.</SPAN>product<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">10</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">100</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1000</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN> E12<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">]</SPAN><BR /> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'R2'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'unit'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'ohm'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'format'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'{:.1f}'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'scale'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'1'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'range'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN> i<SPAN class="operator token">*</SPAN>j <SPAN class="keyword token">for</SPAN> i<SPAN class="punctuation token">,</SPAN> j <SPAN class="keyword token">in</SPAN> itertools<SPAN class="punctuation token">.</SPAN>product<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">10</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">100</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="number token">1000</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN> E12<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">]</SPAN><BR /> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="punctuation token">]</SPAN><BR /><BR /><SPAN class="comment token"># how many sets of answers</SPAN><BR />rows <SPAN class="operator token">=</SPAN> <SPAN class="number token">30</SPAN><BR /><BR /><SPAN class="comment token"># create an empty list of lists (array) for the values</SPAN><BR />values <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">[</SPAN> <SPAN class="punctuation token">[</SPAN> i <SPAN class="keyword token">for</SPAN> i <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>variables<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">]</SPAN> <SPAN class="keyword token">for</SPAN> _ <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>rows<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">]</SPAN><BR /><BR /><SPAN class="comment token"># create an empty list for the calculated results</SPAN><BR />results <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">[</SPAN>i <SPAN class="keyword token">for</SPAN> i <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>rows<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">]</SPAN><BR /><BR /><SPAN class="comment token"># fill the array of input values with random choices from the given ranges</SPAN><BR /><SPAN class="keyword token">for</SPAN> i <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>rows<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN><BR /> <SPAN class="keyword token">for</SPAN> j <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>variables<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN><BR /> values<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN> <SPAN class="operator token">=</SPAN> random<SPAN class="punctuation token">.</SPAN>choice<SPAN class="punctuation token">(</SPAN>variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'range'</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><BR /><BR /> <SPAN class="comment token"># and calculate the result value </SPAN><BR /> results<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN> <SPAN class="operator token">=</SPAN> values<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">0</SPAN><SPAN class="punctuation token">]</SPAN> <SPAN class="operator token">*</SPAN> values<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">2</SPAN><SPAN class="punctuation token">]</SPAN> <SPAN class="operator token">/</SPAN> <SPAN class="punctuation token">(</SPAN>values<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">1</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="operator token">+</SPAN>values<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="number token">2</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">)</SPAN><BR /><BR /><SPAN class="comment token"># format the text field for the question</SPAN><BR /><SPAN class="comment token"># an HTML table is created which presents the variables and their values</SPAN><BR />question_text <SPAN class="operator token">=</SPAN> <SPAN class="string token">'<p><table border="1"><tr><th></th><th>value</th><th>unit</th></tr>'</SPAN><SPAN class="punctuation token">;</SPAN><BR /><SPAN class="keyword token">for</SPAN> j <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>variables<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN><BR /> question_text <SPAN class="operator token">+=</SPAN> <SPAN class="string token">'<tr>'</SPAN><BR /> question_text <SPAN class="operator token">+=</SPAN> <SPAN class="string token">'<td style="text-align:center;">'</SPAN> <SPAN class="operator token">+</SPAN> variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">+</SPAN> <SPAN class="string token">'</td>'</SPAN><BR /> question_text <SPAN class="operator token">+=</SPAN> <SPAN class="string token">'<td style="text-align:right;">['</SPAN> <SPAN class="operator token">+</SPAN> variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">+</SPAN> <SPAN class="string token">']</td>'</SPAN><BR /> question_text <SPAN class="operator token">+=</SPAN> <SPAN class="string token">'<td style="text-align:center;">'</SPAN> <SPAN class="operator token">+</SPAN> variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'unit'</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">+</SPAN> <SPAN class="string token">'</td>'</SPAN><BR /> question_text <SPAN class="operator token">+=</SPAN> <SPAN class="string token">'</tr>'</SPAN><BR />question_text <SPAN class="operator token">+=</SPAN> <SPAN class="string token">'</table></p>'</SPAN><BR /><BR /><SPAN class="comment token"># format the central block of values and results</SPAN><BR />answers <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN><BR /><SPAN class="keyword token">for</SPAN> i <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>rows<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN><BR /> answers<SPAN class="punctuation token">.</SPAN>append<SPAN class="punctuation token">(</SPAN>\<BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'weight'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'100'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'variables'</SPAN><SPAN class="punctuation token">:</SPAN><BR /> <SPAN class="punctuation token">[</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'value'</SPAN><SPAN class="punctuation token">:</SPAN> variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'format'</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>values<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">)</SPAN><BR /> <SPAN class="punctuation token">}</SPAN> <SPAN class="keyword token">for</SPAN> j <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>variables<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><BR /> <SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'answer_text'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'{:.5g}'</SPAN><SPAN class="punctuation token">.</SPAN>format<SPAN class="punctuation token">(</SPAN>results<SPAN class="punctuation token">[</SPAN>i<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">)</SPAN><BR /> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">)</SPAN><BR /><BR /><SPAN class="comment token"># format the block of variables,</SPAN><BR /><SPAN class="comment token"># 'min' and 'max' do not matter since the values are created inside the script</SPAN><BR /><SPAN class="comment token"># 'scale' determines the decimal places during output </SPAN><BR />variables_block <SPAN class="operator token">=</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">]</SPAN><BR /><SPAN class="keyword token">for</SPAN> j <SPAN class="keyword token">in</SPAN> range<SPAN class="punctuation token">(</SPAN>len<SPAN class="punctuation token">(</SPAN>variables<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN><BR /> variables_block<SPAN class="punctuation token">.</SPAN>append<SPAN class="punctuation token">(</SPAN>\<BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'min'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'1.0'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'max'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'10.0'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'scale'</SPAN><SPAN class="punctuation token">:</SPAN> variables<SPAN class="punctuation token">[</SPAN>j<SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">.</SPAN>get<SPAN class="punctuation token">(</SPAN><SPAN class="string token">'scale'</SPAN><SPAN class="punctuation token">)</SPAN><BR /> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">)</SPAN><BR /><BR /><SPAN class="comment token"># put together the structure of the question</SPAN><BR />new_question <SPAN class="operator token">=</SPAN> \<BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'question_name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'Question 6'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'question_type'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'calculated_question'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'question_text'</SPAN><SPAN class="punctuation token">:</SPAN> question_text<SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'points_possible'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'1.0'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'correct_comments'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">''</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'incorrect_comments'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">''</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'neutral_comments'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">''</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'correct_comments_html'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">''</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'incorrect_comments_html'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">''</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'neutral_comments_html'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">''</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'answers'</SPAN><SPAN class="punctuation token">:</SPAN> answers<SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'variables'</SPAN><SPAN class="punctuation token">:</SPAN> variables_block<SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'formulas'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="string token">'automated by python'</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'answer_tolerance'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'5%'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'formula_decimal_places'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'1'</SPAN><SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'matches'</SPAN><SPAN class="punctuation token">:</SPAN> None<SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="string token">'matching_answer_incorrect_matches'</SPAN><SPAN class="punctuation token">:</SPAN> None<SPAN class="punctuation token">,</SPAN><BR /> <SPAN class="punctuation token">}</SPAN><BR /> <BR /><BR />courses <SPAN class="operator token">=</SPAN> canvas<SPAN class="punctuation token">.</SPAN>get_courses<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><BR /><SPAN class="keyword token">for</SPAN> course <SPAN class="keyword token">in</SPAN> courses<SPAN class="punctuation token">:</SPAN><BR /> <SPAN class="keyword token">if</SPAN> course<SPAN class="punctuation token">.</SPAN>name<SPAN class="punctuation token">.</SPAN>lower<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">==</SPAN> coursename<SPAN class="punctuation token">.</SPAN>lower<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN><BR /> <SPAN class="keyword token">print</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="string token">'found course'</SPAN><SPAN class="punctuation token">)</SPAN><BR /> quizzes <SPAN class="operator token">=</SPAN> course<SPAN class="punctuation token">.</SPAN>get_quizzes<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><BR /> <SPAN class="keyword token">for</SPAN> quiz <SPAN class="keyword token">in</SPAN> quizzes<SPAN class="punctuation token">:</SPAN><BR /> <SPAN class="keyword token">if</SPAN> quiz<SPAN class="punctuation token">.</SPAN>title<SPAN class="punctuation token">.</SPAN>lower<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">==</SPAN> quizname<SPAN class="punctuation token">.</SPAN>lower<SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">:</SPAN><BR /> <SPAN class="keyword token">print</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="string token">'found quiz'</SPAN><SPAN class="punctuation token">)</SPAN><BR /><BR /> question <SPAN class="operator token">=</SPAN> quiz<SPAN class="punctuation token">.</SPAN>create_question<SPAN class="punctuation token">(</SPAN>question <SPAN class="operator token">=</SPAN> new_question<SPAN class="punctuation token">)</SPAN> <BR /> <BR /><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>Since this is mostly the result of successful reverse engineering and not based on the actual source code of Canvas the above example should perhaps be used with care, but for me it is what I needed to create usable questions for my students. Perhaps this could also serve the developers as an example on how the interface for calculated questions could be improved in the future.
How does it work?
The dictionary variables (lines 26-49) contains the names and ranges of the variables, as well as formatting instructions. The ranges are given as lists. In lines 61-66 the random values are generated and the results calculated from these values. Lines 70-77 create a rudimentary table to be included in the question text containing the variables and their values as well as physical units for this particular question. Lines 80-93 finally assemble the variable/answer block and lines 109-128 put everything together into the dictionary to create a new question.
The script then inserts the question into an existing quiz in an existing course in line 140.
After running the script
This screenshot shows the inserted question after running the script, obviously this would need some more cosmetics.

And when editing the question this is what you see:

Be careful not to touch the variables or the formula section since this will reset the table values.
Cosmetics
In order to be presentable to the students the above questions needs some cosmetics. What is to be calculated? Perhaps insert a picture or an equation? More text?

After updating the question and leaving the editor it now looks like this in the Canvas UI:

Seeing and answering the question
When you now start the quiz, this is how the question looks:


Summary
- calculated_questions can be generated using the Python canvasapi library
- answer values have to be provided with the key 'answer-text'
<SPAN class="string token">'answers'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><BR /> <SPAN class="string token">'weight'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'100'</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="string token">'variables'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'U0'</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">'value'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'9.0'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="punctuation token">{</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'R1'</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">'value'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'5600.0'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="punctuation token">{</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'R2'</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">'value'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'5600.0'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="string token">'answer_text'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'4.5'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN> - when querying an existing calculated_question through the API the answer values are found with the key 'answer'
answers<SPAN class="operator token">=</SPAN><SPAN class="punctuation token">[</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><SPAN class="string token">'weight'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="number token">100</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="string token">'variables'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN><BR /> <SPAN class="punctuation token">{</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'U0'</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">'value'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'110.0'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="punctuation token">{</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'R1'</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">'value'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'82.0'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="punctuation token">{</SPAN><SPAN class="string token">'name'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'R2'</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="string token">'value'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'8200.0'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="string token">'answer'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="number token">108.91</SPAN><SPAN class="punctuation token">,</SPAN> <BR /> <SPAN class="string token">'id'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="number token">3863</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN> - when supplying an equation for the 'formular' field this has to be done in a list, not a dictionary
<SPAN class="string token">'formulas'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="punctuation token">[</SPAN><SPAN class="string token">'a*b'</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN></SPAN>
- when querying an existing calculated_question through the API the equations are found in a dictionary like this:
formulas<SPAN class="operator token">=</SPAN><SPAN class="punctuation token">[</SPAN><SPAN class="punctuation token">{</SPAN><SPAN class="string token">'formula'</SPAN><SPAN class="punctuation token">:</SPAN> <SPAN class="string token">'a*b'</SPAN><SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">]</SPAN><SPAN class="punctuation token">,</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN></SPAN>