Creating and Developing a New Framework-Derived Model
We explain how to do this in three sections:
Installing the Required Development Environment
Using models built with the Tax-Analyzer-Framework is easy on Linux, Mac, and Windows computers. However, the environment needed to do development work with the Framework is more extensive. In this section, we describe how to install the required development environment on each of those kinds of computers. Do the computer-specific things first, then do the things for all computers.
Linux computers. There are no preliminary things to do, so proceed to the all-computers things-to-do list.
Mac computers. There is only one thing to do: install the Xcode command-line tools. After doing that, proceed to the all-computers things-to-do list.
Windows computers. The native Windows operating system has almost none of what it needed for the development environment. Given that situation, the best strategy is to run Linux on your Windows computer using Microsoft's Windows Subsystem for Linux (WSL) running the free Ubuntu Linux distribution. Once that is done, proceed to the all-computers things-to-do list.
All computers. Once this basic development environment has been setup, make sure all the following things have been done:
- Install the Tax-Analyzer-Framework package
- Download the ETI-Tax-Analyzer source code and unzip it into
a directory named
ETI-Tax-Analyzer
so that thesetup.py
file is in theETI-Tax-Analyzer
directory
After doing the above things, you should be able to change into the
top-level directory of the ETI-Tax-Analyzer source code directory tree
(the one that contains the Makefile
) and display the Makefile
help
by executing this command:
make help
And more importantly, you should be able to pass the code-style
tests and the pytest unit tests. Confirm that this is the case, by
executing the following commands in that top-level directory:
make cstest
make pytest
Using ETI-Tax-Analyzer as Template for the New Model
The Tax-Analyzer-Framework package includes the tacopyfiles
tool
that can be used to create a new source code tree using the files in
the ETI-Tax-Analyzer source code tree as a template. Before using
that tool, create a (mostly empty) directory that is named
CCK-Tax-Analyzer, where you replace the CC with the
two-character country code of the new tax model and you replace the
K with a single character identifying the tax kind. So, for
example, if you want to develop an individual income tax model for
India, you would create a new directory named INI-Tax-Analyzer
using a command like this:
mkdir ~/INI-Tax-Analyzer
Then while in the top-level directory of the ETI-Tax-Analyzer directory tree,
execute this command:
tacopyfiles NEWDIR
where you replace NEWDIR
with the name of the directory you created
in the prior paragraph. So, to continue the example of the individual
income tax model for India, the command would be:
tacopyfiles ~/INI-Tax-Analyzer
To confirm that the file copy worked, change into the top-level
directory of the new model's source code tree and execute this
command:
make alltests
You should be able to pass all the tests.
Tips for Developing the New Model
Here are a few suggestions about how to go about developing the new tax model:
Before beginning any development work on the new model, all the files that were copied into the new model's source code directory tree should be checked into a repository of a version control system (like Git or Fossil). The
tacopyfiles
tool has been designed so that it can copy the files into a newly created repository's checked-out source code tree, which is empty except forREADME.md
files and for files or directories that begin with a dot (.
) character. If you are not sure why using a version control system is being recommended, please read this introduction to version control concepts and benefits.The first thing to do in developing the new model is to specify the parameters in several JSON files. The unit tests in the
???taxanalyzer/tests/test_json.py
module help you do this in a consistent way. You can run just these JSON tests by executing in the top-level directory this command:
pytest -m json
If you get too many test failure messages, try this command:
pytest -m json0
Once that command produces no test failures, change the zero to one and rerun the command to execute the next most difficult tests. Proceed in this way until all thetest_json.py
tests pass. This progression will eventually involve specifying the three CSV data files in a way that is consistent with the JSON parameters, and then specifying the logic of tax calculation in thecalcfunctions.py
module and in theCalculator.calc_preliminary_logic
andCalculator.calc_nonprelim_logic
methods in thecalculator.py
module. Functions containing logic that should be performed just once per year at the beginning of the year should be called from theCalculator.calc_preliminary_logic
method. All other functions should be called from theCalculator.calc_nonprelim_logic
method. (Note that many tax models will have an emptyCalculator.calc_preliminary_logic
method or one that calls theDoNothing
calcfunction. Such models will have no parameters in thecalcoptions.json
file and no methods in thecalcoptions.py
module.) Read the next three tips before beginning work on the tax logic.When you create new or delete old
calcfunctions.py
functions, you need to modify the statement at the top of thecalculator.py
module that imports the functions and you need to modify theCalculator.calc_preliminary_logic
andCalculator.calc_nonprelim_logic
methods accordingly. Then use the Numba code generator,tamakefast
, which is provided by the Tax-Analyzer-Framework and translates the code incalcfunctions.py
into the Numba-decorated code incalcfuncsfast.py
, by executing this command:
make fast
Most functions in the
calcfunctions.py
module have arguments that are a combination of policy parameters and records variables. The body of these multiple-argument functions includes code that employs a simple syntax with if-then-else statements and assignment statements that use min functions, max functions, and arithmetic operators. This simple syntax is required for use of the Numba JIT compiler. However, it is possible to include functions in thecalcfunctions.py
module that have just a Calculator object as an argument (but be sure to include the name of such a function in thecalc_arg_functions
list in thecalcfunctions_spec.json
file). The body of these single-argument functions include code that can access all the Calculator methods (including accessing the value of each CalculatorOptions parameter) and use the full capabilities of Python. Writing these single-argument functions requires Python programming expertise and often produces slower-executing code than Numba-decorated code, but provides full programming flexibility.If you add a function to the
calcfunctions.py
module that returns an intermediate value (that is, a variable that is not a records variable) for use in another function, be sure to include the name of such a function in thejit_only_functions
list in thecalcfunctions_spec.json
file.Ensure all your source code is fully tested by periodically generating a code coverage report using this command:
make coverage
If you have less than 100% code coverage, you should add one or more tests in the unit-tests directory to regain complete code coverage.Once the new tax model is operational, document it using some kind of documentation system, of which there are many. The embedded Fossil documentation for the ETI-Tax-Analyzer, and the tests of the examples used in that documentation, were copied to the new model source code tree in the
???-Tax-Analyzer/www
directory. As you develop documentation for the new tax model, you can remove that copied documentation.