assert_rewriter


Nameassert_rewriter JSON
Version 1.0 PyPI version JSON
download
home_pagehttps://github.com/brandon-rhodes/assert_rewriter/
SummaryRewrite function bytecode to support assert introspection.
upload_time2024-03-19 18:48:51
maintainerNone
docs_urlNone
authorBrandon Rhodes
requires_pythonNone
licenseMIT
keywords
VCS
bugtrack_url
requirements wheel
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
=================================================================
assert_rewriter: rewrite Python bytecode for assert introspection
=================================================================

Maybe I’ll wind up as the only user of this rather abstruse Python module.
But it seemed like this functionality was worth splitting out
from inside of my personal Python testing framework,
where it was hidden.

This ``assert_rewriter`` package
uses fast and efficient regular expressions to rewrite the bytecode
of Python assert statements
so that, on failure, they print out the comparison that failed —
a feature called ‘assert introspection’
that’s more commonly implemented
using slow and ponderous depth-first searches of abstract syntax trees.
It supports Python 2.7 through 3.12.

It’s a deep loss that Python 3 didn’t add assert introspection hooks
as a fully supported part of the language.
It would have been far more useful than most of the other changes they made.
(The only thing more useful that Python 3 could have done
would have been to eliminate the awful ``if __name__ == '__main__':``
that is utter nonsense at the language level
and that deeply and desperately confuses every student
to whom I’ve tried to teach the language.
But, alas, they missed the opportunity.)

Here’s an example of what happens without assert introspection.
You write a test:

>>> def test_function():
...     assert 1 + 1 == 3

But when it fails, you get zero useful information back:

>>> test_function()
Traceback (most recent call last):
  ...
AssertionError

This package aims to solve that.
Take your test functions and pass them to ``rewrite_function()``.
It will rewrite their bytecode in-place.
The functions will then report failures using easy-to-read assert exceptions
that explain what went wrong:

>>> from assert_rewriter import rewrite_function
>>> rewrite_function(test_function)
>>> test_function()
Traceback (most recent call last):
...
AssertionError: 2 != 3

By default,
the rewritten function will call ``unittest.TestCase`` methods
instead of the corresponding asserts.
In the above example,
the ``TestCase.assertEqual()`` method was called with the values
on either side of the ``==`` sign.
If you instead want to provide callables of your own,
then put them in a tuple with the same length as the operations listed in
the ``assert_rewriter.core.comparison_constants`` tuple
and then pass your tuple as a second argument to ``rewrite_function()``.

My own testing framework only does assert rewriting after a test fails,
to save time in the common case that a test passes;
but that runs the risk that the test behaves differently the second time,
so other folks might want to rewrite tests ahead of time.

Anyway, this might be quietly ignored for all time,
which would be fine,
but here it is in case you need it —
or are at least curious how it works,
and think you might learn something by giving it a quick read-through.

Here’s the GitHub repository, for reporting issues with the package:

https://github.com/brandon-rhodes/assert_rewriter/

— Brandon Rhodes

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/brandon-rhodes/assert_rewriter/",
    "name": "assert_rewriter",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": null,
    "author": "Brandon Rhodes",
    "author_email": "brandon@rhodesmill.org",
    "download_url": "https://files.pythonhosted.org/packages/af/1f/6eb89c96ef4818941be6ea570bf8b6d815de5142299d737b751dd899de08/assert_rewriter-1.0.tar.gz",
    "platform": null,
    "description": "\n=================================================================\nassert_rewriter: rewrite Python bytecode for assert introspection\n=================================================================\n\nMaybe I\u2019ll wind up as the only user of this rather abstruse Python module.\nBut it seemed like this functionality was worth splitting out\nfrom inside of my personal Python testing framework,\nwhere it was hidden.\n\nThis ``assert_rewriter`` package\nuses fast and efficient regular expressions to rewrite the bytecode\nof Python assert statements\nso that, on failure, they print out the comparison that failed \u2014\na feature called \u2018assert introspection\u2019\nthat\u2019s more commonly implemented\nusing slow and ponderous depth-first searches of abstract syntax trees.\nIt supports Python\u00a02.7 through\u00a03.12.\n\nIt\u2019s a deep loss that Python\u00a03 didn\u2019t add assert introspection hooks\nas a fully supported part of the language.\nIt would have been far more useful than most of the other changes they made.\n(The only thing more useful that Python\u00a03 could have done\nwould have been to eliminate the awful ``if __name__ == '__main__':``\nthat is utter nonsense at the language level\nand that deeply and desperately confuses every student\nto whom I\u2019ve tried to teach the language.\nBut, alas, they missed the opportunity.)\n\nHere\u2019s an example of what happens without assert introspection.\nYou write a test:\n\n>>> def test_function():\n...     assert 1 + 1 == 3\n\nBut when it fails, you get zero useful information back:\n\n>>> test_function()\nTraceback (most recent call last):\n  ...\nAssertionError\n\nThis package aims to solve that.\nTake your test functions and pass them to ``rewrite_function()``.\nIt will rewrite their bytecode in-place.\nThe functions will then report failures using easy-to-read assert exceptions\nthat explain what went wrong:\n\n>>> from assert_rewriter import rewrite_function\n>>> rewrite_function(test_function)\n>>> test_function()\nTraceback (most recent call last):\n...\nAssertionError: 2 != 3\n\nBy default,\nthe rewritten function will call ``unittest.TestCase`` methods\ninstead of the corresponding asserts.\nIn the above example,\nthe ``TestCase.assertEqual()`` method was called with the values\non either side of the ``==`` sign.\nIf you instead want to provide callables of your own,\nthen put them in a tuple with the same length as the operations listed in\nthe ``assert_rewriter.core.comparison_constants`` tuple\nand then pass your tuple as a second argument to ``rewrite_function()``.\n\nMy own testing framework only does assert rewriting after a test fails,\nto save time in the common case that a test passes;\nbut that runs the risk that the test behaves differently the second time,\nso other folks might want to rewrite tests ahead of time.\n\nAnyway, this might be quietly ignored for all time,\nwhich would be fine,\nbut here it is in case you need it \u2014\nor are at least curious how it works,\nand think you might learn something by giving it a quick read-through.\n\nHere\u2019s the GitHub repository, for reporting issues with the package:\n\nhttps://github.com/brandon-rhodes/assert_rewriter/\n\n\u2014 Brandon Rhodes\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Rewrite function bytecode to support assert introspection.",
    "version": "1.0",
    "project_urls": {
        "Homepage": "https://github.com/brandon-rhodes/assert_rewriter/"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "befc39006fc5f7b1e15a6ce0156cd24cc0f421ea150f0518c78ff349b9ee22e1",
                "md5": "f75cf6514deabef47a57f8371edcbab5",
                "sha256": "41af3ab78dc63f50be2a983f60fadb4e591a79a7687c31f2b9fa950b005baebc"
            },
            "downloads": -1,
            "filename": "assert_rewriter-1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "f75cf6514deabef47a57f8371edcbab5",
            "packagetype": "bdist_wheel",
            "python_version": "3.6",
            "requires_python": null,
            "size": 9594,
            "upload_time": "2024-03-19T18:48:52",
            "upload_time_iso_8601": "2024-03-19T18:48:52.394728Z",
            "url": "https://files.pythonhosted.org/packages/be/fc/39006fc5f7b1e15a6ce0156cd24cc0f421ea150f0518c78ff349b9ee22e1/assert_rewriter-1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "af1f6eb89c96ef4818941be6ea570bf8b6d815de5142299d737b751dd899de08",
                "md5": "c66248c8f4a8f919dc84afa752b35925",
                "sha256": "3032a8e18d8f887d5d7f89c6f3ba69f8e69cef15dafcfa4a5d9e9b745485a789"
            },
            "downloads": -1,
            "filename": "assert_rewriter-1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "c66248c8f4a8f919dc84afa752b35925",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 7635,
            "upload_time": "2024-03-19T18:48:51",
            "upload_time_iso_8601": "2024-03-19T18:48:51.103902Z",
            "url": "https://files.pythonhosted.org/packages/af/1f/6eb89c96ef4818941be6ea570bf8b6d815de5142299d737b751dd899de08/assert_rewriter-1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-19 18:48:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "brandon-rhodes",
    "github_project": "assert_rewriter",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "wheel",
            "specs": [
                [
                    "==",
                    "0.37.1"
                ]
            ]
        }
    ],
    "lcname": "assert_rewriter"
}
        
Elapsed time: 4.26340s