From 13d3b2afdaf8eb1fd40f4f41a113ecd6a581feda Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Mon, 17 Jan 2022 15:40:52 +0100 Subject: [PATCH 01/14] Add min versions to dependencies --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 4a7f6a7..cc6c37c 100644 --- a/setup.py +++ b/setup.py @@ -8,9 +8,10 @@ "version": "0.2", "packages": find_packages(), "install_requires": [ - "jupyter-client", # BSD-3 https://github.com/jupyter/jupyter_client/blob/main/COPYING.md - "nbconvert", # BSD-3 https://github.com/jupyter/nbconvert/blob/main/LICENSE - "pre-commit" # MIT https://github.com/pre-commit/pre-commit/blob/master/LICENSE + "jupyter-client>=7.1.1", # BSD-3 https://github.com/jupyter/jupyter_client/blob/main/COPYING.md + "nbconvert>=6.4.0", # BSD-3 https://github.com/jupyter/nbconvert/blob/main/LICENSE + "pre-commit>=2.16.0", # MIT https://github.com/pre-commit/pre-commit/blob/master/LICENSE + "typer>=0.4.0" # MIT https://github.com/tiangolo/typer/blob/master/LICENSE ], "author": "Tim Vink", "author_email": "vinktim@gmail.com", @@ -19,8 +20,7 @@ "url": "", "entry_points": { "console_scripts": [ - "nbconvert_rename=precommit_nbconvert_rename.precommit:main", - "rename_commithash=precommit_nbconvert_rename.postcommit:main", + "nb_convert_strip=precommit_nbconvert_rename.cli:app", ] }, } From 2f9963cef97c464bc927c7b599871cf3a5e2e1fa Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 09:55:23 +0100 Subject: [PATCH 02/14] Refactor into single typer CLI command --- README.md | 20 ++++- precommit_nbconvert_rename/_utils.py | 33 ++++++++ precommit_nbconvert_rename/cli.py | 66 +++++++++++++++ precommit_nbconvert_rename/files.py | 41 +++++++--- .../{precommit.py => nb_convert_strip.py} | 72 +--------------- precommit_nbconvert_rename/postcommit.py | 82 ------------------- tests/test_files.py | 6 +- tests/test_precommit.py | 2 +- ...tcommit.py => test_rename_placeholders.py} | 7 +- 9 files changed, 154 insertions(+), 175 deletions(-) create mode 100644 precommit_nbconvert_rename/_utils.py create mode 100644 precommit_nbconvert_rename/cli.py rename precommit_nbconvert_rename/{precommit.py => nb_convert_strip.py} (57%) delete mode 100644 precommit_nbconvert_rename/postcommit.py rename tests/{test_postcommit.py => test_rename_placeholders.py} (77%) diff --git a/README.md b/README.md index cbad8a6..f7618a6 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,27 @@ A pre-commit hook that converts any changed jupyter notebooks (`.ipynb`) to `.ht ## Use case -Jupyter notebooks contain not only code but also outputs (tables, plots, interactive elements) as well as execution counts. You should not commit data to git (also because of security) so a common solution for jupyter notebooks is to use [nbstripout](https://github.com/kynan/nbstripout) as [pre-commit](https://pre-commit.com/) hook. This has as added benefit that your notebooks are not more easily version-controlled, as re-running a cell does not lead to a `git diff`. The downside is having to re-execute notebooks everytime you want to view or share them. +You use [jupyter notebooks](https://jupyter.org/) and: -`precommit_nbconvert_rename` runs [nbconvert](https://github.com/jupyter/nbconvert) each time you make a commit that touches a jupyter notebook, and adds a date prefix and commit hash suffix to the filename. Having the commit hash in the file named has the added benefit that you can always find the changes in the file in git. Obviously these `.html` should remain local and not be committed to `git`, so make sure to `*.html` to your `.gitignore` file. Here's an overview of the workflow: +- [nbconvert](https://github.com/jupyter/nbconvert) to convert `.ipynb` files to `.html` files +- [nbstripout](https://github.com/kynan/nbstripout) to avoid committing (potentially sensitive) data to git and get proper `git diff`s on notebooks (only showing changes in code). + +Forget to run `nbconvert`, or use them in the wrong order (`nbstripout` before `nbconvert`) and you will have to re-run your notebooks before you can output HTML, which can be annoying when they are long-running. Especially when you use `nbstripout` as a [pre-commit](https://pre-commit.com/) hook, this can happen quite often. + +`precommit_nbconvert_rename` can help to automatically process notebooks and (optionally) store versioned output in an in output directory. The CLI command `nb_convert_strip` takes a list of directories and/or files to find and convert notebooks. For each notebook: + +- `nbconvert` is used to create an `.html` export +- Date prefix is added `YYYYMMDD_.html` (can be turned off) +- Placeholder for git hash is added `YYYYMMDD__20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` +- `.html` file is moved to `output-dir` (if specified) +- `nbstripout` is used strip output from notebook + +Now you can `git add` and `git commit` the changed notebook files. You can then use `nb_convert_strip rename` will replace insert the commit hashes in the notebook filenames. + +You can setup this entire workflow once as [pre-commit](https://pre-commit.com/) hook, and basically get an up-to-date analysis output directory for free `output-dir`. Schematically: -> Note: `nbstripout` pre-commit hooks will edit your notebook files and fail the pre-commit. When you add the stripped notebook and commit again, `nbconvert-rename` will not run `nbconvert` again because there is already .html file ## Installation diff --git a/precommit_nbconvert_rename/_utils.py b/precommit_nbconvert_rename/_utils.py new file mode 100644 index 0000000..d14bba2 --- /dev/null +++ b/precommit_nbconvert_rename/_utils.py @@ -0,0 +1,33 @@ + +import os +import subprocess + +def git_version(): + """ + Return the git revision as a string. + + Credits: this function was copied from numpy. + https://stackoverflow.com/a/40170206. + """ + + def _minimal_ext_cmd(cmd): + # construct minimal environment + env = {} + for k in ["SYSTEMROOT", "PATH"]: + v = os.environ.get(k) + if v is not None: + env[k] = v + # LANGUAGE is used on win32 + env["LANGUAGE"] = "C" + env["LANG"] = "C" + env["LC_ALL"] = "C" + out = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0] + return out + + try: + out = _minimal_ext_cmd(["git", "rev-parse", "--short", "HEAD"]) + GIT_REVISION = out.strip().decode("ascii") + except OSError: + GIT_REVISION = "Unknown" + + return GIT_REVISION diff --git a/precommit_nbconvert_rename/cli.py b/precommit_nbconvert_rename/cli.py new file mode 100644 index 0000000..c07e905 --- /dev/null +++ b/precommit_nbconvert_rename/cli.py @@ -0,0 +1,66 @@ +import typer +from pathlib import Path +from typing import List, Optional + +from precommit_nbconvert_rename.files import find_files_in_paths, insert_commithash_filename_placeholder +from precommit_nbconvert_rename._utils import git_version +from precommit_nbconvert_rename.nb_convert_strip import convert_notebook + + +app = typer.Typer() + + +@app.command() +def rename( + paths: Optional[List[Path]] = typer.Argument(None, help="Directories and/or files to find and convert notebooks") + ): + """ + Replaces the placeholder NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with the current commit hash. + + For example: + + "20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + "20211026_notebook_26b2841.html" + """ + if paths is None: + paths = Path(os.getcwd()) + + filenames = find_files_in_paths(paths, extension=".html") + + for path in filenames: + insert_commithash_filename_placeholder(path, commithash=git_version()) + + + + +@app.command() +def process( + paths: Optional[List[Path]] = typer.Argument(None, help="Directories and/or files to find and convert notebooks"), + date_prefix: Optional[str] = typer.Option("%Y%m%d", help="Format of the date prefix. Set to empty for no prefix."), + output_dir: Optional[str] = typer.Option(None, help="Path where to place output HTML files."), + exclude: Optional[List[Path]] = typer.Option(None, help="Directories and/or files to exclude from processing"), + nbconvert_template: Optional[str] = typer.Option(None, help="Name of the nbconvert template to use."), + nbconvert_no_input: bool = typer.Option(True, help="Nbconvert: Exclude input cells and output prompts from converted document. Ideal for generating code-free reports."), + ): + """ + Process .ipynb files. + + Applies the following steps:\n + - Convert Jupyter notebooks to HTML\n + - Applies nbstripout to the notebook\n + - Optionally add date prefix to .HTML file + - Add commit hash placeholder. + """ + if paths is None: + paths = Path(os.getcwd()) + + notebook_paths = find_files_in_paths(paths, extension=".ipynb", exclude_list=exclude) + + for path in notebook_paths: + convert_notebook( + path, + date_format=date_prefix, + template=nbconvert_template, + no_input=nbconvert_no_input, + output_dir=output_dir, + ) diff --git a/precommit_nbconvert_rename/files.py b/precommit_nbconvert_rename/files.py index e7b318f..b5cc38f 100644 --- a/precommit_nbconvert_rename/files.py +++ b/precommit_nbconvert_rename/files.py @@ -5,15 +5,16 @@ from contextlib import contextmanager -def find_notebooks(directories: List[str], exclude_list: List[str] = []) -> List[str]: +def find_files_in_paths(directories: List[str], extension: str = ".ipynb", exclude_list: List[str] = []) -> List[str]: """ - Find jupyter notebooks in a list of paths. + Find all files with a certain extension in a list of paths. Args: directories: List of paths to dirs and files. + extension: Extension of target files. exclude_list: List of globs to exclude. - """ + assert extension.startswith(".") filenames = [] @@ -22,18 +23,17 @@ def find_notebooks(directories: List[str], exclude_list: List[str] = []) -> List fn = Path(fn) if not fn.is_dir(): - if fn.suffix == ".ipynb" and not is_excluded(fn, exclude_list): + if fn.suffix == extension and not is_excluded(fn, exclude_list): filenames.append(str(fn)) continue - notebooks = [ - str(f) - for f in fn.glob("**/*.ipynb") - if not f.suffix == ".ipynb_checkpoints" - ] - notebooks = [f for f in notebooks if not is_excluded(f, exclude_list)] + files = [f for f in fn.glob(f"**/*{extension}")] + if extension == ".ipynb": + files = [f for f in files if not f.suffix == ".ipynb_checkpoints"] + + files = [str(f) for f in files if not is_excluded(f, exclude_list)] - filenames += notebooks + filenames += files return filenames @@ -79,6 +79,7 @@ def is_excluded(src_path: str, globs: List[str]) -> bool: return False + @contextmanager def working_directory(path): """ @@ -99,3 +100,21 @@ def working_directory(path): yield finally: os.chdir(prev_cwd) + + +def insert_commithash_filename_placeholder(path: str, commithash: str) -> None: + """ + Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with last commit. + + Args: + path (str): path to notebook + commithash (str): short hash of commit to insert + """ + p = Path(path) + stem = Path(path).stem + if "NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER" not in stem: + return + + stem = stem.replace("NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER", commithash) + p.rename(Path(p.parent, f"{stem}{p.suffix}")) + diff --git a/precommit_nbconvert_rename/precommit.py b/precommit_nbconvert_rename/nb_convert_strip.py similarity index 57% rename from precommit_nbconvert_rename/precommit.py rename to precommit_nbconvert_rename/nb_convert_strip.py index b12d11a..68b9af7 100644 --- a/precommit_nbconvert_rename/precommit.py +++ b/precommit_nbconvert_rename/nb_convert_strip.py @@ -1,11 +1,9 @@ -import sys -import argparse import codecs from datetime import datetime from pathlib import Path from nbconvert import HTMLExporter -from precommit_nbconvert_rename.files import find_notebooks +from precommit_nbconvert_rename.files import find_files_in_paths def convert_notebook( @@ -75,72 +73,4 @@ def convert_notebook( f.write(body) -def parse_args(args): - """ - Parse arguments passed to 'nbconvert_rename'. - """ - parser = argparse.ArgumentParser( - description="Convert Jupyter notebooks to HTML and add date prefix and commit hash placeholder." - ) - parser.add_argument( - "filenames", - nargs="+", - help="List of directories and/or files to find and convert notebooks", - ) - parser.add_argument( - "--date-prefix-format", - type=str, - help="Format of the date prefix. Defaults to %%Y%%m%%d, set to empty for no prefix", - default="%Y%m%d", - ) - parser.add_argument( - "--template", - type=str, - help="Name of the nbconvert template to use.", - default="", - ) - parser.add_argument( - "--output-dir", - type=str, - help="Path of output directory", - default=".", - ) - parser.add_argument( - "--no-input", - action="store_true", - help="When specified code blocks are not include.", - ) - parser.add_argument( - "--exclude", - nargs="+", - help="List of directories to exclude from processing.", - required=False, - ) - - return parser.parse_args() - - -def main(): - """ - The 'nbconvert_rename' command. - - Precommit hook. - """ - args = parse_args(sys.argv[1:]) - - notebook_paths = find_notebooks(args.filenames) - - for path in notebook_paths: - convert_notebook( - path, - date_format=args.date_prefix_format, - template=args.template, - no_input=args.no_input, - output_dir=args.output_dir, - ) - - return 0 - -if __name__ == "__main__": - sys.exit(main()) diff --git a/precommit_nbconvert_rename/postcommit.py b/precommit_nbconvert_rename/postcommit.py deleted file mode 100644 index 5af10a4..0000000 --- a/precommit_nbconvert_rename/postcommit.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -Should run on post-commit hook. - -git rev-parse --short HEAD -""" - -import os -import sys -import subprocess -from pathlib import Path -import argparse - - -def git_version(): - """ - Return the git revision as a string. - - Credits: this function was copied from numpy. - https://stackoverflow.com/a/40170206. - """ - - def _minimal_ext_cmd(cmd): - # construct minimal environment - env = {} - for k in ["SYSTEMROOT", "PATH"]: - v = os.environ.get(k) - if v is not None: - env[k] = v - # LANGUAGE is used on win32 - env["LANGUAGE"] = "C" - env["LANG"] = "C" - env["LC_ALL"] = "C" - out = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0] - return out - - try: - out = _minimal_ext_cmd(["git", "rev-parse", "--short", "HEAD"]) - GIT_REVISION = out.strip().decode("ascii") - except OSError: - GIT_REVISION = "Unknown" - - return GIT_REVISION - - -def convert_filename(path: str, commithash: str) -> None: - """ - Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with last commit. - - Args: - path (str): path to notebook - commithash (str): short hash of commit to insert - """ - p = Path(path) - stem = Path(path).stem - if "NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER" not in stem: - return - - stem = stem.replace("NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER", commithash) - p.rename(Path(p.parent, f"{stem}{p.suffix}")) - - -def main(): - """ - post-commit hook. - """ - parser = argparse.ArgumentParser( - description="Replace all NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER occurances in .html filenames with latest hash." # noqa - ) - _ = parser.parse_args() - - filenames = [] - path = Path(os.getcwd()) - filenames += list(str(fn) for fn in path.glob("**/*.html")) - - for path in filenames: - convert_filename(path, commithash=git_version()) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tests/test_files.py b/tests/test_files.py index 38bc4f7..6dc8c1b 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -1,7 +1,7 @@ import os import shutil -from precommit_nbconvert_rename.files import find_notebooks, is_excluded, working_directory +from precommit_nbconvert_rename.files import find_files_in_paths, is_excluded, working_directory def test_is_excluded(): @@ -23,6 +23,6 @@ def test_find_notebooks(tmp_path): all_notebooks = [f"data{os.sep}example.ipynb", f"data{os.sep}another_example.ipynb"] # all_notebooks = set([os.path.abspath(f) for f in all_notebooks]) - assert set(find_notebooks(".")) == set(all_notebooks) + assert set(find_files_in_paths(".")) == set(all_notebooks) - assert len(find_notebooks(".", exclude_list=["data/*"])) == 0 + assert len(find_files_in_paths(".", exclude_list=["data/*"])) == 0 diff --git a/tests/test_precommit.py b/tests/test_precommit.py index 964f9f0..21ab2c4 100644 --- a/tests/test_precommit.py +++ b/tests/test_precommit.py @@ -3,7 +3,7 @@ from freezegun import freeze_time from pathlib import Path -from precommit_nbconvert_rename.precommit import convert_notebook +from precommit_nbconvert_rename.nb_convert_strip import convert_notebook from precommit_nbconvert_rename.files import working_directory diff --git a/tests/test_postcommit.py b/tests/test_rename_placeholders.py similarity index 77% rename from tests/test_postcommit.py rename to tests/test_rename_placeholders.py index eeb32cc..a755b88 100644 --- a/tests/test_postcommit.py +++ b/tests/test_rename_placeholders.py @@ -1,8 +1,7 @@ import shutil - from pathlib import Path -from precommit_nbconvert_rename.postcommit import convert_filename -from precommit_nbconvert_rename.files import working_directory + +from precommit_nbconvert_rename.files import working_directory, insert_commithash_filename_placeholder def test_convert_filename(tmp_path): @@ -11,7 +10,7 @@ def test_convert_filename(tmp_path): str(tmp_path / "20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html"), ) with working_directory(str(tmp_path)): - convert_filename( + insert_commithash_filename_placeholder( str(tmp_path / "20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html"), commithash="helloworld", ) From 36629f6a1b3382ca209ca29c1ee17725778490af Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 10:55:56 +0100 Subject: [PATCH 03/14] Add tests for CLI app --- precommit_nbconvert_rename/_utils.py | 14 ++++-- precommit_nbconvert_rename/cli.py | 11 +++-- precommit_nbconvert_rename/files.py | 2 + .../nb_convert_strip.py | 12 +++-- tests/test_cli.py | 49 +++++++++++++++++++ ..._precommit.py => test_convert_notebook.py} | 0 tests/test_files.py | 9 ++-- ...insert_commithash_filename_placeholder.py} | 2 +- tests/test_requirements.txt | 3 +- 9 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 tests/test_cli.py rename tests/{test_precommit.py => test_convert_notebook.py} (100%) rename tests/{test_rename_placeholders.py => test_insert_commithash_filename_placeholder.py} (91%) diff --git a/precommit_nbconvert_rename/_utils.py b/precommit_nbconvert_rename/_utils.py index d14bba2..888c20c 100644 --- a/precommit_nbconvert_rename/_utils.py +++ b/precommit_nbconvert_rename/_utils.py @@ -2,11 +2,15 @@ import os import subprocess +class GitError(Exception): + pass + + def git_version(): """ Return the git revision as a string. - Credits: this function was copied from numpy. + Credits: this function was adapted from numpy. https://stackoverflow.com/a/40170206. """ @@ -21,8 +25,12 @@ def _minimal_ext_cmd(cmd): env["LANGUAGE"] = "C" env["LANG"] = "C" env["LC_ALL"] = "C" - out = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env).communicate()[0] - return out + sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + out, err = sp.communicate() + if sp.returncode != 0: + raise GitError(err.strip().decode("ascii")) + else: + return out try: out = _minimal_ext_cmd(["git", "rev-parse", "--short", "HEAD"]) diff --git a/precommit_nbconvert_rename/cli.py b/precommit_nbconvert_rename/cli.py index c07e905..b10459f 100644 --- a/precommit_nbconvert_rename/cli.py +++ b/precommit_nbconvert_rename/cli.py @@ -1,4 +1,5 @@ import typer +import os from pathlib import Path from typing import List, Optional @@ -22,8 +23,8 @@ def rename( "20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" "20211026_notebook_26b2841.html" """ - if paths is None: - paths = Path(os.getcwd()) + if len(paths) == 0: + paths = [Path(os.getcwd())] filenames = find_files_in_paths(paths, extension=".html") @@ -37,7 +38,7 @@ def rename( def process( paths: Optional[List[Path]] = typer.Argument(None, help="Directories and/or files to find and convert notebooks"), date_prefix: Optional[str] = typer.Option("%Y%m%d", help="Format of the date prefix. Set to empty for no prefix."), - output_dir: Optional[str] = typer.Option(None, help="Path where to place output HTML files."), + output_dir: Optional[Path] = typer.Option(".", help="Path where to place output HTML files."), exclude: Optional[List[Path]] = typer.Option(None, help="Directories and/or files to exclude from processing"), nbconvert_template: Optional[str] = typer.Option(None, help="Name of the nbconvert template to use."), nbconvert_no_input: bool = typer.Option(True, help="Nbconvert: Exclude input cells and output prompts from converted document. Ideal for generating code-free reports."), @@ -51,8 +52,8 @@ def process( - Optionally add date prefix to .HTML file - Add commit hash placeholder. """ - if paths is None: - paths = Path(os.getcwd()) + if len(paths) == 0: + paths = [Path(os.getcwd())] notebook_paths = find_files_in_paths(paths, extension=".ipynb", exclude_list=exclude) diff --git a/precommit_nbconvert_rename/files.py b/precommit_nbconvert_rename/files.py index b5cc38f..89776d4 100644 --- a/precommit_nbconvert_rename/files.py +++ b/precommit_nbconvert_rename/files.py @@ -110,6 +110,8 @@ def insert_commithash_filename_placeholder(path: str, commithash: str) -> None: path (str): path to notebook commithash (str): short hash of commit to insert """ + assert len(commithash) != 0 + p = Path(path) stem = Path(path).stem if "NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER" not in stem: diff --git a/precommit_nbconvert_rename/nb_convert_strip.py b/precommit_nbconvert_rename/nb_convert_strip.py index 68b9af7..ef8fe78 100644 --- a/precommit_nbconvert_rename/nb_convert_strip.py +++ b/precommit_nbconvert_rename/nb_convert_strip.py @@ -7,11 +7,11 @@ def convert_notebook( - path: str, + path: Path, date_format: str = "%Y%m%d", template: str = "", no_input: bool = False, - output_dir: str = ".", + output_dir: Path = ".", ) -> None: """ Converts .ipynb to .html. @@ -23,11 +23,17 @@ def convert_notebook( no_input (bool): Remove code input blocks output_dir (str): Path to output directory (rel or abs) """ + if not isinstance(path, Path): + path = Path(path) + if not isinstance(output_dir, Path): + output_dir = Path(output_dir) + if not Path(output_dir).exists(): raise IsADirectoryError( f"The --output-dir specified ('{output_dir}') does not exist" ) + if template: html_exporter = HTMLExporter(template_name=template) else: @@ -38,7 +44,7 @@ def convert_notebook( html_exporter.exclude_input = True html_exporter.exclude_input_prompt = True - (body, _) = html_exporter.from_filename(path) + (body, _) = html_exporter.from_filename(str(path)) date_prefix = datetime.strftime(datetime.now(), date_format) if len(date_prefix) != 0: diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..3d011ff --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,49 @@ +import shutil +import git +from typer.testing import CliRunner +from freezegun import freeze_time + +from precommit_nbconvert_rename.cli import app +from precommit_nbconvert_rename.files import working_directory + +runner = CliRunner() + +def test_app_command_rename(tmp_path): + + shutil.copytree( + "tests/data/", + tmp_path / "data" + ) + with working_directory(str(tmp_path)): + + # there is no git repo in the tmp_dir + result = runner.invoke(app, ["rename"]) + assert result.exit_code == 1 + assert "fatal: not a git repository" in str(result.exception) + + + # Now setup a git repo + repo = git.Repo.init(str(tmp_path), bare=False) + author = "Test Person " + repo.git.add("data/*") + repo.git.commit(message="add stuff", author=author) + + result = runner.invoke(app, ["rename"]) + assert result.exit_code == 0 + assert not "fatal: not a git repository" in str(result.exception) + + newfile = tmp_path / "data" / "20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert not newfile.exists() + +@freeze_time("2000-11-22") +def test_app_command_process(tmp_path): + + shutil.copytree( + "tests/data/", + tmp_path / "data" + ) + with working_directory(str(tmp_path)): + result = runner.invoke(app, ["process"]) + assert result.exit_code == 0 + newfile = tmp_path / "data" / "20001122_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert newfile.exists() diff --git a/tests/test_precommit.py b/tests/test_convert_notebook.py similarity index 100% rename from tests/test_precommit.py rename to tests/test_convert_notebook.py diff --git a/tests/test_files.py b/tests/test_files.py index 6dc8c1b..5995500 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -12,8 +12,7 @@ def test_is_excluded(): assert is_excluded("notebook.ipynb", ["notebook.ipynb"]) -def test_find_notebooks(tmp_path): - +def test_find_files_in_paths(tmp_path): shutil.copytree( "tests/data/", @@ -23,6 +22,10 @@ def test_find_notebooks(tmp_path): all_notebooks = [f"data{os.sep}example.ipynb", f"data{os.sep}another_example.ipynb"] # all_notebooks = set([os.path.abspath(f) for f in all_notebooks]) - assert set(find_files_in_paths(".")) == set(all_notebooks) + assert set(find_files_in_paths(".")) == set(all_notebooks) assert len(find_files_in_paths(".", exclude_list=["data/*"])) == 0 + + html_files = [f"data{os.sep}20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html"] + assert set(find_files_in_paths(".",extension=".html")) == set(html_files) + diff --git a/tests/test_rename_placeholders.py b/tests/test_insert_commithash_filename_placeholder.py similarity index 91% rename from tests/test_rename_placeholders.py rename to tests/test_insert_commithash_filename_placeholder.py index a755b88..296137c 100644 --- a/tests/test_rename_placeholders.py +++ b/tests/test_insert_commithash_filename_placeholder.py @@ -4,7 +4,7 @@ from precommit_nbconvert_rename.files import working_directory, insert_commithash_filename_placeholder -def test_convert_filename(tmp_path): +def test_insert_commithash_filename_placeholder(tmp_path): shutil.copyfile( "tests/data/20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html", str(tmp_path / "20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html"), diff --git a/tests/test_requirements.txt b/tests/test_requirements.txt index 5723307..f3d2b8b 100644 --- a/tests/test_requirements.txt +++ b/tests/test_requirements.txt @@ -4,4 +4,5 @@ flake8 pytest pytest-cov mypy -freezegun \ No newline at end of file +freezegun +GitPython \ No newline at end of file From 877fdfc4994917cbddf35272ebe9c71db1a69201 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 13:18:28 +0100 Subject: [PATCH 04/14] Add nbstripout to nb_convert_strip function --- README.md | 8 +-- precommit_nbconvert_rename/_utils.py | 6 ++- precommit_nbconvert_rename/cli.py | 50 +++++++++++++------ precommit_nbconvert_rename/files.py | 10 ++-- .../nb_convert_strip.py | 35 ++++++++++--- tests/test_convert_notebook.py | 5 ++ 6 files changed, 78 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index f7618a6..0d220f7 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ You can setup this entire workflow once as [pre-commit](https://pre-commit.com/) pip install precommit_nbconvert_rename ``` -## Usage +## Usage [TODO, update] You need to update the `.pre-commit-config.yaml` in your repository. We'll assume you want to use `nbconvert_rename` with [nbstripout](https://github.com/kynan/nbstripout#using-nbstripout-as-a-pre-commit-hook) and include that here: @@ -64,12 +64,6 @@ repos: language_version: python3 always_run: true stages: [post-commit] -- repo: local - hooks: - - id: nbstripout - name: nbstripout - entry: nbstripout - language: system ``` You need to install the pre-commit and the post-commit hooks separately: diff --git a/precommit_nbconvert_rename/_utils.py b/precommit_nbconvert_rename/_utils.py index 888c20c..8c4c262 100644 --- a/precommit_nbconvert_rename/_utils.py +++ b/precommit_nbconvert_rename/_utils.py @@ -1,7 +1,7 @@ - import os import subprocess + class GitError(Exception): pass @@ -25,7 +25,9 @@ def _minimal_ext_cmd(cmd): env["LANGUAGE"] = "C" env["LANG"] = "C" env["LC_ALL"] = "C" - sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + sp = subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env + ) out, err = sp.communicate() if sp.returncode != 0: raise GitError(err.strip().decode("ascii")) diff --git a/precommit_nbconvert_rename/cli.py b/precommit_nbconvert_rename/cli.py index b10459f..7e7b27c 100644 --- a/precommit_nbconvert_rename/cli.py +++ b/precommit_nbconvert_rename/cli.py @@ -3,7 +3,10 @@ from pathlib import Path from typing import List, Optional -from precommit_nbconvert_rename.files import find_files_in_paths, insert_commithash_filename_placeholder +from precommit_nbconvert_rename.files import ( + find_files_in_paths, + insert_commithash_filename_placeholder, +) from precommit_nbconvert_rename._utils import git_version from precommit_nbconvert_rename.nb_convert_strip import convert_notebook @@ -13,36 +16,49 @@ @app.command() def rename( - paths: Optional[List[Path]] = typer.Argument(None, help="Directories and/or files to find and convert notebooks") - ): + paths: Optional[List[Path]] = typer.Argument( + None, help="Directories and/or files to find and convert notebooks" + ) +): """ Replaces the placeholder NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with the current commit hash. For example: - "20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + "20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" "20211026_notebook_26b2841.html" """ if len(paths) == 0: paths = [Path(os.getcwd())] - + filenames = find_files_in_paths(paths, extension=".html") for path in filenames: insert_commithash_filename_placeholder(path, commithash=git_version()) - - @app.command() def process( - paths: Optional[List[Path]] = typer.Argument(None, help="Directories and/or files to find and convert notebooks"), - date_prefix: Optional[str] = typer.Option("%Y%m%d", help="Format of the date prefix. Set to empty for no prefix."), - output_dir: Optional[Path] = typer.Option(".", help="Path where to place output HTML files."), - exclude: Optional[List[Path]] = typer.Option(None, help="Directories and/or files to exclude from processing"), - nbconvert_template: Optional[str] = typer.Option(None, help="Name of the nbconvert template to use."), - nbconvert_no_input: bool = typer.Option(True, help="Nbconvert: Exclude input cells and output prompts from converted document. Ideal for generating code-free reports."), - ): + paths: Optional[List[Path]] = typer.Argument( + None, help="Directories and/or files to find and convert notebooks" + ), + date_prefix: Optional[str] = typer.Option( + "%Y%m%d", help="Format of the date prefix. Set to empty for no prefix." + ), + output_dir: Optional[Path] = typer.Option( + ".", help="Path where to place output HTML files." + ), + exclude: Optional[List[Path]] = typer.Option( + None, help="Directories and/or files to exclude from processing" + ), + nbconvert_template: Optional[str] = typer.Option( + None, help="Name of the nbconvert template to use." + ), + nbconvert_no_input: bool = typer.Option( + True, + help="Nbconvert: Exclude input cells and output prompts from converted document. Ideal for generating code-free reports.", + ), +): """ Process .ipynb files. @@ -54,8 +70,10 @@ def process( """ if len(paths) == 0: paths = [Path(os.getcwd())] - - notebook_paths = find_files_in_paths(paths, extension=".ipynb", exclude_list=exclude) + + notebook_paths = find_files_in_paths( + paths, extension=".ipynb", exclude_list=exclude + ) for path in notebook_paths: convert_notebook( diff --git a/precommit_nbconvert_rename/files.py b/precommit_nbconvert_rename/files.py index 89776d4..3442fb1 100644 --- a/precommit_nbconvert_rename/files.py +++ b/precommit_nbconvert_rename/files.py @@ -5,7 +5,9 @@ from contextlib import contextmanager -def find_files_in_paths(directories: List[str], extension: str = ".ipynb", exclude_list: List[str] = []) -> List[str]: +def find_files_in_paths( + directories: List[str], extension: str = ".ipynb", exclude_list: List[str] = [] +) -> List[str]: """ Find all files with a certain extension in a list of paths. @@ -30,7 +32,7 @@ def find_files_in_paths(directories: List[str], extension: str = ".ipynb", exclu files = [f for f in fn.glob(f"**/*{extension}")] if extension == ".ipynb": files = [f for f in files if not f.suffix == ".ipynb_checkpoints"] - + files = [str(f) for f in files if not is_excluded(f, exclude_list)] filenames += files @@ -79,7 +81,6 @@ def is_excluded(src_path: str, globs: List[str]) -> bool: return False - @contextmanager def working_directory(path): """ @@ -111,7 +112,7 @@ def insert_commithash_filename_placeholder(path: str, commithash: str) -> None: commithash (str): short hash of commit to insert """ assert len(commithash) != 0 - + p = Path(path) stem = Path(path).stem if "NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER" not in stem: @@ -119,4 +120,3 @@ def insert_commithash_filename_placeholder(path: str, commithash: str) -> None: stem = stem.replace("NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER", commithash) p.rename(Path(p.parent, f"{stem}{p.suffix}")) - diff --git a/precommit_nbconvert_rename/nb_convert_strip.py b/precommit_nbconvert_rename/nb_convert_strip.py index ef8fe78..427c83e 100644 --- a/precommit_nbconvert_rename/nb_convert_strip.py +++ b/precommit_nbconvert_rename/nb_convert_strip.py @@ -1,9 +1,14 @@ +import io import codecs -from datetime import datetime +import sys +import warnings -from pathlib import Path +from datetime import datetime from nbconvert import HTMLExporter -from precommit_nbconvert_rename.files import find_files_in_paths +from nbstripout._utils import strip_output +from nbformat import read, write, NO_CONVERT +from nbformat.reader import NotJSONError +from pathlib import Path def convert_notebook( @@ -27,12 +32,13 @@ def convert_notebook( path = Path(path) if not isinstance(output_dir, Path): output_dir = Path(output_dir) - + if not Path(output_dir).exists(): raise IsADirectoryError( f"The --output-dir specified ('{output_dir}') does not exist" ) + ## Run 'nbconvert' if template: html_exporter = HTMLExporter(template_name=template) @@ -78,5 +84,22 @@ def convert_notebook( with codecs.open(str(html_path), "w", "utf-8") as f: f.write(body) - - + ## Run 'nbstripout' + try: + nb = read(path, as_version=NO_CONVERT) + nb = strip_output(nb, keep_output=False, keep_count=False) + + with io.open(path, "w", encoding="utf8", newline="") as f: + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=UserWarning) + write(nb, f) + + except NotJSONError: + print(f"'{path}' is not a valid notebook", file=sys.stderr) + sys.exit(1) + except FileNotFoundError: + print(f"Could not strip '{path}': file not found", file=sys.stderr) + sys.exit(1) + except Exception: + print(f"Could not strip '{path}'", file=sys.stderr) + raise diff --git a/tests/test_convert_notebook.py b/tests/test_convert_notebook.py index 21ab2c4..71bb44a 100644 --- a/tests/test_convert_notebook.py +++ b/tests/test_convert_notebook.py @@ -18,6 +18,11 @@ def test_convert_notebook(tmp_path): convert_notebook(str(tmp_path / "example.ipynb")) assert Path("20120114_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html").exists() + # Make sure output is stripped + nb = tmp_path / "example.ipynb" + txt = nb.read_text() + assert "Hello, World!" not in txt + # No date prefix convert_notebook(str(tmp_path / "example.ipynb"), date_format="") assert Path("example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html").exists() From 01a910ce0bd00ef0bae06e5db4a70de23315a9a9 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 16:03:00 +0100 Subject: [PATCH 05/14] Find and fix all mypy issues --- .pre-commit-config.yaml | 5 +-- precommit_nbconvert_rename/cli.py | 32 +++++------------ precommit_nbconvert_rename/files.py | 34 +++++++++++-------- .../nb_convert_strip.py | 16 ++++----- setup.py | 8 ++--- tests/test_cli.py | 15 +++----- tests/test_files.py | 19 +++++------ tests/test_requirements.txt | 2 ++ 8 files changed, 56 insertions(+), 75 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5cae79d..cda62e9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,7 +24,7 @@ repos: language: system types: [python] exclude: tests/ - args: [--max-line-length=120, --docstring-convention=google, "--ignore=D100,D104,D212,D200,E203,W293,D412,W503,E731"] + args: [--max-line-length=120, --docstring-convention=google, "--ignore=D100,D104,D212,D200,D301,E203,W293,D412,W503,E731"] - repo: local hooks: - id: pytest @@ -41,4 +41,5 @@ repos: # E203 # W293 blank line contains whitespace # W503 line break before binary operator (for compatibility with black) -# E731: allow lambdas to be used, do not enforce def \ No newline at end of file +# E731: allow lambdas to be used, do not enforce def +# D301 Use r""" if any backslashes in a docstring \ No newline at end of file diff --git a/precommit_nbconvert_rename/cli.py b/precommit_nbconvert_rename/cli.py index 7e7b27c..00c9adf 100644 --- a/precommit_nbconvert_rename/cli.py +++ b/precommit_nbconvert_rename/cli.py @@ -15,11 +15,7 @@ @app.command() -def rename( - paths: Optional[List[Path]] = typer.Argument( - None, help="Directories and/or files to find and convert notebooks" - ) -): +def rename(paths: List[Path] = typer.Argument(None, help="Directories and/or files to find and convert notebooks")): """ Replaces the placeholder NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with the current commit hash. @@ -39,24 +35,14 @@ def rename( @app.command() def process( - paths: Optional[List[Path]] = typer.Argument( - None, help="Directories and/or files to find and convert notebooks" - ), - date_prefix: Optional[str] = typer.Option( - "%Y%m%d", help="Format of the date prefix. Set to empty for no prefix." - ), - output_dir: Optional[Path] = typer.Option( - ".", help="Path where to place output HTML files." - ), - exclude: Optional[List[Path]] = typer.Option( - None, help="Directories and/or files to exclude from processing" - ), - nbconvert_template: Optional[str] = typer.Option( - None, help="Name of the nbconvert template to use." - ), + paths: List[Path] = typer.Argument(None, help="Directories and/or files to find and convert notebooks"), + date_prefix: str = typer.Option("%Y%m%d", help="Format of the date prefix. Set to empty for no prefix."), + output_dir: Path = typer.Option(Path("."), help="Path where to place output HTML files."), + exclude: Optional[List[str]] = typer.Option(None, help="Globs of directories/files to exclude from processing"), + nbconvert_template: str = typer.Option("", help="Name of the nbconvert template to use."), nbconvert_no_input: bool = typer.Option( True, - help="Nbconvert: Exclude input cells and output prompts from converted document. Ideal for generating code-free reports.", + help="Nbconvert: Exclude input cells and output prompts from converted document.", ), ): """ @@ -71,9 +57,7 @@ def process( if len(paths) == 0: paths = [Path(os.getcwd())] - notebook_paths = find_files_in_paths( - paths, extension=".ipynb", exclude_list=exclude - ) + notebook_paths = find_files_in_paths(paths, extension=".ipynb", exclude_list=exclude) for path in notebook_paths: convert_notebook( diff --git a/precommit_nbconvert_rename/files.py b/precommit_nbconvert_rename/files.py index 3442fb1..01aac6d 100644 --- a/precommit_nbconvert_rename/files.py +++ b/precommit_nbconvert_rename/files.py @@ -1,13 +1,15 @@ import os import fnmatch from pathlib import Path -from typing import List +from typing import List, Optional from contextlib import contextmanager def find_files_in_paths( - directories: List[str], extension: str = ".ipynb", exclude_list: List[str] = [] -) -> List[str]: + directories: List[Path], + extension: str = ".ipynb", + exclude_list: Optional[List[str]] = None, +) -> List[Path]: """ Find all files with a certain extension in a list of paths. @@ -18,29 +20,31 @@ def find_files_in_paths( """ assert extension.startswith(".") - filenames = [] + filenames = [] # type: List[Path] for fn in directories: - fn = Path(fn) + if not isinstance(fn, Path): + fn = Path(fn) if not fn.is_dir(): if fn.suffix == extension and not is_excluded(fn, exclude_list): - filenames.append(str(fn)) + filenames.append(fn) continue files = [f for f in fn.glob(f"**/*{extension}")] if extension == ".ipynb": files = [f for f in files if not f.suffix == ".ipynb_checkpoints"] - files = [str(f) for f in files if not is_excluded(f, exclude_list)] + if exclude_list is not None: + files = [f for f in files if not is_excluded(f, exclude_list)] filenames += files return filenames -def is_excluded(src_path: str, globs: List[str]) -> bool: +def is_excluded(src_path: Path, globs: Optional[List[str]] = None) -> bool: """ Determine if a src_path should be excluded. @@ -49,19 +53,20 @@ def is_excluded(src_path: str, globs: List[str]) -> bool: https://github.com/apenwarr/mkdocs-exclude/blob/master/mkdocs_exclude/plugin.py Args: - src_path (src): Path of file + src_path (Path): Path of file globs (list): list of globs Returns: (bool): whether src_path should be excluded """ - if not isinstance(src_path, str): - src_path = str(src_path) + if globs is None or len(globs) == 0: + return False + assert isinstance(src_path, Path) assert isinstance(globs, list) for g in globs: - if fnmatch.fnmatchcase(src_path, g): + if fnmatch.fnmatchcase(str(src_path), g): return True # Windows reports filenames as eg. a\\b\\c instead of a/b/c. @@ -74,7 +79,7 @@ def is_excluded(src_path: str, globs: List[str]) -> bool: # report Windows filenames using / separators regardless of # os.sep, so we *always* test with / above. if os.sep != "/": - src_path_fix = src_path.replace(os.sep, "/") + src_path_fix = str(src_path).replace(os.sep, "/") if fnmatch.fnmatchcase(src_path_fix, g): return True @@ -85,6 +90,7 @@ def is_excluded(src_path: str, globs: List[str]) -> bool: def working_directory(path): """ Temporarily change working directory. + A context manager which changes the working directory to the given path, and then changes it back to its previous value on exit. Usage: @@ -103,7 +109,7 @@ def working_directory(path): os.chdir(prev_cwd) -def insert_commithash_filename_placeholder(path: str, commithash: str) -> None: +def insert_commithash_filename_placeholder(path: Path, commithash: str) -> None: """ Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with last commit. diff --git a/precommit_nbconvert_rename/nb_convert_strip.py b/precommit_nbconvert_rename/nb_convert_strip.py index 427c83e..d35d64c 100644 --- a/precommit_nbconvert_rename/nb_convert_strip.py +++ b/precommit_nbconvert_rename/nb_convert_strip.py @@ -16,7 +16,7 @@ def convert_notebook( date_format: str = "%Y%m%d", template: str = "", no_input: bool = False, - output_dir: Path = ".", + output_dir: Path = Path("."), ) -> None: """ Converts .ipynb to .html. @@ -34,11 +34,9 @@ def convert_notebook( output_dir = Path(output_dir) if not Path(output_dir).exists(): - raise IsADirectoryError( - f"The --output-dir specified ('{output_dir}') does not exist" - ) + raise IsADirectoryError(f"The --output-dir specified ('{output_dir}') does not exist") - ## Run 'nbconvert' + # Run 'nbconvert' ############ if template: html_exporter = HTMLExporter(template_name=template) @@ -58,9 +56,7 @@ def convert_notebook( html_path = Path(path) - html_path = html_path.with_name( - f"{date_prefix}{html_path.stem}_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER" - ) + html_path = html_path.with_name(f"{date_prefix}{html_path.stem}_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER") html_path = html_path.with_suffix(".html") output_path = Path(output_dir) @@ -84,12 +80,12 @@ def convert_notebook( with codecs.open(str(html_path), "w", "utf-8") as f: f.write(body) - ## Run 'nbstripout' + # Run 'nbstripout' ############ try: nb = read(path, as_version=NO_CONVERT) nb = strip_output(nb, keep_output=False, keep_count=False) - with io.open(path, "w", encoding="utf8", newline="") as f: + with io.open(path, "w", encoding="utf8", newline="") as f: # type: ignore with warnings.catch_warnings(): warnings.simplefilter("ignore", category=UserWarning) write(nb, f) diff --git a/setup.py b/setup.py index cc6c37c..5398916 100644 --- a/setup.py +++ b/setup.py @@ -8,10 +8,10 @@ "version": "0.2", "packages": find_packages(), "install_requires": [ - "jupyter-client>=7.1.1", # BSD-3 https://github.com/jupyter/jupyter_client/blob/main/COPYING.md - "nbconvert>=6.4.0", # BSD-3 https://github.com/jupyter/nbconvert/blob/main/LICENSE - "pre-commit>=2.16.0", # MIT https://github.com/pre-commit/pre-commit/blob/master/LICENSE - "typer>=0.4.0" # MIT https://github.com/tiangolo/typer/blob/master/LICENSE + "jupyter-client>=7.1.1", # BSD-3 https://github.com/jupyter/jupyter_client/blob/main/COPYING.md + "nbconvert>=6.4.0", # BSD-3 https://github.com/jupyter/nbconvert/blob/main/LICENSE + "pre-commit>=2.16.0", # MIT https://github.com/pre-commit/pre-commit/blob/master/LICENSE + "typer>=0.4.0", # MIT https://github.com/tiangolo/typer/blob/master/LICENSE ], "author": "Tim Vink", "author_email": "vinktim@gmail.com", diff --git a/tests/test_cli.py b/tests/test_cli.py index 3d011ff..981284c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8,19 +8,16 @@ runner = CliRunner() + def test_app_command_rename(tmp_path): - shutil.copytree( - "tests/data/", - tmp_path / "data" - ) + shutil.copytree("tests/data/", tmp_path / "data") with working_directory(str(tmp_path)): # there is no git repo in the tmp_dir result = runner.invoke(app, ["rename"]) assert result.exit_code == 1 - assert "fatal: not a git repository" in str(result.exception) - + assert "fatal: not a git repository" in str(result.exception) # Now setup a git repo repo = git.Repo.init(str(tmp_path), bare=False) @@ -35,13 +32,11 @@ def test_app_command_rename(tmp_path): newfile = tmp_path / "data" / "20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" assert not newfile.exists() + @freeze_time("2000-11-22") def test_app_command_process(tmp_path): - shutil.copytree( - "tests/data/", - tmp_path / "data" - ) + shutil.copytree("tests/data/", tmp_path / "data") with working_directory(str(tmp_path)): result = runner.invoke(app, ["process"]) assert result.exit_code == 0 diff --git a/tests/test_files.py b/tests/test_files.py index 5995500..c46dc29 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -1,31 +1,28 @@ import os import shutil +from pathlib import Path from precommit_nbconvert_rename.files import find_files_in_paths, is_excluded, working_directory def test_is_excluded(): - assert is_excluded("c:/data/notebook.ipynb", ["c:/data/notebook.ipynb"]) - assert is_excluded("data/notebook.ipynb", ["*/notebook.ipynb"]) - assert is_excluded("data/notebook.ipynb", ["data/*"]) - assert is_excluded("notebook.ipynb", ["notebook.ipynb"]) + assert is_excluded(Path("c:/data/notebook.ipynb"), ["c:/data/notebook.ipynb"]) + assert is_excluded(Path("data/notebook.ipynb"), ["*/notebook.ipynb"]) + assert is_excluded(Path("data/notebook.ipynb"), ["data/*"]) + assert is_excluded(Path("notebook.ipynb"), ["notebook.ipynb"]) def test_find_files_in_paths(tmp_path): - shutil.copytree( - "tests/data/", - tmp_path / "data" - ) + shutil.copytree("tests/data/", tmp_path / "data") with working_directory(str(tmp_path)): all_notebooks = [f"data{os.sep}example.ipynb", f"data{os.sep}another_example.ipynb"] # all_notebooks = set([os.path.abspath(f) for f in all_notebooks]) - assert set(find_files_in_paths(".")) == set(all_notebooks) + assert set([str(f) for f in find_files_in_paths(".")]) == set(all_notebooks) assert len(find_files_in_paths(".", exclude_list=["data/*"])) == 0 html_files = [f"data{os.sep}20211028_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html"] - assert set(find_files_in_paths(".",extension=".html")) == set(html_files) - + assert set([str(f) for f in find_files_in_paths(".", extension=".html")]) == set(html_files) diff --git a/tests/test_requirements.txt b/tests/test_requirements.txt index f3d2b8b..882bc84 100644 --- a/tests/test_requirements.txt +++ b/tests/test_requirements.txt @@ -1,8 +1,10 @@ pre-commit black flake8 +flake8-docstrings pytest pytest-cov mypy freezegun +types-freezegun GitPython \ No newline at end of file From 3cab56c1b81a1bb5019546f472b3ba571e87a851 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 16:06:17 +0100 Subject: [PATCH 06/14] Add badges to README --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0d220f7..24f065d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ [![Unit tests](https://github.com/allianz-direct/precommit_nbconvert_rename/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/allianz-direct/precommit_nbconvert_rename/actions/workflows/unit_tests.yml) +![PyPI - Python Version](https://img.shields.io/pypi/pyversions/precommit-nbconvert-rename) +![PyPI](https://img.shields.io/pypi/v/precommit-nbconvert-rename) +![PyPI - Downloads](https://img.shields.io/pypi/dm/precommit-nbconvert-rename) +![GitHub contributors](https://img.shields.io/github/contributors/timvink/precommit-nbconvert-rename) +![PyPI - License](https://img.shields.io/pypi/l/precommit-nbconvert-rename) + # precommit_nbconvert_rename From 0ad125a850a9b3e72835f7789cf3bd9a973ceb53 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 16:09:30 +0100 Subject: [PATCH 07/14] Add more package classifiers to setup.py --- setup.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 5398916..df810eb 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup_args = { "name": "precommit_nbconvert_rename", - "version": "0.2", + "version": "1.0", "packages": find_packages(), "install_requires": [ "jupyter-client>=7.1.1", # BSD-3 https://github.com/jupyter/jupyter_client/blob/main/COPYING.md @@ -14,10 +14,22 @@ "typer>=0.4.0", # MIT https://github.com/tiangolo/typer/blob/master/LICENSE ], "author": "Tim Vink", - "author_email": "vinktim@gmail.com", + "author_email": "tim.vink@allianzdirect.nl", "long_description": long_description, "long_description_content_type": "text/markdown", - "url": "", + "url": "https://github.com/allianz-direct/precommit_nbconvert_rename", + "keywords": "precommit nbconvert nbstripout jupyter notebook python", + "license": "MIT", + "python_requires": ">=3.7", + "classifiers": [ + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + ], "entry_points": { "console_scripts": [ "nb_convert_strip=precommit_nbconvert_rename.cli:app", From ff40ae6f51dccccba07ac19d5c71a03093fb0955 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 16:51:32 +0100 Subject: [PATCH 08/14] Rename from precommit_nbconvert_rename to nb_prep --- .github/workflows/unit_tests.yml | 4 +- .pre-commit-hooks.yaml | 4 +- CONTRIBUTING.md | 13 +++--- README.md | 40 ++++++++++++------- .../__init__.py | 0 .../_utils.py | 8 ++-- .../cli.py | 6 +-- .../files.py | 0 .../nb_convert_strip.py | 0 setup.py | 6 +-- tests/data/pre-commit-test-config.yaml | 4 +- tests/test_cli.py | 4 +- tests/test_convert_notebook.py | 4 +- tests/test_files.py | 2 +- ..._insert_commithash_filename_placeholder.py | 2 +- 15 files changed, 55 insertions(+), 42 deletions(-) rename {precommit_nbconvert_rename => nb_prep}/__init__.py (100%) rename {precommit_nbconvert_rename => nb_prep}/_utils.py (87%) rename {precommit_nbconvert_rename => nb_prep}/cli.py (92%) rename {precommit_nbconvert_rename => nb_prep}/files.py (100%) rename {precommit_nbconvert_rename => nb_prep}/nb_convert_strip.py (100%) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index ca2ba04..c92b066 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -35,11 +35,11 @@ jobs: - name: Static code checking with pyflakes run: | - pyflakes precommit_nbconvert_rename + pyflakes nb_prep - name: Run unit tests run: | git config --global user.name "Github Action" git config --global user.email "githubaction@gmail.com" - pytest --cov=precommit_nbconvert_rename + pytest --cov=nb_prep \ No newline at end of file diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 68604fe..b2f1418 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -1,5 +1,5 @@ - id: nbconvert_rename_precommit - name: precommit_nbconvert_rename (pre-commit; run nbconvert) + name: nb_prep (pre-commit; run nbconvert) description: 'Converts to .ipynb to .html and adds date prefix and hash placeholder.' entry: nbconvert_rename language: python @@ -7,7 +7,7 @@ types: [jupyter] stages: [commit] - id: nbconvert_rename_postcommit - name: precommit_nbconvert_rename (post-commit; replace commithash in .html filenames) + name: nb_prep (post-commit; replace commithash in .html filenames) description: 'Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with commit hash in any .html filenames.' entry: rename_commithash types: [html] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee14ee5..61f6a89 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,13 +3,14 @@ ## Dev setup ```shell -pip install -r dev_requirements.txt +pip install -r tests/test_requirements.txt pre-commit install ``` ## Edit drawings We useed excalidraw, you can edit the vector image [here](https://excalidraw.com/#json=5272425855975424,sXm3L5A8Yr5EH9nkuENJIQ). + ## Testing There are some unit tests you can run with `pytest`. @@ -20,13 +21,13 @@ In a workspace directory, assuming already have a local clone of this repo: ```shell mkdir test_prj -cp precommit_nbconvert_rename/tests/data/example.ipynb test_prj/ +cp nb_prep/tests/data/example.ipynb test_prj/ cd test_prj git init git add --all -pre-commit try-repo ..\precommit_nbconvert_rename\ --verbose +pre-commit try-repo ..\nb_prep\ --verbose git commit -m "test" -pre-commit try-repo ..\precommit_nbconvert_rename\ --verbose --hook-stage post-commit +pre-commit try-repo ..\nb_prep\ --verbose --hook-stage post-commit ``` ### manually test a precommit config @@ -35,8 +36,8 @@ In a workspace directory, assuming already have a local clone of this repo: ```shell mkdir test_precommit_prj -cp precommit_nbconvert_rename/tests/data/example.ipynb test_precommit_prj/ -cp precommit_nbconvert_rename/tests/data/pre-commit-test-config.yaml test_precommit_prj/.pre-commit-config.yaml +cp nb_prep/tests/data/example.ipynb test_precommit_prj/ +cp nb_prep/tests/data/pre-commit-test-config.yaml test_precommit_prj/.pre-commit-config.yaml cd test_precommit_prj git init pre-commit install diff --git a/README.md b/README.md index 24f065d..471d8eb 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -[![Unit tests](https://github.com/allianz-direct/precommit_nbconvert_rename/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/allianz-direct/precommit_nbconvert_rename/actions/workflows/unit_tests.yml) -![PyPI - Python Version](https://img.shields.io/pypi/pyversions/precommit-nbconvert-rename) -![PyPI](https://img.shields.io/pypi/v/precommit-nbconvert-rename) -![PyPI - Downloads](https://img.shields.io/pypi/dm/precommit-nbconvert-rename) -![GitHub contributors](https://img.shields.io/github/contributors/timvink/precommit-nbconvert-rename) -![PyPI - License](https://img.shields.io/pypi/l/precommit-nbconvert-rename) +[![Unit tests](https://github.com/allianz-direct/nb_prep/actions/workflows/unit_tests.yml/badge.svg)](https://github.com/allianz-direct/nb_prep/actions/workflows/unit_tests.yml) +![PyPI - Python Version](https://img.shields.io/pypi/pyversions/nb-prep) +![PyPI](https://img.shields.io/pypi/v/nb-prep) +![PyPI - Downloads](https://img.shields.io/pypi/dm/nb-prep) +![GitHub contributors](https://img.shields.io/github/contributors/timvink/nb-prep) +![PyPI - License](https://img.shields.io/pypi/l/nb-prep) -# precommit_nbconvert_rename +# nb_prep Use `nbconvert` and `nbstripout` together as precommit hooks. @@ -23,7 +23,7 @@ You use [jupyter notebooks](https://jupyter.org/) and: Forget to run `nbconvert`, or use them in the wrong order (`nbstripout` before `nbconvert`) and you will have to re-run your notebooks before you can output HTML, which can be annoying when they are long-running. Especially when you use `nbstripout` as a [pre-commit](https://pre-commit.com/) hook, this can happen quite often. -`precommit_nbconvert_rename` can help to automatically process notebooks and (optionally) store versioned output in an in output directory. The CLI command `nb_convert_strip` takes a list of directories and/or files to find and convert notebooks. For each notebook: +`nb_prep` can help to automatically process notebooks and (optionally) store versioned output in an in output directory. The CLI command `nb_convert_strip` takes a list of directories and/or files to find and convert notebooks. For each notebook: - `nbconvert` is used to create an `.html` export - Date prefix is added `YYYYMMDD_.html` (can be turned off) @@ -41,7 +41,7 @@ You can setup this entire workflow once as [pre-commit](https://pre-commit.com/) ## Installation ```bash -pip install precommit_nbconvert_rename +pip install nb_prep ``` ## Usage [TODO, update] @@ -54,7 +54,7 @@ repos: - repo: local hooks: - id: nbconvert_rename_precommit - name: precommit_nbconvert_rename (pre-commit; run nbconvert) + name: nb_prep (pre-commit; run nbconvert) description: 'Converts to .ipynb to .html and adds date prefix and hash placeholder.' entry: nbconvert_rename language: python @@ -62,7 +62,7 @@ repos: types: [jupyter] stages: [commit] - id: nbconvert_rename_postcommit - name: precommit_nbconvert_rename (post-commit; replace commithash in .html filenames) + name: nb_prep (post-commit; replace commithash in .html filenames) description: 'Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with commit hash in any .html filenames.' entry: rename_commithash types: [html] @@ -72,6 +72,16 @@ repos: stages: [post-commit] ``` +```yaml +repos: +- repo: https://github.com/psf/black + rev: stable + hooks: + - id: black +``` + + + You need to install the pre-commit and the post-commit hooks separately: ```shell @@ -84,11 +94,11 @@ When you commit a notebook, you might see something like: ```shell git add notebook.ipynb git commit -m "Add notebook" -# precommit_nbconvert_rename (pre-commit; run nbconvert)............................Passed +# nb_prep (pre-commit; run nbconvert)............................Passed # nbstripout........................................................................Failed # - hook id: nbstripout # - files were modified by this hook -# precommit_nbconvert_rename (post-commit; replace commithash in .html filenames)...Passed +# nb_prep (post-commit; replace commithash in .html filenames)...Passed ``` `nbstripout` has overwritten `notebook.ipynb` and `nbconvert-rename` has created a file named something like `20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html`. @@ -97,9 +107,9 @@ Make sure to avoid committing HTML files by adding `.html` added to your `.gitig ```shell git add notebook.ipynb git commit -m "Add notebook" -# precommit_nbconvert_rename (pre-commit; run nbconvert)............................Passed +# nb_prep (pre-commit; run nbconvert)............................Passed # nbstripout........................................................................Passed -# precommit_nbconvert_rename (post-commit; replace commithash in .html filenames)...Passed +# nb_prep (post-commit; replace commithash in .html filenames)...Passed ``` Now, you've committed a clean, stripped version of `notebook.ipynb` and you have a local snapshot of your notebook named something like `20211026_notebook_eac9e43.html`. diff --git a/precommit_nbconvert_rename/__init__.py b/nb_prep/__init__.py similarity index 100% rename from precommit_nbconvert_rename/__init__.py rename to nb_prep/__init__.py diff --git a/precommit_nbconvert_rename/_utils.py b/nb_prep/_utils.py similarity index 87% rename from precommit_nbconvert_rename/_utils.py rename to nb_prep/_utils.py index 8c4c262..0f9e1f6 100644 --- a/precommit_nbconvert_rename/_utils.py +++ b/nb_prep/_utils.py @@ -3,6 +3,10 @@ class GitError(Exception): + """ + Exception with Git. + """ + pass @@ -25,9 +29,7 @@ def _minimal_ext_cmd(cmd): env["LANGUAGE"] = "C" env["LANG"] = "C" env["LC_ALL"] = "C" - sp = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env - ) + sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) out, err = sp.communicate() if sp.returncode != 0: raise GitError(err.strip().decode("ascii")) diff --git a/precommit_nbconvert_rename/cli.py b/nb_prep/cli.py similarity index 92% rename from precommit_nbconvert_rename/cli.py rename to nb_prep/cli.py index 00c9adf..a72da33 100644 --- a/precommit_nbconvert_rename/cli.py +++ b/nb_prep/cli.py @@ -3,12 +3,12 @@ from pathlib import Path from typing import List, Optional -from precommit_nbconvert_rename.files import ( +from nb_prep.files import ( find_files_in_paths, insert_commithash_filename_placeholder, ) -from precommit_nbconvert_rename._utils import git_version -from precommit_nbconvert_rename.nb_convert_strip import convert_notebook +from nb_prep._utils import git_version +from nb_prep.nb_convert_strip import convert_notebook app = typer.Typer() diff --git a/precommit_nbconvert_rename/files.py b/nb_prep/files.py similarity index 100% rename from precommit_nbconvert_rename/files.py rename to nb_prep/files.py diff --git a/precommit_nbconvert_rename/nb_convert_strip.py b/nb_prep/nb_convert_strip.py similarity index 100% rename from precommit_nbconvert_rename/nb_convert_strip.py rename to nb_prep/nb_convert_strip.py diff --git a/setup.py b/setup.py index df810eb..b8e7e25 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ long_description = readme.read() setup_args = { - "name": "precommit_nbconvert_rename", + "name": "nb_prep", "version": "1.0", "packages": find_packages(), "install_requires": [ @@ -17,7 +17,7 @@ "author_email": "tim.vink@allianzdirect.nl", "long_description": long_description, "long_description_content_type": "text/markdown", - "url": "https://github.com/allianz-direct/precommit_nbconvert_rename", + "url": "https://github.com/allianz-direct/nb_prep", "keywords": "precommit nbconvert nbstripout jupyter notebook python", "license": "MIT", "python_requires": ">=3.7", @@ -32,7 +32,7 @@ ], "entry_points": { "console_scripts": [ - "nb_convert_strip=precommit_nbconvert_rename.cli:app", + "nb_prep=nb_prep.cli:app", ] }, } diff --git a/tests/data/pre-commit-test-config.yaml b/tests/data/pre-commit-test-config.yaml index 5a866b4..a65b1da 100644 --- a/tests/data/pre-commit-test-config.yaml +++ b/tests/data/pre-commit-test-config.yaml @@ -2,7 +2,7 @@ repos: - repo: local hooks: - id: nbconvert_rename_precommit - name: precommit_nbconvert_rename (pre-commit; run nbconvert) + name: nb_prep (pre-commit; run nbconvert) description: 'Converts to .ipynb to .html and adds date prefix and hash placeholder.' entry: nbconvert_rename language: python @@ -10,7 +10,7 @@ repos: types: [jupyter] stages: [commit] - id: nbconvert_rename_postcommit - name: precommit_nbconvert_rename (post-commit; replace commithash in .html filenames) + name: nb_prep (post-commit; replace commithash in .html filenames) description: 'Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with commit hash in any .html filenames.' entry: rename_commithash types: [html] diff --git a/tests/test_cli.py b/tests/test_cli.py index 981284c..d15637d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -3,8 +3,8 @@ from typer.testing import CliRunner from freezegun import freeze_time -from precommit_nbconvert_rename.cli import app -from precommit_nbconvert_rename.files import working_directory +from nb_prep.cli import app +from nb_prep.files import working_directory runner = CliRunner() diff --git a/tests/test_convert_notebook.py b/tests/test_convert_notebook.py index 71bb44a..f9527f0 100644 --- a/tests/test_convert_notebook.py +++ b/tests/test_convert_notebook.py @@ -3,8 +3,8 @@ from freezegun import freeze_time from pathlib import Path -from precommit_nbconvert_rename.nb_convert_strip import convert_notebook -from precommit_nbconvert_rename.files import working_directory +from nb_prep.nb_convert_strip import convert_notebook +from nb_prep.files import working_directory @freeze_time("2012-01-14") diff --git a/tests/test_files.py b/tests/test_files.py index c46dc29..9a33326 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -2,7 +2,7 @@ import shutil from pathlib import Path -from precommit_nbconvert_rename.files import find_files_in_paths, is_excluded, working_directory +from nb_prep.files import find_files_in_paths, is_excluded, working_directory def test_is_excluded(): diff --git a/tests/test_insert_commithash_filename_placeholder.py b/tests/test_insert_commithash_filename_placeholder.py index 296137c..d2b797c 100644 --- a/tests/test_insert_commithash_filename_placeholder.py +++ b/tests/test_insert_commithash_filename_placeholder.py @@ -1,7 +1,7 @@ import shutil from pathlib import Path -from precommit_nbconvert_rename.files import working_directory, insert_commithash_filename_placeholder +from nb_prep.files import working_directory, insert_commithash_filename_placeholder def test_insert_commithash_filename_placeholder(tmp_path): From 3b2d95b70bb22a3f4c530aade269e648683309ef Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Tue, 18 Jan 2022 22:26:11 +0100 Subject: [PATCH 09/14] Add unit tests for precommit hooks setup --- .pre-commit-hooks.yaml | 15 ++++---- CONTRIBUTING.md | 4 +- README.md | 4 ++ nb_prep/_utils.py | 2 +- setup.py | 1 + tests/test_precommit.py | 84 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 10 deletions(-) create mode 100644 tests/test_precommit.py diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index b2f1418..7b861b7 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -1,17 +1,18 @@ -- id: nbconvert_rename_precommit - name: nb_prep (pre-commit; run nbconvert) - description: 'Converts to .ipynb to .html and adds date prefix and hash placeholder.' - entry: nbconvert_rename +- id: nb_prep_precommit + name: nb_prep (pre-commit; process notebooks) + description: 'Converts to .ipynb to .html and adds date prefix and hash placeholder. Strips notebook of outputs.' + entry: nb_prep process language: python language_version: python3 types: [jupyter] stages: [commit] -- id: nbconvert_rename_postcommit +- id: nb_prep_postcommit name: nb_prep (post-commit; replace commithash in .html filenames) description: 'Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with commit hash in any .html filenames.' - entry: rename_commithash + entry: nb_prep rename types: [html] language: python language_version: python3 + # always_run because .html files are probably gitignored always_run: true - stages: [post-commit] \ No newline at end of file + stages: [post-commit] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 61f6a89..59e3552 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,9 +25,9 @@ cp nb_prep/tests/data/example.ipynb test_prj/ cd test_prj git init git add --all -pre-commit try-repo ..\nb_prep\ --verbose +pre-commit try-repo ../nb_prep --verbose git commit -m "test" -pre-commit try-repo ..\nb_prep\ --verbose --hook-stage post-commit +pre-commit try-repo ../nb_prep/ --verbose --hook-stage post-commit ``` ### manually test a precommit config diff --git a/README.md b/README.md index 471d8eb..58e039f 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,10 @@ pip install nb_prep ## Usage [TODO, update] + +- You'll probably want to `.gitignore` the `.html` files generated. Especially if you use `--output-dir`. + + You need to update the `.pre-commit-config.yaml` in your repository. We'll assume you want to use `nbconvert_rename` with [nbstripout](https://github.com/kynan/nbstripout#using-nbstripout-as-a-pre-commit-hook) and include that here: ```yaml diff --git a/nb_prep/_utils.py b/nb_prep/_utils.py index 0f9e1f6..9ace84f 100644 --- a/nb_prep/_utils.py +++ b/nb_prep/_utils.py @@ -32,7 +32,7 @@ def _minimal_ext_cmd(cmd): sp = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) out, err = sp.communicate() if sp.returncode != 0: - raise GitError(err.strip().decode("ascii")) + raise GitError(err) else: return out diff --git a/setup.py b/setup.py index b8e7e25..e2d9afa 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ "nbconvert>=6.4.0", # BSD-3 https://github.com/jupyter/nbconvert/blob/main/LICENSE "pre-commit>=2.16.0", # MIT https://github.com/pre-commit/pre-commit/blob/master/LICENSE "typer>=0.4.0", # MIT https://github.com/tiangolo/typer/blob/master/LICENSE + "nbstripout>=0.5.0", # MIT https://github.com/kynan/nbstripout/blob/master/LICENSE.txt ], "author": "Tim Vink", "author_email": "tim.vink@allianzdirect.nl", diff --git a/tests/test_precommit.py b/tests/test_precommit.py new file mode 100644 index 0000000..16dc69b --- /dev/null +++ b/tests/test_precommit.py @@ -0,0 +1,84 @@ +import shutil +import git +import os + +from pathlib import Path +from datetime import date + +from nb_prep.files import working_directory + + +def shell_output(command) -> str: + """ + Lightweight function to quickly run a shell command. + For longer queries with json output use 'run_command' + """ + print(f"Running:\n\t{command}") + std_out = os.popen(command).read().rstrip() + std_out = std_out.lstrip('"').rstrip('"') + return std_out.strip() + + +def test_precommit_hook(tmp_path): + """ + Tests if the full setup with precommit hooks works properly. + + Equivalent to running: + + ```bash + mkdir test_prj + cp nb_prep/tests/data/example.ipynb test_prj/ + cd test_prj + git init + git add --all + pre-commit try-repo ../nb_prep --verbose + git commit -m "test" + pre-commit try-repo ../nb_prep --verbose --hook-stage post-commit + ``` + """ + + current_dir = os.getcwd() + + test_prj = tmp_path / "test_prj" + shutil.copytree("tests/data/", test_prj) + with working_directory(str(test_prj)): + + # we'll gitignore HTML files + f = open(".gitignore", "a") + f.write("*.html") + f.close() + + # Now setup a git repo + repo = git.Repo.init(str(test_prj), bare=False) + author = "Test Person " + repo.git.add(all=True) + + # First pass pre-commit. Will output something like: + # nb_prep (pre-commit; process notebooks)..................................Failed + # - hook id: nb_prep_precommit + out = shell_output(f"pre-commit try-repo {current_dir} --verbose") + assert "nb_prep (pre-commit; process notebooks).." in out + assert "...Failed" in out + + # Add changes + repo.git.add(all=True) + # Second pass should succeed + out = shell_output(f"pre-commit try-repo {current_dir} --verbose") + assert "nb_prep (pre-commit; process notebooks).." in out + assert "...Passed" in out + + # Make sure notebook stripping worked + nb = test_prj / "example.ipynb" + txt = nb.read_text() + assert "Hello, World!" not in txt + + # Make sure notebook conversion worked + assert Path(f"{date.today().strftime('%Y%m%d')}_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html").exists() + + # Now for the post-commit hook + repo.git.add(all=True) + repo.git.commit(message="add stuff", author=author) + + out = shell_output(f"pre-commit try-repo {current_dir} --verbose --hook-stage post-commit") + assert "nb_prep (post-commit; replace commithash in .html filenames)...." in out + assert "...Passed" in out From 95b6c3eb0576c50f2d4e2efcc4388f9049955ba7 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Thu, 20 Jan 2022 13:23:59 +0100 Subject: [PATCH 10/14] Update README with documentation --- .pre-commit-hooks.yaml | 2 +- README.md | 191 +++++++++++++++++++++---------------- images/schema_workflow.png | Bin 85504 -> 153427 bytes tests/test_precommit.py | 2 +- 4 files changed, 110 insertions(+), 85 deletions(-) diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 7b861b7..6b2c313 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -7,7 +7,7 @@ types: [jupyter] stages: [commit] - id: nb_prep_postcommit - name: nb_prep (post-commit; replace commithash in .html filenames) + name: nb_prep (post-commit; replace hash placeholder in .html filenames) description: 'Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with commit hash in any .html filenames.' entry: nb_prep rename types: [html] diff --git a/README.md b/README.md index 58e039f..8ac9e5c 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,25 @@ ![GitHub contributors](https://img.shields.io/github/contributors/timvink/nb-prep) ![PyPI - License](https://img.shields.io/pypi/l/nb-prep) - # nb_prep -Use `nbconvert` and `nbstripout` together as precommit hooks. +`nb_prep` makes it easier to prepare jupyter notebooks for storing in git and sharing with stakeholders. + +You can use the `nb_prep` CLI to: -A pre-commit hook that converts any changed jupyter notebooks (`.ipynb`) to `.html` files with a YYYMMDD date prefix and commit hash suffix added: +- Convert jupyter notebooks to HTML (using [`nbconvert`](https://nbconvert.readthedocs.io/)) and: + - add a date prefix to the filename. + - add a git hash suffix to the filename. + - move the HTML file to a configured output directory +- Strip all cell outputs (using [`nbstripout`](https://github.com/kynan/nbstripout)) -`my_notebook.ipynb` -> `20211026_my_notebook_eac9e43.html` +You can also configure `nb_prep` once as a pre-commit hook and have notebook output automatically prepared every time you `git commit`. + +## Installation + +```bash +pip install nb_prep +``` ## Use case @@ -21,71 +32,45 @@ You use [jupyter notebooks](https://jupyter.org/) and: - [nbconvert](https://github.com/jupyter/nbconvert) to convert `.ipynb` files to `.html` files - [nbstripout](https://github.com/kynan/nbstripout) to avoid committing (potentially sensitive) data to git and get proper `git diff`s on notebooks (only showing changes in code). -Forget to run `nbconvert`, or use them in the wrong order (`nbstripout` before `nbconvert`) and you will have to re-run your notebooks before you can output HTML, which can be annoying when they are long-running. Especially when you use `nbstripout` as a [pre-commit](https://pre-commit.com/) hook, this can happen quite often. +Forget to run `nbconvert` or use them in the wrong order (`nbstripout` before `nbconvert`) and you will have to re-run your notebooks before you can output HTML, which can be annoying when they are long-running. Especially when you use `nbstripout` as a [pre-commit](https://pre-commit.com/) hook, this can happen quite often. -`nb_prep` can help to automatically process notebooks and (optionally) store versioned output in an in output directory. The CLI command `nb_convert_strip` takes a list of directories and/or files to find and convert notebooks. For each notebook: +`nb_prep` can help to automatically process notebooks and (optionally) store versioned output in an in output directory. -- `nbconvert` is used to create an `.html` export -- Date prefix is added `YYYYMMDD_.html` (can be turned off) -- Placeholder for git hash is added `YYYYMMDD__20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` -- `.html` file is moved to `output-dir` (if specified) -- `nbstripout` is used strip output from notebook -Now you can `git add` and `git commit` the changed notebook files. You can then use `nb_convert_strip rename` will replace insert the commit hashes in the notebook filenames. +## Usage -You can setup this entire workflow once as [pre-commit](https://pre-commit.com/) hook, and basically get an up-to-date analysis output directory for free `output-dir`. Schematically: +The CLI command `nb_prep process` takes a list of directories and/or files to find and process notebooks. For each notebook: - +- `nbconvert` is used to create an `.html` export +- A date prefix is added `YYYYMMDD_.html` (can be turned off) +- A placeholder for git hash is added `YYYYMMDD__NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` +- The `.html` file is moved to an `output-dir` (if specified) +- The `nbstripout` is used strip output from the `.ipynb` file +Now you can `git add` and `git commit` the changed notebook files. You can then use `nb_prep rename` to insert the commit hashes in the notebook filenames. For example: -## Installation +`20220101_my_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` -> `20220101_my_notebook_eac9e43.html` -```bash -pip install nb_prep -``` +Tip: You'll probably want to `.gitignore` the `.html` files generated. Especially if you use `--output-dir`. -## Usage [TODO, update] +## Setting up as a pre-commit hook +You can setup this entire workflow once as [pre-commit](https://pre-commit.com/) hook, and basically get an up-to-date analysis output directory for free `output-dir`. Schematically: -- You'll probably want to `.gitignore` the `.html` files generated. Especially if you use `--output-dir`. + -You need to update the `.pre-commit-config.yaml` in your repository. We'll assume you want to use `nbconvert_rename` with [nbstripout](https://github.com/kynan/nbstripout#using-nbstripout-as-a-pre-commit-hook) and include that here: +You need to update the `.pre-commit-config.yaml` in your repository to include `nb_prep`: ```yaml -default_stages: [commit] repos: -- repo: local +- repo: https://github.com/allianz-direct/nb_prep + rev: main hooks: - - id: nbconvert_rename_precommit - name: nb_prep (pre-commit; run nbconvert) - description: 'Converts to .ipynb to .html and adds date prefix and hash placeholder.' - entry: nbconvert_rename - language: python - language_version: python3 - types: [jupyter] - stages: [commit] - - id: nbconvert_rename_postcommit - name: nb_prep (post-commit; replace commithash in .html filenames) - description: 'Replaces NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with commit hash in any .html filenames.' - entry: rename_commithash - types: [html] - language: python - language_version: python3 - always_run: true - stages: [post-commit] + - id: nb_prep_precommit + - id: nb_prep_postcommit ``` -```yaml -repos: -- repo: https://github.com/psf/black - rev: stable - hooks: - - id: black -``` - - - You need to install the pre-commit and the post-commit hooks separately: ```shell @@ -98,76 +83,116 @@ When you commit a notebook, you might see something like: ```shell git add notebook.ipynb git commit -m "Add notebook" -# nb_prep (pre-commit; run nbconvert)............................Passed -# nbstripout........................................................................Failed -# - hook id: nbstripout +# nb_prep (pre-commit; process notebooks)...................................Failed +# - hook id: nb_prep_precommit # - files were modified by this hook -# nb_prep (post-commit; replace commithash in .html filenames)...Passed +# nb_prep (post-commit; replace hash placeholder in .html filenames)........Passed ``` -`nbstripout` has overwritten `notebook.ipynb` and `nbconvert-rename` has created a file named something like `20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html`. -Make sure to avoid committing HTML files by adding `.html` added to your `.gitignore` file. Next: +`nb_prep` has used [nbstripout](https://github.com/kynan/nbstripout) to overwrite `notebook.ipynb`. It has also created a file in the output directory named something like `20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html`. + +Re-add and re-commit the notebook again: ```shell git add notebook.ipynb git commit -m "Add notebook" -# nb_prep (pre-commit; run nbconvert)............................Passed -# nbstripout........................................................................Passed -# nb_prep (post-commit; replace commithash in .html filenames)...Passed +# nb_prep (pre-commit; process notebooks)...................................Passed +# nb_prep (post-commit; replace hash placeholder in .html filenames)........Passed ``` -Now, you've committed a clean, stripped version of `notebook.ipynb` and you have a local snapshot of your notebook named something like `20211026_notebook_eac9e43.html`. +Because the output file already exists, `nb_prep` will not overwrite it, because if we would convert again and output it would be a stripped version without any cell outputs. + +Now, you've committed a clean, stripped version of `notebook.ipynb`. and you have a local snapshot of your notebook named something like `20211026_notebook_eac9e43.html`. ## Options +Options are documented also in the CLI tool, see `nb_prep --help`. + ### Using templates -If you want to specify a different template for `nbconvert`, you can add an argument to the `nbconvert_rename_precommit` hook: +If you want to specify a different template for `nbconvert`, you can add an argument to the `nb_prep process` hook: + +CLI: + +```shell +nb_prep process --nbconvert-template 'reveal' . +``` + +Pre-commit hook: ```yaml -- repo: local +repos: +- repo: https://github.com/allianz-direct/nb_prep + rev: main hooks: - - id: nbconvert_rename_precommit - entry: nbconvert_rename - ... - args: ["--template","reveal"] + - id: nb_prep_precommit + args: ["--nbconvert-template","reveal"] + - id: nb_prep_postcommit ``` ### Removing cell blocks -You can also choose to remove input code blocks (equivalent to `jupyter nbconvert --no-input`) +You can also choose to remove input code blocks from the converted HTML (equivalent to `jupyter nbconvert --no-input`). + +CLI: + +```bash +nb_prep process --nbconvert-no-input . +``` + +Pre-commit hook: ```yaml -- repo: local +repos: +- repo: https://github.com/allianz-direct/nb_prep + rev: main hooks: - - id: nbconvert_rename_precommit - entry: nbconvert_rename - ... - args: ["--no-input"] + - id: nb_prep_precommit + args: ["--nbconvert-no-input"] + - id: nb_prep_postcommit ``` ### Specifying an output directory -You might want to output all HTML notebooks in a specific folder. You can specify a relative (to project root) or absolute path using `--output-dir`: +You might want to output all HTML notebooks in a specific folder. The default is using the same folder as the notebook. You can specify different folder relative to the project root or by absolute path using `--output-dir`: + +CLI: + +```bash +nb_prep process --output-dir "~/workspace/notebook_output" . +``` + +Pre-commit hook: + ```yaml -- repo: local +repos: +- repo: https://github.com/allianz-direct/nb_prep + rev: main hooks: - - id: nbconvert_rename_precommit - entry: nbconvert_rename - ... - args: ["--output-dir","../data/notebooks"] + - id: nb_prep_precommit + args: ["--output-dir","~/workspace/notebook_output"] + - id: nb_prep_postcommit ``` ### Excluding directories and files You can ignore certain notebooks or even entire directories with [globs](https://docs.python.org/3/library/glob.html), using a relative (to project root) or absolute path with `--exclude`. For example: +CLI: + +```bash +nb_prep process --exclude "templates/*", "a_notebook.ipynb" . +``` + +Pre-commit hook: + ```yaml -- repo: local +repos: +- repo: https://github.com/allianz-direct/nb_prep + rev: main hooks: - - id: nbconvert_rename_precommit - entry: nbconvert_rename - ... - args: ["--exclude","../data/notebooks/*", "a_notebook.ipynb"] + - id: nb_prep_precommit + args: ["--exclude","templates/*", "a_notebook.ipynb"] + - id: nb_prep_postcommit ``` diff --git a/images/schema_workflow.png b/images/schema_workflow.png index 76ebe6be74be321caa8e57ff5bacf7f05872def0..2675448779baaee223ba8d135601093391529e74 100644 GIT binary patch literal 153427 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

y-^-@6f%{P;J8?@* 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�m?Wg6tF??a6 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Π=yCptQ7ObpZQwFh%=ZrX&eY8!jiXW>k%Z` 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 diff --git a/tests/test_precommit.py b/tests/test_precommit.py index 16dc69b..35337e4 100644 --- a/tests/test_precommit.py +++ b/tests/test_precommit.py @@ -80,5 +80,5 @@ def test_precommit_hook(tmp_path): repo.git.commit(message="add stuff", author=author) out = shell_output(f"pre-commit try-repo {current_dir} --verbose --hook-stage post-commit") - assert "nb_prep (post-commit; replace commithash in .html filenames)...." in out + assert "nb_prep (post-commit; replace hash placeholder in .html filenames)...." in out assert "...Passed" in out From 7a162f770a5a70db71fe3fe7acacdb13eafa5793 Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Thu, 20 Jan 2022 14:03:01 +0100 Subject: [PATCH 11/14] Add a git hash suffix placeholder command Fix a bug with --exclude And add more unit tests --- nb_prep/cli.py | 4 ++++ nb_prep/files.py | 34 ++++++++++++++++-------------- nb_prep/nb_convert_strip.py | 17 ++++++++++----- tests/test_cli.py | 42 +++++++++++++++++++++++++++++++++++++ tests/test_files.py | 1 + 5 files changed, 77 insertions(+), 21 deletions(-) diff --git a/nb_prep/cli.py b/nb_prep/cli.py index a72da33..779cc96 100644 --- a/nb_prep/cli.py +++ b/nb_prep/cli.py @@ -37,6 +37,9 @@ def rename(paths: List[Path] = typer.Argument(None, help="Directories and/or fil def process( paths: List[Path] = typer.Argument(None, help="Directories and/or files to find and convert notebooks"), date_prefix: str = typer.Option("%Y%m%d", help="Format of the date prefix. Set to empty for no prefix."), + git_hash_suffix: bool = typer.Option( + True, help="Whether to include a placeholder in HTML filename for a git commit hash." + ), output_dir: Path = typer.Option(Path("."), help="Path where to place output HTML files."), exclude: Optional[List[str]] = typer.Option(None, help="Globs of directories/files to exclude from processing"), nbconvert_template: str = typer.Option("", help="Name of the nbconvert template to use."), @@ -63,6 +66,7 @@ def process( convert_notebook( path, date_format=date_prefix, + git_hash_suffix=git_hash_suffix, template=nbconvert_template, no_input=nbconvert_no_input, output_dir=output_dir, diff --git a/nb_prep/files.py b/nb_prep/files.py index 01aac6d..b312b3a 100644 --- a/nb_prep/files.py +++ b/nb_prep/files.py @@ -63,25 +63,27 @@ def is_excluded(src_path: Path, globs: Optional[List[str]] = None) -> bool: return False assert isinstance(src_path, Path) - assert isinstance(globs, list) + assert hasattr(globs, "__iter__") # list or tuple + + # Windows reports filenames as eg. a\\b\\c instead of a/b/c. + # To make the same globs/regexes match filenames on Windows and + # other OSes, let's try matching against converted filenames. + # On the other hand, Unix actually allows filenames to contain + # literal \\ characters (although it is rare), so we won't + # always convert them. We only convert if os.sep reports + # something unusual. Conversely, some future mkdocs might + # report Windows filenames using / separators regardless of + # os.sep, so we *always* test with / above. + if os.sep != "/": + src_path_fix = str(src_path).replace(os.sep, "/") + else: + src_path_fix = str(src_path) for g in globs: - if fnmatch.fnmatchcase(str(src_path), g): + if fnmatch.fnmatchcase(src_path_fix, g): + return True + if src_path.name == g: return True - - # Windows reports filenames as eg. a\\b\\c instead of a/b/c. - # To make the same globs/regexes match filenames on Windows and - # other OSes, let's try matching against converted filenames. - # On the other hand, Unix actually allows filenames to contain - # literal \\ characters (although it is rare), so we won't - # always convert them. We only convert if os.sep reports - # something unusual. Conversely, some future mkdocs might - # report Windows filenames using / separators regardless of - # os.sep, so we *always* test with / above. - if os.sep != "/": - src_path_fix = str(src_path).replace(os.sep, "/") - if fnmatch.fnmatchcase(src_path_fix, g): - return True return False diff --git a/nb_prep/nb_convert_strip.py b/nb_prep/nb_convert_strip.py index d35d64c..e8dc894 100644 --- a/nb_prep/nb_convert_strip.py +++ b/nb_prep/nb_convert_strip.py @@ -14,6 +14,7 @@ def convert_notebook( path: Path, date_format: str = "%Y%m%d", + git_hash_suffix: bool = True, template: str = "", no_input: bool = False, output_dir: Path = Path("."), @@ -24,6 +25,7 @@ def convert_notebook( Args: path (str): path to notebook date_format (str): format to write date prefix in + git_hash_suffix (bool): Whether to include a placeholder in HTML filename for a git commit hash. template (str): Name of the nbconvert template no_input (bool): Remove code input blocks output_dir (str): Path to output directory (rel or abs) @@ -50,15 +52,20 @@ def convert_notebook( (body, _) = html_exporter.from_filename(str(path)) + html_path = Path(path) + + # Add date prefix date_prefix = datetime.strftime(datetime.now(), date_format) if len(date_prefix) != 0: date_prefix += "_" + html_path = html_path.with_name(f"{date_prefix}{html_path.stem}") - html_path = Path(path) + # Add git hash suffix + if git_hash_suffix: + html_path = html_path.with_name(f"{html_path.stem}_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER") - html_path = html_path.with_name(f"{date_prefix}{html_path.stem}_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER") + # Determine output filename. html_path = html_path.with_suffix(".html") - output_path = Path(output_dir) if output_path.is_absolute(): # absolute output directory @@ -76,8 +83,8 @@ def convert_notebook( # using html_path_.exists() prevents this. # If a user would continue editing the .ipynb after the failed precommit nbstripout # Then the nbconvert .html would be outdated of course. - if not html_path.exists(): - with codecs.open(str(html_path), "w", "utf-8") as f: + if not output_file.exists(): + with codecs.open(str(output_file), "w", "utf-8") as f: f.write(body) # Run 'nbstripout' ############ diff --git a/tests/test_cli.py b/tests/test_cli.py index d15637d..1ffe6b7 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -42,3 +42,45 @@ def test_app_command_process(tmp_path): assert result.exit_code == 0 newfile = tmp_path / "data" / "20001122_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" assert newfile.exists() + + +@freeze_time("2000-11-22") +def test_app_command_process_with_exclude(tmp_path): + + shutil.copytree("tests/data/", tmp_path / "data") + with working_directory(str(tmp_path)): + result = runner.invoke(app, ["process", "--exclude", "example.ipynb"]) + assert result.exit_code == 0 + + example = tmp_path / "data" / "20001122_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert not example.exists() + another_example = tmp_path / "data" / "20001122_another_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert another_example.exists() + + +@freeze_time("2000-11-22") +def test_app_command_process_with_no_hash_suffix(tmp_path): + + shutil.copytree("tests/data/", tmp_path / "data") + with working_directory(str(tmp_path)): + result = runner.invoke(app, ["process", "--no-git-hash-suffix"]) + assert result.exit_code == 0 + + example = tmp_path / "data" / "20001122_example.html" + assert example.exists() + another_example = tmp_path / "data" / "20001122_another_example.html" + assert another_example.exists() + + +@freeze_time("2000-11-22") +def test_app_command_process_with_different_date_prefix(tmp_path): + + shutil.copytree("tests/data/", tmp_path / "data") + with working_directory(str(tmp_path)): + result = runner.invoke(app, ["process", "--date-prefix", "%Y"]) + assert result.exit_code == 0 + + example = tmp_path / "data" / "2000_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert example.exists() + another_example = tmp_path / "data" / "2000_another_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert another_example.exists() diff --git a/tests/test_files.py b/tests/test_files.py index 9a33326..24bdc9d 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -11,6 +11,7 @@ def test_is_excluded(): assert is_excluded(Path("data/notebook.ipynb"), ["*/notebook.ipynb"]) assert is_excluded(Path("data/notebook.ipynb"), ["data/*"]) assert is_excluded(Path("notebook.ipynb"), ["notebook.ipynb"]) + assert is_excluded(Path("/tmp/pytest-136/data/example.ipynb"), ["example.ipynb"]) def test_find_files_in_paths(tmp_path): From 80eef12f090a5713d9c6dfffed6651e242df237d Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Thu, 20 Jan 2022 14:47:51 +0100 Subject: [PATCH 12/14] Add output-dir to nb_prep rename also --- README.md | 3 ++- nb_prep/cli.py | 8 +++++++- nb_prep/files.py | 2 +- tests/__init__.py | 0 tests/test_cli.py | 33 +++++++++++++++++++++++++++++++++ tests/test_requirements.txt | 1 + 6 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/__init__.py diff --git a/README.md b/README.md index 8ac9e5c..f02f245 100644 --- a/README.md +++ b/README.md @@ -160,11 +160,11 @@ CLI: ```bash nb_prep process --output-dir "~/workspace/notebook_output" . +nb_prep rename --output-dir "~/workspace/notebook_output" . ``` Pre-commit hook: - ```yaml repos: - repo: https://github.com/allianz-direct/nb_prep @@ -173,6 +173,7 @@ repos: - id: nb_prep_precommit args: ["--output-dir","~/workspace/notebook_output"] - id: nb_prep_postcommit + args: ["--output-dir","~/workspace/notebook_output"] ``` ### Excluding directories and files diff --git a/nb_prep/cli.py b/nb_prep/cli.py index 779cc96..77cf767 100644 --- a/nb_prep/cli.py +++ b/nb_prep/cli.py @@ -15,7 +15,10 @@ @app.command() -def rename(paths: List[Path] = typer.Argument(None, help="Directories and/or files to find and convert notebooks")): +def rename( + paths: List[Path] = typer.Argument(None, help="Directories and/or files to find and convert notebooks"), + output_dir: Optional[Path] = typer.Option(None, help="Additional path where to find and rename HTML files."), +): """ Replaces the placeholder NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER with the current commit hash. @@ -27,6 +30,9 @@ def rename(paths: List[Path] = typer.Argument(None, help="Directories and/or fil if len(paths) == 0: paths = [Path(os.getcwd())] + if output_dir is not None: + paths += [output_dir] + filenames = find_files_in_paths(paths, extension=".html") for path in filenames: diff --git a/nb_prep/files.py b/nb_prep/files.py index b312b3a..dbc9cdf 100644 --- a/nb_prep/files.py +++ b/nb_prep/files.py @@ -41,7 +41,7 @@ def find_files_in_paths( filenames += files - return filenames + return list(set(filenames)) def is_excluded(src_path: Path, globs: Optional[List[str]] = None) -> bool: diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cli.py b/tests/test_cli.py index 1ffe6b7..80b10d8 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -84,3 +84,36 @@ def test_app_command_process_with_different_date_prefix(tmp_path): assert example.exists() another_example = tmp_path / "data" / "2000_another_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" assert another_example.exists() + + +@freeze_time("2000-11-22") +def test_app_command_process_with_output_dir(tmp_path, mocker): + + mocker.patch("nb_prep.cli.git_version", return_value="abcd1234") + + shutil.copytree("tests/data/", tmp_path / "data") + with working_directory(str(tmp_path)): + output_dir = tmp_path / "my_output_dir" + result = runner.invoke(app, ["process", "--output-dir", str(output_dir)]) + + assert result.exit_code == 1 + assert "The --output-dir specified" in str(result.exception) + assert " does not exist" in str(result.exception) + + output_dir = tmp_path + result = runner.invoke(app, ["process", "--output-dir", str(output_dir)]) + assert result.exit_code == 0 + + example = output_dir / "20001122_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert example.exists() + another_example = output_dir / "20001122_another_example_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html" + assert another_example.exists() + + # Test with renaming in output dir + result = runner.invoke(app, ["rename", "--output-dir", str(output_dir)]) + assert result.exit_code == 0 + + example = output_dir / "20001122_example_abcd1234.html" + assert example.exists() + another_example = output_dir / "20001122_another_example_abcd1234.html" + assert another_example.exists() diff --git a/tests/test_requirements.txt b/tests/test_requirements.txt index 882bc84..6a9e854 100644 --- a/tests/test_requirements.txt +++ b/tests/test_requirements.txt @@ -4,6 +4,7 @@ flake8 flake8-docstrings pytest pytest-cov +pytest-mock mypy freezegun types-freezegun From a05cdc646d7af9e2282743de0eef6587a3a5868a Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Thu, 20 Jan 2022 15:12:18 +0100 Subject: [PATCH 13/14] Add MkDocs website --- README.md | 173 +----------------- .../assets/images}/schema_workflow.png | Bin .../assets/images}/schema_workflow.svg | 0 docs/index.md | 6 + docs/options.md | 107 +++++++++++ docs/overrides/main.html | 13 ++ docs/usage.md | 86 +++++++++ mkdocs.yml | 70 +++++++ setup.py | 1 + tests/test_requirements.txt | 6 +- 10 files changed, 290 insertions(+), 172 deletions(-) rename {images => docs/assets/images}/schema_workflow.png (100%) rename {images => docs/assets/images}/schema_workflow.svg (100%) create mode 100644 docs/index.md create mode 100644 docs/options.md create mode 100644 docs/overrides/main.html create mode 100644 docs/usage.md create mode 100644 mkdocs.yml diff --git a/README.md b/README.md index f02f245..18f497b 100644 --- a/README.md +++ b/README.md @@ -25,175 +25,6 @@ You can also configure `nb_prep` once as a pre-commit hook and have notebook out pip install nb_prep ``` -## Use case +## Documentation -You use [jupyter notebooks](https://jupyter.org/) and: - -- [nbconvert](https://github.com/jupyter/nbconvert) to convert `.ipynb` files to `.html` files -- [nbstripout](https://github.com/kynan/nbstripout) to avoid committing (potentially sensitive) data to git and get proper `git diff`s on notebooks (only showing changes in code). - -Forget to run `nbconvert` or use them in the wrong order (`nbstripout` before `nbconvert`) and you will have to re-run your notebooks before you can output HTML, which can be annoying when they are long-running. Especially when you use `nbstripout` as a [pre-commit](https://pre-commit.com/) hook, this can happen quite often. - -`nb_prep` can help to automatically process notebooks and (optionally) store versioned output in an in output directory. - - -## Usage - -The CLI command `nb_prep process` takes a list of directories and/or files to find and process notebooks. For each notebook: - -- `nbconvert` is used to create an `.html` export -- A date prefix is added `YYYYMMDD_.html` (can be turned off) -- A placeholder for git hash is added `YYYYMMDD__NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` -- The `.html` file is moved to an `output-dir` (if specified) -- The `nbstripout` is used strip output from the `.ipynb` file - -Now you can `git add` and `git commit` the changed notebook files. You can then use `nb_prep rename` to insert the commit hashes in the notebook filenames. For example: - -`20220101_my_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` -> `20220101_my_notebook_eac9e43.html` - -Tip: You'll probably want to `.gitignore` the `.html` files generated. Especially if you use `--output-dir`. - -## Setting up as a pre-commit hook - -You can setup this entire workflow once as [pre-commit](https://pre-commit.com/) hook, and basically get an up-to-date analysis output directory for free `output-dir`. Schematically: - - - - -You need to update the `.pre-commit-config.yaml` in your repository to include `nb_prep`: - -```yaml -repos: -- repo: https://github.com/allianz-direct/nb_prep - rev: main - hooks: - - id: nb_prep_precommit - - id: nb_prep_postcommit -``` - -You need to install the pre-commit and the post-commit hooks separately: - -```shell -pre-commit install -pre-commit install --hook-type post-commit -``` - -When you commit a notebook, you might see something like: - -```shell -git add notebook.ipynb -git commit -m "Add notebook" -# nb_prep (pre-commit; process notebooks)...................................Failed -# - hook id: nb_prep_precommit -# - files were modified by this hook -# nb_prep (post-commit; replace hash placeholder in .html filenames)........Passed -``` - -`nb_prep` has used [nbstripout](https://github.com/kynan/nbstripout) to overwrite `notebook.ipynb`. It has also created a file in the output directory named something like `20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html`. - -Re-add and re-commit the notebook again: - -```shell -git add notebook.ipynb -git commit -m "Add notebook" -# nb_prep (pre-commit; process notebooks)...................................Passed -# nb_prep (post-commit; replace hash placeholder in .html filenames)........Passed -``` - -Because the output file already exists, `nb_prep` will not overwrite it, because if we would convert again and output it would be a stripped version without any cell outputs. - -Now, you've committed a clean, stripped version of `notebook.ipynb`. and you have a local snapshot of your notebook named something like `20211026_notebook_eac9e43.html`. - -## Options - -Options are documented also in the CLI tool, see `nb_prep --help`. - -### Using templates - -If you want to specify a different template for `nbconvert`, you can add an argument to the `nb_prep process` hook: - -CLI: - -```shell -nb_prep process --nbconvert-template 'reveal' . -``` - -Pre-commit hook: - -```yaml -repos: -- repo: https://github.com/allianz-direct/nb_prep - rev: main - hooks: - - id: nb_prep_precommit - args: ["--nbconvert-template","reveal"] - - id: nb_prep_postcommit -``` - -### Removing cell blocks - -You can also choose to remove input code blocks from the converted HTML (equivalent to `jupyter nbconvert --no-input`). - -CLI: - -```bash -nb_prep process --nbconvert-no-input . -``` - -Pre-commit hook: - -```yaml -repos: -- repo: https://github.com/allianz-direct/nb_prep - rev: main - hooks: - - id: nb_prep_precommit - args: ["--nbconvert-no-input"] - - id: nb_prep_postcommit -``` - -### Specifying an output directory - -You might want to output all HTML notebooks in a specific folder. The default is using the same folder as the notebook. You can specify different folder relative to the project root or by absolute path using `--output-dir`: - -CLI: - -```bash -nb_prep process --output-dir "~/workspace/notebook_output" . -nb_prep rename --output-dir "~/workspace/notebook_output" . -``` - -Pre-commit hook: - -```yaml -repos: -- repo: https://github.com/allianz-direct/nb_prep - rev: main - hooks: - - id: nb_prep_precommit - args: ["--output-dir","~/workspace/notebook_output"] - - id: nb_prep_postcommit - args: ["--output-dir","~/workspace/notebook_output"] -``` - -### Excluding directories and files - -You can ignore certain notebooks or even entire directories with [globs](https://docs.python.org/3/library/glob.html), using a relative (to project root) or absolute path with `--exclude`. For example: - -CLI: - -```bash -nb_prep process --exclude "templates/*", "a_notebook.ipynb" . -``` - -Pre-commit hook: - -```yaml -repos: -- repo: https://github.com/allianz-direct/nb_prep - rev: main - hooks: - - id: nb_prep_precommit - args: ["--exclude","templates/*", "a_notebook.ipynb"] - - id: nb_prep_postcommit -``` +See [allianz-direct.github.io/nb_prep](https://allianz-direct.github.io/nb_prep). \ No newline at end of file diff --git a/images/schema_workflow.png b/docs/assets/images/schema_workflow.png similarity index 100% rename from images/schema_workflow.png rename to docs/assets/images/schema_workflow.png diff --git a/images/schema_workflow.svg b/docs/assets/images/schema_workflow.svg similarity index 100% rename from images/schema_workflow.svg rename to docs/assets/images/schema_workflow.svg diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..f8e5c92 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,6 @@ +--- +hide: + - navigation +--- + +--8<-- "README.md" \ No newline at end of file diff --git a/docs/options.md b/docs/options.md new file mode 100644 index 0000000..7e1f1dc --- /dev/null +++ b/docs/options.md @@ -0,0 +1,107 @@ +--- +hide: + - navigation +--- + +# Options + +Options are also documented in the CLI tool, see + +```shell +nb_prep --help +``` + +## Using templates + +If you want to specify a different template for `nbconvert`, you can add an argument to the `nb_prep process` hook: + +=== "CLI" + + ```bash + nb_prep process --nbconvert-template 'reveal' . + ``` + +=== "Pre-commit hook" + + ```yaml + # .pre-commit-config.yaml + repos: + - repo: https://github.com/allianz-direct/nb_prep + rev: main + hooks: + - id: nb_prep_precommit + args: ["--nbconvert-template","reveal"] + - id: nb_prep_postcommit + ``` + +## Removing cell blocks + +You can also choose to remove input code blocks from the converted HTML (equivalent to `jupyter nbconvert --no-input`). + + +=== "CLI" + + ```bash + nb_prep process --nbconvert-no-input . + ``` + +=== "Pre-commit hook" + + ```yaml + # .pre-commit-config.yaml + repos: + - repo: https://github.com/allianz-direct/nb_prep + rev: main + hooks: + - id: nb_prep_precommit + args: ["--nbconvert-no-input"] + - id: nb_prep_postcommit + ``` + +## Specifying an output directory + +You might want to output all HTML notebooks in a specific folder. The default is using the same folder as the notebook. You can specify different folder relative to the project root or by absolute path using `--output-dir`: + +=== "CLI" + + ```bash + nb_prep process --output-dir "~/workspace/notebook_output" . + nb_prep rename --output-dir "~/workspace/notebook_output" . + ``` + +=== "Pre-commit hook" + + ```yaml + # .pre-commit-config.yaml + repos: + - repo: https://github.com/allianz-direct/nb_prep + rev: main + hooks: + - id: nb_prep_precommit + args: ["--output-dir","~/workspace/notebook_output"] + - id: nb_prep_postcommit + args: ["--output-dir","~/workspace/notebook_output"] + ``` + +## Excluding directories and files + +You can ignore certain notebooks or even entire directories with [globs](https://docs.python.org/3/library/glob.html), using a relative (to project root) or absolute path with `--exclude`. For example: + +=== "CLI" + + ```bash + nb_prep process --exclude "templates/*", "a_notebook.ipynb" . + ``` + +=== "Pre-commit hook" + + ```yaml + # .pre-commit-config.yaml + repos: + - repo: https://github.com/allianz-direct/nb_prep + rev: main + hooks: + - id: nb_prep_precommit + args: ["--exclude","templates/*", "a_notebook.ipynb"] + - id: nb_prep_postcommit + ``` diff --git a/docs/overrides/main.html b/docs/overrides/main.html new file mode 100644 index 0000000..ec4ec2a --- /dev/null +++ b/docs/overrides/main.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block content %} + {{ super() }} + + {% if git_page_authors %} +

+ + Authors: {{ git_page_authors | default('enable mkdocs-git-authors-plugin') }} + +
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..17901eb --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,86 @@ +--- +hide: + - navigation +--- + +# Usage + +## Use case +You use [jupyter notebooks](https://jupyter.org/) and: + +- [nbconvert](https://github.com/jupyter/nbconvert) to convert `.ipynb` files to `.html` files +- [nbstripout](https://github.com/kynan/nbstripout) to avoid committing (potentially sensitive) data to git and get proper `git diff`s on notebooks (only showing changes in code). + +Forget to run `nbconvert` or use them in the wrong order (`nbstripout` before `nbconvert`) and you will have to re-run your notebooks before you can output HTML, which can be annoying when they are long-running. Especially when you use `nbstripout` as a [pre-commit](https://pre-commit.com/) hook, this can happen quite often. + +`nb_prep` can help to automatically process notebooks and (optionally) store versioned output in an in output directory. + +## Using as a CLI + +The CLI command `nb_prep process` takes a list of directories and/or files to find and process notebooks. For each notebook: + +- `nbconvert` is used to create an `.html` export +- A date prefix is added `YYYYMMDD_.html` (can be turned off) +- A placeholder for git hash is added `YYYYMMDD__NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` +- The `.html` file is moved to an `output-dir` (if specified) +- The `nbstripout` is used strip output from the `.ipynb` file + +Now you can `git add` and `git commit` the changed notebook files. You can then use `nb_prep rename` to insert the commit hashes in the notebook filenames. For example: + +`20220101_my_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html` -> `20220101_my_notebook_eac9e43.html` + +!!! tip + + You'll probably want to `.gitignore` the `.html` files generated. Especially if you use `--output-dir`. + +## Setting up as a pre-commit hook + +You can setup this entire workflow once as [pre-commit](https://pre-commit.com/) hook, and basically get an up-to-date analysis output directory for free `output-dir`. Schematically: + + + + +You need to update the `.pre-commit-config.yaml` in your repository to include `nb_prep`: + +```yaml +repos: +- repo: https://github.com/allianz-direct/nb_prep + rev: main + hooks: + - id: nb_prep_precommit + - id: nb_prep_postcommit +``` + +You need to install the pre-commit and the post-commit hooks separately: + +```shell +pre-commit install +pre-commit install --hook-type post-commit +``` + +When you commit a notebook, you might see something like: + +```shell +git add notebook.ipynb +git commit -m "Add notebook" +# nb_prep (pre-commit; process notebooks)...................................Failed +# - hook id: nb_prep_precommit +# - files were modified by this hook +# nb_prep (post-commit; replace hash placeholder in .html filenames)........Passed +``` + +`nb_prep` has used [nbstripout](https://github.com/kynan/nbstripout) to overwrite `notebook.ipynb`. It has also created a file in the output directory named something like `20211026_notebook_NBCONVERT_RENAME_COMMITHASH_PLACEHOLDER.html`. + +Re-add and re-commit the notebook again: + +```shell +git add notebook.ipynb +git commit -m "Add notebook" +# nb_prep (pre-commit; process notebooks)...................................Passed +# nb_prep (post-commit; replace hash placeholder in .html filenames)........Passed +``` + +Because the output file already exists, `nb_prep` will not overwrite it, because if we would convert again and output it would be a stripped version without any cell outputs. + +Now, you've committed a clean, stripped version of `notebook.ipynb`. and you have a local snapshot of your notebook named something like `20211026_notebook_eac9e43.html`. + diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..4472706 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,70 @@ +site_name: "nb_prep" +site_description: "Prepare jupyter notebooks for storing in git and sharing as HTML" +edit_uri: '' +copyright: 'Copyright © 2022' +repo_url: https://github.com/allianz-direct/nb_prep + +nav: + - index.md + - usage.md + - options.md + +theme: + name: material + custom_dir: docs/overrides + icon: + logo: material/notebook-check-outline + repo: fontawesome/brands/github + features: + - content.tabs.link + - navigation.instant + - navigation.tracking + - navigation.tabs + - navigation.tabs.sticky + - navigation.sections + - navigation.expand + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + toggle: + icon: material/toggle-switch-off-outline + name: Switch to dark mode + primary: blue + accent: blue + - media: "(prefers-color-scheme: dark)" + scheme: slate + toggle: + icon: material/toggle-switch + name: Switch to light mode + primary: blue + accent: blue + +plugins: + - search + - git-authors: + exclude: + - index.md + - git-revision-date-localized: + type: timeago + timezone: Europe/Amsterdam + locale: en + fallback_to_build_date: false + enable_creation_date: false + +markdown_extensions: + - meta + - admonition + - pymdownx.keys + - pymdownx.highlight + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - pymdownx.details + - pymdownx.tabbed: + alternate_style: true + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + options: + custom_icons: + - site/overrides/.icons \ No newline at end of file diff --git a/setup.py b/setup.py index e2d9afa..38a12b6 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ ], "author": "Tim Vink", "author_email": "tim.vink@allianzdirect.nl", + "description": "Prepare jupyter notebooks for storing in git and sharing as HTML", "long_description": long_description, "long_description_content_type": "text/markdown", "url": "https://github.com/allianz-direct/nb_prep", diff --git a/tests/test_requirements.txt b/tests/test_requirements.txt index 6a9e854..baa822b 100644 --- a/tests/test_requirements.txt +++ b/tests/test_requirements.txt @@ -8,4 +8,8 @@ pytest-mock mypy freezegun types-freezegun -GitPython \ No newline at end of file +GitPython +# for documentation +mkdocs-material +mkdocs-git-authors-plugin +mkdocs-git-revision-date-localized-plugin \ No newline at end of file From 07939ab16cae7a9ad94bed5a63def86796a3414d Mon Sep 17 00:00:00 2001 From: Tim Vink Date: Thu, 20 Jan 2022 15:14:04 +0100 Subject: [PATCH 14/14] Publish MkDocs on deploying new version --- .github/workflows/publish.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 91d5079..ab7bb2a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -34,7 +34,6 @@ jobs: python setup.py sdist bdist_wheel twine upload dist/* - # - name: Deploy mkdocs site - # run: | - # pip install mkdocs-git-authors-plugin - # mkdocs gh-deploy --force \ No newline at end of file + - name: Deploy mkdocs site + run: | + mkdocs gh-deploy --force