-
Notifications
You must be signed in to change notification settings - Fork 49
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
Loader with aggregation and visual loading state #555
Loader with aggregation and visual loading state #555
Conversation
Instead of querying documents again when toggling subsets, just reuse previous fetched result.
To improve the performance of tree view.
Hmmm, just had a stab on merging #550, seems not an easy task. |
painter = QtGui.QPainter(self.viewport()) | ||
rect = event.rect() | ||
rect = QtCore.QRectF(rect.topLeft(), rect.bottomRight()) | ||
qtext_opt = QtGui.QTextOption(QtCore.Qt.AlignHCenter | |
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.
line break after binary operator
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.
Either before or after line break, Hound barks. 😠
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 use line break before so operators are on new line (both won't work with hound if hound is not set ;) ).
I would personally in this case use:
qtext_opt = QtGui.QTextOption(
QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter
)
{"$group": {"_id": "$parent", | ||
"_version_id": {"$last": "$_id"}, | ||
"name": {"$last": "$name"}, | ||
"data": {"$last": "$data"}, |
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 would add "type" key here, but don't have explanation why :)
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.
Sure :D
_subsets.append(subset) | ||
_ids.append(subset["_id"]) | ||
|
||
_pipeline = [ |
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.
Would be great if there is (e.g. in avalon.lib) function for this pipeline to be usable in multiple places.
def last_version_pipeline(subset_ids):
return [
# Find all versions of those subsets
{"$match": {"type": "version", "parent": {"$in": subset_ids}}},
...
]
But it is only nice to have, because it is not used in other places yet.
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 it could be in the avalon.io
module. 🤔
def __init__(self, parent=None): | ||
super(SubsetTreeView, self).__init__(parent=parent) | ||
loading_gif = os.path.dirname(style.__file__) + "/svg/spinner-200.svg" | ||
spinner = QtSvg.QSvgRenderer(loading_gif) |
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.
My experience with svg in Qt is that it is slow in comparison to png or gif. Recommendation is to implement rotating QLabel with png, on the other side I guess that one svg won't affect Qt much.
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.
Yep, there's only one, and it's animation playback will be stopped once the loading is completed. So yeah, I think we are safe :P
some of the first level field may not be presented. | ||
|
||
""" | ||
def _fetch(): |
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.
_fetch
should be class method, there is not much reason to have it inside.
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 guess it's there because it acts more like a local lambda written as a function.
Also, if it were put on the class it shouldn't be a classmethod right? Because it uses variables/functions of the instance of the class inside of it (not how it refers to self). So if put on the class it would be a regular method.
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.
Also, if it were put on the class it shouldn't be a classmethod right?
I meant as object method def _fetch(self):
, not as class method, my fault.
it acts more like a local lambda written as a function
I see advantage of lamda but there's no advantage of that here, all _fetch
need is self
. Method fetch_subset_and_version
has 4 lines in fact. All what these lines do, is preparation and launching another method in thread, but because the definition of launched method is inside it's harder to read (for me) what's really happening inside.
This is "formatting" comment of my preferences. I have no ambition to change mindset because I know it's hard to change mine :)
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.
Looks right to me. Nesting a function tells me that it is only useful to the parent function, which seems to be the case here. If you put it in the class or instance, I would expect it to be useful standalone and by others, and require its own tests. The smaller the interface the better. Also, if Python did support multiline lambdas, this would be a good place for it.
Logic seems to be ok for me. I'll have to modify it to be able to test it in our fork, but at this moment I don't see any possibly breaking part. Notes I have are nice to have changes, nothing will happen if they're not accepted. |
for subset in _subsets] | ||
self.doc_fetched.emit() | ||
|
||
self._doc_payload[:] = [] |
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 curious why this is used self._doc_payload[:] = []
and not just self._doc_payload = []
?
EDITED:
Because [:]
creates copy of list but assigning new value to it is strange to me.
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.
This is basically an in-place assignment. It would be the same as doing:
my_list = ["a", "b", "c"]
my_list.clear()
And this replaces the list in place:
a = ["a", "b"]
b = a
# Show mutability
a.append("c")
print(b)
# ["a", "b", "c"]
# Assign new value to a does not change value of b, because it's assigning a new list
a = ["aa", "bb"]
print(b)
# ["a", "b", "c"]
# But when using in place assignment it would, because it's changing the same mutable list.
a = ["a", "b"]
b = a
a[:] = ["aa", "bb"]
print(b)
# ["aa", "bb"]
Edit: added example above of the in-place assignment that is not just clearing it
I believe the reason to do explicit in-place assignments is due to the "mutable list" potentially being shared to another thread and otherwise that one working on an older copy of a list that isn't actually the same list as self._doc_payload
. However, because it doesn't seem to be passed around as an object I don't think that's actually the case. @davidlatwe is it redundant for this case?
There should be some informational topics online on replacing lists in-place with regards to its mutability if you're looking for more info.
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.
However, because it doesn't seem to be passed around as an object I don't think that's actually the case.
Yes, it's true that there's no need to use in-place assignment, just re-using the same object for no special reason. Will change it for good.
I can confirm it works with current multiselection implementation. |
Nice ! 🎉 |
Should we get this PR ready for merging? I imagine @davidlatwe you've been using this in production since. |
Yes, we use it. |
Hope you're not waiting for me, please go ahead and merge if it's ready! |
Tested this and worked flawlessly here. @davidlatwe feel free to merge - or I'll merge in a few days. |
Merging this !! |
This PR supersede and will close #553.
The problem in #533 was, quoting from #553 (comment):
And this is the PR what was promised in that comment.
What's changed
ResizeToContents
resize mode to improve the performance of layout changing. (Inherited from Non blocking loader #553)And here's the visual result. Note that I am not in the office at the moment, so I mocked the loading time in order to see the loading spinner in view.
And sorry for Pype guys @mkolar, @iLLiCiTiT , need another review from you and test if this PR will cause any trouble to merge #550.
Please let me know what you think !