{"id":13607536,"url":"https://github.com/chmp/ipytest","last_synced_at":"2025-05-15T02:07:15.209Z","repository":{"id":41891441,"uuid":"51264625","full_name":"chmp/ipytest","owner":"chmp","description":"Pytest in IPython notebooks.","archived":false,"fork":false,"pushed_at":"2025-02-16T18:16:37.000Z","size":816,"stargazers_count":326,"open_issues_count":3,"forks_count":19,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-13T23:55:13.671Z","etag":null,"topics":["ipython-notebook","jupyter-notebook","pytest","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chmp.png","metadata":{"files":{"readme":"Readme.md","changelog":"Changes.md","contributing":null,"funding":null,"license":"License.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-07T20:24:41.000Z","updated_at":"2025-03-29T15:54:22.000Z","dependencies_parsed_at":"2024-01-03T07:09:14.241Z","dependency_job_id":"6423e463-46d5-4c78-8602-c1979f5c6b63","html_url":"https://github.com/chmp/ipytest","commit_stats":{"total_commits":246,"total_committers":8,"mean_commits":30.75,"dds":0.3617886178861789,"last_synced_commit":"f1b8f698f289872598cb0a7d19969100297c05e8"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmp%2Fipytest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmp%2Fipytest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmp%2Fipytest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chmp%2Fipytest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chmp","download_url":"https://codeload.github.com/chmp/ipytest/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254259383,"owners_count":22040820,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ipython-notebook","jupyter-notebook","pytest","python"],"created_at":"2024-08-01T19:01:19.500Z","updated_at":"2025-05-15T02:07:15.171Z","avatar_url":"https://github.com/chmp.png","language":"Python","readme":"# ipytest - Pytest in Jupyter notebooks\n\n[PyPI](https://pypi.org/project/ipytest)\n| [Usage](#usage)\n| [Global state](#global-state)\n| [How does it work?](#how-does-it-work)\n| [Changes](Changes.md)\n| [Reference](#reference)\n| [Development](#development)\n| [Related packages](#related-packages)\n| [License](#license)\n\n`ipytest` allows you to run [Pytest](https://pytest.org) in Jupyter notebooks.\n`ipytest` aims to give access to the full `pytest` experience and to make it\neasy to transfer tests out of notebooks into separate test files.\n\n## Usage\n\nInstall `ipytest` by running\n\n```bash\npip install ipytest\n```\n\nThe suggested way to import `ipytest` is\n\n```python\nimport ipytest\nipytest.autoconfig()\n```\n\nAfterwards in a *new* cell, tests can be executed as in\n\n```python\n%%ipytest -qq\n\ndef test_example():\n    assert [1, 2, 3] == [1, 2, 3]\n```\n\nThis command will first delete any previously defined tests, execute the cell\nand then run pytest. For further details on how to use `ipytest` see the\n[**example notebook**](./Example.ipynb) or the [reference](#reference) below.\n\n### Enabling by default for all notebooks\n\n[IPython startup scripts][ci-ipy-startup-scripts] allow to customize the interpreter,\nfor example to import and configure ipytest by default.Their location can be configured\nvia the `IPYTHONDIR` environment variable.\n\n[ci-ipy-startup-scripts]: https://ipython.readthedocs.io/en/stable/interactive/tutorial.html#startup-files\n\n### Running in CI\n\nTo run notebook tests in a CI workflow, you may want to\n\n1. Set `raise_on_error=True` to ensure any `pytest` errors raise exceptions visible to the CI\n   system. For example via\n\n    ```python\n    import ipytest\n    ipytest.autoconfig(raise_on_error=True)\n    ```\n\n2. Execute the notebooks with [`nbval`](https://github.com/computationalmodelling/nbval). The\n   `--nbval-lax` flag allows to only check for errors, not the exact notebook output which is likely\n   to change between `pytest` runs\n\nTo only set `raise_on_error=True` in CI systems you can check for common environment variables. See\n[cibuildwheel.ci.detect_ci_provider][ci-detect_ci_provider] for a listing. For example\n\n```python\nimport ipytest\nimport os\n\nipytest.autoconfig(raise_on_error=\"GITHUB_ACTIONS\" in os.environ)\n```\n\n[ci-detect_ci_provider]: https://github.com/pypa/cibuildwheel/blob/c93d51ec540da7537ae66107a32c60dccd705102/cibuildwheel/ci.py#L21\n\n## Global state\n\nThere are multiple sources of global state when using pytest inside the notebook:\n\n1. pytest will find any test function ever defined. This behavior can lead to\n   unexpected results when test functions are renamed, as their previous\n   definition is still available inside the kernel. Running\n   [`%%ipytest`][ipytest.ipytest] per default deletes any previously defined\n   tests. As an alternative the [`ipytest.clean()`][ipytest.clean]\n   function allows to delete previously defined tests.\n2. Python's module system caches imports and therefore acts as a global state.\n   To test the most recent version of any module, the module needs to be\n   reloaded. `ipytest` offers the\n   [`ipytest.force_reload()`][ipytest.force_reload] function. The `autoreload`\n   extension of IPython may also help here. To test local packages, it is\n   advisable to install them as development packages, e.g., `pip install -e .`.\n3. For async code, IPython will create an event loop in the current thread. This\n   setup may interfere with async tests. To support these use cases, ipytest\n   supports running tests in a separate thread. Simply setup ipytest via\n   `ipytest.autoconfig(run_in_thread=True)`.\n\n## How does it work?\n\nIn its default configuration (via `autoconfig()`), `ipytest` performs the\nfollowing steps:\n\n1. Register pytest's assertion rewriter with the IPython kernel. The rewriter\n   will rewrite any assert statements entered into the notebook to give better\n   error messages. This change will affect also non test based code, but should\n   generally improve the development experience.\n2. Ensure the notebook can be mapped to a file. `ipytest` will create a\n   temporary file in the current directory and remove if afterwards.\n3. Register the notebook scope temporarily as a module. This step is necessary\n   to allow pytest's doctest plugin to import the notebook.\n4. Call pytest with the name of the temporary module\n\n**NOTE:** Some notebook implementations modify the core IPython package and\nmagics may not work correctly (see [here][issue-47] or [here][issue-50]). In\nthis case, using [`ipytest.run()`][ipytest.run] and\n[`ipytest.clean()`][ipytest.clean] directly should still work as expected.\n\n[issue-47]: https://github.com/chmp/ipytest/issues/47\n[issue-50]: https://github.com/chmp/ipytest/issues/50\n\n## Reference\n\n[`autoconfig`][ipytest.autoconfig]\n| [`%%ipytest`][ipytest.ipytest]\n| [`config`][ipytest.config]\n| [`exit_code`][ipytest.exit_code]\n| [`run`][ipytest.run]\n| [`clean`][ipytest.clean]\n| [`force_reload`][ipytest.force_reload]\n| [`Error`][ipytest.Error]\n| [`ipytest.cov`](#ipytestcov)\n\n\u003c!-- minidoc \"function\": \"ipytest.autoconfig\", \"header_depth\": 3 --\u003e\n### `ipytest.autoconfig(rewrite_asserts=\u003cdefault\u003e, magics=\u003cdefault\u003e, clean=\u003cdefault\u003e, addopts=\u003cdefault\u003e, run_in_thread=\u003cdefault\u003e, defopts=\u003cdefault\u003e, display_columns=\u003cdefault\u003e, raise_on_error=\u003cdefault\u003e, coverage=\u003cdefault\u003e)`\n\n[ipytest.autoconfig]: #ipytestautoconfigrewrite_assertsdefault-magicsdefault-cleandefault-addoptsdefault-run_in_threaddefault-defoptsdefault-display_columnsdefault-raise_on_errordefault-coveragedefault\n\nConfigure `ipytest` with reasonable defaults.\n\nSpecifically, it sets:\n\n* `addopts`: `('-q', '--color=yes')`\n* `clean`: `'[Tt]est*'`\n* `coverage`: `False`\n* `defopts`: `'auto'`\n* `display_columns`: `100`\n* `magics`: `True`\n* `raise_on_error`: `False`\n* `rewrite_asserts`: `True`\n* `run_in_thread`: `False`\n\nSee [`ipytest.config`][ipytest.config] for details.\n\n\u003c!-- minidoc --\u003e\n\n### `%%ipytest ...`\n\n[ipytest.ipytest]: #ipytest-\n\n\u003c!-- minidoc \"function\": \"ipytest._impl.ipytest_magic\", \"header\": false, \"header_depth\": 3 --\u003e\nIPython magic to first execute the cell, then execute [`ipytest.run()`][ipytest.run].\n\n**Note:** the magics are only available after running\n[`ipytest.autoconfig()`][ipytest.autoconfig] or\n[`ipytest.config(magics=True)`][ipytest.config].\n\nIt cleans any previously found tests, i.e., only tests defined in the\ncurrent cell are executed. To disable this behavior, use\n[`ipytest.config(clean=False)`][ipytest.config].\n\nAny arguments passed on the magic line are interpreted as command line\narguments to to pytest. For example calling the magic as\n\n```python\n%%ipytest -qq\n```\n\nis equivalent to passing `-qq` to pytest. The arguments are formatted using\nPython's standard string formatting. Currently, only the `{MODULE}` variable\nis understood. It is replaced with the filename associated with the\nnotebook. In addition node ids for tests can be generated by using the test\nname as a key, e.g., `{test_example}` will expand to\n`{MODULE}::test_example`.\n\nThe keyword arguments passed to [`ipytest.run()`][ipytest.run] can be\ncustomized by including a comment of the form `# ipytest: arg1=value1,\narg=value2` in the cell source. For example:\n\n```python\n%%ipytest {MODULE}::test1\n# ipytest: defopts=False\n```\n\nis equivalent to `ipytest.run(\"{MODULE}::test1\", defopts=False)`. In this\ncase, it deactivates default arguments and then instructs pytest to only\nexecute `test1`.\n\n**NOTE:** In the default configuration `%%ipytest` will not raise\nexceptions, when tests fail. To raise exceptions on test errors, e.g.,\ninside a CI/CD context, use `ipytest.autoconfig(raise_on_error=True)`.\n\n\u003c!-- minidoc --\u003e\n\n\u003c!-- minidoc \"function\": \"ipytest.config\", \"header_depth\": 3 --\u003e\n### `ipytest.config(rewrite_asserts=\u003ckeep\u003e, magics=\u003ckeep\u003e, clean=\u003ckeep\u003e, addopts=\u003ckeep\u003e, run_in_thread=\u003ckeep\u003e, defopts=\u003ckeep\u003e, display_columns=\u003ckeep\u003e, raise_on_error=\u003ckeep\u003e, coverage=\u003cdefault\u003e)`\n\n[ipytest.config]: #ipytestconfigrewrite_assertskeep-magicskeep-cleankeep-addoptskeep-run_in_threadkeep-defoptskeep-display_columnskeep-raise_on_errorkeep-coveragedefault\n\nConfigure `ipytest`\n\nTo update the configuration, call this function as in:\n\n```python\nipytest.config(rewrite_asserts=True)\n```\n\nThe following settings are supported:\n\n* `rewrite_asserts` (default: `False`): enable ipython AST transforms\n  globally to rewrite asserts\n* `magics` (default: `False`): if set to `True` register the ipytest magics\n* `coverage` (default: `False`): if `True` configure `pytest` to collect\n  coverage information. This functionality requires the `pytest-cov` package\n  to be installed. It adds `--cov --cov-config={GENERATED_CONFIG}` to the\n  arguments when invoking `pytest`. **WARNING**: this option will hide\n  existing coverage configuration files. See [`ipytest.cov`](#ipytestcov)\n  for details\n* `clean` (default: `[Tt]est*`): the pattern used to clean variables\n* `addopts` (default: `()`): pytest command line arguments to prepend to\n  every pytest invocation. For example setting\n  `ipytest.config(addopts=['-qq'])` will execute pytest with the least\n  verbosity. Consider adding `--color=yes` to force color output\n* `run_in_thread` (default: `False`): if `True`, pytest will be run a\n  separate thread. This way of running is required when testing async code\n  with `pytest_asyncio` since it starts a separate event loop\n* `defopts` (default: `\"auto\"`): either `\"auto\"`, `True` or `False`\n  * if `\"auto\"`, `ipytest` will add the current notebook module to the\n    command line arguments, if no pytest node ids that reference the\n    notebook are provided by the user\n  * If `True`, ipytest will add the current module to the arguments passed\n    to pytest\n  * If `False` only the arguments given and `adopts` are passed to pytest\n* `display_columns` (default: `100`): if not `False`, configure pytest to\n  use the given number of columns for its output. This option will\n  temporarily override the `COLUMNS` environment variable.\n* `raise_on_error` (default `False` ): if `True`,\n  [`ipytest.run`][ipytest.run] and [`%%ipytest`][ipytest.ipytest] will raise\n  an `ipytest.Error` if pytest fails.\n\n\u003c!-- minidoc --\u003e\n\n### `ipytest.exit_code`\n\n[ipytest.exit_code]: #ipytestexit_code\n\nThe return code of the last pytest invocation.\n\n\u003c!-- minidoc \"function\": \"ipytest.run\", \"header_depth\": 3 --\u003e\n### `ipytest.run(*args, module=None, plugins=(), run_in_thread=\u003cdefault\u003e, raise_on_error=\u003cdefault\u003e, addopts=\u003cdefault\u003e, defopts=\u003cdefault\u003e, display_columns=\u003cdefault\u003e, coverage=\u003cdefault\u003e)`\n\n[ipytest.run]: #ipytestrunargs-modulenone-plugins-run_in_threaddefault-raise_on_errordefault-addoptsdefault-defoptsdefault-display_columnsdefault-coveragedefault\n\nExecute all tests in the passed module (defaults to `__main__`) with pytest.\n\nThis function is a thin wrapper around `pytest.main` and will execute any tests\ndefined in the current notebook session.\n\n**NOTE:** In the default configuration `ipytest.run()` will not raise\nexceptions, when tests fail. To raise exceptions on test errors, e.g.,\ninside a CI/CD context, use `ipytest.autoconfig(raise_on_error=True)`.\n\n**Parameters:**\n\n- `args`: additional commandline options passed to pytest\n- `module`: the module containing the tests. If not given, `__main__` will\n  be used.\n- `plugins`: additional plugins passed to pytest.\n\nThe following parameters override the config options set with\n[`ipytest.config()`][ipytest.config] or\n[`ipytest.autoconfig()`][ipytest.autoconfig].\n\n- `run_in_thread`: if given, override the config option \"run_in_thread\".\n- `raise_on_error`: if given, override the config option \"raise_on_error\".\n- `addopts`: if given, override the config option \"addopts\".\n- `defopts`: if given, override the config option \"defopts\".\n- `display_columns`: if given, override the config option \"display_columns\".\n\n**Returns**: the exit code of `pytest.main`.\n\n\u003c!-- minidoc --\u003e\n\u003c!-- minidoc \"function\": \"ipytest.clean\", \"header_depth\": 3 --\u003e\n### `ipytest.clean(pattern=\u003cdefault\u003e, *, module=None)`\n\n[ipytest.clean]: #ipytestcleanpatterndefault--modulenone\n\nDelete tests with names matching the given pattern.\n\nIn IPython the results of all evaluations are kept in global variables\nunless explicitly deleted. This behavior implies that when tests are renamed\nthe previous definitions will still be found if not deleted. This method\naims to simply this process.\n\nAn effective pattern is to start with the cell containing tests with a call\nto [`ipytest.clean()`][ipytest.clean], then defined all test cases, and\nfinally call [`ipytest.run()`][ipytest.run]. This way renaming tests works\nas expected.\n\n**Parameters:**\n\n- `pattern`: a glob pattern used to match the tests to delete. If not given,\n  the `\"clean\"` config option is used.\n- `items`: the globals object containing the tests. If `None` is given, the\n    globals object is determined from the call stack.\n\n\u003c!-- minidoc --\u003e\n\u003c!-- minidoc \"function\": \"ipytest.force_reload\", \"header_depth\": 3 --\u003e\n### `ipytest.force_reload(*include, modules: Optional[Dict[str, module]] = None)`\n\n[ipytest.force_reload]: #ipytestforce_reloadinclude-modules-optionaldictstr-module--none\n\nEnsure following imports of the listed modules reload the code from disk\n\nThe given modules and their submodules are removed from `sys.modules`.\nNext time the modules are imported, they are loaded from disk.\n\nIf given, the parameter `modules` should be a dictionary of modules to use\ninstead of `sys.modules`.\n\nUsage:\n\n```python\nipytest.force_reload(\"my_package\")\nfrom my_package.submodule import my_function\n```\n\n\u003c!-- minidoc --\u003e\n\u003c!-- minidoc \"class\": \"ipytest.Error\", \"header_depth\": 3 --\u003e\n### `ipytest.Error(exit_code)`\n\n[ipytest.Error]: #ipytesterrorexit_code\n\nError raised by ipytest on test failure\n\n\u003c!-- minidoc --\u003e\n\n\u003c!-- minidoc \"module\": \"ipytest.cov\", \"header_depth\": 3 --\u003e\n### `ipytest.cov`\n\nA coverage.py plugin to support coverage in Jupyter notebooks\n\nThe plugin must be enabled in a `.coveragerc` next to the current notebook or\nthe `pyproject.toml` file. See the [coverage.py docs][coverage-py-config-docs]\nfor details. In case of a `.coveragerc` file, the minimal configuration reads:\n\n```ini\n[run]\nplugins =\n    ipytest.cov\n```\n\nWith this config file, coverage information can be collected using\n[pytest-cov][ipytest-cov-pytest-cov] with\n\n```python\n%%ipytest --cov\n\ndef test():\n    ...\n```\n\n`ipytest.autoconfig(coverage=True)` automatically adds the `--cov` flag and the\npath of a generated config file to the Pytest invocation. In this case no\nfurther configuration is required.\n\nThere are some known issues of `ipytest.cov`\n\n- Each notebook cell is reported as an individual file\n- Lines that are executed at import time may not be encountered in tracing and\n  may be reported as not-covered (One example is the line of a function\n  definition)\n- Marking code to be excluded in branch coverage is currently not supported\n  (incl. coveragepy pragmas)\n\n[coverage-py-config-docs]: https://coverage.readthedocs.io/en/latest/config.html\n[ipytest-cov-pytest-cov]: https://pytest-cov.readthedocs.io/en/latest/config.html\n\n#### `ipytest.cov.translate_cell_filenames(enabled=True)`\n\n[ipytest.cov.translate_cell_filenames]: #ipytestcovtranslate_cell_filenamesenabledtrue\n\nTranslate the filenames of notebook cells in coverage information.\n\nIf enabled, `ipytest.cov` will translate the temporary file names generated\nby ipykernel (e.g, `ipykernel_24768/3920661193.py`) to their cell names\n(e.g., `In[6]`).\n\n**Warning**: this is an experimental feature and not subject to any\nstability guarantees.\n\n\u003c!-- minidoc --\u003e\n\n## Development\n\nSetup a Python 3.10 virtual environment and install the requirements via\n\n```bash\npip install -r requirements-dev.txt\npip install -e .\n```\n\nTo execute the unit tests of `ipytest` run\n\n```bash\npython x.py test\npython x.py integration\n```\n\nBefore committing, execute `python x.py precommit` to update the documentation,\nformat the code, and run tests.\n\nTo create a new release execute:\n\n```bash\npython x.py release\n```\n\n## Related packages\n\n`ipytest` is designed to enable running tests within an interactive notebook\nsession. There are also other packages that aim to use test full notebooks:\nthese packages run the notebook and compare the output of cells to the output of\nprevious runs. These packages include:\n\n- [nbval](https://github.com/computationalmodelling/nbval)\n- [nbmake](https://github.com/treebeardtech/nbmake)\n- [pytest-ipynb](https://github.com/zonca/pytest-ipynb) is no longer\n  maintained\n- ...\n\nWhile PyTest itself is generally supported, support for PyTest plugins depends\nvery much on the plugin. The following plugins are known to not work:\n\n- [pytest-xdist](https://github.com/chmp/ipytest/issues/90)\n\nSee [`ipytest.cov`](#ipytestcov) on how to use `ipytest` with\n[pytest-cov](https://pytest-cov.readthedocs.io/en/latest/config.html).\n\nPlease create an issue, if I missed a packaged or mischaracterized any package.\n\n## License\n\n```\nThe MIT License (MIT)\nCopyright (c) 2015 - 2024 Christopher Prohm\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n\n```\n","funding_links":[],"categories":["Notebook Tools","Jupyter-Notebook工具","Testing"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchmp%2Fipytest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchmp%2Fipytest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchmp%2Fipytest/lists"}