From dba5bf84c58018962bb8fd369dac25bacc690c98 Mon Sep 17 00:00:00 2001 From: Wasi Mohammed Abdullah Date: Wed, 8 Nov 2023 15:53:43 +0600 Subject: [PATCH 1/5] implemented rename command for task and project --- PyTM/cli.py | 8 ++++++++ PyTM/commands/project.py | 29 ++++++++++++++++++++++++++++ PyTM/commands/task.py | 37 ++++++++++++++++++++++++++++++++++++ PyTM/core/project_handler.py | 7 +++++++ PyTM/core/task_handler.py | 10 ++++++++++ README.rst | 4 +++- 6 files changed, 94 insertions(+), 1 deletion(-) diff --git a/PyTM/cli.py b/PyTM/cli.py index 5a2b940..a911726 100644 --- a/PyTM/cli.py +++ b/PyTM/cli.py @@ -104,6 +104,7 @@ def show(): - shows list of projects and status """ data = data_handler.load_data() + state = data_handler.load_data(settings.state_filepath) table = Table() table.add_column("Project Name", style="blue bold") table.add_column("Created at") @@ -114,6 +115,13 @@ def show(): f'{datetime.datetime.fromisoformat(value["created_at"]).strftime("%Y, %B, %d, %H:%M:%S %p")}', value["status"], ) + message = "" + if state[settings.CURRENT_PROJECT]: + message += f"Active Project: [bold blue]{state[settings.CURRENT_PROJECT]}\n" + if state[settings.CURRENT_TASK]: + message += f"Active Task: [bold green]{state[settings.CURRENT_TASK]}" + if message: + console.print(message) console.print(table) diff --git a/PyTM/commands/project.py b/PyTM/commands/project.py index 5696bbd..833ba2b 100644 --- a/PyTM/commands/project.py +++ b/PyTM/commands/project.py @@ -183,3 +183,32 @@ def json(project_name): console.print_json( data=project_handler.summary(data_handler.load_data(), project_name) ) + + +@project.command() +@click.argument("project_name") +@click.argument("new_name") +def rename(project_name, new_name): + """ + - Renames an existing project. + """ + data = data_handler.load_data() + state = data_handler.load_data(settings.state_filepath) + + if not data.get(project_name): + console.print( + f"[bold red] {project_name} doesn't exists. Make sure the spelling is correct." + ) + return + if data.get(new_name): + console.print( + f"[bold red] {new_name} already exists. Choose a different project name." + ) + return + data_handler.update( + partial(project_handler.rename, project_name=project_name, new_name=new_name) + ) + console.print(f"The project: {project_name} is renamed to {new_name}.") + if state[settings.CURRENT_PROJECT] == project_name: + state[settings.CURRENT_PROJECT] = new_name + data_handler.save_data(state, settings.state_filepath) diff --git a/PyTM/commands/task.py b/PyTM/commands/task.py index b19207e..ff8d0de 100644 --- a/PyTM/commands/task.py +++ b/PyTM/commands/task.py @@ -141,3 +141,40 @@ def status(): console.print("[red bold]No active task.") else: console.print("[red bold]No active project.") + + +@task.command() +@click.argument("task_name") +@click.argument("new_name") +def rename(task_name, new_name): + """ + - Renames a task of the active project. + """ + state = data_handler.load_data(settings.state_filepath) + data = data_handler.load_data() + project_name = state.get(settings.CURRENT_PROJECT) + if project_name: + if not data.get(project_name): + console.print(f"[red bold]Project doesn't exist.") + state[settings.CURRENT_PROJECT] = "" + data_handler.save_data(state, settings.state_filepath) + return + if task_name not in data.get(project_name).get("tasks", []): + console.print(f"[bold red] {task_name} doesn't exists.") + return + if new_name in data.get(project_name).get("tasks", []): + console.print(f"Task {new_name} already exists. Choose a different name.") + return + data_handler.update( + partial( + task_handler.rename, + project_name=project_name, + task_name=task_name, + new_name=new_name, + ) + ) + state[settings.CURRENT_TASK] = new_name + data_handler.save_data(state, settings.state_filepath) + console.print(f"Renamed task: [green]{task_name}[/green] to {new_name}.") + else: + console.print("[red bold]No active project.") diff --git a/PyTM/core/project_handler.py b/PyTM/core/project_handler.py index ffe26f4..9cc4559 100644 --- a/PyTM/core/project_handler.py +++ b/PyTM/core/project_handler.py @@ -52,3 +52,10 @@ def remove(data, project_name): if data.get(project_name): del data[project_name] return data + + +def rename(data, project_name, new_name): + if not new_name in data.keys(): + if data.get(project_name): + data[new_name] = data.pop(project_name) + return data diff --git a/PyTM/core/task_handler.py b/PyTM/core/task_handler.py index ba06bfa..03be979 100644 --- a/PyTM/core/task_handler.py +++ b/PyTM/core/task_handler.py @@ -76,3 +76,13 @@ def remove(data, project_name, task_name): if data.get(project_name)["tasks"].get(task_name): del data.get(project_name)["tasks"][task_name] return data + + +def rename(data, project_name, task_name, new_name): + if data.get(project_name): + if data.get(project_name).get("tasks"): + if not data.get(project_name).get("tasks").get(new_name): + data[project_name]["tasks"][new_name] = data[project_name]["tasks"].pop( + task_name + ) + return data diff --git a/README.rst b/README.rst index 1527ce2..ea28302 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,7 @@ Screenshots Installing PyTM --------------- -* First download and install the latest version of `Python `_ (Python 3.12+ is required). +* First download and install the latest version of `Python 3 `_ (Python 3.12+ is required). * Next, install PyTM from `PyPI `_ using :code:`pip`:: python -m pip install python-pytm @@ -84,6 +84,7 @@ Commands related to projects * Finish active project: :code:`pytm project finish` * Pause active project: :code:`pytm project pause` * Abort active project: :code:`pytm project abort` +* Rename a project: :code:`pytm project rename OLD_PROJECT_NAME NEW_NAME` Commands related to Task ======================== @@ -94,6 +95,7 @@ Commands related to Task * Finish active task: :code:`pytm task finish` * Pause active task: :code:`pytm task pause` * Abort active task: :code:`pytm task abort` +* Rename a task of the active project: :code:`pytm task rename OLD_TASK_NAME NEW_NAME` Others ====== From d41556eedb4eb133e25ce4182bd1b309261c35e9 Mon Sep 17 00:00:00 2001 From: Wasi Mohammed Abdullah Date: Wed, 8 Nov 2023 18:25:13 +0600 Subject: [PATCH 2/5] make project name optional for starting --- PyTM/cli.py | 2 +- PyTM/commands/project.py | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/PyTM/cli.py b/PyTM/cli.py index a911726..4b7cf78 100644 --- a/PyTM/cli.py +++ b/PyTM/cli.py @@ -117,7 +117,7 @@ def show(): ) message = "" if state[settings.CURRENT_PROJECT]: - message += f"Active Project: [bold blue]{state[settings.CURRENT_PROJECT]}\n" + message += f"Active Project: [bold blue]{state[settings.CURRENT_PROJECT]}[/bold blue]\n" if state[settings.CURRENT_TASK]: message += f"Active Task: [bold green]{state[settings.CURRENT_TASK]}" if message: diff --git a/PyTM/commands/project.py b/PyTM/commands/project.py index 833ba2b..7b691cc 100644 --- a/PyTM/commands/project.py +++ b/PyTM/commands/project.py @@ -112,15 +112,23 @@ def pause(): @project.command() -@click.argument("project_name") +@click.argument("project_name", required=False) def start(project_name): """ - starts an existing project or creates a new project. """ data = data_handler.load_data() + + if project_name is None: + num = len(data.keys()) + while project_name is None or data.get(project_name): + num += 1 + project_name = f"UNNAMED_{num}" + data_handler.update(partial(project_handler.create, project_name=project_name)) state = data_handler.load_data(settings.state_filepath) state[settings.CURRENT_PROJECT] = project_name + state[settings.CURRENT_TASK] = "" data_handler.save_data(state, settings.state_filepath) console.print(f"[bold blue]{project_name}[/bold blue] started.") if project_name not in data.keys(): From 97db796db1d3b8d4b869087336c6f2e61cc7cfef Mon Sep 17 00:00:00 2001 From: Wasi Mohammed Abdullah Date: Wed, 8 Nov 2023 18:55:00 +0600 Subject: [PATCH 3/5] made task name optional for starting a new task --- PyTM/commands/task.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/PyTM/commands/task.py b/PyTM/commands/task.py index ff8d0de..29d87a6 100644 --- a/PyTM/commands/task.py +++ b/PyTM/commands/task.py @@ -88,14 +88,22 @@ def pause(): @task.command() -@click.argument("task_name") +@click.argument("task_name", required=False) def start(task_name): """ - starts a new/existing task in current project. """ + data = data_handler.load_data() state = data_handler.load_data(settings.state_filepath) project_name = state.get(settings.CURRENT_PROJECT) - if project_name: + if project_name and data.get(project_name): + if task_name is None: + num = len(data.get(project_name).get("tasks", {}).keys()) + while task_name is None or data.get(project_name).get("tasks", {}).get( + task_name, "" + ): + num += 1 + task_name = f"UNTITLED_{num}" data_handler.update( partial(task_handler.create, project_name=project_name, task_name=task_name) ) From 2d5d8fb19f615df5bb35c7d2bba09cf935165a54 Mon Sep 17 00:00:00 2001 From: Wasi Mohammed Abdullah Date: Wed, 8 Nov 2023 19:12:40 +0600 Subject: [PATCH 4/5] bump version update history --- HISTORY.rst | 16 +++++++++++++++- PyTM/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 54afaf8..c5d97d0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -95,4 +95,18 @@ History * copy logo instead of moving it permanently when configuring invoice. * fixed f strings quote issue. * made init command hidden. -* improved doc strings and help texts. \ No newline at end of file +* improved doc strings and help texts. + +0.0.15 (2023-11-08) +------------------- + +* added new command rename for renaming existing projects. +* added new command rename for renaming existing tasks. +* updated show command to show active task and project when available. +* Simplified project start command. +* New projects can be started without project name. +* Project started without a name will now have a default name which can be renamed later. +* Simplified task start command. +* New tasks can be started without task name. +* Task started without a name will have a default name which can be renamed later at ease. +* Bug fix \ No newline at end of file diff --git a/PyTM/__init__.py b/PyTM/__init__.py index 698aa3a..3121eca 100644 --- a/PyTM/__init__.py +++ b/PyTM/__init__.py @@ -1,3 +1,3 @@ __author__ = "Wasi" __email__ = "wasi0013@gmail.com" -__version__ = "0.0.14" +__version__ = "0.0.15" diff --git a/setup.py b/setup.py index 9b9ed48..c99cdcc 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup( name="python-pytm", - version="0.0.14", + version="0.0.15", description="PyTM - an Open Source Python Time Management Tool for Mankind", long_description=readme + "\n\n" + doclink + "\n\n" + history, long_description_content_type="text/x-rst", From 8d1bda4c81749b48fa40814bafb1ed82d2fbfeab Mon Sep 17 00:00:00 2001 From: Wasi Mohammed Abdullah Date: Wed, 8 Nov 2023 19:27:00 +0600 Subject: [PATCH 5/5] update readme. --- README.rst | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index ea28302..e03a224 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,17 @@ Screenshots Installing PyTM --------------- -* First download and install the latest version of `Python 3 `_ (Python 3.12+ is required). +* First download and install `pyenv `_. Use the command:: + + curl https://pyenv.run | bash + +* Next, install Python 3.12 using the command:: + + pyenv install 3.12.0 + + Alternatively, you can skip pyenv installation and download python 3.12 or above from the official website and setup a virtualenv as well. + + * Next, install PyTM from `PyPI `_ using :code:`pip`:: python -m pip install python-pytm @@ -76,26 +86,26 @@ To see the available commands type:: Commands related to projects ============================ - -* Start a new/existing project: :code:`pytm project start PROJECT_NAME` +* Start a new project with a default name: :code:`pytm project start` +* Start a new project with the given name or, start an existing project: :code:`pytm project start PROJECT_NAME` +* Rename a project: :code:`pytm project rename OLD_PROJECT_NAME NEW_NAME` * Remove a project: :code:`pytm project remove PROJECT_NAME` * Check the status of a project: :code:`pytm project status PROJECT_NAME` * Check the list of tasks and duration of a project: :code:`pytm project summary PROJECT_NAME` * Finish active project: :code:`pytm project finish` * Pause active project: :code:`pytm project pause` * Abort active project: :code:`pytm project abort` -* Rename a project: :code:`pytm project rename OLD_PROJECT_NAME NEW_NAME` Commands related to Task ======================== - -* Start a new or existing task in the current active project: :code:`pytm task start TASK_NAME` +* Start a new task with a default name in the current active project: :code:`pytm task start` +* Start a new task with the given name or existing task in the current active project: :code:`pytm task start TASK_NAME` +* Rename a task of the active project: :code:`pytm task rename OLD_TASK_NAME NEW_NAME` * Remove a task: :code:`pytm task remove TASK_NAME` * current task's status: :code:`pytm task status` * Finish active task: :code:`pytm task finish` * Pause active task: :code:`pytm task pause` * Abort active task: :code:`pytm task abort` -* Rename a task of the active project: :code:`pytm task rename OLD_TASK_NAME NEW_NAME` Others ======