Metadata-Version: 2.4
Name: python-pytm
Version: 0.0.18
Summary: PyTM - an Open Source Python Time Management Tool for Mankind
Home-page: https://github.com/wasi0013/PyTM
Author: Wasi
Author-email: wasi0013@gmail.com
License: MIT
Keywords: PyTM
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Programming Language :: Python :: 3.12
Description-Content-Type: text/x-rst
License-File: LICENSE
License-File: AUTHORS.rst
Requires-Dist: click
Requires-Dist: rich
Requires-Dist: filelock
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: summary

 .. image:: https://github.com/wasi0013/PyTM/raw/master/ext/images/PyTM-logo.png
    :target: https://github.com/wasi0013/PyTM/
    :alt: PyTM - Logo




**PyTM** -  A CLI time tracker for projects with invoice generation
-------------------------------------------------------------------


|image1| |coverage| |image3| |Contributors| |DownloadStats| |DocsStats| |image2|
================================================================================

.. |image1| image:: https://badge.fury.io/py/python-pytm.png
   :target: https://badge.fury.io/py/python-pytm
.. |image2| image:: https://img.shields.io/pypi/l/python-pytm.svg
   :target: https://pypi.org/project/python-pytm/
.. |image3| image:: https://img.shields.io/pypi/pyversions/python-pytm.svg
   :target: https://pypi.org/project/python-pytm/
   :alt: Supported Python Versions
.. |Contributors| image:: https://img.shields.io/github/contributors/wasi0013/PyTM.svg
   :target: https://github.com/wasi0013/PyTM/graphs/contributors
   :alt: List of Contributors
.. |DownloadStats| image:: https://pepy.tech/badge/python-pytm
   :target: https://pepy.tech/project/python-pytm
   :alt: Download Stats
.. |DocsStats| image:: https://readthedocs.org/projects/pytm/badge/?version=latest
   :target: https://pytm.readthedocs.io/
   :alt: Documentation Status
.. |coverage| image:: https://img.shields.io/badge/coverage-56%25-blue
   :target: https://pytm.readthedocs.io/
   :alt: Documentation Status

Goals
-----

Project time management, billing, and invoice generation.

Preview
-------

 .. image:: https://github.com/wasi0013/PyTM/raw/master/ext/images/demo.gif
    :target: https://github.com/wasi0013/PyTM/raw/master/ext/images/demo.gif
    :alt: PyTM - Preview

Screenshots
-----------

 .. image:: https://github.com/wasi0013/PyTM/raw/master/ext/images/demo.png
    :target: https://github.com/wasi0013/PyTM/
    :alt: PyTM - Screenshot

 .. image:: https://github.com/wasi0013/PyTM/raw/master/ext/images/Demo-Invoice.png
    :target: https://github.com/wasi0013/PyTM/
    :alt: PyTM - Invoice

Installing PyTM
---------------

PyTM is installed with `uv <https://docs.astral.sh/uv/>`_, a fast, single-binary
Python package manager. It takes care of getting a suitable Python version for
you too, so there's nothing else to install first.

* Install uv (skip this if you already have it)::

    curl -LsSf https://astral.sh/uv/install.sh | sh

  Windows, and other install options, are covered in the
  `uv installation docs <https://docs.astral.sh/uv/getting-started/installation/>`_.

* Install PyTM as a standalone command-line tool::

    uv tool install python-pytm

  This puts a ``pytm`` command on your ``PATH``, isolated in its own
  environment, without touching any other Python project on your machine.

  Prefer not to install anything permanently? Try it in one shot instead::

    uvx python-pytm --help

Check the version by typing the following in your terminal.::

     pytm --version


Basic commands
---------------

To see the available commands type::

    pytm --help


Commands related to projects
============================
* 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`

Commands related to Task
========================
* 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`
* Atomically pause the active task and start/resume another: :code:`pytm task switch TASK_NAME`
* Correct a task's recorded duration by hand: :code:`pytm task edit TASK_NAME --duration HOURS`

Time digests
============
* Time logged today, across all projects: :code:`pytm today`
* Time logged this week, across all projects: :code:`pytm week`
* The week's start day (default Saturday) is configurable: :code:`pytm config user --week-start monday`

Ambient tracking (shell hooks)
===============================
Automatically start/switch tasks based on the directory you `cd` into and the
git branch you're on — opt-in, per directory, no auto-detection.

* Link a directory (and its subdirectories) to a project::

    cd ~/code/my-client-project
    pytm hook link my-client-project

* Enable the hook in your shell rc file (``~/.bashrc`` or ``~/.zshrc``)::

    eval "$(pytm hook init bash)"   # or: pytm hook init zsh

  From then on, `cd`-ing into a linked directory (or any of its
  subdirectories) starts/resumes its project, and switching git branch
  there switches to a task named after the branch. Directories that were
  never linked are left untouched — nothing is inferred automatically.

* Manage links: :code:`pytm hook list`, :code:`pytm hook unlink`
* See what a directory would resolve to without applying it: :code:`pytm hook resolve`

Others
======
Configure project, user and invoice info::

    pytm config project PROJECT_NAME
    pytm config user
    pytm config invoice

Generate Invoice::
    
    pytm invoice auto PROJECT_NAME
    pytm invoice manual

Check version::

    pytm --version
    pytm -v

Check summary of all the projects::

    pytm summary

For a list of all the available commands try::

    pytm --help


Running the tests
-----------------

This is for working on PyTM itself, not for just using it — if you only want
the ``pytm`` command, see `Installing PyTM`_ above instead.

* Clone this `repository <https://github.com/wasi0013/PyTM>`_ and ``cd`` into it::

    git clone https://github.com/wasi0013/PyTM.git
    cd PyTM

* Create a virtual environment (uv downloads a matching Python for you if
  needed) and install dependencies into it::

    uv venv
    uv pip install -r requirements.txt

* Run the tests::

    uv run pytest

  ``uv run`` finds the ``.venv`` created above automatically, so there's no
  need to manually activate it first.


Notes
-----

* **Author** - `Wasi <https://www.wasi0013.com/>`_ - (`wasi0013 <https://github.com/wasi0013>`_).
* **License** - see the `LICENSE <LICENSE>`_ file.
* **Contributing** - see `CONTRIBUTING.rst <CONTRIBUTING.rst>`_ for detail. You can also help by creating `issues <https://github.com/wasi0013/PyTM/issues/new/>`_.
* **Version** - see the `tags on this repository <https://github.com/wasi0013/PyTM/tags>`_.
* **Acknowledgments** - bootstrapped using `this cookiecutter package <https://github.com/audreyr/cookiecutter-pypackage>`_.
* Built With :heart: using `Python <https://python.org/>`_.



Documentation
-------------

The full documentation is at http://PyTM.rtfd.org.



History
-------

0.0.1 (2018-10-23)
------------------

* First release on PyPI.

0.0.2 (2018-11-09)
------------------

* Second release on PyPI.
* Created Skeleton of the command line Interface.

0.0.3 (2023-10-18)
------------------

* Implemented data store in home directory. 
* Made project commands functional.

0.0.4 (2023-10-28)
------------------

* Implemented state.
* Improved project commands.

0.0.5 (2023-10-30)
------------------

* Made task commands functional.
* Improved project summary.
* Project summary now shows total duration of the project.

0.0.6 (2023-10-31)
------------------

* bug fix
* readme and doc update
* Improved Command line interface outputs.

0.0.7 (2023-11-01)
------------------

* Added show sub command for project.
* Added json sub command for project.
* refactored project and task commands output messages.
* fixed bugs in project sub commands.

0.0.8 (2023-11-01)
------------------

* Added config sub command.
* added command to save default user information.
* refactored project and task commands.
* fixed bugs.
* added config command to configure project meta data such as title, billable? etc.
  
0.0.9 (2023-11-02)
------------------

* Added config invoice command for configuring default invoice texts and logo.
* Added invoice sub command.
* Added invoice manual command to generate manual invoice using prompts.
* Added invoice auto <Project> command to generate invoice from existing projects.
* invoice manual and auto command generates HTML invoices using Tailwind CSS and opens it in a Browser.

0.0.10 (2023-11-03)
-------------------

* open invoices using python's standard library.
* code refactor
* bug fix

0.0.11 (2023-11-03)
-------------------

* Major bug fix.

0.0.12 (2023-11-04)
-------------------

* Bug fix.

0.0.13 (2023-11-07)
-------------------

* Made the init command optional.

0.0.14 (2023-11-07)
-------------------

* config invoice command bug fix.
* 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.

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

0.0.16 (2023-11-11)
-------------------

* added new command summary.
* fixed bug and refactored invoice handler.
* added tests for project handler.
* added tests for task handler.
* added tests for invoice handler.
* updated make command to update README coverage percentage while testing.

0.0.18 (unreleased)
--------------------

* **`pytm task switch NAME`**: atomically pauses the active task (if any)
  and starts/resumes `NAME` in a single locked operation, closing the gap
  where switching used to be two separate, independently-locked commands.
* **`pytm task edit NAME --duration HOURS`**: manually corrects a task's
  recorded duration (e.g. after a hook mis-tracked it). Recorded as a
  dated adjustment so `today`/`week` stay consistent with the correction.
* **`pytm today` / `pytm week`**: digests of time logged today / this
  week, aggregated per project and task from the new per-task session
  log. Tasks recorded before this release (no session log) are shown
  with a best-effort "(legacy, approximate)" attribution bucketed on
  their finish date. `pytm week`'s start day defaults to Saturday and is
  configurable via `pytm config user --week-start DAY`.
* **`pytm hook`**: opt-in ambient tracking. `pytm hook link PROJECT`
  (run inside a directory) tracks that directory (and its
  subdirectories) against `PROJECT`; `pytm hook init bash|zsh` prints a
  shell snippet (`eval "$(pytm hook init zsh)"`) that switches the active
  project/task automatically on `cd` and git branch changes, based only
  on directories you've explicitly linked. Never auto-creates a project
  from an unlinked directory.
* fixed a crash (`ValueError: Invalid isoformat string`) when `task
  pause`/`task finish`/`task abort` were called on a task that wasn't
  currently running (e.g. called twice in a row) — these are now no-ops
  on a task that isn't in the relevant state, instead of raising. This
  matters more now that ambient hooks can call them redundantly.
* fixed `task abort` silently discarding the time logged since the task
  was last resumed instead of folding it into `duration`.
* fixed `task start`/`task switch` on an already-running task resetting
  its start time, which used to silently drop the time already accrued.
* `task_handler.switch` (and so `pytm task switch` and `pytm hook
  resolve --apply`) now pauses *every* running task in the project
  before starting the target task, not just the one `state` happens to
  be tracking — closes a gap where a task left running in the project
  you're switching *into* (started manually, or by an earlier hook
  resolve that didn't get to update state) could end up running
  alongside the new one, both simultaneously marked "running".
* fixed `pytm today`/`pytm week` rendering a downward `task edit`
  correction (one that outweighs other time logged that day) as a
  misleadingly small or zero duration instead of a real negative value.
* fixed `task edit` on a task recorded before per-session tracking
  existed silently dropping its original duration from `today`/`week`
  the moment it was corrected, instead of preserving that original
  day's total and dating the correction itself on the day it was made.
* `pytm hook resolve --apply`'s state updates are now held under one
  lock for its whole read-modify-write sequence, instead of several
  separate load/save round trips — this runs automatically and
  frequently (every shell prompt, potentially from several terminals at
  once), so two invocations racing could otherwise silently clobber
  each other's state update.
* minor: `pytm hook`'s directory matching no longer re-normalizes every
  linked path (a stat syscall each) on every `cd`/branch check — only
  the current directory needs it, since linked paths are already
  normalized when they're stored.

0.0.17 (2026-08-12)
--------------------

* **Billing fix:** invoice generation converted task duration to hours using
  `/360` instead of `/3600`, billing every invoice at 10x the correct
  amount. If you generated an invoice with a prior version, please
  regenerate and re-check it before sending.
* fixed a crash in `project summary` (`TypeError: 'Group' object is not
  subscriptable`).
* fixed a crash in `invoice auto` (`KeyError: 'meta'`) for any project that
  was never configured via `config project`.
* fixed `task rename` silently overwriting the active task pointer when
  renaming a task that wasn't the active one.
* `data.json`/`state.json` writes are now atomic (crash-safe) and
  file-locked (concurrency-safe).
* `save_data` no longer silently drops writes of an empty/falsy store
  (e.g. removing the last project now actually persists).
* added `--non-interactive` support (with per-field flags) to
  `config user`, `config invoice`, `config project`, `invoice auto`, and
  `invoice manual`, so invoices and config can be scripted.
* corrected a boundary bug in duration formatting where exactly 1 hour or
  exactly 24 hours displayed as e.g. "60 mins" instead of rolling over.
* fixed `pytm project`/`task`/`config`/`invoice` (no subcommand) exiting
  with different codes depending on the installed Click version (exit 0
  on Click 8.1.x, exit 2 on Click 8.2+); behavior is now pinned to
  "print help, exit 0" regardless of Click version.
