The Minitorch codebase is structured to mimic the experience of contributing to a real open-source project. It is not sufficient to implement functions correctly; the code itself needs to meet the specific contributor requirements. These are checked by the system automatically before acceptance.
It is required to keep your code organized and clean to make it easier to debug, optimize, and document. To help with this process, we utilize required formatting on all assignments.
Fixing style bugs can be an annoying process. However, there are now tools
to fix most formatting issues automatically. We use
black to automatically
all of your code to fit most of the requirements (see
>>> black .
Black will fix many of your issues, but cannot check for aspects
like using unknown variables. You will also need to run the
linter in your directory to check for remaining issues:
We recommend setting up your editor or IDE to highlight other style issues. Many developers utilize VSCode with plugins to check for these issues as they code.
Each assignment has a series of tests that require your code to pass.
These tests are in the
tests/ directory and are in the
format (https://docs.pytest.org/en/stable/). Any function in that
directory starting with
test is run as part of the test
Each assignment has 4 task groups that you will need to pass. To run
individual task groups you can use the
>>> pytest -m task0_0
In addition to running a full task which runs all of the tests, you can run tests in a single file with:
>>> pytest tests/test_operators.py
Or even a particular test with:
>>> pytest tests/test_operators.py -k test_sum
Note: PyTest will hide all print statements unless a test fails. If you want to see output for a given tests you may need to cause an assertion failure.
Modern versions of Python allow for static type checking to ensure that functions take and returns objects of the correct type. The Minitorch code base is fully annoted with typed on each function. Users will not have to provide types, but they provide documentation as to what functions expect as arguments and as for their return values. For example, if we are writing a function that does multiplication it would have the following signature.
def mul(x: float, y: float) -> float:
As we get to more complex topics the type signatures will get more
complex as well. For example,
Iterable is use to represent a type
that can be iterated over.
def negList(ls: Iterable[float]) -> Iterable[float]:
In order to check that the code matches the types, the project requires
that you use the
mypy library. This is run as part of the style check.
Throughout the codebase, we require to document all functions in a standardized style. Documentation is critical for our Python codebase, and we use it to convey requirements on many functions. Functions should have docstrings in the following form (known as Google docstyle):
def index(ls: List[Any], i: int) -> Any:
ls: A list of any type.
i: An index into the list
Value at ls[i].
A full description of this docstyle is listed here https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html.
The project also requires that you keep documentation up-to-standard
throughout. Lint errors will be thrown by
flake8 if your documentation is in
the incorrect format.
These elements can be checked automatically through a tool known as pre-commit. Using the precommit tool is optional but will likely save you time in your coding process and ensure that you are not making too many unnecessary failed pull requests. You can install the tool by running,
pip install pre-commit
You can run all the checks (black, flake8, mypy, etc) and corrections on your code with the following command:
pre-commit run --all
You can also 'install' pre-commits which will run on every commit automatically, and prevent you from committing bad code.
Continuous Integration (CI)
In addition to local testing, the project is set up such that on each code push, tests are automatically run and checked on the server. You are able to see how well you are doing on the assignment by committing your code, pushing to the server, and then logging in to GitHub. This process takes several minutes, but it is an easy way to keep track of your progress as you go.
Specifically, you can run:
>>> git commit -am "First commit"
>>> git push origin master
Then go to your GitHub and click on "Pull requests". Clicking on the request itself gives a link to show the current progress of your work.