kanban-python 0.3.7__tar.gz → 0.3.9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {kanban-python-0.3.7 → kanban-python-0.3.9}/CHANGELOG.md +10 -0
  2. {kanban-python-0.3.7/src/kanban_python.egg-info → kanban-python-0.3.9}/PKG-INFO +9 -6
  3. {kanban-python-0.3.7 → kanban-python-0.3.9}/README.md +7 -5
  4. kanban-python-0.3.9/images/image_header.PNG +0 -0
  5. kanban-python-0.3.9/images/image_kanban.PNG +0 -0
  6. kanban-python-0.3.9/images/image_kanban_change.PNG +0 -0
  7. {kanban-python-0.3.7 → kanban-python-0.3.9}/setup.cfg +1 -0
  8. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/constants.py +2 -1
  9. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/controls.py +3 -1
  10. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/interface.py +81 -26
  11. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/utils.py +38 -0
  12. {kanban-python-0.3.7 → kanban-python-0.3.9/src/kanban_python.egg-info}/PKG-INFO +9 -6
  13. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python.egg-info/requires.txt +1 -0
  14. {kanban-python-0.3.7 → kanban-python-0.3.9}/tests/conftest.py +1 -0
  15. {kanban-python-0.3.7 → kanban-python-0.3.9}/tests/test_utils.py +71 -4
  16. kanban-python-0.3.7/images/image_header.PNG +0 -0
  17. kanban-python-0.3.7/images/image_kanban.PNG +0 -0
  18. kanban-python-0.3.7/images/image_kanban_change.PNG +0 -0
  19. {kanban-python-0.3.7 → kanban-python-0.3.9}/.coveragerc +0 -0
  20. {kanban-python-0.3.7 → kanban-python-0.3.9}/.github/workflows/ci.yml +0 -0
  21. {kanban-python-0.3.7 → kanban-python-0.3.9}/.gitignore +0 -0
  22. {kanban-python-0.3.7 → kanban-python-0.3.9}/.isort.cfg +0 -0
  23. {kanban-python-0.3.7 → kanban-python-0.3.9}/.pre-commit-config.yaml +0 -0
  24. {kanban-python-0.3.7 → kanban-python-0.3.9}/.readthedocs.yml +0 -0
  25. {kanban-python-0.3.7 → kanban-python-0.3.9}/AUTHORS.md +0 -0
  26. {kanban-python-0.3.7 → kanban-python-0.3.9}/CONTRIBUTING.md +0 -0
  27. {kanban-python-0.3.7 → kanban-python-0.3.9}/LICENSE.txt +0 -0
  28. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/Makefile +0 -0
  29. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/_static/.gitignore +0 -0
  30. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/authors.md +0 -0
  31. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/changelog.md +0 -0
  32. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/conf.py +0 -0
  33. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/contributing.md +0 -0
  34. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/index.md +0 -0
  35. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/license.md +0 -0
  36. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/readme.md +0 -0
  37. {kanban-python-0.3.7 → kanban-python-0.3.9}/docs/requirements.txt +0 -0
  38. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_config.PNG +0 -0
  39. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_kanban_configure.PNG +0 -0
  40. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_kanban_init.PNG +0 -0
  41. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_kanban_report.PNG +0 -0
  42. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_kanban_report_document.PNG +0 -0
  43. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_scan_table.PNG +0 -0
  44. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_scan_view.PNG +0 -0
  45. {kanban-python-0.3.7 → kanban-python-0.3.9}/images/image_task_example.PNG +0 -0
  46. {kanban-python-0.3.7 → kanban-python-0.3.9}/pyproject.toml +0 -0
  47. {kanban-python-0.3.7 → kanban-python-0.3.9}/setup.py +0 -0
  48. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/__init__.py +0 -0
  49. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/app.py +0 -0
  50. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/cli_parser.py +0 -0
  51. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python/config.py +0 -0
  52. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python.egg-info/SOURCES.txt +0 -0
  53. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python.egg-info/dependency_links.txt +0 -0
  54. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python.egg-info/entry_points.txt +0 -0
  55. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python.egg-info/not-zip-safe +0 -0
  56. {kanban-python-0.3.7 → kanban-python-0.3.9}/src/kanban_python.egg-info/top_level.txt +0 -0
  57. {kanban-python-0.3.7 → kanban-python-0.3.9}/tests/test_config.py +0 -0
  58. {kanban-python-0.3.7 → kanban-python-0.3.9}/tests/test_interface.py +0 -0
  59. {kanban-python-0.3.7 → kanban-python-0.3.9}/tox.ini +0 -0
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## Version 0.3.9
4
+ - Add `from __future__ import annotations` to controls.py to not error on Union TypeHint if python version is <=3.9
5
+
6
+ ## Version 0.3.8
7
+ - Add `Due_Date` to Task Structure
8
+ - App now asks for `Due_Date` on task creation and task update
9
+ - Show `days left` on board for task with `Due_Date`
10
+ - Show `days left` of most overdue or urgent task for each board when changing boards
11
+ - Add `freezegun` as test requirement
12
+
3
13
  ## Version 0.3.7
4
14
  - Bug Fix, `Complete_Time`-Key was wrong in Task Creation, when task was created with `kanban scan`
5
15
  - Add new function `kanban report` to show a github contribution like visual + creating a `.md` report
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kanban-python
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: Terminal Kanban App written in Python
5
5
  Home-page: https://github.com/Zaloog/kanban-python
6
6
  Author: Zaloog
@@ -19,6 +19,7 @@ Requires-Dist: platformdirs<4,>=3
19
19
  Provides-Extra: testing
20
20
  Requires-Dist: setuptools; extra == "testing"
21
21
  Requires-Dist: pytest; extra == "testing"
22
+ Requires-Dist: freezegun; extra == "testing"
22
23
  Requires-Dist: pytest-cov; extra == "testing"
23
24
 
24
25
  <!-- These are examples of badges you might want to add to your README:
@@ -35,7 +36,7 @@ Requires-Dist: pytest-cov; extra == "testing"
35
36
  [![Project generated with PyScaffold](https://img.shields.io/badge/-PyScaffold-005CA0?logo=pyscaffold)](https://pyscaffold.org/)
36
37
  [![PyPI-Server](https://img.shields.io/pypi/v/kanban-python.svg)](https://pypi.org/project/kanban-python/)
37
38
  [![Downloads](https://static.pepy.tech/badge/kanban-python)](https://pepy.tech/project/kanban-python)
38
- [![Coverage Status](https://coveralls.io/repos/github/Zaloog/kanban-python/badge.svg?branch=refs/tags/v0.3.7)](https://coveralls.io/github/Zaloog/kanban-python?branch=refs/tags/v0.3.7)
39
+ [![Coverage Status](https://coveralls.io/repos/github/Zaloog/kanban-python/badge.svg?branch=refs/tags/v0.3.9)](https://coveralls.io/github/Zaloog/kanban-python?branch=refs/tags/v0.3.9)
39
40
  # kanban-python
40
41
 
41
42
  > A Terminal Kanban Application written in Python to boost your productivity :rocket:
@@ -58,7 +59,9 @@ It was a great help for developing my first package and I can highly recommend i
58
59
  <details><summary>Colorful and Interactive</summary>
59
60
 
60
61
  - kanban-python uses [rich] under the hood to process user input
61
- and display nice looking tables to the terminal.
62
+ and display nice looking kanban-boards to the terminal.
63
+ - Each task has a unique `ID` per board and also has an optional `Tag` and `Due Date` associated with it,
64
+ which are displayed alongside its `Title`
62
65
 
63
66
  </details>
64
67
 
@@ -100,7 +103,7 @@ This can be edited manually or within the kanban-python application. It tracks t
100
103
 
101
104
  - Each created board comes with its own name and `pykanban.json` file,
102
105
  which stores all tasks for that board. The files are stored in board specific folders under `$USER_DATA_DIR/kanban-python/kanban_boards/<BOARDNAME>`.
103
- When changing Boards you also get an overview over tasks in visible columns for each board.
106
+ When changing Boards you also get an overview over tasks in visible columns for each board and the most urgent or overdue task on that board.
104
107
  ![change_view](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_change.PNG)
105
108
 
106
109
  </details>
@@ -129,7 +132,7 @@ with `kanban configure`.
129
132
 
130
133
  - When you use [kanban report](#create-report) a github-like contribution map is displayed for the current year,
131
134
  Also a markdown file is created with all tasks comleted based on the moment, when the tasks were moved to Done Column.
132
- ![task](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report.PNG)
135
+ ![task](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report_document.PNG)
133
136
 
134
137
  </details>
135
138
 
@@ -179,7 +182,7 @@ The filepath were the task was found will be added as description of the task.
179
182
  ```
180
183
  Goes over all your Boards and creates a single markdown file by checking the `Completion Dates` of your tasks.
181
184
  Also shows a nice github-like contribution table for the current year.
182
- ![report](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report_document.PNG)
185
+ ![report](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report.PNG)
183
186
 
184
187
  ### Change Settings
185
188
  ```bash
@@ -12,7 +12,7 @@
12
12
  [![Project generated with PyScaffold](https://img.shields.io/badge/-PyScaffold-005CA0?logo=pyscaffold)](https://pyscaffold.org/)
13
13
  [![PyPI-Server](https://img.shields.io/pypi/v/kanban-python.svg)](https://pypi.org/project/kanban-python/)
14
14
  [![Downloads](https://static.pepy.tech/badge/kanban-python)](https://pepy.tech/project/kanban-python)
15
- [![Coverage Status](https://coveralls.io/repos/github/Zaloog/kanban-python/badge.svg?branch=refs/tags/v0.3.7)](https://coveralls.io/github/Zaloog/kanban-python?branch=refs/tags/v0.3.7)
15
+ [![Coverage Status](https://coveralls.io/repos/github/Zaloog/kanban-python/badge.svg?branch=refs/tags/v0.3.9)](https://coveralls.io/github/Zaloog/kanban-python?branch=refs/tags/v0.3.9)
16
16
  # kanban-python
17
17
 
18
18
  > A Terminal Kanban Application written in Python to boost your productivity :rocket:
@@ -35,7 +35,9 @@ It was a great help for developing my first package and I can highly recommend i
35
35
  <details><summary>Colorful and Interactive</summary>
36
36
 
37
37
  - kanban-python uses [rich] under the hood to process user input
38
- and display nice looking tables to the terminal.
38
+ and display nice looking kanban-boards to the terminal.
39
+ - Each task has a unique `ID` per board and also has an optional `Tag` and `Due Date` associated with it,
40
+ which are displayed alongside its `Title`
39
41
 
40
42
  </details>
41
43
 
@@ -77,7 +79,7 @@ This can be edited manually or within the kanban-python application. It tracks t
77
79
 
78
80
  - Each created board comes with its own name and `pykanban.json` file,
79
81
  which stores all tasks for that board. The files are stored in board specific folders under `$USER_DATA_DIR/kanban-python/kanban_boards/<BOARDNAME>`.
80
- When changing Boards you also get an overview over tasks in visible columns for each board.
82
+ When changing Boards you also get an overview over tasks in visible columns for each board and the most urgent or overdue task on that board.
81
83
  ![change_view](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_change.PNG)
82
84
 
83
85
  </details>
@@ -106,7 +108,7 @@ with `kanban configure`.
106
108
 
107
109
  - When you use [kanban report](#create-report) a github-like contribution map is displayed for the current year,
108
110
  Also a markdown file is created with all tasks comleted based on the moment, when the tasks were moved to Done Column.
109
- ![task](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report.PNG)
111
+ ![task](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report_document.PNG)
110
112
 
111
113
  </details>
112
114
 
@@ -156,7 +158,7 @@ The filepath were the task was found will be added as description of the task.
156
158
  ```
157
159
  Goes over all your Boards and creates a single markdown file by checking the `Completion Dates` of your tasks.
158
160
  Also shows a nice github-like contribution table for the current year.
159
- ![report](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report_document.PNG)
161
+ ![report](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report.PNG)
160
162
 
161
163
  ### Change Settings
162
164
  ```bash
@@ -36,6 +36,7 @@ exclude =
36
36
  testing =
37
37
  setuptools
38
38
  pytest
39
+ freezegun
39
40
  pytest-cov
40
41
 
41
42
  [options.entry_points]
@@ -30,7 +30,7 @@ QUOTES = [
30
30
  ]
31
31
 
32
32
  BOARD_CAPTION_STRING = "Tasks have the following Structure:\
33
- [[cyan]ID[/]] ([orange3]TAG[/]) [white]Task Title[/]"
33
+ [[cyan]ID[/]] ([orange3]TAG[/]) [white]Task Title[/] |[red]Days Left[/]|"
34
34
 
35
35
  COLOR_DICT = {
36
36
  "Ready": "[red]Ready[/]",
@@ -49,6 +49,7 @@ DUMMY_TASK = {
49
49
  "Complete_Time": "",
50
50
  "Duration": 0,
51
51
  "Creation_Date": "",
52
+ "Due_Date": "",
52
53
  }
53
54
  DUMMY_DB = {1: DUMMY_TASK}
54
55
 
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from json import dump, load
2
4
 
3
5
  from rich.pretty import pprint
@@ -197,7 +199,7 @@ def show_tasks():
197
199
  {
198
200
  key: val
199
201
  for key, val in task.items()
200
- if key in ["Title", "Description", "Tag", "Status"]
202
+ if key in ["Title", "Description", "Tag", "Status", "Due_Date"]
201
203
  },
202
204
  console=console,
203
205
  expand_all=True,
@@ -14,12 +14,16 @@ from .constants import (
14
14
  REPORT_COLORS,
15
15
  )
16
16
  from .utils import (
17
+ calculate_days_left_till_due,
17
18
  calculate_time_delta_str,
19
+ check_due_date_format,
18
20
  console,
19
21
  create_color_mapping,
20
22
  create_dict_for_report_view,
21
23
  create_status_dict_for_rows,
22
24
  current_time_to_str,
25
+ due_date_date_to_datetime,
26
+ due_date_datetime_to_date,
23
27
  )
24
28
 
25
29
 
@@ -95,26 +99,40 @@ def input_ask_for_action():
95
99
  # Action 1: New Task
96
100
  def input_create_new_task() -> dict:
97
101
  title = Prompt.ask(
98
- prompt="[1/4] Add Task Title",
102
+ prompt="[1/5] Add Task Title",
99
103
  )
100
104
 
101
105
  description = Prompt.ask(
102
- prompt="[2/4] Add Task Description",
106
+ prompt="[2/5] Add Task Description",
103
107
  show_default=True,
104
- default=None,
108
+ default="",
105
109
  )
106
110
 
107
111
  tag = Prompt.ask(
108
- prompt="[3/4] Add a Tag",
112
+ prompt="[3/5] Add a Tag",
109
113
  show_default=True,
110
114
  default="ETC",
111
115
  )
112
116
 
117
+ while True:
118
+ due_date = Prompt.ask(
119
+ prompt="[4/5] Add a Due Date (YYYY-MM-DD)",
120
+ show_default=True,
121
+ default="",
122
+ )
123
+ if not due_date or check_due_date_format(date_str=due_date):
124
+ break
125
+ else:
126
+ console.print(
127
+ f":warning: '{due_date}' has [red]not[/] "
128
+ + "the right format YYYY-MM-DD"
129
+ )
130
+
113
131
  console.print(f"\t[1] {COLOR_DICT['Ready']}")
114
132
  console.print(f"\t[2] {COLOR_DICT['Doing']}")
115
133
 
116
134
  status = IntPrompt.ask(
117
- prompt="[4/4] Status of Task",
135
+ prompt="[5/5] Status of Task",
118
136
  show_choices=False,
119
137
  choices=["1", "2"],
120
138
  show_default=True,
@@ -127,6 +145,7 @@ def input_create_new_task() -> dict:
127
145
  "Status": "Ready" if str(status) == "1" else "Doing",
128
146
  "Tag": tag.upper(),
129
147
  "Creation_Date": current_time_to_str(),
148
+ "Due_Date": due_date_date_to_datetime(due_date),
130
149
  "Begin_Time": current_time_to_str() if str(status) == "2" else "",
131
150
  "Complete_Time": "",
132
151
  "Duration": 0,
@@ -149,7 +168,7 @@ def input_ask_which_task_to_update(data: dict) -> str:
149
168
 
150
169
  def input_update_task_title(current_title) -> str:
151
170
  return Prompt.ask(
152
- prompt="[1/4] Update Task Title",
171
+ prompt="[1/5] Update Task Title",
153
172
  show_default=True,
154
173
  default=current_title,
155
174
  )
@@ -157,7 +176,7 @@ def input_update_task_title(current_title) -> str:
157
176
 
158
177
  def input_update_task_description(current_desc) -> str:
159
178
  return Prompt.ask(
160
- prompt="[2/4] Update Task Description",
179
+ prompt="[2/5] Update Task Description",
161
180
  show_default=True,
162
181
  default=current_desc,
163
182
  )
@@ -165,16 +184,52 @@ def input_update_task_description(current_desc) -> str:
165
184
 
166
185
  def input_update_task_tag(current_tag) -> str:
167
186
  return Prompt.ask(
168
- prompt="[3/4] Update Tag",
187
+ prompt="[3/5] Update Tag",
169
188
  show_default=True,
170
189
  default=current_tag,
171
190
  )
172
191
 
173
192
 
193
+ def input_update_due_date(current_due) -> str:
194
+ while True:
195
+ due_date_str = Prompt.ask(
196
+ prompt="[4/5] Update Due Date (YYYY-MM-DD or ` `)",
197
+ show_default=True,
198
+ # fix default view
199
+ default=due_date_datetime_to_date(date_datetime=current_due),
200
+ )
201
+
202
+ if not due_date_str or check_due_date_format(date_str=due_date_str):
203
+ break
204
+ else:
205
+ console.print(
206
+ f":warning: '{due_date_str}' has [red]not[/] "
207
+ + "the right format YYYY-MM-DD"
208
+ )
209
+
210
+ return due_date_date_to_datetime(due_date_str)
211
+
212
+
213
+ def input_ask_to_what_status_to_move(task_title):
214
+ possible_status = [cat for cat in cfg.kanban_columns_dict]
215
+
216
+ console.print(f'Updating Status of Task "[white]{task_title}[/]"')
217
+ for idx, status in enumerate(possible_status, start=1):
218
+ console.print(f"\t[{idx}] {COLOR_DICT.get(status, status)}")
219
+
220
+ new_status = IntPrompt.ask(
221
+ prompt="[5/5] New Status of Task?",
222
+ show_choices=False,
223
+ choices=[f"{i}" for i, _ in enumerate(possible_status, start=1)],
224
+ )
225
+ return possible_status[int(new_status) - 1]
226
+
227
+
174
228
  def input_update_task(current_task: dict) -> dict:
175
229
  title = input_update_task_title(current_task["Title"])
176
230
  description = input_update_task_description(current_task["Description"])
177
231
  tag = input_update_task_tag(current_task["Tag"])
232
+ due_date = input_update_due_date(current_task.get("Due_Date", ""))
178
233
  status = input_ask_to_what_status_to_move(current_task["Title"])
179
234
 
180
235
  if (status == "Doing") and (current_task["Status"] != "Doing"):
@@ -204,6 +259,7 @@ def input_update_task(current_task: dict) -> dict:
204
259
  "Description": description,
205
260
  "Status": status,
206
261
  "Tag": tag.upper(),
262
+ "Due_Date": due_date,
207
263
  "Begin_Time": start_doing,
208
264
  "Complete_Time": stop_doing,
209
265
  "Duration": duration,
@@ -212,21 +268,6 @@ def input_update_task(current_task: dict) -> dict:
212
268
  return current_task
213
269
 
214
270
 
215
- def input_ask_to_what_status_to_move(task_title):
216
- possible_status = [cat for cat in cfg.kanban_columns_dict]
217
-
218
- console.print(f'Updating Status of Task "[white]{task_title}[/]"')
219
- for idx, status in enumerate(possible_status, start=1):
220
- console.print(f"\t[{idx}] {COLOR_DICT.get(status, status)}")
221
-
222
- new_status = IntPrompt.ask(
223
- prompt="[4/4] New Status of Task?",
224
- show_choices=False,
225
- choices=[f"{i}" for i, _ in enumerate(possible_status, start=1)],
226
- )
227
- return possible_status[int(new_status) - 1]
228
-
229
-
230
271
  def input_confirm_set_board_active(name) -> bool:
231
272
  return Confirm.ask(
232
273
  f"Do you want to set the Board '{name}' as active:question_mark:"
@@ -255,6 +296,13 @@ def input_ask_for_change_board(boards_dict: dict) -> str:
255
296
 
256
297
  for idx, (board, board_data) in enumerate(boards_dict.items(), start=1):
257
298
  status_dict = create_status_dict_for_rows(board_data, cfg.vis_cols)
299
+ days_left_list = [
300
+ calculate_days_left_till_due(val["Due_Date"])
301
+ for val in board_data.values()
302
+ if (val.get("Due_Date") and (val["Status"] in ["Ready", "Doing"]))
303
+ ]
304
+ # Use -9999 to as placeholder for no tasks to make comparison later
305
+ days_left = min(days_left_list) if days_left_list else -9999
258
306
  console.print(
259
307
  f"[{idx}] {board}"
260
308
  + " " * ((max_board_len - len(board) + 1))
@@ -264,6 +312,13 @@ def input_ask_for_change_board(boards_dict: dict) -> str:
264
312
  for col in cfg.vis_cols
265
313
  ]
266
314
  )
315
+ + (
316
+ f"\t next due in {days_left} day/s"
317
+ if days_left > 0
318
+ else f"[red]\t task {-days_left} day/s overdue[/]"
319
+ if days_left != -9999
320
+ else "\t no dues present here"
321
+ )
267
322
  )
268
323
 
269
324
  answer = IntPrompt.ask(
@@ -328,7 +383,7 @@ def print_all_todos(todos: list) -> None:
328
383
  console.print(todo_string)
329
384
 
330
385
 
331
- def input_confirm_add_todos_to_board(todos) -> bool:
386
+ def input_confirm_add_todos_to_board(todos: list) -> bool:
332
387
  # Question Also print tasks already in Board?
333
388
  console.print(f"Found [blue]{len(todos)}[/] TODOs.")
334
389
  if len(todos) > 10:
@@ -393,7 +448,7 @@ def create_github_like_report_table(boards_dict: dict):
393
448
 
394
449
 
395
450
  # Ask for Actions
396
- def input_ask_for_action_settings():
451
+ def input_ask_for_action_settings() -> int:
397
452
  console.print(
398
453
  "[yellow]Not happy with current settings!?[/],"
399
454
  + "which [blue]Section[/] do you want to change :hammer_and_wrench:?"
@@ -458,7 +513,7 @@ def input_change_footer_settings():
458
513
  return footer_visible
459
514
 
460
515
 
461
- def input_change_done_limit_settings():
516
+ def input_change_done_limit_settings() -> int:
462
517
  done_limit = IntPrompt.ask(
463
518
  prompt=f"What should the Limit of Tasks in {COLOR_DICT.get('Done','Done')} "
464
519
  + f"Column be, before moving to {COLOR_DICT.get('Archived','Archived')}?",
@@ -41,6 +41,10 @@ def create_status_dict_for_rows(data: dict, vis_cols: list) -> dict:
41
41
  task_str = f"[[cyan]{id}[/]]" if int(id) > 9 else f"[[cyan]0{id}[/]]"
42
42
  task_str += f'([orange3]{task.get("Tag")}[/])'
43
43
  task_str += f' [white]{task["Title"]}[/]'
44
+ # Add days left
45
+ if all((task["Status"] in ["Ready", "Doing"], task.get("Due_Date", False))):
46
+ days_left = calculate_days_left_till_due(task["Due_Date"])
47
+ task_str += f" |[red]{days_left:02d}[/]|"
44
48
  status_dict[task["Status"]].append(task_str)
45
49
 
46
50
  return status_dict
@@ -198,6 +202,8 @@ def create_color_mapping(amount_list: list, max_val: int):
198
202
  mapped_list.append(3)
199
203
  elif (val / max_val) <= 1:
200
204
  mapped_list.append(4)
205
+ else:
206
+ continue
201
207
 
202
208
  return mapped_list
203
209
 
@@ -233,3 +239,35 @@ def create_report_document(boards_dict: dict):
233
239
  report_file.write("".join(completed))
234
240
 
235
241
  return date_dict
242
+
243
+
244
+ def check_due_date_format(date_str: str) -> bool:
245
+ try:
246
+ datetime.strptime(date_str, "%Y-%m-%d")
247
+ return True
248
+ except ValueError:
249
+ return False
250
+
251
+
252
+ def due_date_datetime_to_date(date_datetime: str) -> str:
253
+ if date_datetime:
254
+ date_str = str(datetime.strptime(date_datetime, "%Y-%m-%d %H:%M:%S").date())
255
+ return date_str
256
+ return date_datetime
257
+
258
+
259
+ def due_date_date_to_datetime(date_str: str) -> str:
260
+ if date_str:
261
+ date_datetime = str(
262
+ datetime.strptime(f"{date_str} 23:59:59", "%Y-%m-%d %H:%M:%S")
263
+ )
264
+ return date_datetime
265
+ return date_str
266
+
267
+
268
+ def calculate_days_left_till_due(due_date: str):
269
+ time_now = datetime.now()
270
+ time_due = datetime.strptime(due_date, "%Y-%m-%d %H:%M:%S")
271
+
272
+ delta_days = (time_due - time_now).days
273
+ return delta_days
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kanban-python
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: Terminal Kanban App written in Python
5
5
  Home-page: https://github.com/Zaloog/kanban-python
6
6
  Author: Zaloog
@@ -19,6 +19,7 @@ Requires-Dist: platformdirs<4,>=3
19
19
  Provides-Extra: testing
20
20
  Requires-Dist: setuptools; extra == "testing"
21
21
  Requires-Dist: pytest; extra == "testing"
22
+ Requires-Dist: freezegun; extra == "testing"
22
23
  Requires-Dist: pytest-cov; extra == "testing"
23
24
 
24
25
  <!-- These are examples of badges you might want to add to your README:
@@ -35,7 +36,7 @@ Requires-Dist: pytest-cov; extra == "testing"
35
36
  [![Project generated with PyScaffold](https://img.shields.io/badge/-PyScaffold-005CA0?logo=pyscaffold)](https://pyscaffold.org/)
36
37
  [![PyPI-Server](https://img.shields.io/pypi/v/kanban-python.svg)](https://pypi.org/project/kanban-python/)
37
38
  [![Downloads](https://static.pepy.tech/badge/kanban-python)](https://pepy.tech/project/kanban-python)
38
- [![Coverage Status](https://coveralls.io/repos/github/Zaloog/kanban-python/badge.svg?branch=refs/tags/v0.3.7)](https://coveralls.io/github/Zaloog/kanban-python?branch=refs/tags/v0.3.7)
39
+ [![Coverage Status](https://coveralls.io/repos/github/Zaloog/kanban-python/badge.svg?branch=refs/tags/v0.3.9)](https://coveralls.io/github/Zaloog/kanban-python?branch=refs/tags/v0.3.9)
39
40
  # kanban-python
40
41
 
41
42
  > A Terminal Kanban Application written in Python to boost your productivity :rocket:
@@ -58,7 +59,9 @@ It was a great help for developing my first package and I can highly recommend i
58
59
  <details><summary>Colorful and Interactive</summary>
59
60
 
60
61
  - kanban-python uses [rich] under the hood to process user input
61
- and display nice looking tables to the terminal.
62
+ and display nice looking kanban-boards to the terminal.
63
+ - Each task has a unique `ID` per board and also has an optional `Tag` and `Due Date` associated with it,
64
+ which are displayed alongside its `Title`
62
65
 
63
66
  </details>
64
67
 
@@ -100,7 +103,7 @@ This can be edited manually or within the kanban-python application. It tracks t
100
103
 
101
104
  - Each created board comes with its own name and `pykanban.json` file,
102
105
  which stores all tasks for that board. The files are stored in board specific folders under `$USER_DATA_DIR/kanban-python/kanban_boards/<BOARDNAME>`.
103
- When changing Boards you also get an overview over tasks in visible columns for each board.
106
+ When changing Boards you also get an overview over tasks in visible columns for each board and the most urgent or overdue task on that board.
104
107
  ![change_view](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_change.PNG)
105
108
 
106
109
  </details>
@@ -129,7 +132,7 @@ with `kanban configure`.
129
132
 
130
133
  - When you use [kanban report](#create-report) a github-like contribution map is displayed for the current year,
131
134
  Also a markdown file is created with all tasks comleted based on the moment, when the tasks were moved to Done Column.
132
- ![task](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report.PNG)
135
+ ![task](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report_document.PNG)
133
136
 
134
137
  </details>
135
138
 
@@ -179,7 +182,7 @@ The filepath were the task was found will be added as description of the task.
179
182
  ```
180
183
  Goes over all your Boards and creates a single markdown file by checking the `Completion Dates` of your tasks.
181
184
  Also shows a nice github-like contribution table for the current year.
182
- ![report](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report_document.PNG)
185
+ ![report](https://raw.githubusercontent.com/Zaloog/kanban-python/main/images/image_kanban_report.PNG)
183
186
 
184
187
  ### Change Settings
185
188
  ```bash
@@ -7,4 +7,5 @@ importlib-metadata
7
7
  [testing]
8
8
  setuptools
9
9
  pytest
10
+ freezegun
10
11
  pytest-cov
@@ -33,6 +33,7 @@ def test_task():
33
33
  "Complete_Time": "",
34
34
  "Duration": "0",
35
35
  "Creation_Date": "",
36
+ "Due_Date": "",
36
37
  }
37
38
 
38
39
 
@@ -1,6 +1,7 @@
1
- from datetime import datetime
1
+ import datetime
2
2
 
3
3
  import pytest
4
+ from freezegun import freeze_time
4
5
 
5
6
  from kanban_python import utils
6
7
 
@@ -10,7 +11,7 @@ def test_get_motivational_quote():
10
11
 
11
12
 
12
13
  def test_current_time_to_str():
13
- current_time = datetime.now()
14
+ current_time = datetime.datetime.now()
14
15
  result = utils.current_time_to_str()
15
16
  expected_format = current_time.strftime("%Y-%m-%d %H:%M:%S")
16
17
 
@@ -198,14 +199,80 @@ def test_get_iso_calender_info():
198
199
  assert weekday == 2
199
200
 
200
201
 
202
+ def test_create_dict_for_report_view():
203
+ tasks = [
204
+ {"Complete_Time": "2022-12-05 23:41:41"},
205
+ {"Complete_Time": "2023-12-05 23:41:41"},
206
+ ]
207
+
208
+ result_max = 1
209
+ result_dict = {2: {49: 1}}
210
+
211
+ max_val, report_dict = utils.create_dict_for_report_view(tasks)
212
+ assert result_max == max_val
213
+ assert result_dict == report_dict
214
+
215
+
201
216
  def test_create_color_mapping():
202
- task_amount = [1, 3, 4, 0, 5, 8, 12, 16]
203
- max_val = max(task_amount)
217
+ task_amount = [1, 3, 4, 0, 5, 8, 12, 16, 25]
218
+ max_val = 16
204
219
  result = utils.create_color_mapping(amount_list=task_amount, max_val=max_val)
205
220
 
206
221
  assert result == [1, 1, 1, 0, 2, 2, 3, 4]
207
222
 
208
223
 
224
+ @pytest.mark.parametrize(
225
+ "date, expected_result",
226
+ [
227
+ ("2023-12-24", True),
228
+ ("2023-17-3", False),
229
+ ("30.05.2023", False),
230
+ ("30.05.223", False),
231
+ ],
232
+ )
233
+ def test_check_due_date_format(date, expected_result):
234
+ result = utils.check_due_date_format(date)
235
+
236
+ assert result is expected_result
237
+
238
+
239
+ @pytest.mark.parametrize(
240
+ "datetime, expected_result",
241
+ [
242
+ ("2023-12-24 00:00:00", "2023-12-24"),
243
+ ("", ""),
244
+ ],
245
+ )
246
+ def test_due_date_datetime_to_date(datetime, expected_result):
247
+ result = utils.due_date_datetime_to_date(datetime)
248
+
249
+ assert result == expected_result
250
+
251
+
252
+ @pytest.mark.parametrize(
253
+ "datetime, expected_result",
254
+ [
255
+ ("2023-12-24", "2023-12-24 23:59:59"),
256
+ ("", ""),
257
+ ],
258
+ )
259
+ def test_due_date_date_to_datetime(datetime, expected_result):
260
+ result = utils.due_date_date_to_datetime(datetime)
261
+
262
+ assert result == expected_result
263
+
264
+
265
+ def test_calculate_days_left_till_due():
266
+ fake_now = datetime.datetime(2023, 12, 10, 0, 0, 0)
267
+ test_time = "2023-12-24 23:59:59"
268
+ delta_days = 14
269
+
270
+ with freeze_time(fake_now):
271
+ result = utils.calculate_days_left_till_due(test_time)
272
+
273
+ assert result == delta_days
274
+
275
+
209
276
  # def test_main(capsys):
210
277
  # """CLI Tests"""
211
278
  # # capsys is a pytest fixture that allows asserts against stdout/stderr
Binary file
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes