DRAFT DESIGN (SOME NOTES, SUMMARISING ABOVE)
Idea: a simple mapping from API calls to the corresponding tests and vice versa.
Incentives for this initiative:
- having more runable examples of how to use a certain API in addition to docs nbs
- entice more tests to be written where tests are lacking
api2test - find which tests, if any, exercise/test a given API function.
Examples of what one may type into a notebook:
doctest('ImageDataBunch.from_name_re')
returns:
pytest -sv -k test_from_name_re tests/test_vision_data.py
- [link into GitHub tests folder to the test script]
doctest('Learner.fit_one_cycle')
returns:
pytest -sv -k test_fit_one_cycle tests/test_train.py
- [link into GitHub tests folder to the test script]
Note, the user has to run these tests locally her-/himself
Users should be able to type in the shortest function like: doctest('fit_one_cycle')
, and only need the class name if itâs a method that appears in more than one class. But the function should be able to give the same results for any level of qualification. For example for the unique function fit_one_cycle
:
doctest('basic_train.Learner.fit_one_cycle')
doctest('Learner.fit_one_cycle')
doctest('fit_one_cycle')
docs.fast.ai built-in link
in addition to [Source] link the docs will now have [Test] link, which will give the user a pop up with the same information as if they were to run doctest('this api function name').
test2api - how a test registers that it exercises a given set of functions
Example:
def test_from_name_re(path):
this_tests(ImageDataBunch.from_name_re, âŚ)
# normal test continues here
def test_lr_find(learn):
# can be anywhere in the test, in case objects appear later in the test
this_tests(learn.lr_find)
this_tests()
:
- will automatically derive the fully qualified function name if an alias or short imported form is passed (e.g. could pass
learn.fit
and it should sort it out - this would be preferred way since itâll register the correct subclass this way if any) - will automatically derive the test module and test name using
inspect
(inspect.currentframe().f_back
) - will add the map entries into a map db
A test may register one or more functions. But tests shouldnât register functions already tested elsewhere. (e.g. fit()
is in 100s of tests.
data collection and doc integration
collection
make test
needs to be instrumented to collect the output of all test_this()
calls into a single map db (e.g. json file), so that it can later be used by doctest()
. The docbuilder (fastai/gen_doc/*) will use it to integrate the testing information into the API docs.
The map file should probably be saved under fastai
and added to MANIFEST.in so that itâs installed with the .py
files if we want doctest()
to work on userâs machines, which may or may not have a fastai
git checkout. i.e. it should be in the distribution. or perhaps the first stage is where we only make this feature available via docs.fast.ai then we donât need to worry about it right away.
To simplify things the map should probably be only updated on make test
which will be instrumented with extra commands to save the map db. And only if it was 100% successful, otherwise the previous copy of the map db is preserved.
Normal pytest
will not do anything special. reason: when running a single test module we donât want to break the map db.
coding
Package: this is all docs, so some place under fastai.gen_docs
- probably just stick it in one of the existing modules, we can move them later if need be.
map file format/contents
The elements that will be made available are:
test_file, test_name, fully qualified API function, e.g.:
test_vision_data.py, test_from_name_re, vision.data.ImageDataBunch.from_name_re
questions:
- probably no need to add
fastai.
in the function name? or should we add it in case we document some other APIs? Andrew?
notes:
- one api function may have multiple corresponding test_names,
- and vice versa any test_name may have multiple API functions it exercises.
- if there are no tests registered for a given function, we will have a placeholder explaining how to write such tests.
.json format? a flat list of entries?