Repository: ayasyrev/nbmetaclean (language: python)

Issue:
Fix_get_nbfiles



Discussion / hints:

Fix patch:
diff --git a/.flake8 b/.flake8
index 6ed7291..fe13e52 100644
--- a/.flake8
+++ b/.flake8
@@ -8,4 +8,4 @@ application-import-names = nbmetaclean, tests
 import-order-style = google
 per-file-ignores =
     # imported but unused
-    __init__.py: F401
\ No newline at end of file
+    __init__.py: F401
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 416d96f..c686b53 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,7 +1,51 @@
 repos:
 - repo: https://github.com/ayasyrev/nbmetaclean
-  rev: 0.0.5
+  rev: 0.0.7
   hooks:
   -   id: nbclean
       name: nbclean
-      entry: nbclean
\ No newline at end of file
+      entry: nbclean
+
+- repo: https://github.com/pre-commit/pre-commit-hooks
+  rev: v4.5.0
+  hooks:
+    - id: check-added-large-files
+    - id: check-ast
+    - id: check-builtin-literals
+    - id: check-case-conflict
+    - id: check-docstring-first
+    - id: check-executables-have-shebangs
+    - id: check-shebang-scripts-are-executable
+    - id: check-symlinks
+    - id: check-toml
+    - id: check-xml
+    - id: detect-private-key
+    - id: forbid-new-submodules
+    - id: forbid-submodules
+    - id: mixed-line-ending
+    - id: destroyed-symlinks
+    - id: fix-byte-order-marker
+    - id: check-json
+    - id: check-yaml
+      args: [ --unsafe ]
+    - id: debug-statements
+    - id: end-of-file-fixer
+    - id: trailing-whitespace
+    - id: requirements-txt-fixer
+- repo: https://github.com/astral-sh/ruff-pre-commit
+  # Ruff version.
+  rev: v0.3.5
+  hooks:
+    # Run the linter.
+    - id: ruff
+      args: [ --fix ]
+    # Run the formatter.
+    - id: ruff-format
+- repo: https://github.com/pre-commit/pygrep-hooks
+  rev: v1.10.0
+  hooks:
+    - id: python-check-mock-methods
+    - id: python-use-type-annotations
+    - id: python-check-blanket-noqa
+    - id: python-use-type-annotations
+    - id: text-unicode-replacement-char
diff --git a/Makefile b/Makefile
index 5a99780..35a8a3f 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ pypi: dist
 	twine upload --repository pypi dist/*
 
 dist: clean
-	python3 -m build 
+	python3 -m build
 
 clean:
-	rm -rf dist
\ No newline at end of file
+	rm -rf dist
diff --git a/README.md b/README.md
index dda3fca..0b29f63 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,34 @@
 # nbmetaclean
-nbmetaclean
\ No newline at end of file
+
+Pre-commit hook to clean Jupyter Notebooks metadata, execution_count and optionally output.
+
+Pure Python, no dependencies.
+
+Can be used as a pre-commit hook or as a command line tool.
+
+## Usage
+
+### Pre-commit hook
+add to `.pre-commit-config.yaml`:
+```yaml
+repos:
+    - repo: https://github.com/ayasyrev/nbmetaclean
+        rev: 0.0.8
+        hooks:
+        - id: nbclean
+          name: nbclean
+          entry: nbclean
+```
+
+### Command line tool
+
+Install:
+```bash
+pip install nbmetaclean
+```
+
+Usage:
+
+```bash
+nbclean
+```
diff --git a/noxfile_lint.py b/noxfile_lint.py
index db17853..84af18a 100644
--- a/noxfile_lint.py
+++ b/noxfile_lint.py
@@ -1,6 +1,5 @@
 import nox
 
-
 locations = "src/nbmetaclean", "tests", "noxfile.py"
 
 
diff --git a/requirements_dev.txt b/requirements_dev.txt
new file mode 100644
index 0000000..8778d84
--- /dev/null
+++ b/requirements_dev.txt
@@ -0,0 +1,7 @@
+black
+black[jupyter]
+flake8
+isort
+mypy
+pre-commit
+ruff
diff --git a/setup.cfg b/setup.cfg
index 4d6c8b7..49d3e88 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -30,4 +30,4 @@ where = src
 console_scripts =
     nbclean=nbmetaclean.app:app
 pipx.run =
-    nbclean=nbmetaclean.app:app
\ No newline at end of file
+    nbclean=nbmetaclean.app:app
diff --git a/setup.py b/setup.py
index a887580..f7abcb7 100644
--- a/setup.py
+++ b/setup.py
@@ -1,8 +1,7 @@
 from setuptools import setup
 
-
-REQUIREMENTS_FILENAME = 'requirements.txt'
-REQUIREMENTS_TEST_FILENAME = 'requirements_test.txt'
+REQUIREMENTS_FILENAME = "requirements.txt"
+REQUIREMENTS_TEST_FILENAME = "requirements_test.txt"
 
 
 # Requirements
diff --git a/src/nbmetaclean/app.py b/src/nbmetaclean/app.py
index bc2e4b8..68e969e 100644
--- a/src/nbmetaclean/app.py
+++ b/src/nbmetaclean/app.py
@@ -1,8 +1,9 @@
 import argparse
 from pathlib import Path
+from typing import Union
 
-from .clean import CleanConfig, clean_nb_file
-from .core import get_nb_names
+from .clean import CleanConfig, TupleStr, clean_nb_file
+from .helpers import get_nb_names
 
 parser = argparse.ArgumentParser(
     prog="nbclean",
@@ -25,6 +26,47 @@
     action="store_true",
     help="Do not preserve timestamp.",
 )
+parser.add_argument(
+    "--dont_clear_nb_metadata",
+    action="store_true",
+    help="Do not clear notebook metadata.",
+)
+parser.add_argument(
+    "--clear_cell_metadata",
+    action="store_true",
+    help="Clear cell metadata.",
+)
+parser.add_argument(
+    "--clear_outputs",
+    action="store_true",
+    help="Clear outputs.",
+)
+parser.add_argument(
+    "--nb_metadata_preserve_mask",
+    nargs="+",
+    help="Preserve mask for notebook metadata.",
+)
+parser.add_argument(
+    "--cell_metadata_preserve_mask",
+    nargs="+",
+    help="Preserve mask for cell metadata.",
+)
+parser.add_argument(
+    "--dont_merge_masks",
+    action="store_true",
+    help="Do not merge masks.",
+)
+parser.add_argument(
+    "--clean_hidden_nbs",
+    action="store_true",
+    help="Clean hidden notebooks.",
+)
+
+
+def process_mask(mask: Union[list[str], None]) -> Union[tuple[TupleStr, ...], None]:
+    if mask is None:
+        return None
+    return tuple(tuple(item.split(".")) for item in mask)
 
 
 def app() -> None:
@@ -36,17 +78,25 @@ def app() -> None:
         print(f"Path: {', '.join(cfg.path)}, preserve timestamp: {not cfg.not_pt}")
     for path in path_list:
         try:
-            nb_files.extend(get_nb_names(path))
+            nb_files.extend(get_nb_names(path, hidden=cfg.clean_hidden_nbs))
         except FileNotFoundError:
             print(f"{path} not exists!")
     if not cfg.silent:
         print(f"notebooks to check: {len(nb_files)} ")
+    clean_config = CleanConfig(
+        clear_nb_metadata=not cfg.dont_clear_nb_metadata,
+        clear_cell_metadata=cfg.clear_cell_metadata,
+        clear_execution_count=True,
+        clear_outputs=cfg.clear_outputs,
+        preserve_timestamp=not cfg.not_pt,
+        silent=cfg.silent,
+        nb_metadata_preserve_mask=process_mask(cfg.nb_metadata_preserve_mask),
+        cell_metadata_preserve_mask=process_mask(cfg.cell_metadata_preserve_mask),
+        mask_merge=not cfg.dont_merge_masks,
+    )
     cleaned, errors = clean_nb_file(
         nb_files,
-        CleanConfig(
-            silent=cfg.silent,
-            preserve_timestamp=not cfg.not_pt,
-        ),
+        clean_config,
     )
     if not cfg.silent:
         print(f"cleaned nbs: {len(cleaned)}")
diff --git a/src/nbmetaclean/clean.py b/src/nbmetaclean/clean.py
index 747a302..cf69e55 100644
--- a/src/nbmetaclean/clean.py
+++ b/src/nbmetaclean/clean.py
@@ -1,14 +1,16 @@
 from __future__ import annotations
+
 import copy
-from dataclasses import dataclass
 import os
-
+from dataclasses import dataclass
 from pathlib import Path
-from typing import Iterable, Optional, Union
+from typing import Optional, Tuple, Union
+
+from nbmetaclean.helpers import read_nb, write_nb
 
-from nbmetaclean.core import read_nb, write_nb
+from .typing import Cell, CodeCell, Metadata, Nb, Output
 
-from .typing import NbNode, Metadata
+TupleStr = Tuple[str, ...]
 
 NB_METADATA_PRESERVE_MASKS = (
     ("language_info", "name"),
@@ -41,14 +43,14 @@ class CleanConfig:
     clear_outputs: bool = False
     preserve_timestamp: bool = True
     silent: bool = False
-    nb_metadata_preserve_mask: Optional[Iterable[tuple[str, ...]]] = None
-    cell_metadata_preserve_mask: Optional[Iterable[tuple[str, ...]]] = None
+    nb_metadata_preserve_mask: Optional[tuple[TupleStr, ...]] = None
+    cell_metadata_preserve_mask: Optional[tuple[TupleStr, ...]] = None
     mask_merge: bool = True
 
 
 def filter_meta_mask(
     nb_meta: Union[str, int, Metadata],
-    mask: Optional[Iterable[tuple[str, ...]]] = None,
+    mask: Optional[tuple[str, ...]] = None,
 ) -> Union[str, int, Metadata]:
     """Filter metadata by mask. If no mask return empty dict."""
     if isinstance(nb_meta, (str, int)) or mask == ():
@@ -65,7 +67,7 @@ def filter_meta_mask(
 
 def filter_metadata(
     nb_meta: Metadata,
-    masks: Optional[list[tuple[str, ...]]] = None,
+    masks: Optional[tuple[TupleStr, ...]] = None,
 ) -> Metadata:
     """Clean notebooknode metadata."""
     if masks is None:
@@ -77,14 +79,15 @@ def filter_metadata(
 
 
 def clean_cell(
-    cell: NbNode,
+    cell: Cell | CodeCell,
     cfg: CleanConfig,
 ) -> bool:
     """Clean cell: optionally metadata, execution_count and outputs."""
     changed = False
 
     if cfg.clear_cell_metadata:
-        if metadata := cell.get("metadata", None):
+        if cell.get("metadata", None):
+            metadata = cell["metadata"]
             old_metadata = copy.deepcopy(metadata)
             cell["metadata"] = filter_metadata(
                 metadata, cfg.cell_metadata_preserve_mask
@@ -92,23 +95,24 @@ def clean_cell(
             if cell["metadata"] != old_metadata:
                 changed = True
 
-    if cfg.clear_execution_count and cell.get("execution_count"):
-        cell["execution_count"] = None
-        changed = True
-
-    if cell.get("outputs"):
-        if cfg.clear_outputs:
-            cell["outputs"] = []
+    if cell["cell_type"] == "code":
+        if cfg.clear_execution_count and cell.get("execution_count"):
+            cell["execution_count"] = None  # type: ignore # it's code cell
             changed = True
-        elif cfg.clear_cell_metadata or cfg.clear_execution_count:
-            result = clean_outputs(cell["outputs"], cfg)
-            if result:
+
+        if cell.get("outputs"):
+            if cfg.clear_outputs:
+                cell["outputs"] = []  # type: ignore  # it's code cell
                 changed = True
+            elif cfg.clear_cell_metadata or cfg.clear_execution_count:
+                result = clean_outputs(cell["outputs"], cfg)  # type: ignore # it's code cell
+                if result:
+                    changed = True
 
     return changed
 
 
-def clean_outputs(outputs: list[NbNode], cfg: CleanConfig) -> bool:
+def clean_outputs(outputs: list[Output], cfg: CleanConfig) -> bool:
     """Clean outputs."""
     changed = False
     for output in outputs:
@@ -126,7 +130,7 @@ def clean_outputs(outputs: list[NbNode], cfg: CleanConfig) -> bool:
 
 
 def clean_nb(
-    nb: NbNode,
+    nb: Nb,
     cfg: CleanConfig,
 ) -> bool:
     """Clean notebook - metadata, execution_count, outputs.
@@ -148,7 +152,6 @@ def clean_nb(
                 masks = cfg.nb_metadata_preserve_mask
             else:
                 masks = cfg.nb_metadata_preserve_mask + masks
-
         nb["metadata"] = filter_metadata(metadata, masks=masks)
         if nb["metadata"] != old_metadata:
             changed = True
diff --git a/src/nbmetaclean/core.py b/src/nbmetaclean/helpers.py
similarity index 63%
rename from src/nbmetaclean/core.py
rename to src/nbmetaclean/helpers.py
index 8b24a7d..b3f1c3a 100644
--- a/src/nbmetaclean/core.py
+++ b/src/nbmetaclean/helpers.py
@@ -4,10 +4,10 @@
 from pathlib import Path
 from typing import Optional
 
-from .typing import NbNode, PathOrStr
+from .typing import Nb, PathOrStr
 
 
-def read_nb(path: PathOrStr) -> NbNode:
+def read_nb(path: PathOrStr) -> Nb:
     """Read notebook from filename.
 
     Args:
@@ -20,7 +20,7 @@ def read_nb(path: PathOrStr) -> NbNode:
 
 
 def write_nb(
-    nb: NbNode,
+    nb: Nb,
     path: PathOrStr,
 ) -> Path:
     """Write notebook to file
@@ -29,7 +29,7 @@ def write_nb(
         nb (Notebook): Notebook to write
         path (Union[str, PosixPath]): filename to write
     Returns:
-        Path: Filename of writed Nb.
+        Path: Filename of written notebook.
     """
     filename = Path(path)
     if filename.suffix != ".ipynb":
@@ -48,6 +48,23 @@ def write_nb(
     return filename
 
 
+def is_notebook(path: Path, hidden: bool = False) -> bool:
+    """Check if `path` is a notebook and not hidden. If `hidden` is True check also hidden files.
+
+    Args:
+        path (Union[Path, str]): Path to check.
+        hidden bool: If True also check hidden files, defaults to False.
+
+    Returns:
+        bool: True if `path` is a notebook and not hidden.
+    """
+    if path.suffix == ".ipynb":
+        if path.name.startswith(".") and not hidden:
+            return False
+        return True
+    return False
+
+
 def get_nb_names(
     path: Optional[PathOrStr] = None,
     recursive: bool = True,
@@ -71,21 +88,22 @@ def get_nb_names(
     if not nb_path.exists():
         raise FileNotFoundError(f"{nb_path} not exists!")
 
+    if nb_path.is_file():
+        if is_notebook(nb_path, hidden):
+            return [nb_path]
+
     if nb_path.is_dir():
         result = []
         for item in nb_path.iterdir():
-            if item.is_file() and item.suffix == ".ipynb":
-                if not hidden and item.name.startswith("."):
-                    continue
+            if item.is_file() and is_notebook(item, hidden):
                 result.append(item)
-            if item.is_dir():
-                if recursive:
-                    if not hidden and item.name.startswith("."):
-                        continue
-                    if "checkpoint" in item.name:
-                        continue
-                    result.extend(get_nb_names(item, recursive, hidden))
+            if item.is_dir() and recursive:
+                if item.name.startswith(".") and not hidden:
+                    continue
+                if "checkpoint" in item.name:
+                    continue
+                result.extend(get_nb_names(item, recursive, hidden))
 
         return result
 
-    return [nb_path]
+    return []
diff --git a/src/nbmetaclean/typing.py b/src/nbmetaclean/typing.py
index b3d3946..27829d0 100644
--- a/src/nbmetaclean/typing.py
+++ b/src/nbmetaclean/typing.py
@@ -1,8 +1,70 @@
 from pathlib import Path, PosixPath
-from typing import Dict, List, TypeVar, Union
+from typing import Dict, List, Literal, Optional, TypedDict, TypeVar, Union
 
 PathOrStr = TypeVar("PathOrStr", Path, PosixPath, str)
 
 NbNode = Dict[str, Union[str, int, "NbNode"]]
 Metadata = Dict[str, Union[str, int, "Metadata"]]
-Source = Union[str, List[str]]
+MultilineText = Union[str, List[str]]
+
+
+class NbMetadata(TypedDict):
+    language_info: Metadata
+    kernelspec: Metadata
+    authors: Metadata
+
+
+class Output(TypedDict):
+    output_type: Literal[
+        "execute_result",
+        "display_data",
+        "stream",
+        "error",
+    ]
+    execution_count: Optional[int]
+    metadata: Metadata
+
+
+class ExecuteResult(Output):  # output_type = "execute_result"
+    data: Dict[str, MultilineText]
+
+
+class DisplayData(Output):  # output_type = "display_data"
+    data: Dict[str, MultilineText]  # fix it - mimebundle
+
+
+class Stream(Output):  # output_type = "stream"
+    name: Literal["stdout", "stderr"]  # "The name of the stream (stdout, stderr)."
+    text: MultilineText
+
+
+class Error(Output):  # output_type = "error"
+    ename: str  # "The name of the error."
+    evalue: str  # "The value, or message, of the error."
+    traceback: List[str]
+
+
+class Cell(TypedDict):
+    """Notebook cell base."""
+
+    id: int  # from nbformat 4.5
+    cell_type: Literal["code", "markdown", "raw"]
+    metadata: Metadata
+    source: MultilineText
+    attachments: Optional[Dict[str, MultilineText]]
+
+
+class CodeCell(Cell):  # cell_type = "code"
+    """Code cell."""
+
+    outputs: List[Output]
+    execution_count: Optional[int]
+
+
+class Nb(TypedDict):
+    """Notebook."""
+
+    nbformat: int
+    nbformat_minor: int
+    cells: List[Cell]
+    metadata: Metadata
diff --git a/src/nbmetaclean/version.py b/src/nbmetaclean/version.py
index 5382d2c..0e12f90 100644
--- a/src/nbmetaclean/version.py
+++ b/src/nbmetaclean/version.py
@@ -1,1 +1,1 @@
-__version__ = "0.0.7"  # pragma: no cover
+__version__ = "0.0.8"  # pragma: no cover


Test patch:
diff --git a/requirements_test_extra.txt b/requirements_test_extra.txt
index 053ae33..16ac163 100644
--- a/requirements_test_extra.txt
+++ b/requirements_test_extra.txt
@@ -1,4 +1,2 @@
 coverage[toml]
 nox
-black
-flake8
diff --git a/tests/test_clean.py b/tests/test_clean.py
index f0e8f6b..813f3e1 100644
--- a/tests/test_clean.py
+++ b/tests/test_clean.py
@@ -13,7 +13,7 @@
     filter_meta_mask,
     filter_metadata,
 )
-from nbmetaclean.core import read_nb, write_nb
+from nbmetaclean.helpers import read_nb, write_nb
 
 
 def test_get_meta_by_mask():
@@ -83,6 +83,7 @@ def test_clean_cell_metadata():
 
     # clear outputs
     cell = copy.deepcopy(test_nb.get("cells")[1])
+    assert cell["cell_type"] == "code"
     assert cell.get("outputs")
     assert not cell.get("metadata")
     assert cell.get("execution_count") == 1
@@ -98,6 +99,15 @@ def test_clean_cell_metadata():
     assert not cell.get("outputs")
     assert not cell.get("metadata")
     assert not cell.get("execution_count")
+    # run again - no changes
+    changed = clean_cell(
+        cell,
+        cfg=CleanConfig(
+            clear_outputs=True,
+            clear_cell_metadata=True,
+        ),
+    )
+    assert not changed
 
     # dont clear outputs, execution_count, mask
     cell = copy.deepcopy(test_nb.get("cells")[1])
diff --git a/tests/test_get_nbnames.py b/tests/test_get_nbnames.py
new file mode 100644
index 0000000..63747db
--- /dev/null
+++ b/tests/test_get_nbnames.py
@@ -0,0 +1,107 @@
+from pathlib import Path
+
+from nbmetaclean.helpers import get_nb_names, is_notebook
+
+
+def test_is_notebook():
+    """test is_notebook"""
+    assert is_notebook(Path("tests/test_nbs/test_nb_1.ipynb"))
+    assert not is_notebook(Path("tests/test_nbs/test_nb_1.py"))
+    assert not is_notebook(Path("tests/test_nbs/.test_nb_2_meta.ipynb"))
+    assert is_notebook(Path("tests/test_nbs/.test_nb_2_meta.ipynb"), hidden=True)
+
+
+def test_get_nb_names():
+    """test get_nb_names"""
+    path = Path("tests/test_nbs")
+    # filename as argument
+    file = path / "test_nb_1.ipynb"
+    names = get_nb_names(file)
+    assert len(names) == 1
+    names.sort(key=lambda x: x.name)
+    assert names[0] == file
+    # filename but not nb
+    names = get_nb_names("tests/test_clean.py")
+    assert len(names) == 0
+
+    # path as argument
+    names = get_nb_names(path)
+    assert len(names) == 2
+    names.sort(key=lambda x: x.name)
+    assert names[0] == file
+    # path as argument. add hidden files
+    names = get_nb_names(path, hidden=True)
+    assert len(names) == 3
+    try:
+        get_nb_names("wrong_name")
+        assert False
+    except FileNotFoundError as ex:
+        assert True
+        assert str(ex) == "wrong_name not exists!"
+
+
+def test_get_nb_names_recursive_hidden(tmp_path: Path):
+    """test get_nb_names recursive hidden"""
+    suffix = ".ipynb"
+    # add one nb
+    with open((tmp_path / "tst").with_suffix(suffix), "w", encoding="utf-8") as _:
+        pass
+    files = get_nb_names(tmp_path)
+    assert len(files) == 1
+
+    # add hidden nb
+    with open((tmp_path / ".tst").with_suffix(suffix), "w", encoding="utf-8") as _:
+        pass
+    files = get_nb_names(tmp_path)
+    assert len(files) == 1
+    files = get_nb_names(tmp_path, hidden=True)
+    assert len(files) == 2
+    # add simple file
+    with open((tmp_path / "simple"), "w", encoding="utf-8") as _:
+        pass
+    files = get_nb_names(tmp_path)
+    assert len(files) == 1
+
+    # add dir with one nb, hidden nb
+    new_dir = tmp_path / "new_dir"
+    new_dir.mkdir()
+    with open((new_dir / "tst").with_suffix(suffix), "w", encoding="utf-8") as _:
+        pass
+    with open((new_dir / ".tst").with_suffix(suffix), "w", encoding="utf-8") as _:
+        pass
+    files = get_nb_names(tmp_path)
+    assert len(files) == 2
+    files = get_nb_names(tmp_path, hidden=True)
+    assert len(files) == 4
+
+    files = get_nb_names(tmp_path, recursive=False)
+    assert len(files) == 1
+
+    # add hidden dir
+    hid_dir = tmp_path / ".hid_dir"
+    hid_dir.mkdir()
+    with open((hid_dir / "tst").with_suffix(suffix), "w", encoding="utf-8") as _:
+        pass
+    with open((hid_dir / ".tst").with_suffix(suffix), "w", encoding="utf-8") as _:
+        pass
+    files = get_nb_names(tmp_path, hidden=True)
+    assert len(files) == 6
+    files = get_nb_names(tmp_path)
+    assert len(files) == 2
+
+    # add checkpoint dir and file
+    # files at this dir will be skipped
+    checkpoint_dir = tmp_path / ".ipynb_checkpoints"
+    checkpoint_dir.mkdir()
+    with open(
+        (checkpoint_dir / "nb-checkpoint").with_suffix(suffix), "w", encoding="utf-8"
+    ) as _:
+        pass
+    with open(
+        (checkpoint_dir / "some_nb").with_suffix(suffix), "w", encoding="utf-8"
+    ) as _:
+        pass
+    files = get_nb_names(tmp_path)
+    assert len(files) == 2
+    files = get_nb_names(tmp_path, hidden=True)
+    assert len(files) == 6
diff --git a/tests/test_read_write.py b/tests/test_read_write.py
index 964959d..0a7e301 100644
--- a/tests/test_read_write.py
+++ b/tests/test_read_write.py
@@ -1,6 +1,6 @@
 from pathlib import Path
 
-from nbmetaclean.core import get_nb_names, read_nb, write_nb
+from nbmetaclean.helpers import read_nb, write_nb
 
 
 def test_read_nb():
@@ -41,78 +41,3 @@ def test_write_nb(tmp_path: Path):
     # write with name w/o suffix
     result = write_nb(nb, tmp_path / "test_nb_1")
     assert result == tmp_path / "test_nb_1.ipynb"
-
-
-def test_get_nb_names():
-    """test get_nb_names"""
-    path = Path("tests/test_nbs")
-    # filename as argument
-    file = path / "test_nb_1.ipynb"
-    names = get_nb_names(file)
-    assert len(names) == 1
-    names.sort(key=lambda x: x.name)
-    assert names[0] == file
-    # path as argument
-    names = get_nb_names(path)
-    assert len(names) == 2
-    names.sort(key=lambda x: x.name)
-    assert names[0] == file
-    # path as argument. add hidden files
-    names = get_nb_names(path, hidden=True)
-    assert len(names) == 3
-    try:
-        get_nb_names("wrong_name")
-        assert False
-    except FileNotFoundError as ex:
-        assert True
-        assert str(ex) == "wrong_name not exists!"
-
-
-def test_get_nb_names_recursive_hidden(tmp_path: Path):
-    """test get_nb_names recursive hidden"""
-    suffix = ".ipynb"
-    # add one nb
-    with open((tmp_path / "tst").with_suffix(suffix), "w", encoding="utf-8") as _:
-        pass
-    files = get_nb_names(tmp_path)
-    assert len(files) == 1
-
-    # add hidden nb
-    with open((tmp_path / ".tst").with_suffix(suffix), "w", encoding="utf-8") as _:
-        pass
-    files = get_nb_names(tmp_path)
-    assert len(files) == 1
-    files = get_nb_names(tmp_path, hidden=True)
-    assert len(files) == 2
-    # add simple file
-    with open((tmp_path / "simple"), "w", encoding="utf-8") as _:
-        pass
-    files = get_nb_names(tmp_path)
-    assert len(files) == 1
-
-    # add dir with one nb, hidden nb
-    new_dir = tmp_path / "new_dir"
-    new_dir.mkdir()
-    with open((new_dir / "tst").with_suffix(suffix), "w", encoding="utf-8") as _:
-        pass
-    with open((new_dir / ".tst").with_suffix(suffix), "w", encoding="utf-8") as _:
-        pass
-    files = get_nb_names(tmp_path)
-    assert len(files) == 2
-    files = get_nb_names(tmp_path, hidden=True)
-    assert len(files) == 4
-
-    files = get_nb_names(tmp_path, recursive=False)
-    assert len(files) == 1
-
-    # add hidden dir
-    hid_dir = tmp_path / ".hid_dir"
-    hid_dir.mkdir()
-    with open((hid_dir / "tst").with_suffix(suffix), "w", encoding="utf-8") as _:
-        pass
-    with open((hid_dir / ".tst").with_suffix(suffix), "w", encoding="utf-8") as _:
-        pass
-    files = get_nb_names(tmp_path, hidden=True)
-    assert len(files) == 6
-    files = get_nb_names(tmp_path)
-    assert len(files) == 2