I have a working interview (yay!), and I'm working on refactoring it. I'm trying to figure out what might be a good way to move my code
blocks into .py
files. In particular, I'm worried about maintaining some of the fancy things docassemble does (the particular code
block I'm thinking about is marked initial: True
, for example).
Would the idea be to convert whatever your code
blocks are doing into functions, and then assign the variables docassemble
is looking for in a way that uses those functions? Presumably the results of those functions still need to be dealt with in code
blocks?
Is the below roughly the right approach (code below)? I'm assuming that:
Bcode.func(A ...)
as below, if A
was undefined, would trigger the exception necessary to cause docassemble
to search for the question needed to set A
?returning
from functions works as set out below.Are any / all of these assumptions correct / incorrect?
So...
If this was my questions.yml
file:
---
question: A?
yesno: A
---
# code setting value of B
---
code: |
if A:
answer = "A"
elif B:
answer = "B"
else:
answer = "C"
---
To abstract away the code, I assume I might do something like this?
questions.yml
:
---
imports:
- Bcode
---
question: A?
yesno: A
---
initial: True
code: |
answer = Bcode.func(A, *args_to_set_value_of_B)
---
Bcode.py
:
---
def func(a, *args_to_set_value_of_b):
# code computing value of b
if a:
return "A"
elif b:
return "B"
else:
return "C"
---
If you do
modules:
- .Bcode
Then docassemble will run (in effect):
exec("from docassemble.yourpackage.Bcode import *", user_dict)
where user_dict
is the interview answers (the namespace of Python code in your YAML file). This will make the name func
available in the namespace of your interview so that it can be used in code
blocks, Mako templating, etc.
Your initial
block will raise an exception because Bcode
is not a name in the interview answers.
Your function func()
will always raise an exception whenever a
is true, because b
is not defined in the namespace of func()
.
Docassemble works by trapping NameError
, IndexError
, and AttributeError
exceptions and then looking for a question
or code
block that will define whatever variable was undefined. NameError
exceptions work with any type of variable, but IndexError
and AttributeError
exceptions only work on instances of DAObject
or subclasses thereof.
When you move code into module files, it is important to make sure that the code in the module file does not raise NameError
exceptions, because those will cause confusion; docassemble will try to define the variable in the interview answer namespace, but this will never fix the problem inside the module because that name will be undefined inside the module no matter what. However, it is safe for code in a module file to raise IndexError
and AttributeError
errors on DAObject
variables that have been passed from the interview namespace to the module namespace, because when docassemble defines those variables in the interview answer namespace, the definitions will be available inside the module as well.