From 5424bc34346de51807227ce717626f1fde7e6785 Mon Sep 17 00:00:00 2001 From: Tyler Date: Mon, 9 Sep 2024 14:59:57 -0700 Subject: [PATCH] Add rename subcommand and test happy case --- pyproject.toml | 6 ++++++ src/z/__init__.py | 1 + src/z/create.py | 25 +++++++++++++++-------- src/z/rename.py | 28 +++++++++++++++++++++++++ src/z/z.py | 8 +++++++- tests/__init__.py | 3 +++ tests/conftest.py | 3 +++ tests/helpers/utils.py | 12 +++++++++++ tests/test_rename.py | 46 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 src/z/rename.py create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/helpers/utils.py create mode 100644 tests/test_rename.py diff --git a/pyproject.toml b/pyproject.toml index 23e5345..1d6c417 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,7 @@ [build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" + [project] name = "z-py" version = "0.0.1" @@ -17,8 +18,13 @@ classifiers = [ ] dependencies = [ ] + [project.urls] "Homepage" = "https://github.com/starr-dusT/z-py" "Repository" = "https://github.com/starr-dusT/z-py" + [project.scripts] z = "z.z:main" + +[tool.pytest.ini_options] +addopts = "--ignore=tests/helpers" \ No newline at end of file diff --git a/src/z/__init__.py b/src/z/__init__.py index 4b4024a..d183fe8 100644 --- a/src/z/__init__.py +++ b/src/z/__init__.py @@ -1,3 +1,4 @@ from .z import * from .create import * from .tags import * +from .rename import * diff --git a/src/z/create.py b/src/z/create.py index 41d66a0..12fa7a0 100644 --- a/src/z/create.py +++ b/src/z/create.py @@ -6,15 +6,24 @@ import datetime import re # Format: --__<tag1>_<tag2>.<ext> -def normalize_name(name: str, tags: str, time: Union[datetime.date, None] = None, ext: str ="md"): - if "-" in name or "_" in name: - raise ArgumentTypeError("Title cannot have '-' or '_'") - if "-" in name or "_" in tags: - raise ArgumentTypeError("Note cannot have '-' or '_'") +def normalize_name(name: str, tags: str, time: Union[str, None] = None, ext: str ="md"): + if "--" in name or "__" in name: + raise ArgumentTypeError("Title cannot have '--' or '__'") + if "--" not in tags and "__" not in tags: + if "_" in tags and "," in tags: + raise ArgumentTypeError("Tags must be seperated by ',' or '_'") + elif "_" in tags: + tag_sep = "_" + else: + tag_sep = "," + else: + raise ArgumentTypeError("Tags cannot have '--' or '__'") # timestamp if time: - f = time.strftime("%Y%m%dT%H%M%S") + if not re.match("[0-9]{8}T[0-9]{6}", time): + raise ArgumentTypeError("Time must be string in format: YYMMDDTHHmmSS") + f = time else: f = datetime.datetime.now().strftime("%Y%m%dT%H%M%S") @@ -24,14 +33,14 @@ def normalize_name(name: str, tags: str, time: Union[datetime.date, None] = None # tags f += "__" - for tag in tags.split(","): + for tag in tags.split(tag_sep): tag = tag.strip() tag = re.sub(r" ", "-", tag) f += tag + "_" f = f[:-1] # ext - if ext[0] == ".": + if ext + " "[0] == ".": f += ext else: f += "." + ext diff --git a/src/z/rename.py b/src/z/rename.py new file mode 100644 index 0000000..6179678 --- /dev/null +++ b/src/z/rename.py @@ -0,0 +1,28 @@ +import os +from typing import Union +from z.create import normalize_name +from argparse import ArgumentTypeError + +def rename_file(source:str, dest:str, tags:str, date:Union[str, None] = None): + ext = None + if '.' in dest: + os.rename(source, normalize_name(dest.split('.')[0], tags, time=date, ext=dest.split('.')[1])) + else: + if '.' in source: + os.rename(source, normalize_name(dest, tags, time=date, ext=source.split('.')[1])) + else: + os.rename(source, normalize_name(dest, tags, time=date, ext="")) + +def main(args): + tags = args.source.split("__")[1] if "--" in args.source else "" + + if args.timestamp: + date = args.source.split("--")[0] if "--" in args.source else -1 + if date == -1: + raise ArgumentTypeError("Timestamp option only works for source files that are formatted like Denote files.") + rename_file(args.source, args.dest, tags, date=date) + else: + rename_file(args.source, args.dest, tags) + +if __name__ == "__main__": + main(None) diff --git a/src/z/z.py b/src/z/z.py index 68b88a5..4064de7 100644 --- a/src/z/z.py +++ b/src/z/z.py @@ -1,6 +1,6 @@ from pathlib import Path import argparse -from z import create, tags +from z import create, tags, rename import sys def init_parser(): @@ -14,6 +14,12 @@ def init_parser(): create_parser.add_argument("-s", "--silo", nargs="?", default="", const="", help="Optionally create note in silo") create_parser.add_argument("-o", "--outline", nargs="?", default="", const="", help="Optionally initialize note with outline") + rename_parser = sub_parsers.add_parser("rename", help="rename note") + rename_parser.set_defaults(func=rename.main) + rename_parser.add_argument("source", help="name of note to change") + rename_parser.add_argument("dest", help="new name of note") + rename_parser.add_argument("-t", "--timestamp", action="store_true", help="don't update timestamp of note") + tags_parser = sub_parsers.add_parser("tags", help="edit tags") tags_parser.set_defaults(func=tags.main) tags_parser.add_argument("file", help="name of file to create") diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e06298c --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,3 @@ +import sys + +sys.path.append("src") \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..501ed17 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,3 @@ +import sys +import os +sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers')) \ No newline at end of file diff --git a/tests/helpers/utils.py b/tests/helpers/utils.py new file mode 100644 index 0000000..8e4d173 --- /dev/null +++ b/tests/helpers/utils.py @@ -0,0 +1,12 @@ +import shutil +import os + +def pre_test(tmp_path): + owd = os.getcwd() + path = tmp_path / "z" + shutil.copytree("./example", path) + os.chdir(path / "test") + return owd + +def post_test(owd): + os.chdir(owd) \ No newline at end of file diff --git a/tests/test_rename.py b/tests/test_rename.py new file mode 100644 index 0000000..f289b77 --- /dev/null +++ b/tests/test_rename.py @@ -0,0 +1,46 @@ +from z.z import main +import glob +import utils +import sys +import os +from unittest.mock import patch +import re +from pathlib import Path + +def path_search(glob_str:str): + return glob.glob(glob_str) + +def read_file(file_path:str): + with open(file_path, "r") as f: + return f.read() + +def test_rename_denote(tmp_path): + utils.pre_test(tmp_path) + + # New timestamp + src = "19700101T000000--example-file-3__test1_test2_test3" + input = "new example file 3" + with patch("sys.argv", ["", "rename", src, input]): + main() + # original file gone + assert not path_search(src) + # new file created + files = path_search("*--new-example-file-3__test1_test2_test3") + assert len(files) == 1 + # contents unchanged + assert read_file(files[0]) == "test 3" + + # Keep old timestamp + src = "19700101T000000--example-file-4__test1_test2_test3" + input = "new example file 4" + with patch("sys.argv", ["", "rename", src, input, "-t"]): + main() + # original file gone + assert not path_search(src) + # new file created + files = path_search("19700101T000000--new-example-file-4__test1_test2_test3") + assert len(files) == 1 + # contents unchanged + assert read_file(files[0]) == "test 4" + + utils.post_test(tmp_path) \ No newline at end of file