-
Notifications
You must be signed in to change notification settings - Fork 168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Core #668
New Core #668
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it is late here, not so throughout basic look at the diff, mostly about the implementation itself.
I like that properties are now being used.
- Not exactly related, but I want to add a function or module that generates a large dataset of tasks, tags and saved searches with random words and properties. Something more real and dynamic than 'mmmm mmmm mmmmmmm' :p
There is a stress test script in the scripts folder, but it uses an old currently removed DBus interface.
Ok too late here, good night.
|
||
def save_file(self, path: str) -> None: | ||
|
||
temp_file = path + '__' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using tempfile.mkstemp
might be better, just in case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're not actually creating the file there, just figuring out the name. Later we rename the main file into the temp name before saving.
encoding='UTF-8') | ||
|
||
except (IOError, FileNotFoundError): | ||
log.error('Could not write XML file at %r', path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering about passing errors. Like imagine if you exit GTG and for some reason you can't write the data. We could then display a dialog box telling the user that and the user could decide not to exit GTG to maybe export the precious tasks somewhere else.
GTG/core/datastore2.py
Outdated
except PermissionError: | ||
log.debug('Not allowed to open: %r. Trying next.', filepath) | ||
continue | ||
|
||
except etree.XMLSyntaxError as error: | ||
log.debug('Syntax error in %r. %r. Trying next.', | ||
filepath, error) | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe save that as well and maybe report to the user? Like another dialog box saying that it found files but couldn't open them (and thus loaded the defaulted one)
@Neui thanks for the quick review! I'll hopefully get to these by the weekend.
What I'm thinking about is a module that fills up the datastore and we can use from the dev console, then we can write that to a xml file to profile and test. About errors, I kept swinging between letting the exceptions happen and get caught at a higher level or trying to manage the errors somehow. Maybe this can tie with your work on the error handler? |
I think letting it throw exception is better (unless it does something like trying all files while trying to open the database).
The error handler more for generic, unexpected errors and is a bit technical for normal end-users. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only commented on what I seem to understand the best which are the tasks stuff.
All in all it seems so much cleaner 👍 :)
|
||
return task | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both method below from_xml
and to_xml
seems misplaced, don't they ? I may be mistaking but I see them more belonging in an xml related module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is that each store class is responsible for its xml representation. So taskstore reads/writes <tasklist>
tags, tagstore does taglist
and so on. Then the Datastore pulls them all together to read/write the entire file.
Quick update: I did most of the suggested changes. I've also converted the dataclasses and store objects to GObjects and I've started adding signals. Will squash the Does anyone know if there's a performance hit for connecting lots of signals? For instance if we were to add signals to task objects and connect them in the taskstore. Would it be slow if there were +1000 task objects? |
53e1b84
to
23121b5
Compare
d07d0f2
to
a507306
Compare
Hey @zeddo123 o/, I've completed almost everything in this branch. I think it's a good time to talk about how to implement recurring tasks, do you have any ideas? I remember we talked about a python library to parse dates on some other ticket. I've added an overview doc here: And the new Task class and TaskStore are here: |
According to #645 (comment) it was dateutil. |
Great, I'll try the new core and write up a small doc of how we could do repeating tasks. A while ago, I've made some experiments with dateutil. I found myself writing less code for repeating tasks overall. To get the next occurrence, I only had to do: rruleset.after(today, True) # to get the date
rruleset.exdate(self.task.due_date) # to exclude the previous date |
I thought we could first agree on the related fields that repeating tasks should have. Here's what I came up with: Fields related to repeating tasksAll of these fields should cover the issues we've had with repeating tasks.
XML example<repeating enabled="true">
<repeats_on>ON_DUE</repeats_on>
<next_tid>234234-234234-234234-234-234</next_tid>
<timestamp>23-04-2020</timestamp>
<count>3</count>
<rules>
<rule>
<freq>TUE</freq>
<start>05-02-2020</start>
</rule>
<rule>
<freq>WEEKLY</freq>
<start>05-02-2020</start>
</rule>
</rules>
</repeating> We could also make a dedicated |
If I may, rrule casting to string might be simplified to great extent. Considering the following snippet : >>> from dateutil import rrule
>>> rrule.rrulestr('RRULE:FREQ=MONTHLY')
<dateutil.rrule.rrule at 0x7fc5427e0b50>
>>> str(rrule.rrulestr('RRULE:FREQ=MONTHLY'))
'DTSTART:20210905T231505\nRRULE:FREQ=MONTHLY' And considering the <repeating enabled="true">RRULE:FREQ=MONTHLY</repeating> removing the need to parse out the actual rule in the xml.
As stated here and there I'm really not in favor of cloning task for the sake of the repeating task feature. I would add to the list of benefit from another implementation that we would skip the whole "keeping-track-of-previous-iteration" thingy that is then mandatory and adds a lot of complexity to (among other thing) the xml payload. |
That might work for one repeating term. However if we had more than one, they would have different
I'm not that attached to cloning tasks either. On the other hand, users might rely on having a history of the tasks they've done. |
Rrule allow you various concurrent repetition, see here, twice a week on Tuesday and Thursday
If That would cover several repetition in a single term (weekly / monthly and all) but it wouldn't allow various repetition term (somehow weekly and monthly for example). Is that something we want ?
The history is an interesting point. There is a feature in the caldav spec where you exclude occurrences but nothing to actually keep track of history. In the same way, we could mark history as a list of passed occurrences. It's definitely not handled by the Although, a simpler way to look at it would be : history are just all occurrences from TL;DR I feel it adds in complexity to an already complex feature. |
@zeddo123 I like where this is going!
Is there a reason to have a specific update for the repeating fields, instead of using the
That's a good question. Multiple repetition terms would be a powerful feature, but it would also increase complexity. Are there any good use cases?
What would happen if the user changes the recurring term? Say going from weekly to monthly? Would that "obliterate" the previously done tasks from history? Maybe we should keep track of closed occurrences (their date). That would probably bloat the file too, so we would have to include them in the method that purges tasks. |
I can't say what we should do, but taking example on various implementation of Caldav, when the recursion is changed, either the But again, do we need this history ? We don't keep it for any other value change (category, status, or anything).
A simple way to look at that is that would be that all closed occurrences, are those that happened between |
I guess not. with dateutil begin powerful enough we might get a way with using
I tried to think about some cases where it might be needed, but I could find any. @nekohayo might have some thoughts on this.
As an alternative to cloning tasks, this has less bloat. Instead of having many duplicated tasks, we would have a (very) long task. The downside is displaying the history. Could we make a "meta" task? (a task that appears in the trees, but isn't really a task) |
Mostly for statistics, or to see if you payed that bill that you were supposed to pay.
Yup, with this branch we are now in "anything goes" territory. Ideally we would always use the stores as |
12fb8c8
to
34f5f08
Compare
Ah that makes sense, I'll change that too |
34f5f08
to
23eaa9b
Compare
Alright, fixed most of the issues. Still need to take care of backends |
b494b80
to
4228a95
Compare
@Neui pushed all the changes you suggested now. The |
c1ac45d
to
4670621
Compare
I've been thinking about this, and I am not sure if we should drop cloning tasks. one behaviour that I liked when repeating tasks were cloned is that they had their separate description. For instance, if I had a repeating task The discussions about repeating tasks have been all over the place, we probably should stick to a single thread. |
Yeah it might be better to stick with what we know, at least for the initial port. |
@zeddo123 the eagle has landed. Feel free to hack on the repeating dates there. |
This is it! The new core, at least the first part of it.
Note that this isn't plugged into GTG at all. You can only interact with it through unit tests and the developer console.
This is heavily WIP and subject to a lot of change. I also
push --force
a lot. Also this doesn't include any UI changes that will be necessary to actually plug this into gtg.Inviting @Neui @jaesivsm @leio @zeddo123 to chime in on this. No pressure, it's not a blocker for 0.6. Let me know what you think of the API, internals, etc. ☕
New stuff
dataclasses into GObject subclasses and thestores into nested list models, and get that sweet sweet performance.(Maybe we can do the former now and just be done with it?)Not done yet
Missing unit tests for all the sorting and filteringI think task and tag purging should be here too (in the appropiate store classes)Signals. I haven't added any Gtk signals yet, as I need to research them more thorougly. This probably means all the store classes will have to subclass GObject.Not exactly related, but I want to add a function or module that generates a large dataset of tasks, tags and saved searches with random words and properties. Something more real and dynamic than 'mmmm mmmm mmmmmmm' :pMore documentation, examples, "spit and polish" stuff, etc`Testing
You can run tests with the usual
./run-tests
. Or enable the Developer Console plugin and press F12 to open it.From there import whatever modules and classes you want to play with. Almost all of them work independently. You need to give
TaskStore.from_xml()
aTagStore
.Examples:
Here's a one-liner import for the datastore and the xml to make life easier:
Here's a one-liner to init a datastore and fill it with random data (500 tasks):