def test_regex_replace_nb_source(): """Test regex replacing notebook source.""" notebook = create_notebook() notebook.cells.extend( [ prepare_cell( {"metadata": {}, "outputs": [], "source": ["print(1)\n", "print(2)"]} ), prepare_cell( {"metadata": {}, "outputs": [], "source": ["print(1)\n", "print(2)"]} ), ] ) new_notebook = regex_replace_nb( notebook, [("/cells/0/source", "p", "s"), ("/cells/1/source", "p", "t")] ) new_notebook.nbformat_minor = None assert mapping_to_dict(new_notebook) == { "cells": [ {"metadata": {}, "outputs": [], "source": "srint(1)\nsrint(2)"}, {"metadata": {}, "outputs": [], "source": "trint(1)\ntrint(2)"}, ], "metadata": {}, "nbformat": 4, "nbformat_minor": None, }
def test_regex_replace_nb_output(): """Test regex replacing notebook output.""" notebook = create_notebook() notebook.cells.extend([ prepare_cell({ "metadata": {}, "outputs": [{ "name": "stdout", "output_type": "stream", "text": ["2019-08-11\n"], }], "source": ["from datetime import date\n", "print(date.today())"], }) ]) new_notebook = regex_replace_nb( notebook, [("/cells/0/outputs/0", r"\d{2,4}-\d{1,2}-\d{1,2}", "DATE-STAMP")]) output = mapping_to_dict(new_notebook) output.pop("nbformat_minor") assert output == { "cells": [{ "metadata": {}, "outputs": [{ "name": "stdout", "output_type": "stream", "text": ["DATE-STAMP\n"], }], "source": "from datetime import date\nprint(date.today())", }], "metadata": {}, "nbformat": 4, }
def test_regex_replace_nb_no_change(): """Test that, if no replacements are made, the notebook remains the same.""" notebook = create_notebook() notebook.cells.extend( [prepare_cell({"metadata": {}, "outputs": [], "source": ["print(1)\n"]})] ) new_notebook = regex_replace_nb(notebook, []) assert notebook == new_notebook
def test_regex_replace_nb_with_wildcard(): """Test regex replacing notebook values.""" notebook = create_notebook() notebook.cells.extend([ prepare_cell({ "metadata": {}, "outputs": [], "source": ["print(1)\n", "print(2)"] }), prepare_cell({ "metadata": {}, "outputs": [], "source": ["print(1)\n", "print(2)"] }), ]) new_notebook = regex_replace_nb(notebook, [("/cells/*/source", "p", "s"), ("/cells/0/source", "t", "y")]) output = mapping_to_dict(new_notebook) output.pop("nbformat_minor") assert output == { "cells": [ { "metadata": {}, "outputs": [], "source": "sriny(1)\nsriny(2)" }, { "metadata": {}, "outputs": [], "source": "srint(1)\nsrint(2)" }, ], "metadata": {}, "nbformat": 4, }
def check( self, path: Union[TextIO, str], raise_errors: bool = True ) -> NBRegressionResult: """Execute the Notebook and compare its initial vs. final contents. if ``force_regen`` is True, the new notebook will be written to ``path`` if ``raise_errors`` is True: :raise nbconvert.preprocessors.CellExecutionError: if error in execution :raise NBConfigValidationError: if the notebook metadata is invalid :raise NBRegressionError: if diffs present :rtype: NBRegressionResult """ __tracebackhide__ = True if hasattr(path, "name"): abspath = os.path.abspath(path.name) else: abspath = os.path.abspath(str(path)) logger.debug(f"Checking file: {abspath}") nb_initial, nb_config = load_notebook_with_config(path) resources = copy.deepcopy(self.process_resources) if not self.exec_cwd: self.exec_cwd = os.path.dirname(abspath) if self.exec_notebook: logger.debug("Executing notebook.") exec_results = execute_notebook( nb_initial, resources=resources, cwd=self.exec_cwd, timeout=self.exec_timeout, allow_errors=self.exec_allow_errors, with_coverage=self.coverage, cov_config_file=self.cov_config, cov_source=self.cov_source, ) exec_error = exec_results.exec_error nb_final = exec_results.notebook resources = exec_results.resources else: exec_error = None nb_final = nb_initial # TODO merge on fail option (using pytest-cov --no-cov-on-fail) if self.cov_merge and exec_results.has_coverage: logger.info(f"Merging coverage.") self.cov_merge.data.update( exec_results.coverage_data(self.cov_merge.debug), aliases=_get_coverage_aliases(self.cov_merge), ) # we also take this opportunity to remove '' # from the unmatched source packages, which is caused by using `--cov=` self.cov_merge.source_pkgs_unmatched = [ p for p in self.cov_merge.source_pkgs_unmatched if p ] for proc_name in self.post_processors: logger.debug(f"Applying post processor: {proc_name}") post_proc = load_processor(proc_name) nb_final, resources = post_proc(nb_final, resources) regex_replace = list(self.diff_replace) + list(nb_config.diff_replace) if regex_replace: logger.debug(f"Applying replacements: {regex_replace}") nb_initial_replace = regex_replace_nb(nb_initial, regex_replace) nb_final_replace = regex_replace_nb(nb_final, regex_replace) else: nb_initial_replace = nb_initial nb_final_replace = nb_final full_diff = diff_notebooks(nb_initial_replace, nb_final_replace) diff_ignore = copy.deepcopy(nb_config.diff_ignore) diff_ignore.update(self.diff_ignore) logger.debug(f"filtering diff by ignoring: {diff_ignore}") filtered_diff = filter_diff(full_diff, diff_ignore) diff_string = diff_to_string( nb_initial_replace, filtered_diff, use_color=self.diff_use_color, color_words=self.diff_color_words, ) # TODO optionally write diff to file regen_exc = None if filtered_diff and self.force_regen and not exec_error: if hasattr(path, "close") and hasattr(path, "name"): path.close() with open(path.name, "w") as handle: nbformat.write(nb_final, handle) else: nbformat.write(nb_final, str(path)) regen_exc = NBRegressionError( f"Files differ and --nb-force-regen set, " f"regenerating file at:\n- {abspath}" ) if not raise_errors: pass elif exec_error: print("Diff up to exception:\n" + diff_string, file=sys.stderr) raise exec_error elif regen_exc: print("Diff before regeneration:\n" + diff_string, file=sys.stderr) raise regen_exc elif filtered_diff: raise NBRegressionError(diff_string) return NBRegressionResult( nb_initial, nb_final, full_diff, filtered_diff, diff_string, resources )