backlogops 1.2__tar.gz → 1.3__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 (73) hide show
  1. {backlogops-1.2 → backlogops-1.3}/PKG-INFO +43 -9
  2. {backlogops-1.2 → backlogops-1.3}/README_pypi.md +40 -6
  3. {backlogops-1.2 → backlogops-1.3}/backlogops.egg-info/PKG-INFO +43 -9
  4. {backlogops-1.2 → backlogops-1.3}/backlogops.egg-info/SOURCES.txt +4 -0
  5. {backlogops-1.2 → backlogops-1.3}/backlogops.egg-info/requires.txt +2 -2
  6. {backlogops-1.2 → backlogops-1.3}/setup.py +3 -3
  7. {backlogops-1.2 → backlogops-1.3}/src/backlogops/__init__.py +19 -8
  8. {backlogops-1.2 → backlogops-1.3}/src/backlogops/backlog.py +7 -2
  9. {backlogops-1.2 → backlogops-1.3}/src/backlogops/backlog_helpers.py +39 -3
  10. {backlogops-1.2 → backlogops-1.3}/src/backlogops/backlog_ops_config.py +17 -6
  11. {backlogops-1.2 → backlogops-1.3}/src/backlogops/backlog_ops_wizard.py +64 -2
  12. {backlogops-1.2 → backlogops-1.3}/src/backlogops/backlog_releases.py +11 -3
  13. {backlogops-1.2 → backlogops-1.3}/src/backlogops/config_descriptions.py +38 -2
  14. backlogops-1.3/src/backlogops/default_story_points.py +371 -0
  15. {backlogops-1.2 → backlogops-1.3}/src/backlogops/demo_backlog.py +69 -16
  16. {backlogops-1.2 → backlogops-1.3}/src/backlogops/estimate_ready_date.py +70 -12
  17. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_order_releases.py +9 -8
  18. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_rank_move_keys.py +11 -11
  19. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_read.py +6 -13
  20. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_rename_releases.py +20 -19
  21. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_update_backlog.py +124 -96
  22. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_update_releases.py +13 -13
  23. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_write.py +261 -299
  24. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_write_fields.py +64 -7
  25. backlogops-1.3/src/backlogops/jira_write_format.py +173 -0
  26. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_write_releases.py +16 -15
  27. backlogops-1.3/src/backlogops/jira_write_status.py +136 -0
  28. backlogops-1.3/src/backlogops/jira_write_types.py +154 -0
  29. {backlogops-1.2 → backlogops-1.3}/src/backlogops/table_rows.py +26 -4
  30. backlogops-1.3/src/backlogops/use_story_points.py +76 -0
  31. {backlogops-1.2 → backlogops-1.3}/src/backlogops/wizard_helpers.py +109 -0
  32. {backlogops-1.2 → backlogops-1.3}/src/backlogops/wizard_navigator.py +17 -3
  33. backlogops-1.2/src/backlogops/jira_write_format.py +0 -101
  34. {backlogops-1.2 → backlogops-1.3}/LICENSE.txt +0 -0
  35. {backlogops-1.2 → backlogops-1.3}/backlogops.egg-info/dependency_links.txt +0 -0
  36. {backlogops-1.2 → backlogops-1.3}/backlogops.egg-info/top_level.txt +0 -0
  37. {backlogops-1.2 → backlogops-1.3}/pyproject.toml +0 -0
  38. {backlogops-1.2 → backlogops-1.3}/setup.cfg +0 -0
  39. {backlogops-1.2 → backlogops-1.3}/src/backlogops/apply_format_rules.py +0 -0
  40. {backlogops-1.2 → backlogops-1.3}/src/backlogops/available_teams.py +0 -0
  41. {backlogops-1.2 → backlogops-1.3}/src/backlogops/available_teams_config.py +0 -0
  42. {backlogops-1.2 → backlogops-1.3}/src/backlogops/backlog_in_release_order.py +0 -0
  43. {backlogops-1.2 → backlogops-1.3}/src/backlogops/backlog_releases_io.py +0 -0
  44. {backlogops-1.2 → backlogops-1.3}/src/backlogops/blo_version_reporter.py +0 -0
  45. {backlogops-1.2 → backlogops-1.3}/src/backlogops/config_editing.py +0 -0
  46. {backlogops-1.2 → backlogops-1.3}/src/backlogops/config_file_io.py +0 -0
  47. {backlogops-1.2 → backlogops-1.3}/src/backlogops/date_ranges.py +0 -0
  48. {backlogops-1.2 → backlogops-1.3}/src/backlogops/format_rules.py +0 -0
  49. {backlogops-1.2 → backlogops-1.3}/src/backlogops/io_config.py +0 -0
  50. {backlogops-1.2 → backlogops-1.3}/src/backlogops/io_preset_wizard.py +0 -0
  51. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_connect.py +0 -0
  52. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_io_config.py +0 -0
  53. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_rank_backlog.py +0 -0
  54. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_rank_by_keys.py +0 -0
  55. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_search.py +0 -0
  56. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_token.py +0 -0
  57. {backlogops-1.2 → backlogops-1.3}/src/backlogops/jira_wizard.py +0 -0
  58. {backlogops-1.2 → backlogops-1.3}/src/backlogops/key_list_io.py +0 -0
  59. {backlogops-1.2 → backlogops-1.3}/src/backlogops/levels.py +0 -0
  60. {backlogops-1.2 → backlogops-1.3}/src/backlogops/move_keys_first.py +0 -0
  61. {backlogops-1.2 → backlogops-1.3}/src/backlogops/name_list_io.py +0 -0
  62. {backlogops-1.2 → backlogops-1.3}/src/backlogops/no_text_io.py +0 -0
  63. {backlogops-1.2 → backlogops-1.3}/src/backlogops/order_by_dependencies.py +0 -0
  64. {backlogops-1.2 → backlogops-1.3}/src/backlogops/person.py +0 -0
  65. {backlogops-1.2 → backlogops-1.3}/src/backlogops/py.typed +0 -0
  66. {backlogops-1.2 → backlogops-1.3}/src/backlogops/release_backlog_updates.py +0 -0
  67. {backlogops-1.2 → backlogops-1.3}/src/backlogops/release_change_io.py +0 -0
  68. {backlogops-1.2 → backlogops-1.3}/src/backlogops/releases.py +0 -0
  69. {backlogops-1.2 → backlogops-1.3}/src/backlogops/rename_list_io.py +0 -0
  70. {backlogops-1.2 → backlogops-1.3}/src/backlogops/table_create.py +0 -0
  71. {backlogops-1.2 → backlogops-1.3}/src/backlogops/team.py +0 -0
  72. {backlogops-1.2 → backlogops-1.3}/src/backlogops/wizard_forms.py +0 -0
  73. {backlogops-1.2 → backlogops-1.3}/src/backlogops/work_hours.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: backlogops
3
- Version: 1.2
3
+ Version: 1.3
4
4
  Summary: Library with backlog operations.
5
5
  Author: Tom Björkholm
6
6
  Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
@@ -26,9 +26,9 @@ Requires-Dist: cryptography>=50.0.1
26
26
  Requires-Dist: jira[cli,opt]>=3.10.5
27
27
  Requires-Dist: tableio>=1.1
28
28
  Requires-Dist: tableio-cfg-json>=1.4
29
- Requires-Dist: wizard-ui-bridge[textual]>=1.3
29
+ Requires-Dist: wizard-ui-bridge[textual]>=1.4
30
30
  Requires-Dist: versionreporter>=0.4
31
- Requires-Dist: edit-cfg-json>=0.2.0
31
+ Requires-Dist: edit-cfg-json>=0.3.0
32
32
  Dynamic: author
33
33
  Dynamic: license-file
34
34
  Dynamic: requires-dist
@@ -77,6 +77,10 @@ The following functionality is available in all 3 packages:
77
77
  - Estimate ready date for the backlog items based on available teams, team
78
78
  velocity, vacation dates, periods with half time work, etc.
79
79
 
80
+ - Configure what a backlog item that nobody has estimated counts as, per backlog
81
+ item level, so that an unestimated item does not make the estimated dates too
82
+ optimistic.
83
+
80
84
  - Extract backlog keys at given backlog item levels.
81
85
 
82
86
  - Reorder the backlog so that the dependencies are satisfied.
@@ -111,7 +115,16 @@ The following functionality is available in all 3 packages:
111
115
  - Migrate an older configuration or preset file to the current file format.
112
116
 
113
117
  - A wizard to create a backlog-ops configuration file with the workforce, named
114
- input and output presets, level names, and status name mapping.
118
+ input and output presets, level names, status name mapping, the guess for
119
+ unestimated items, how the graphical user interface shows the data, and the
120
+ Jira integration.
121
+
122
+ - An editor showing a whole configuration file or a stand-alone preset file at
123
+ once, folded where it is deep, to change a single value without stepping
124
+ through the wizard.
125
+
126
+ - Encrypt the Jira API token to a pass-phrase-protected file, so that no
127
+ configuration file holds the token in clear text.
115
128
 
116
129
  - Read a backlog and releases from Jira into a backlog and release table.
117
130
 
@@ -130,6 +143,10 @@ The following functionality is available in all 3 packages:
130
143
  - Move backlog items to a chosen anchor in the Jira rank order, following a key
131
144
  list.
132
145
 
146
+ - Report what a Jira operation did not do. Every Jira result opens with what
147
+ Jira refused or what was skipped, so a value that was not written is visible
148
+ without reading the whole listing.
149
+
133
150
  ## The operating model
134
151
 
135
152
  The operating model that most of the functionality is designed for is that the
@@ -154,7 +171,10 @@ the library:
154
171
 
155
172
  - `title` The title of the backlog item. Required.
156
173
 
157
- - `story_points` The story points of the backlog item. Required.
174
+ - `story_points` The story points of the backlog item. Optional. An item with no
175
+ story points is one that nobody has estimated yet, and what such an item is
176
+ worked with when a completion date is estimated is configured. May be a
177
+ fraction, such as 0.5.
158
178
 
159
179
  - `status` The status of the backlog item. Required.
160
180
 
@@ -262,8 +282,10 @@ from backlogops import (
262
282
 
263
283
  - `read_backlog_ops_config`, `write_backlog_ops_config`,
264
284
  `get_backlog_ops_config`: read, write, and look up the top-level
265
- `BacklogOpsConfig` (workforce, named input and output presets, and the
266
- optional backlog item levels).
285
+ `BacklogOpsConfig` (workforce, named input and output presets, the
286
+ status-name map, the guess for unestimated items, the GUI display
287
+ settings, the Jira configuration, and the optional backlog item
288
+ levels).
267
289
 
268
290
  - `read_key_list`, `write_key_list`: read and write a list of keys.
269
291
 
@@ -295,6 +317,11 @@ from backlogops import (
295
317
  - `estimate_ready_date`, `set_plan_from_estimate`: estimate ready dates
296
318
  and set planned dates from the estimate.
297
319
 
320
+ - `DefaultStoryPoints`, `use_story_points`: what a backlog item that
321
+ nobody has estimated counts as, and the story points to work any one
322
+ item with. The estimate uses them, so an unestimated item does not
323
+ count as free.
324
+
298
325
  - `estimate_release_dates`, `release_plan_on_estimate`,
299
326
  `adjust_release_content`: estimate and plan release dates, and adjust
300
327
  release content to fit the planned dates.
@@ -321,14 +348,21 @@ from backlogops import (
321
348
  - `JiraIOConfig`, `JiraPreset`: the Jira connection and preset
322
349
  configuration.
323
350
 
351
+ - `format_add_result`, `format_backlog_updates`, `format_release_result`,
352
+ `format_release_updates`, `format_rank_result`, `format_order_result`,
353
+ `format_rename_result`: turn the result of a Jira operation into a
354
+ listing that opens with what Jira refused or what was skipped.
355
+ `report_has_problems` answers whether such a listing reports something
356
+ that did not happen, which is what marks it in a user interface.
357
+
324
358
  For the full set of public names see the API documentation linked above.
325
359
 
326
360
  ## Test summary
327
361
 
328
- - Test result: 2309 passed, 1 deselected in 58s
362
+ - Test result: 2555 passed, 1 deselected in 58s
329
363
  - No flake8 warnings.
330
364
  - No mypy errors found.
331
365
  - No pylint warnings.
332
366
  - No python layout warnings.
333
- - Built version(s): 1.2
367
+ - Built version(s): 1.3
334
368
  - Build and test using Python 3.14.7
@@ -41,6 +41,10 @@ The following functionality is available in all 3 packages:
41
41
  - Estimate ready date for the backlog items based on available teams, team
42
42
  velocity, vacation dates, periods with half time work, etc.
43
43
 
44
+ - Configure what a backlog item that nobody has estimated counts as, per backlog
45
+ item level, so that an unestimated item does not make the estimated dates too
46
+ optimistic.
47
+
44
48
  - Extract backlog keys at given backlog item levels.
45
49
 
46
50
  - Reorder the backlog so that the dependencies are satisfied.
@@ -75,7 +79,16 @@ The following functionality is available in all 3 packages:
75
79
  - Migrate an older configuration or preset file to the current file format.
76
80
 
77
81
  - A wizard to create a backlog-ops configuration file with the workforce, named
78
- input and output presets, level names, and status name mapping.
82
+ input and output presets, level names, status name mapping, the guess for
83
+ unestimated items, how the graphical user interface shows the data, and the
84
+ Jira integration.
85
+
86
+ - An editor showing a whole configuration file or a stand-alone preset file at
87
+ once, folded where it is deep, to change a single value without stepping
88
+ through the wizard.
89
+
90
+ - Encrypt the Jira API token to a pass-phrase-protected file, so that no
91
+ configuration file holds the token in clear text.
79
92
 
80
93
  - Read a backlog and releases from Jira into a backlog and release table.
81
94
 
@@ -94,6 +107,10 @@ The following functionality is available in all 3 packages:
94
107
  - Move backlog items to a chosen anchor in the Jira rank order, following a key
95
108
  list.
96
109
 
110
+ - Report what a Jira operation did not do. Every Jira result opens with what
111
+ Jira refused or what was skipped, so a value that was not written is visible
112
+ without reading the whole listing.
113
+
97
114
  ## The operating model
98
115
 
99
116
  The operating model that most of the functionality is designed for is that the
@@ -118,7 +135,10 @@ the library:
118
135
 
119
136
  - `title` The title of the backlog item. Required.
120
137
 
121
- - `story_points` The story points of the backlog item. Required.
138
+ - `story_points` The story points of the backlog item. Optional. An item with no
139
+ story points is one that nobody has estimated yet, and what such an item is
140
+ worked with when a completion date is estimated is configured. May be a
141
+ fraction, such as 0.5.
122
142
 
123
143
  - `status` The status of the backlog item. Required.
124
144
 
@@ -226,8 +246,10 @@ from backlogops import (
226
246
 
227
247
  - `read_backlog_ops_config`, `write_backlog_ops_config`,
228
248
  `get_backlog_ops_config`: read, write, and look up the top-level
229
- `BacklogOpsConfig` (workforce, named input and output presets, and the
230
- optional backlog item levels).
249
+ `BacklogOpsConfig` (workforce, named input and output presets, the
250
+ status-name map, the guess for unestimated items, the GUI display
251
+ settings, the Jira configuration, and the optional backlog item
252
+ levels).
231
253
 
232
254
  - `read_key_list`, `write_key_list`: read and write a list of keys.
233
255
 
@@ -259,6 +281,11 @@ from backlogops import (
259
281
  - `estimate_ready_date`, `set_plan_from_estimate`: estimate ready dates
260
282
  and set planned dates from the estimate.
261
283
 
284
+ - `DefaultStoryPoints`, `use_story_points`: what a backlog item that
285
+ nobody has estimated counts as, and the story points to work any one
286
+ item with. The estimate uses them, so an unestimated item does not
287
+ count as free.
288
+
262
289
  - `estimate_release_dates`, `release_plan_on_estimate`,
263
290
  `adjust_release_content`: estimate and plan release dates, and adjust
264
291
  release content to fit the planned dates.
@@ -285,14 +312,21 @@ from backlogops import (
285
312
  - `JiraIOConfig`, `JiraPreset`: the Jira connection and preset
286
313
  configuration.
287
314
 
315
+ - `format_add_result`, `format_backlog_updates`, `format_release_result`,
316
+ `format_release_updates`, `format_rank_result`, `format_order_result`,
317
+ `format_rename_result`: turn the result of a Jira operation into a
318
+ listing that opens with what Jira refused or what was skipped.
319
+ `report_has_problems` answers whether such a listing reports something
320
+ that did not happen, which is what marks it in a user interface.
321
+
288
322
  For the full set of public names see the API documentation linked above.
289
323
 
290
324
  ## Test summary
291
325
 
292
- - Test result: 2309 passed, 1 deselected in 58s
326
+ - Test result: 2555 passed, 1 deselected in 58s
293
327
  - No flake8 warnings.
294
328
  - No mypy errors found.
295
329
  - No pylint warnings.
296
330
  - No python layout warnings.
297
- - Built version(s): 1.2
331
+ - Built version(s): 1.3
298
332
  - Build and test using Python 3.14.7
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: backlogops
3
- Version: 1.2
3
+ Version: 1.3
4
4
  Summary: Library with backlog operations.
5
5
  Author: Tom Björkholm
6
6
  Author-email: Tom Björkholm <klausuler_linnet0q@icloud.com>
@@ -26,9 +26,9 @@ Requires-Dist: cryptography>=50.0.1
26
26
  Requires-Dist: jira[cli,opt]>=3.10.5
27
27
  Requires-Dist: tableio>=1.1
28
28
  Requires-Dist: tableio-cfg-json>=1.4
29
- Requires-Dist: wizard-ui-bridge[textual]>=1.3
29
+ Requires-Dist: wizard-ui-bridge[textual]>=1.4
30
30
  Requires-Dist: versionreporter>=0.4
31
- Requires-Dist: edit-cfg-json>=0.2.0
31
+ Requires-Dist: edit-cfg-json>=0.3.0
32
32
  Dynamic: author
33
33
  Dynamic: license-file
34
34
  Dynamic: requires-dist
@@ -77,6 +77,10 @@ The following functionality is available in all 3 packages:
77
77
  - Estimate ready date for the backlog items based on available teams, team
78
78
  velocity, vacation dates, periods with half time work, etc.
79
79
 
80
+ - Configure what a backlog item that nobody has estimated counts as, per backlog
81
+ item level, so that an unestimated item does not make the estimated dates too
82
+ optimistic.
83
+
80
84
  - Extract backlog keys at given backlog item levels.
81
85
 
82
86
  - Reorder the backlog so that the dependencies are satisfied.
@@ -111,7 +115,16 @@ The following functionality is available in all 3 packages:
111
115
  - Migrate an older configuration or preset file to the current file format.
112
116
 
113
117
  - A wizard to create a backlog-ops configuration file with the workforce, named
114
- input and output presets, level names, and status name mapping.
118
+ input and output presets, level names, status name mapping, the guess for
119
+ unestimated items, how the graphical user interface shows the data, and the
120
+ Jira integration.
121
+
122
+ - An editor showing a whole configuration file or a stand-alone preset file at
123
+ once, folded where it is deep, to change a single value without stepping
124
+ through the wizard.
125
+
126
+ - Encrypt the Jira API token to a pass-phrase-protected file, so that no
127
+ configuration file holds the token in clear text.
115
128
 
116
129
  - Read a backlog and releases from Jira into a backlog and release table.
117
130
 
@@ -130,6 +143,10 @@ The following functionality is available in all 3 packages:
130
143
  - Move backlog items to a chosen anchor in the Jira rank order, following a key
131
144
  list.
132
145
 
146
+ - Report what a Jira operation did not do. Every Jira result opens with what
147
+ Jira refused or what was skipped, so a value that was not written is visible
148
+ without reading the whole listing.
149
+
133
150
  ## The operating model
134
151
 
135
152
  The operating model that most of the functionality is designed for is that the
@@ -154,7 +171,10 @@ the library:
154
171
 
155
172
  - `title` The title of the backlog item. Required.
156
173
 
157
- - `story_points` The story points of the backlog item. Required.
174
+ - `story_points` The story points of the backlog item. Optional. An item with no
175
+ story points is one that nobody has estimated yet, and what such an item is
176
+ worked with when a completion date is estimated is configured. May be a
177
+ fraction, such as 0.5.
158
178
 
159
179
  - `status` The status of the backlog item. Required.
160
180
 
@@ -262,8 +282,10 @@ from backlogops import (
262
282
 
263
283
  - `read_backlog_ops_config`, `write_backlog_ops_config`,
264
284
  `get_backlog_ops_config`: read, write, and look up the top-level
265
- `BacklogOpsConfig` (workforce, named input and output presets, and the
266
- optional backlog item levels).
285
+ `BacklogOpsConfig` (workforce, named input and output presets, the
286
+ status-name map, the guess for unestimated items, the GUI display
287
+ settings, the Jira configuration, and the optional backlog item
288
+ levels).
267
289
 
268
290
  - `read_key_list`, `write_key_list`: read and write a list of keys.
269
291
 
@@ -295,6 +317,11 @@ from backlogops import (
295
317
  - `estimate_ready_date`, `set_plan_from_estimate`: estimate ready dates
296
318
  and set planned dates from the estimate.
297
319
 
320
+ - `DefaultStoryPoints`, `use_story_points`: what a backlog item that
321
+ nobody has estimated counts as, and the story points to work any one
322
+ item with. The estimate uses them, so an unestimated item does not
323
+ count as free.
324
+
298
325
  - `estimate_release_dates`, `release_plan_on_estimate`,
299
326
  `adjust_release_content`: estimate and plan release dates, and adjust
300
327
  release content to fit the planned dates.
@@ -321,14 +348,21 @@ from backlogops import (
321
348
  - `JiraIOConfig`, `JiraPreset`: the Jira connection and preset
322
349
  configuration.
323
350
 
351
+ - `format_add_result`, `format_backlog_updates`, `format_release_result`,
352
+ `format_release_updates`, `format_rank_result`, `format_order_result`,
353
+ `format_rename_result`: turn the result of a Jira operation into a
354
+ listing that opens with what Jira refused or what was skipped.
355
+ `report_has_problems` answers whether such a listing reports something
356
+ that did not happen, which is what marks it in a user interface.
357
+
324
358
  For the full set of public names see the API documentation linked above.
325
359
 
326
360
  ## Test summary
327
361
 
328
- - Test result: 2309 passed, 1 deselected in 58s
362
+ - Test result: 2555 passed, 1 deselected in 58s
329
363
  - No flake8 warnings.
330
364
  - No mypy errors found.
331
365
  - No pylint warnings.
332
366
  - No python layout warnings.
333
- - Built version(s): 1.2
367
+ - Built version(s): 1.3
334
368
  - Build and test using Python 3.14.7
@@ -23,6 +23,7 @@ src/backlogops/config_descriptions.py
23
23
  src/backlogops/config_editing.py
24
24
  src/backlogops/config_file_io.py
25
25
  src/backlogops/date_ranges.py
26
+ src/backlogops/default_story_points.py
26
27
  src/backlogops/demo_backlog.py
27
28
  src/backlogops/estimate_ready_date.py
28
29
  src/backlogops/format_rules.py
@@ -45,6 +46,8 @@ src/backlogops/jira_write.py
45
46
  src/backlogops/jira_write_fields.py
46
47
  src/backlogops/jira_write_format.py
47
48
  src/backlogops/jira_write_releases.py
49
+ src/backlogops/jira_write_status.py
50
+ src/backlogops/jira_write_types.py
48
51
  src/backlogops/key_list_io.py
49
52
  src/backlogops/levels.py
50
53
  src/backlogops/move_keys_first.py
@@ -60,6 +63,7 @@ src/backlogops/rename_list_io.py
60
63
  src/backlogops/table_create.py
61
64
  src/backlogops/table_rows.py
62
65
  src/backlogops/team.py
66
+ src/backlogops/use_story_points.py
63
67
  src/backlogops/wizard_forms.py
64
68
  src/backlogops/wizard_helpers.py
65
69
  src/backlogops/wizard_navigator.py
@@ -3,6 +3,6 @@ cryptography>=50.0.1
3
3
  jira[cli,opt]>=3.10.5
4
4
  tableio>=1.1
5
5
  tableio-cfg-json>=1.4
6
- wizard-ui-bridge[textual]>=1.3
6
+ wizard-ui-bridge[textual]>=1.4
7
7
  versionreporter>=0.4
8
- edit-cfg-json>=0.2.0
8
+ edit-cfg-json>=0.3.0
@@ -5,7 +5,7 @@ from setuptools import setup
5
5
 
6
6
  setup(
7
7
  name='backlogops',
8
- version='1.2',
8
+ version='1.3',
9
9
  description='Library with backlog operations.',
10
10
  author='Tom Björkholm',
11
11
  author_email='klausuler_linnet0q@icloud.com',
@@ -19,8 +19,8 @@ setup(
19
19
  'jira[cli,opt] >= 3.10.5',
20
20
  'tableio >= 1.1',
21
21
  'tableio-cfg-json >= 1.4',
22
- 'wizard-ui-bridge[textual] >= 1.3',
22
+ 'wizard-ui-bridge[textual] >= 1.4',
23
23
  'versionreporter >= 0.4',
24
- 'edit-cfg-json >= 0.2.0',
24
+ 'edit-cfg-json >= 0.3.0',
25
25
  ]
26
26
  )
@@ -36,6 +36,8 @@ from backlogops.config_editing import EDIT_SETTINGS, descriptions_for
36
36
  from backlogops.config_file_io import (
37
37
  CONFIG_EXTENSION, io_preset_class, read_io_preset, safe_write_config)
38
38
  from backlogops.date_ranges import check_date_range, check_no_overlap
39
+ from backlogops.default_story_points import (
40
+ DefaultStoryPointLevel, DefaultStoryPoints)
39
41
  from backlogops.demo_backlog import get_demo_backlog
40
42
  from backlogops.estimate_ready_date import (
41
43
  estimate_ready_date, set_plan_from_estimate)
@@ -72,11 +74,14 @@ from backlogops.jira_update_releases import (
72
74
  UpdatedReleasesInJira, format_release_updates, update_releases_in_jira)
73
75
  from backlogops.jira_write import (
74
76
  AddedToJira, ExistsInJiraError, FailedItem, ItemNotInJiraError,
75
- OnExistingKey, OnMissingKey, StatusMismatch, UnknownIssueTypeError,
77
+ OnExistingKey, OnMissingKey,
76
78
  add_backlog_to_jira, apply_jira_keys, jira_custom_fields,
77
79
  jira_editable_fields)
78
- from backlogops.jira_write_fields import FailedLink
79
- from backlogops.jira_write_format import format_add_result
80
+ from backlogops.jira_write_fields import FailedField, FailedLink
81
+ from backlogops.jira_write_status import StatusMismatch
82
+ from backlogops.jira_write_types import UnknownIssueTypeError
83
+ from backlogops.jira_write_format import (
84
+ format_add_result, report_has_problems)
80
85
  from backlogops.jira_write_releases import (
81
86
  AddedReleasesToJira, FailedRelease, ReleaseExistsError,
82
87
  add_releases_to_jira, format_release_result)
@@ -105,6 +110,8 @@ from backlogops.table_rows import (
105
110
  display_level_rows, fold_level_name, item_to_row, map_column_order,
106
111
  release_to_row, row_to_item, row_to_release)
107
112
  from backlogops.team import FteException, Membership, Team
113
+ from backlogops.use_story_points import find_keys_with_children, \
114
+ use_story_points
108
115
  from backlogops.work_hours import (
109
116
  CompanyWorkHours, DEFAULT_WORK_WEEK, ExceptionWorkHours, ScheduleWorkHours,
110
117
  WeekDay)
@@ -116,9 +123,11 @@ __all__ = [
116
123
  'CLEAR_TOKEN_WARNING', 'CONFIG_DESCRIPTIONS', 'CONFIG_EXTENSION',
117
124
  'CompanyWorkHours', 'DEFAULT_LEVELS',
118
125
  'DEFAULT_WORK_WEEK', 'DEF_BACKLOG_COLUMN_MAP', 'DEF_RELEASE_COLUMN_MAP',
119
- 'DEF_STATUS_INPUT_MAP', 'DependencyMode', 'EDIT_SETTINGS',
126
+ 'DEF_STATUS_INPUT_MAP', 'DefaultStoryPointLevel', 'DefaultStoryPoints',
127
+ 'DependencyMode', 'EDIT_SETTINGS',
120
128
  'ExceptionWorkHours',
121
- 'ExistsInJiraError', 'FailedItem', 'FailedLink', 'FailedRelease',
129
+ 'ExistsInJiraError', 'FailedField', 'FailedItem', 'FailedLink',
130
+ 'FailedRelease',
122
131
  'FailedRename', 'FileExistsCb', 'FormatRules', 'FteException',
123
132
  'GUI_DESCRIPTIONS', 'GuiDisplayConfig', 'INPUT_DESCRIPTIONS',
124
133
  'InputFormatConfig', 'ItemNotInJiraError', 'JIRA_DESCRIPTIONS',
@@ -145,7 +154,8 @@ __all__ = [
145
154
  'display_level_order', 'display_level_rows',
146
155
  'encrypt_token_file',
147
156
  'encrypt_token_to_file', 'estimate_ready_date', 'estimate_release_dates',
148
- 'event_finish', 'event_start', 'find_cycle', 'fold_level_name',
157
+ 'event_finish', 'event_start', 'find_cycle', 'find_keys_with_children',
158
+ 'fold_level_name',
149
159
  'format_add_result', 'format_backlog', 'format_backlog_updates',
150
160
  'format_content_changes', 'format_date_changes', 'format_order_result',
151
161
  'format_rank_result', 'format_release_result', 'format_release_updates',
@@ -163,10 +173,11 @@ __all__ = [
163
173
  'read_backlog_ops_config', 'read_backlog_releases', 'read_io_preset',
164
174
  'read_jira_from_config', 'read_key_list', 'read_name_list', 'read_renames',
165
175
  'release_plan_on_estimate', 'release_to_row', 'rename_release_in_jira',
166
- 'rename_releases_in_jira', 'resolve_input_config', 'resolve_jql',
176
+ 'rename_releases_in_jira', 'report_has_problems',
177
+ 'resolve_input_config', 'resolve_jql',
167
178
  'resolve_output_config', 'row_to_item', 'row_to_release',
168
179
  'safe_write_config', 'set_plan_from_estimate', 'updatable_backlog_fields',
169
- 'update_backlog_in_jira', 'update_releases_in_jira',
180
+ 'update_backlog_in_jira', 'update_releases_in_jira', 'use_story_points',
170
181
  'write_available_teams', 'write_backlog_ops_config',
171
182
  'write_backlog_releases', 'write_content_changes', 'write_date_changes',
172
183
  'write_key_list']
@@ -61,7 +61,12 @@ class BacklogItem: # pylint: disable=too-many-instance-attributes
61
61
  not contain any of the characters , . ; : ( ) [ ] { }.
62
62
  level: The level of the backlog item. Required. Must be an integer.
63
63
  title: The title of the backlog item. Required.
64
- story_points: The story points of the backlog item.
64
+ story_points: The story points of the backlog item, or None
65
+ when nobody has estimated it yet. May be a
66
+ fraction, such as 0.5. What the work on the
67
+ item is counted as, which is another matter,
68
+ is answered by
69
+ :func:`backlogops.use_story_points`.
65
70
  status: The status of the backlog item.
66
71
  parent_key: The key of the parent backlog item. Optional.
67
72
  Must exist as a key in the backlog.
@@ -100,7 +105,7 @@ class BacklogItem: # pylint: disable=too-many-instance-attributes
100
105
  key: str
101
106
  level: int
102
107
  title: str
103
- story_points: int
108
+ story_points: Optional[float]
104
109
  status: Status
105
110
  parent_key: Optional[str] = None
106
111
  release: Optional[str] = None
@@ -128,14 +128,19 @@ def accepts_none(data_type: object) -> bool:
128
128
  def _matches_class(value: object, data_type: type) -> bool:
129
129
  """Return True if a value matches a plain (unparameterized) class.
130
130
 
131
- A boolean is rejected where an integer is expected, because a
131
+ A boolean is rejected where a number is expected, because a
132
132
  boolean is rarely a meaningful story point or numeric value here.
133
+ An integer is accepted where a ``float`` is expected, because that
134
+ is what the type hint itself means: a hint of ``float`` covers a
135
+ whole number as well, as the type checker reads it.
133
136
  A ``datetime`` is rejected where a ``date`` is expected, even though
134
137
  ``datetime`` is a subclass of ``date``, so that a date field never
135
138
  silently holds a value carrying a time component.
136
139
  """
137
140
  if data_type is int:
138
141
  return isinstance(value, int) and not isinstance(value, bool)
142
+ if data_type is float:
143
+ return isinstance(value, (int, float)) and not isinstance(value, bool)
139
144
  if data_type is date:
140
145
  return isinstance(value, date) and not isinstance(value, datetime)
141
146
  return isinstance(value, data_type)
@@ -422,14 +427,43 @@ def convert_to_str(field_name: str, value: object,
422
427
  report_wrong_type(field_name, value, str, stderr_file)
423
428
 
424
429
 
430
+ def convert_to_float(field_name: str, value: object,
431
+ stderr_file: TextIO = sys.stderr) -> float:
432
+ """Convert a whole or decimal number to a ``float``.
433
+
434
+ A value that is already a float is returned unchanged, and a whole
435
+ number is widened to a float, so that story points written as ``5``
436
+ and as ``5.0`` are stored as one type. A boolean is rejected, even
437
+ though Python counts it as a whole number. A string is rejected as
438
+ well: a numeric field of a backlog item holds a number, and the
439
+ reading of a table cell that holds text is where such text is
440
+ turned into a number.
441
+
442
+ Args:
443
+ field_name: The name of the field being converted.
444
+ value: The number to convert.
445
+ stderr_file: The file to report errors to.
446
+
447
+ Returns:
448
+ The converted float.
449
+
450
+ Raises:
451
+ TypeError: If the value is not a whole or decimal number.
452
+ """
453
+ if isinstance(value, bool) or not isinstance(value, (int, float)):
454
+ report_wrong_type(field_name, value, float, stderr_file)
455
+ return float(value)
456
+
457
+
425
458
  def convert_field_value(field_name: str, value: object, data_type: object,
426
459
  stderr_file: TextIO = sys.stderr) -> object:
427
460
  """Convert and validate a single field value against its type hint.
428
461
 
429
462
  ``None`` is accepted for optional fields. Enum fields are converted
430
463
  with :func:`convert_to_enum`, date fields with :func:`convert_to_date`,
431
- string fields with :func:`convert_to_str`, and all other fields are
432
- checked with :func:`value_matches_type`.
464
+ string fields with :func:`convert_to_str`, float fields with
465
+ :func:`convert_to_float`, and all other fields are checked with
466
+ :func:`value_matches_type`.
433
467
 
434
468
  Args:
435
469
  field_name: The name of the field being converted.
@@ -453,6 +487,8 @@ def convert_field_value(field_name: str, value: object, data_type: object,
453
487
  return convert_to_date(field_name, value, stderr_file)
454
488
  if inner_type is str:
455
489
  return convert_to_str(field_name, value, stderr_file)
490
+ if inner_type is float:
491
+ return convert_to_float(field_name, value, stderr_file)
456
492
  if not value_matches_type(value, data_type):
457
493
  report_wrong_type(field_name, value, data_type, stderr_file)
458
494
  return value
@@ -15,6 +15,9 @@ item levels:
15
15
  * ``gui_display`` holds the GUI column-rename and level-display settings;
16
16
  * ``jira`` is the Jira input and output configuration, bridged to JSON by
17
17
  :class:`backlogops.jira_io_config.JiraIOConfig`;
18
+ * ``default_story_points`` is what a backlog item that nobody has
19
+ estimated counts as, bridged to JSON by
20
+ :class:`backlogops.default_story_points.DefaultStoryPoints`;
18
21
  * ``levels`` is the optional list of backlog item levels. It is omitted
19
22
  from the file while it is ``None``; :meth:`BacklogOpsConfig.get_levels`
20
23
  then falls back to :data:`backlogops.levels.DEFAULT_LEVELS`. An empty
@@ -45,6 +48,7 @@ from backlogops.available_teams import AvailableTeams
45
48
  from backlogops.available_teams_config import AvailableTeamsConfig
46
49
  from backlogops.backlog import Status
47
50
  from backlogops.backlog_helpers import report_bad_value, report_wrong_type
51
+ from backlogops.default_story_points import DefaultStoryPoints
48
52
  from backlogops.io_config import GuiDisplayConfig, InputFormatConfig, \
49
53
  OutputFormatConfig, _StatusMapValidator
50
54
  from backlogops.jira_io_config import JiraIOConfig
@@ -165,9 +169,10 @@ def _levels_to_json(value: object, *, path_text: str, stderr_file: TextIO,
165
169
  class _BacklogOpsReadOldConfig(ReadOldConfiguration):
166
170
  """Normalize older backlog-ops configuration files on read.
167
171
 
168
- Two shape changes are accepted. The named input and output preset
169
- maps were added after the first released file; an empty map is
170
- supplied when an old file omits them. The workforce members were
172
+ Two shape changes are accepted. Sections added after a released file,
173
+ such as the named preset maps and the default story points, are
174
+ supplied empty when an old file omits them, which for the default
175
+ story points means guessing nothing. The workforce members were
171
176
  later moved from the top level into a nested ``available_teams``
172
177
  object; the move rules relocate them so old files keep loading.
173
178
  """
@@ -186,7 +191,7 @@ class _BacklogOpsReadOldConfig(ReadOldConfiguration):
186
191
  """Return defaults for the members old files may omit."""
187
192
  return {('input_configs',): {}, ('output_configs',): {},
188
193
  ('gui_display',): {}, ('status_input_map',): {},
189
- ('jira',): {}}
194
+ ('jira',): {}, ('default_story_points',): {}}
190
195
 
191
196
 
192
197
  DEF_STATUS_INPUT_MAP: dict[str, Status] = {
@@ -241,6 +246,9 @@ class BacklogOpsConfig(Config): # pylint: disable=too-many-instance-attributes
241
246
  stderr_file=stderr_file,
242
247
  member_name=member_path(member_name, 'jira'))
243
248
  self.levels: Optional[list[Level]] = None
249
+ self.default_story_points: DefaultStoryPoints = DefaultStoryPoints(
250
+ stderr_file=stderr_file,
251
+ member_name=member_path(member_name, 'default_story_points'))
244
252
  self._unchecked_dicts = ['status_input_map']
245
253
  Config.__init__(self, from_json_data_text=from_json_data_text,
246
254
  from_json_filename=from_json_filename,
@@ -254,7 +262,7 @@ class BacklogOpsConfig(Config): # pylint: disable=too-many-instance-attributes
254
262
 
255
263
  @override
256
264
  def nested_configs(self) -> NestedConfigs:
257
- """Declare the workforce and the named TableIO preset maps."""
265
+ """Declare the workforce, the preset maps and the other sections."""
258
266
  member = ConfigNesting(kind=ConfigNestingKind.MEMBER,
259
267
  config_type=AvailableTeamsConfig)
260
268
  in_cfg = ConfigNesting(kind=ConfigNestingKind.DICT_VALUE,
@@ -265,8 +273,11 @@ class BacklogOpsConfig(Config): # pylint: disable=too-many-instance-attributes
265
273
  config_type=GuiDisplayConfig)
266
274
  jira = ConfigNesting(kind=ConfigNestingKind.MEMBER,
267
275
  config_type=JiraIOConfig)
276
+ points = ConfigNesting(kind=ConfigNestingKind.MEMBER,
277
+ config_type=DefaultStoryPoints)
268
278
  return {'available_teams': member, 'input_configs': in_cfg,
269
- 'output_configs': out_cfg, 'gui_display': gui, 'jira': jira}
279
+ 'output_configs': out_cfg, 'gui_display': gui, 'jira': jira,
280
+ 'default_story_points': points}
270
281
 
271
282
  @override
272
283
  def _omit_none_from_json(self) -> list[str]: