targetprocess-py 0.1.0__py3-none-any.whl
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.
- targetprocess/__init__.py +231 -0
- targetprocess/_assignables.py +162 -0
- targetprocess/_base.py +318 -0
- targetprocess/_content.py +287 -0
- targetprocess/_dates.py +70 -0
- targetprocess/_entity_types.py +33 -0
- targetprocess/_generals.py +324 -0
- targetprocess/_joins.py +217 -0
- targetprocess/_lookups.py +477 -0
- targetprocess/_nested.py +223 -0
- targetprocess/_observability.py +368 -0
- targetprocess/client.py +430 -0
- targetprocess/exceptions.py +147 -0
- targetprocess/models.py +121 -0
- targetprocess/py.typed +1 -0
- targetprocess/request_handler.py +724 -0
- targetprocess/resources/__init__.py +76 -0
- targetprocess/resources/assignments.py +29 -0
- targetprocess/resources/attachments.py +164 -0
- targetprocess/resources/base.py +563 -0
- targetprocess/resources/bugs.py +20 -0
- targetprocess/resources/comments.py +23 -0
- targetprocess/resources/custom_activities.py +56 -0
- targetprocess/resources/custom_fields.py +27 -0
- targetprocess/resources/custom_rules.py +28 -0
- targetprocess/resources/entities.py +433 -0
- targetprocess/resources/entity_states.py +20 -0
- targetprocess/resources/entity_types.py +61 -0
- targetprocess/resources/epics.py +20 -0
- targetprocess/resources/features.py +20 -0
- targetprocess/resources/iterations.py +20 -0
- targetprocess/resources/priorities.py +85 -0
- targetprocess/resources/processes.py +65 -0
- targetprocess/resources/projects.py +20 -0
- targetprocess/resources/relation_types.py +59 -0
- targetprocess/resources/relations.py +34 -0
- targetprocess/resources/releases.py +20 -0
- targetprocess/resources/requests.py +20 -0
- targetprocess/resources/role_efforts.py +21 -0
- targetprocess/resources/roles.py +52 -0
- targetprocess/resources/severities.py +53 -0
- targetprocess/resources/tasks.py +20 -0
- targetprocess/resources/team_assignments.py +21 -0
- targetprocess/resources/team_iterations.py +24 -0
- targetprocess/resources/teams.py +20 -0
- targetprocess/resources/terms.py +28 -0
- targetprocess/resources/test_cases.py +20 -0
- targetprocess/resources/times.py +392 -0
- targetprocess/resources/user_stories.py +20 -0
- targetprocess/resources/users.py +20 -0
- targetprocess/resources/workflows.py +27 -0
- targetprocess/response_parser.py +113 -0
- targetprocess/transport.py +116 -0
- targetprocess/types.py +56 -0
- targetprocess_py-0.1.0.dist-info/METADATA +476 -0
- targetprocess_py-0.1.0.dist-info/RECORD +58 -0
- targetprocess_py-0.1.0.dist-info/WHEEL +4 -0
- targetprocess_py-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Entity type name validation, shared by every layer that interpolates one."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
_ENTITY_TYPE_RE = re.compile(r"[A-Za-z][A-Za-z0-9_]*")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def require_entity_type(entity_type: str) -> None:
|
|
9
|
+
"""Refuse an entity type name that is not a plain TP identifier.
|
|
10
|
+
|
|
11
|
+
An entity type name is interpolated straight into a request path (and,
|
|
12
|
+
in ``priorities.for_entity_type``, into a ``where=`` filter). On the
|
|
13
|
+
generic ``entities`` resource it is caller-supplied at runtime - often
|
|
14
|
+
echoing a server-returned ``ResourceType`` - so anything beyond a bare
|
|
15
|
+
identifier changes what the request does: ``"UserStories/57731"`` turns
|
|
16
|
+
a create into an update of that entity, and a trailing slash or stray
|
|
17
|
+
whitespace slips past a name-keyed guard. TP collection names are plain
|
|
18
|
+
identifiers, so that is all that is accepted - the same stance as
|
|
19
|
+
``RequestHandler._require_instance_path``: enforced, not merely
|
|
20
|
+
documented.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
entity_type: The entity type name to check
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
ValueError: ``entity_type`` is not letters, digits and underscores
|
|
27
|
+
starting with a letter.
|
|
28
|
+
"""
|
|
29
|
+
if not _ENTITY_TYPE_RE.fullmatch(entity_type):
|
|
30
|
+
raise ValueError(
|
|
31
|
+
"entity_type must be a TP entity type name (letters, digits, "
|
|
32
|
+
f"underscore): {entity_type!r}"
|
|
33
|
+
)
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"""The ``General`` types that are not work items.
|
|
2
|
+
|
|
3
|
+
``Project``, ``Team``, ``Release``, ``Iteration``, ``TeamIteration`` and
|
|
4
|
+
``TestCase`` derive from TP's ``General`` base but not from ``Assignable``, so
|
|
5
|
+
they inherit :class:`targetprocess._base.GeneralEntity` and declare their own
|
|
6
|
+
effort and planning fields rather than the assignable set.
|
|
7
|
+
|
|
8
|
+
Several carry ``Effort``/``EffortCompleted``/``EffortToDo``/``Progress``/
|
|
9
|
+
``Units`` as roll-ups of the work items inside them, identically. They are
|
|
10
|
+
repeated per class rather than hoisted into a shared mixin because TP declares
|
|
11
|
+
no such base: the grouping would be this library's invention, and the next type
|
|
12
|
+
to gain or lose one of the five would have to be pulled back out of it. The
|
|
13
|
+
repetition is the cost of each class listing exactly what its own ``/meta``
|
|
14
|
+
declares, which is the property ``scripts/check_model_coverage.py`` checks.
|
|
15
|
+
|
|
16
|
+
Re-exported by :mod:`targetprocess.models`, which stays the import surface
|
|
17
|
+
callers use.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from pydantic import Field
|
|
21
|
+
|
|
22
|
+
from targetprocess._base import GeneralEntity
|
|
23
|
+
from targetprocess._dates import TPDateTime
|
|
24
|
+
from targetprocess._nested import AssignedUsers, EntityRef, RefWithImportance
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Project(GeneralEntity):
|
|
28
|
+
"""Project entity for organisational structure.
|
|
29
|
+
|
|
30
|
+
The container every other entity hangs off. Carries its own workflow state
|
|
31
|
+
and process, the effort roll-up of the work inside it, and the branding
|
|
32
|
+
fields TP renders in the project picker.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
effort: Rolled-up effort
|
|
36
|
+
effort_completed: Rolled-up completed effort
|
|
37
|
+
effort_todo: Rolled-up remaining effort
|
|
38
|
+
progress: Completion ratio derived from effort (0.0 - 1.0)
|
|
39
|
+
units: The unit effort is expressed in (e.g. "h", "pt")
|
|
40
|
+
is_active: Whether the project is active
|
|
41
|
+
is_product: Whether the project is a product rather than a project
|
|
42
|
+
is_private: Whether the project is hidden from non-members
|
|
43
|
+
abbreviation: Short code TP renders in compact views
|
|
44
|
+
mail_reply_address: Address inbound request email is accepted on
|
|
45
|
+
color: Project colour TP renders in the UI
|
|
46
|
+
planned_start_date: Planned start date/time
|
|
47
|
+
planned_end_date: Planned end date/time
|
|
48
|
+
last_state_change_date: When the entity state last changed
|
|
49
|
+
forecast_end_date: TP's projected completion date
|
|
50
|
+
anticipated_end_date: Manually anticipated completion date
|
|
51
|
+
lead_time: Days from creation to completion
|
|
52
|
+
cycle_time: Days from work starting to completion
|
|
53
|
+
entity_state: Current workflow state reference
|
|
54
|
+
process: Process (workflow definition) reference
|
|
55
|
+
program: Program reference
|
|
56
|
+
company: Company reference
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
# Effort roll-up
|
|
60
|
+
effort: float | None = Field(default=None, alias="Effort", description="Rolled-up effort")
|
|
61
|
+
effort_completed: float | None = Field(
|
|
62
|
+
default=None, alias="EffortCompleted", description="Completed effort"
|
|
63
|
+
)
|
|
64
|
+
effort_todo: float | None = Field(
|
|
65
|
+
default=None, alias="EffortToDo", description="Remaining effort"
|
|
66
|
+
)
|
|
67
|
+
progress: float | None = Field(default=None, alias="Progress", description="Completion ratio")
|
|
68
|
+
units: str | None = Field(default=None, alias="Units", description="Effort unit")
|
|
69
|
+
|
|
70
|
+
# Flags and branding
|
|
71
|
+
is_active: bool | None = Field(default=None, alias="IsActive", description="Active status")
|
|
72
|
+
is_product: bool | None = Field(default=None, alias="IsProduct", description="Is a product")
|
|
73
|
+
is_private: bool | None = Field(default=None, alias="IsPrivate", description="Is private")
|
|
74
|
+
abbreviation: str | None = Field(
|
|
75
|
+
default=None, alias="Abbreviation", description="Short project code"
|
|
76
|
+
)
|
|
77
|
+
mail_reply_address: str | None = Field(
|
|
78
|
+
default=None, alias="MailReplyAddress", description="Inbound mail address"
|
|
79
|
+
)
|
|
80
|
+
color: str | None = Field(default=None, alias="Color", description="Display colour")
|
|
81
|
+
|
|
82
|
+
# Date tracking
|
|
83
|
+
planned_start_date: TPDateTime | None = Field(
|
|
84
|
+
default=None, alias="PlannedStartDate", description="Planned start"
|
|
85
|
+
)
|
|
86
|
+
planned_end_date: TPDateTime | None = Field(
|
|
87
|
+
default=None, alias="PlannedEndDate", description="Planned end"
|
|
88
|
+
)
|
|
89
|
+
last_state_change_date: TPDateTime | None = Field(
|
|
90
|
+
default=None, alias="LastStateChangeDate", description="Last state change"
|
|
91
|
+
)
|
|
92
|
+
forecast_end_date: TPDateTime | None = Field(
|
|
93
|
+
default=None, alias="ForecastEndDate", description="Forecast end"
|
|
94
|
+
)
|
|
95
|
+
anticipated_end_date: TPDateTime | None = Field(
|
|
96
|
+
default=None, alias="AnticipatedEndDate", description="Anticipated end"
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Flow metrics
|
|
100
|
+
lead_time: float | None = Field(default=None, alias="LeadTime", description="Lead time (days)")
|
|
101
|
+
cycle_time: float | None = Field(
|
|
102
|
+
default=None, alias="CycleTime", description="Cycle time (days)"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Relationships
|
|
106
|
+
entity_state: EntityRef | None = Field(
|
|
107
|
+
default=None, alias="EntityState", description="Workflow state"
|
|
108
|
+
)
|
|
109
|
+
process: EntityRef | None = Field(default=None, alias="Process", description="Process")
|
|
110
|
+
program: EntityRef | None = Field(default=None, alias="Program", description="Program")
|
|
111
|
+
company: EntityRef | None = Field(default=None, alias="Company", description="Company")
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class Team(GeneralEntity):
|
|
115
|
+
"""Team entity for organisational structure.
|
|
116
|
+
|
|
117
|
+
A bare ``General`` upstream - TP adds only the activity flag and the
|
|
118
|
+
identity TP renders in team pickers.
|
|
119
|
+
|
|
120
|
+
Attributes:
|
|
121
|
+
is_active: Whether the team is active
|
|
122
|
+
abbreviation: Short code TP renders in compact views
|
|
123
|
+
emoji_icon: Emoji shorthand TP renders beside the team name
|
|
124
|
+
icon_uri: Path to the team's icon image
|
|
125
|
+
icon: Legacy icon field (deprecated upstream; prefer icon_uri)
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
is_active: bool | None = Field(default=None, alias="IsActive", description="Active status")
|
|
129
|
+
abbreviation: str | None = Field(
|
|
130
|
+
default=None, alias="Abbreviation", description="Short team code"
|
|
131
|
+
)
|
|
132
|
+
emoji_icon: str | None = Field(default=None, alias="EmojiIcon", description="Emoji icon")
|
|
133
|
+
icon_uri: str | None = Field(default=None, alias="IconUri", description="Icon image path")
|
|
134
|
+
icon: str | None = Field(
|
|
135
|
+
default=None, alias="Icon", description="Legacy icon (deprecated upstream)"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class Release(GeneralEntity):
|
|
140
|
+
"""Release entity for planning and tracking releases.
|
|
141
|
+
|
|
142
|
+
A dated window grouping iterations, with the effort roll-up of everything
|
|
143
|
+
scheduled into it. ``start_date`` and ``end_date`` are required upstream.
|
|
144
|
+
|
|
145
|
+
Attributes:
|
|
146
|
+
effort: Rolled-up effort
|
|
147
|
+
effort_completed: Rolled-up completed effort
|
|
148
|
+
effort_todo: Rolled-up remaining effort
|
|
149
|
+
progress: Completion ratio derived from effort (0.0 - 1.0)
|
|
150
|
+
units: The unit effort is expressed in (e.g. "h", "pt")
|
|
151
|
+
is_current: Whether this is the current release
|
|
152
|
+
forecast_end_date: TP's projected completion date
|
|
153
|
+
process: Process (workflow definition) reference
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
effort: float | None = Field(default=None, alias="Effort", description="Rolled-up effort")
|
|
157
|
+
effort_completed: float | None = Field(
|
|
158
|
+
default=None, alias="EffortCompleted", description="Completed effort"
|
|
159
|
+
)
|
|
160
|
+
effort_todo: float | None = Field(
|
|
161
|
+
default=None, alias="EffortToDo", description="Remaining effort"
|
|
162
|
+
)
|
|
163
|
+
progress: float | None = Field(default=None, alias="Progress", description="Completion ratio")
|
|
164
|
+
units: str | None = Field(default=None, alias="Units", description="Effort unit")
|
|
165
|
+
is_current: bool | None = Field(
|
|
166
|
+
default=None, alias="IsCurrent", description="Is the current release"
|
|
167
|
+
)
|
|
168
|
+
forecast_end_date: TPDateTime | None = Field(
|
|
169
|
+
default=None, alias="ForecastEndDate", description="Forecast end"
|
|
170
|
+
)
|
|
171
|
+
process: EntityRef | None = Field(default=None, alias="Process", description="Process")
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class Iteration(GeneralEntity):
|
|
175
|
+
"""Iteration entity for agile sprints.
|
|
176
|
+
|
|
177
|
+
A project-level sprint inside a ``Release``. TP scopes iterations to the
|
|
178
|
+
release, not to a team - the team-scoped equivalent is
|
|
179
|
+
:class:`TeamIteration`.
|
|
180
|
+
|
|
181
|
+
Attributes:
|
|
182
|
+
effort: Rolled-up effort
|
|
183
|
+
effort_completed: Rolled-up completed effort
|
|
184
|
+
effort_todo: Rolled-up remaining effort
|
|
185
|
+
progress: Completion ratio derived from effort (0.0 - 1.0)
|
|
186
|
+
units: The unit effort is expressed in (e.g. "h", "pt")
|
|
187
|
+
velocity: Effort completed per unit time
|
|
188
|
+
duration: Iteration length in days
|
|
189
|
+
is_current: Whether this is the current iteration
|
|
190
|
+
can_be_finished: Whether TP will allow the iteration to be closed
|
|
191
|
+
forecast_end_date: TP's projected completion date
|
|
192
|
+
release: Release reference
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
effort: float | None = Field(default=None, alias="Effort", description="Rolled-up effort")
|
|
196
|
+
effort_completed: float | None = Field(
|
|
197
|
+
default=None, alias="EffortCompleted", description="Completed effort"
|
|
198
|
+
)
|
|
199
|
+
effort_todo: float | None = Field(
|
|
200
|
+
default=None, alias="EffortToDo", description="Remaining effort"
|
|
201
|
+
)
|
|
202
|
+
progress: float | None = Field(default=None, alias="Progress", description="Completion ratio")
|
|
203
|
+
units: str | None = Field(default=None, alias="Units", description="Effort unit")
|
|
204
|
+
velocity: float | None = Field(default=None, alias="Velocity", description="Velocity")
|
|
205
|
+
duration: int | None = Field(default=None, alias="Duration", description="Length in days")
|
|
206
|
+
is_current: bool | None = Field(
|
|
207
|
+
default=None, alias="IsCurrent", description="Is the current iteration"
|
|
208
|
+
)
|
|
209
|
+
can_be_finished: bool | None = Field(
|
|
210
|
+
default=None, alias="CanBeFinished", description="Can be closed"
|
|
211
|
+
)
|
|
212
|
+
forecast_end_date: TPDateTime | None = Field(
|
|
213
|
+
default=None, alias="ForecastEndDate", description="Forecast end"
|
|
214
|
+
)
|
|
215
|
+
release: EntityRef | None = Field(default=None, alias="Release", description="Release")
|
|
216
|
+
|
|
217
|
+
# Not declared in TP's /meta for Iteration and rejected by include= there;
|
|
218
|
+
# kept because removing a published field would break callers. The
|
|
219
|
+
# team-scoped sprint is TeamIteration.
|
|
220
|
+
team: EntityRef | None = Field(
|
|
221
|
+
default=None, alias="Team", description="Team (absent upstream; prefer TeamIteration)"
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class TeamIteration(GeneralEntity):
|
|
226
|
+
"""Team-specific iteration (sprint) entity.
|
|
227
|
+
|
|
228
|
+
In TP each team owns its own iterations; a TeamIteration carries the
|
|
229
|
+
team's sprint window, effort/velocity/capacity, and its Release.
|
|
230
|
+
|
|
231
|
+
Attributes:
|
|
232
|
+
effort: Rolled-up effort
|
|
233
|
+
effort_completed: Rolled-up completed effort
|
|
234
|
+
effort_todo: Rolled-up remaining effort
|
|
235
|
+
progress: Completion ratio derived from effort (0.0 - 1.0)
|
|
236
|
+
units: The unit effort is expressed in (e.g. "h", "pt")
|
|
237
|
+
velocity: Effort completed per unit time
|
|
238
|
+
capacity: Effort the team can absorb in the window
|
|
239
|
+
duration: Iteration length in days
|
|
240
|
+
is_current: Whether this is the team's current iteration
|
|
241
|
+
can_be_finished: Whether TP will allow the iteration to be closed
|
|
242
|
+
forecast_end_date: TP's projected completion date
|
|
243
|
+
team: Team reference
|
|
244
|
+
release: Release reference
|
|
245
|
+
"""
|
|
246
|
+
|
|
247
|
+
effort: float | None = Field(default=None, alias="Effort", description="Rolled-up effort")
|
|
248
|
+
effort_completed: float | None = Field(
|
|
249
|
+
default=None, alias="EffortCompleted", description="Completed effort"
|
|
250
|
+
)
|
|
251
|
+
effort_todo: float | None = Field(
|
|
252
|
+
default=None, alias="EffortToDo", description="Remaining effort"
|
|
253
|
+
)
|
|
254
|
+
progress: float | None = Field(default=None, alias="Progress", description="Completion ratio")
|
|
255
|
+
units: str | None = Field(default=None, alias="Units", description="Effort unit")
|
|
256
|
+
velocity: float | None = Field(default=None, alias="Velocity", description="Team velocity")
|
|
257
|
+
capacity: float | None = Field(default=None, alias="Capacity", description="Team capacity")
|
|
258
|
+
duration: int | None = Field(default=None, alias="Duration", description="Length in days")
|
|
259
|
+
is_current: bool | None = Field(
|
|
260
|
+
default=None, alias="IsCurrent", description="Is the current iteration"
|
|
261
|
+
)
|
|
262
|
+
can_be_finished: bool | None = Field(
|
|
263
|
+
default=None, alias="CanBeFinished", description="Can be closed"
|
|
264
|
+
)
|
|
265
|
+
forecast_end_date: TPDateTime | None = Field(
|
|
266
|
+
default=None, alias="ForecastEndDate", description="Forecast end"
|
|
267
|
+
)
|
|
268
|
+
team: EntityRef | None = Field(default=None, alias="Team", description="Team")
|
|
269
|
+
release: EntityRef | None = Field(default=None, alias="Release", description="Release")
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class TestCase(GeneralEntity):
|
|
273
|
+
"""TestCase entity for quality assurance.
|
|
274
|
+
|
|
275
|
+
A ``General`` rather than an ``Assignable``: a test case has no effort, no
|
|
276
|
+
iteration and no workflow state - its status is the outcome of its last
|
|
277
|
+
run.
|
|
278
|
+
|
|
279
|
+
Attributes:
|
|
280
|
+
last_run_status: Outcome of the most recent run (e.g. "Passed")
|
|
281
|
+
last_run_date: When the test case was last run
|
|
282
|
+
last_failure_comment: Comment recorded against the last failure
|
|
283
|
+
last_status: Legacy boolean pass flag (deprecated; prefer last_run_status)
|
|
284
|
+
steps: Legacy free-text steps (deprecated upstream)
|
|
285
|
+
success: Legacy free-text expected result (deprecated upstream)
|
|
286
|
+
priority: Priority reference, scoped to this entity type
|
|
287
|
+
user_story: Parent user story reference (deprecated upstream)
|
|
288
|
+
"""
|
|
289
|
+
|
|
290
|
+
last_run_status: str | None = Field(
|
|
291
|
+
default=None, alias="LastRunStatus", description="Last run outcome"
|
|
292
|
+
)
|
|
293
|
+
last_run_date: TPDateTime | None = Field(
|
|
294
|
+
default=None, alias="LastRunDate", description="Last run date/time"
|
|
295
|
+
)
|
|
296
|
+
last_failure_comment: str | None = Field(
|
|
297
|
+
default=None, alias="LastFailureComment", description="Last failure comment"
|
|
298
|
+
)
|
|
299
|
+
last_status: bool | None = Field(
|
|
300
|
+
default=None, alias="LastStatus", description="Legacy pass flag (deprecated upstream)"
|
|
301
|
+
)
|
|
302
|
+
steps: str | None = Field(
|
|
303
|
+
default=None, alias="Steps", description="Legacy steps (deprecated upstream)"
|
|
304
|
+
)
|
|
305
|
+
success: str | None = Field(
|
|
306
|
+
default=None, alias="Success", description="Legacy expected result (deprecated upstream)"
|
|
307
|
+
)
|
|
308
|
+
priority: RefWithImportance | None = Field(
|
|
309
|
+
default=None, alias="Priority", description="Priority"
|
|
310
|
+
)
|
|
311
|
+
user_story: EntityRef | None = Field(
|
|
312
|
+
default=None,
|
|
313
|
+
alias="UserStory",
|
|
314
|
+
description="Parent user story (deprecated upstream)",
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# Neither is declared in TP's /meta for TestCase, and include= rejects both
|
|
318
|
+
# there; kept because removing a published field would break callers.
|
|
319
|
+
entity_state: EntityRef | None = Field(
|
|
320
|
+
default=None, alias="EntityState", description="Workflow state (absent upstream)"
|
|
321
|
+
)
|
|
322
|
+
assigned_user: AssignedUsers | None = Field(
|
|
323
|
+
default=None, alias="AssignedUser", description="Assigned users (absent upstream)"
|
|
324
|
+
)
|
targetprocess/_joins.py
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"""The join entities that connect two records rather than describing one.
|
|
2
|
+
|
|
3
|
+
``Assignment``, ``TeamAssignment``, ``RoleEffort``, ``Relation`` and ``Time``
|
|
4
|
+
each pair an ``Assignable`` with a user, team, role or another entity. None
|
|
5
|
+
carries a ``Name``, and none sits in TP's ``General`` hierarchy, so all extend
|
|
6
|
+
:class:`targetprocess._base.Entity` directly.
|
|
7
|
+
|
|
8
|
+
Re-exported by :mod:`targetprocess.models`, which stays the import surface
|
|
9
|
+
callers use.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from pydantic import Field
|
|
13
|
+
|
|
14
|
+
from targetprocess._base import Entity
|
|
15
|
+
from targetprocess._dates import TPDateTime
|
|
16
|
+
from targetprocess._nested import EntityRef, UserRef
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Assignment(Entity):
|
|
20
|
+
"""User-to-work-item role assignment (join entity).
|
|
21
|
+
|
|
22
|
+
Pairs a user (``GeneralUser``) with a ``Role`` on an ``Assignable`` -
|
|
23
|
+
the authoritative record of who is assigned to a work item and in which
|
|
24
|
+
capacity (``Owner`` only records who created it).
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
general_user: Assigned user reference
|
|
28
|
+
role: Role reference
|
|
29
|
+
assignable: Assignable (work item) reference
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
general_user: UserRef | None = Field(
|
|
33
|
+
default=None, alias="GeneralUser", description="Assigned user"
|
|
34
|
+
)
|
|
35
|
+
role: EntityRef | None = Field(default=None, alias="Role", description="Role")
|
|
36
|
+
assignable: EntityRef | None = Field(
|
|
37
|
+
default=None, alias="Assignable", description="Assignable (work item)"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TeamAssignment(Entity):
|
|
42
|
+
"""Team-to-work-item assignment (join entity).
|
|
43
|
+
|
|
44
|
+
Assigns a Team to an Assignable over a time window, carrying the
|
|
45
|
+
assignment's entity state.
|
|
46
|
+
|
|
47
|
+
Attributes:
|
|
48
|
+
start_date: Assignment start date/time
|
|
49
|
+
end_date: Assignment end date/time
|
|
50
|
+
team: Team reference
|
|
51
|
+
assignable: Assignable (work item) reference
|
|
52
|
+
entity_state: Workflow state reference
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
# Date tracking
|
|
56
|
+
start_date: TPDateTime | None = Field(
|
|
57
|
+
default=None, alias="StartDate", description="Start date/time"
|
|
58
|
+
)
|
|
59
|
+
end_date: TPDateTime | None = Field(default=None, alias="EndDate", description="End date/time")
|
|
60
|
+
|
|
61
|
+
# Relationships
|
|
62
|
+
team: EntityRef | None = Field(default=None, alias="Team", description="Team")
|
|
63
|
+
assignable: EntityRef | None = Field(
|
|
64
|
+
default=None, alias="Assignable", description="Assignable (work item)"
|
|
65
|
+
)
|
|
66
|
+
entity_state: EntityRef | None = Field(
|
|
67
|
+
default=None, alias="EntityState", description="Workflow state"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class RoleEffort(Entity):
|
|
72
|
+
"""Per-role effort allocation on an Assignable (join entity).
|
|
73
|
+
|
|
74
|
+
Breaks an Assignable's effort down by Role.
|
|
75
|
+
|
|
76
|
+
Attributes:
|
|
77
|
+
initial_estimate: Initial effort estimate >= 0
|
|
78
|
+
effort: Total effort >= 0
|
|
79
|
+
effort_completed: Completed effort >= 0
|
|
80
|
+
effort_todo: Remaining effort >= 0
|
|
81
|
+
time_spent: Time spent >= 0
|
|
82
|
+
time_remain: Time remaining >= 0
|
|
83
|
+
assignable: Assignable (work item) reference
|
|
84
|
+
role: Role reference
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# Effort / time tracking
|
|
88
|
+
initial_estimate: float | None = Field(
|
|
89
|
+
default=None, alias="InitialEstimate", ge=0, description="Initial estimate"
|
|
90
|
+
)
|
|
91
|
+
effort: float | None = Field(default=None, alias="Effort", ge=0, description="Total effort")
|
|
92
|
+
effort_completed: float | None = Field(
|
|
93
|
+
default=None, alias="EffortCompleted", ge=0, description="Completed effort"
|
|
94
|
+
)
|
|
95
|
+
effort_todo: float | None = Field(
|
|
96
|
+
default=None, alias="EffortToDo", ge=0, description="Remaining effort"
|
|
97
|
+
)
|
|
98
|
+
time_spent: float | None = Field(
|
|
99
|
+
default=None, alias="TimeSpent", ge=0, description="Time spent"
|
|
100
|
+
)
|
|
101
|
+
time_remain: float | None = Field(
|
|
102
|
+
default=None, alias="TimeRemain", ge=0, description="Time remaining"
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Relationships
|
|
106
|
+
assignable: EntityRef | None = Field(
|
|
107
|
+
default=None, alias="Assignable", description="Assignable (work item)"
|
|
108
|
+
)
|
|
109
|
+
role: EntityRef | None = Field(default=None, alias="Role", description="Role")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class Relation(Entity):
|
|
113
|
+
"""Entity-to-entity relation (join entity).
|
|
114
|
+
|
|
115
|
+
Links two entities, typed by a ``RelationType`` (Dependency, Blocker,
|
|
116
|
+
Relation, Duplicate, ...). The direction carries meaning: the source is the
|
|
117
|
+
origin of the dependency - in a Blocker relation the source is the blocking
|
|
118
|
+
item and the target the blocked one.
|
|
119
|
+
|
|
120
|
+
TP exposes the same pair twice. ``Master``/``Slave`` are the original names
|
|
121
|
+
and are marked deprecated in ``/meta``; ``Inbound``/``Outbound`` are the
|
|
122
|
+
current ones. They are the same two records - ``Inbound`` mirrors
|
|
123
|
+
``Master`` and ``Outbound`` mirrors ``Slave`` - so prefer the latter pair in
|
|
124
|
+
new code.
|
|
125
|
+
|
|
126
|
+
Attributes:
|
|
127
|
+
inbound: Source entity reference
|
|
128
|
+
outbound: Target entity reference
|
|
129
|
+
master: Source entity reference (deprecated upstream; prefer inbound)
|
|
130
|
+
slave: Target entity reference (deprecated upstream; prefer outbound)
|
|
131
|
+
relation_type: Relation-type reference
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
# Relationships
|
|
135
|
+
inbound: EntityRef | None = Field(default=None, alias="Inbound", description="Source entity")
|
|
136
|
+
outbound: EntityRef | None = Field(default=None, alias="Outbound", description="Target entity")
|
|
137
|
+
master: EntityRef | None = Field(
|
|
138
|
+
default=None, alias="Master", description="Source entity (deprecated upstream)"
|
|
139
|
+
)
|
|
140
|
+
slave: EntityRef | None = Field(
|
|
141
|
+
default=None, alias="Slave", description="Target entity (deprecated upstream)"
|
|
142
|
+
)
|
|
143
|
+
relation_type: EntityRef | None = Field(
|
|
144
|
+
default=None, alias="RelationType", description="Relation type"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class Time(Entity):
|
|
149
|
+
"""Time entry logged against an Assignable (join entity).
|
|
150
|
+
|
|
151
|
+
Records spent and remaining hours for a User against an Assignable on a
|
|
152
|
+
given date.
|
|
153
|
+
|
|
154
|
+
``assignable`` is the general reference; TP additionally exposes a narrower
|
|
155
|
+
back-reference per work-item type, of which exactly one is populated for
|
|
156
|
+
any given entry (a ``CustomActivity`` entry, for instance, has a null
|
|
157
|
+
``assignable``). They are declared so an entry's origin is readable without
|
|
158
|
+
a second fetch.
|
|
159
|
+
|
|
160
|
+
Attributes:
|
|
161
|
+
spent: Hours spent >= 0
|
|
162
|
+
remain: Hours remaining >= 0
|
|
163
|
+
is_estimation: Entry records an estimate rather than actual time
|
|
164
|
+
date: Date/time the work is logged against
|
|
165
|
+
description: Free-text description of the work
|
|
166
|
+
assignable: Assignable (work item) reference
|
|
167
|
+
user: User the time is logged for
|
|
168
|
+
project: Project reference (TP derives it from the Assignable)
|
|
169
|
+
role: Role reference
|
|
170
|
+
user_story: User story the entry was logged against, if any
|
|
171
|
+
task: Task the entry was logged against, if any
|
|
172
|
+
bug: Bug the entry was logged against, if any
|
|
173
|
+
request: Request the entry was logged against, if any
|
|
174
|
+
test_plan: Test plan the entry was logged against, if any
|
|
175
|
+
test_plan_run: Test plan run the entry was logged against, if any
|
|
176
|
+
custom_activity: Custom activity the entry was logged against, if any
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
# Effort / time tracking
|
|
180
|
+
spent: float | None = Field(default=None, alias="Spent", ge=0, description="Hours spent")
|
|
181
|
+
remain: float | None = Field(default=None, alias="Remain", ge=0, description="Hours remaining")
|
|
182
|
+
is_estimation: bool | None = Field(
|
|
183
|
+
default=None, alias="IsEstimation", description="Entry is an estimation"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# Date tracking
|
|
187
|
+
date: TPDateTime | None = Field(default=None, alias="Date", description="Date/time logged")
|
|
188
|
+
|
|
189
|
+
# Content
|
|
190
|
+
description: str | None = Field(default=None, alias="Description", description="Description")
|
|
191
|
+
|
|
192
|
+
# Relationships
|
|
193
|
+
assignable: EntityRef | None = Field(
|
|
194
|
+
default=None, alias="Assignable", description="Assignable (work item)"
|
|
195
|
+
)
|
|
196
|
+
user: UserRef | None = Field(default=None, alias="User", description="User")
|
|
197
|
+
project: EntityRef | None = Field(default=None, alias="Project", description="Project")
|
|
198
|
+
role: EntityRef | None = Field(default=None, alias="Role", description="Role")
|
|
199
|
+
|
|
200
|
+
# Narrow back-references: at most one is populated per entry.
|
|
201
|
+
user_story: EntityRef | None = Field(
|
|
202
|
+
default=None, alias="UserStory", description="User story logged against"
|
|
203
|
+
)
|
|
204
|
+
task: EntityRef | None = Field(default=None, alias="Task", description="Task logged against")
|
|
205
|
+
bug: EntityRef | None = Field(default=None, alias="Bug", description="Bug logged against")
|
|
206
|
+
request: EntityRef | None = Field(
|
|
207
|
+
default=None, alias="Request", description="Request logged against"
|
|
208
|
+
)
|
|
209
|
+
test_plan: EntityRef | None = Field(
|
|
210
|
+
default=None, alias="TestPlan", description="Test plan logged against"
|
|
211
|
+
)
|
|
212
|
+
test_plan_run: EntityRef | None = Field(
|
|
213
|
+
default=None, alias="TestPlanRun", description="Test plan run logged against"
|
|
214
|
+
)
|
|
215
|
+
custom_activity: EntityRef | None = Field(
|
|
216
|
+
default=None, alias="CustomActivity", description="Custom activity logged against"
|
|
217
|
+
)
|