Repository navigation
Typed task model - #1226
Typed task model#1226Lotram wants to merge 22 commits into
Conversation
ryneeverett
left a comment
There was a problem hiding this comment.
1. Using our own Task model decreases the dependency to taskw, and improves typing / readability, instead of using plain dicts. Having our own abstraction simplifies the changes needed to switch the dependency from taskw to taskchampion. ...If we proceed with this changes, I would then use Task even more in
db.py, and try avoid using dicts. We could also replace calls totaskw.task.FIELDSby our ownTaskobject
This makes sense to me in principle, but it doesn't seem like the decreased dependency on taskw has manifested in this PR. I'm kind of thinking a well-scoped PR might be focused on completely abstracting away taskw usage to prepare for #1078 . What do you think?
2. The `Issue` (and child classes) becomes less useful, it does not hold any specific logic, I suggest an implementation where it's merged into Service.
I think there is a bit of a principled distinction between the two (described in the original doc-comments) but it might not be useful and probably isn't consistently enforced. I also think it's going to be hard to evaluate whether this change is an improvement if it is done at the same time as the Task model. Maybe we can hold off on this in order to reduce the scope of the Task model transition and so that we can better focus on getting it right if/when we do it?
|
Thinking about this a bit more, I'd note that I think we are essentially on the same page. I see where removing UDA's from Issue makes that class even less useful and suggests elimination. I'd still suggest pushing that out to a separate PR though. |
Yes, as I see it, removing taskw dependency would be enabled by introducing our own But I definitely can remove the "Issue into Service" changes from this PR, and we'll do that later. |
Could you elaborate on this a little bit? I noticed that some of the naming was more consistent which i appreciated, but I'm assuming you mean something more abstract/conceptual... |
My point is to have a single "entrypoint" (not sure it's the right word here), the At some point, I think we'll also be able to add all the "update an existing task" logic inside that model (e.g. updating the tags, the annotations, etc) |
ryneeverett
left a comment
There was a problem hiding this comment.
Gotcha. I do see the benefits of centralizing validation. I think transitioning to the Task model is an acceptable PR scope.
c3a7f59 to
10d4493
Compare
|
@ryneeverett I finally finished working on this MR. As all the services used to have their own implementation (e.g. no shared taskwarrior field definition, I kept the |
Introduce bugwarrior.task, a pydantic description of a Taskwarrior record.
Every service now maps a foreign record to a Task and declares its UDAs as a Udas subclass. TaskConstructor is gone. Two behaviours change. An azuredevops work item with no priority now leaves adopriority empty. The bugzilla UDAs bugzillaneedinfo and bugzillaassignedon are always written, so a stale date is cleared. It also fixes annotations leaking between trello cards in the same list.
The UDA has been declared since 2016 and never populated: the creation timestamp goes to the generic entry field instead.
|
Sorry I've been too busy to look at this, but please rebase. |
10d4493 to
69f50dc
Compare
The three class methods which read the Udas model now share one prefix. A property would read better, but these are class methods and chaining classmethod with property was removed in python 3.13.
6c8d2f6 to
1383bf1
Compare
1b532e5 to
796f30d
Compare
Every service identifies a task by its UDAs, never by a generic field. A generic field also only works by accident: to_taskwarrior_data leaves out the generic fields the service did not set, so unique_identifier raises a KeyError as soon as one is missing. Check the unique key when the Udas subclass is created. Nothing else catches a misspelled name: unique_identifier is called from db.py during synchronization and from no test, so a service ships and fails on the user's machine.
9f51b84 to
3be18ec
Compare
367b95b to
2e9c3e5
Compare
| targets_udas = {} | ||
| for service in services: | ||
| targets_udas.update(get_service(service).ISSUE_CLASS.UDAS) | ||
| targets_udas.update(get_service(service).TASK_SCHEMA.serialize()) |
There was a problem hiding this comment.
What would you think about dropping prefixes from the Udas field names and automatically adding them here? My thought is it easier to enforce consistency and makes the UDA's classes more readable (githubtitle -> title).
| targets_udas.update(get_service(service).TASK_SCHEMA.serialize()) | |
| service = get_service(service) | |
| targets_udas.update({ | |
| f"{service.CONFIG_SCHEMA.service if service.CONFIG_SCHEMA.service != "azuredevops" else "ado"}{key}": value | |
| for key, value in service.TASK_SCHEMA.serialize()}) |
There was a problem hiding this comment.
To be honest, I think the best solution would be to compute a unique bugwarrior_id to identify each task in taskwarrior, then get rid of the prefixes entirely (e.g. an url should be called url, no matter the underlying service).
But your suggestion is reasonable, and a good first step towards the prefix removal
There was a problem hiding this comment.
I used a UDA_PREFIX attribute though, as we don't always have access to the service, if I'm not mistaken.
There was a problem hiding this comment.
This is not perfect, maybe I'll find a way to re-use the Config.service attribute (though it would be fixed by dropping the prefix entirely, too)
There was a problem hiding this comment.
The uda's were prefixed long before the UNIQUE_KEY method of differentiating bugwarrior-tracked tasks was developed. I'm guessing the main motivation was to avoid namespace conflicts with core attributes. Jira was one of the first services and I see id and status would conflict with the core attributes. But maybe only the conflicting fields ought to be prefixed? At the very least we'd want to add a Udas validator that makes sure no fields conflict with core attributes. IMO this is best left for another PR.
we don't always have access to the service
Huh? Do you mean in another context or this line in db.py?
This PR is a suggestion of data models refactoring.
Why ?
Issue(and child classes) becomes less useful, it does not hold any specific logic, I suggest an implementation where it's merged into Service.Service, record) and data inserted in taskwarriorWhat's inside this PR
TaskandUdasmodelsService/Issue, so we use that instead of plain dicts (indb.py,collect.pyetc)IssueinsideService, as there is no clear difference between the twoselfis only used to access the config) out ofServiceCommits 3 and 4 are optional, I think they're improvements, but not necessary.
I only modified Linear to demonstrate this.
The idea is not to review it in details for now, there are probably some bugs, but to discuss the overall shape of the changes.
What's next ?
If we proceed with this changes, I would then use Task even more in
db.py, and try avoid using dicts.We could also replace calls to
taskw.task.FIELDSby our ownTaskobject