unittest: optimise for code size and memory use by dpgeorge · Pull Request #1125 · micropython/micropython-lib · GitHub
Skip to content

unittest: optimise for code size and memory use#1125

Open
dpgeorge wants to merge 4 commits into
micropython:masterfrom
dpgeorge:unittest-optimise
Open

unittest: optimise for code size and memory use#1125
dpgeorge wants to merge 4 commits into
micropython:masterfrom
dpgeorge:unittest-optimise

Conversation

@dpgeorge

Copy link
Copy Markdown
Member

Summary

Based on discussion and testing in micropython/micropython#16311, this PR applies some optimisations to unittest to reduce its bytecode size, and reduce the amount of RAM it uses at runtime.

  • reuse AssertRaisesContext for assertWarns
  • remove support for running it with CPython
  • optimise calling of _handle_test_exception
  • only format msg if needed

The use of raise AssertionError instead of assert also means the module can now be compiled with -O3 and still function correctly (-O3 disables assert expressions!).

Testing

Tested on ADAFRUIT_ITSYBITSY_M0_EXPRESS which has about 20k heap memory.

Prior to this change:

  • __init__.mpy has size 5795 bytes
  • import unittest costs 9648 bytes of heap RAM (measured via g.collect(); micropython.mem_info() before and after import)

With this change:

  • __init__.pym has size 5516 bytes (-279 byte change)
  • import unittest costs 9440 bytes (-208 byte change)

Also, the current version of unittest unconditionally does string formatting for the error message for each call to self.assert<Condition>(...), which is really expensive in terms of RAM use and computation. The changes here improve the situation so the string formatting of msg is only done if the assert fails. That should free up a lot of RAM during the execution.

With these changes, ADAFRUIT_ITSYBITSY_M0_EXPRESS can successfully run the tests modified/added in micropython/micropython#16311, they now all pass or skip correctly.

Trade-offs and Alternatives

This module is no longer runnable under CPython due to removal of traceback module support. But IMO it's too restrictive to get this working under CPython, we need to be able to optimise it for running under MicroPython. The unittest test suite which runs under CI here anyway tests the behaviour, CPython is not needed for that.

Generative AI

Not used.

dpgeorge added 4 commits June 25, 2026 13:38
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Note that using `if not expr: raise AssertionError(msg)` is pretty much
equivalent in terms of bytecode to `assert expr, msg`.  But the use of
`raise AssertionError` is clearer and means that the code can now be
compiled with -O3 and still function.

Signed-off-by: Damien George <damien@micropython.org>
@dpgeorge

Copy link
Copy Markdown
Member Author

@projectgus projectgus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look simple to me, that's great it reduces footprint significantly! Should churn the heap a lot less with the string formatting moved into the failure path, too.

@dpgeorge

Copy link
Copy Markdown
Member Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants