Closed ChrisCScott closed 5 years ago
Alternatively, migrate much of that functionality to Settings
by adding a setting-to-arg dict for each class and providing a build_*
function for each supported object type that (a) receives args from users and (b) fills in any missing args with Settings
defaults.
This logic can be implemented generically, so each specific function could simply consist of referencing the appropriate mapping and calling generic code.
We could then delete Forecaster
entirely and require that users build objects in the usual way before building a Forecast. (Consider how this might interact with inflation_adjust; perhaps that should be kept in Scenario and passed as an optional arg on a per-function-call basis? Or perhaps simply at __init__
time - can we build out inflation-adjusted contribution room limits/etc. statically?)
Refactor
Forecaster
to provide generic logic for taking in a mapping of{type: {'argname': defaultval}}
and building objects based on that mapping. It would only be necessary to provide a handful of methods to do this, and then we could rely on client code passing suitable object types to the method.For instance, client code might call
add_account(cls=RRSP, *args, **kwargs)
, which would build an RRSP with the passed args and would fill in any not-provided args if defaults are provided in the mapping. It wouldn't be necessary to implementadd_rrsp
(although we might need to provide the subclassForecasterCanada
to provide a Canada-specific mapping).It might be necessary for
defaultval
to be a string which is executed viaeval
at the time of building the related object. This lets us accommodate attributes ofForecaster
which might not be defined at class-definition (or even init) time, likeself.scenario
.Consider whether we can avoid using
eval
by testing for attribute syntax and then getting the attribute (e.g. usingoperator.attrgetter
to allow for dynamically resolving nested attributes). If we're OK with usingeval
, this likely isn't necessary.It will still be necessary to provide, e.g., an
add_account
method to ensure that the appropriate assets and debts objects are populated, although it might not be necessary to add the variousadd_*
methods for subclasses ofAccount
. It may also be practical to avoid the various set_*_strategy methods, e.g. if the methods return strategy objects, which are then assigned manually to the relevant attribute.