Closed huguesdevimeux closed 3 years ago
Is dataclassess introduced in python 3.7 right?
Some updates, dataclassess is supported in python 3.6 but not as a default module instead can be installed as a dependency from pip. I had know about this which working poetry and rich causeing me trouble lol.
But uuh .. isn't the plan to use attrs
instead of dataclasses
?
correct, kilacoda. We're not going to use dataclasses, but attrs, which supports most python versions, including python 2
I talked some with Grant and he's now planning to migrate toward using regular classes, so it'd be better for consistency if we did that. Is anyone opposed to that?
As opposed to dataclasses OR attrs?
My takeaway from #271 is that attrs don't fit our use case. Dataclasses might but we don't know what problems we might run into so it'd be safer to stick with vanilla python. If someone is willing to vouch for dataclasses then maybe it'd be worth going back and asking him about it, but my prediction is that it will have some quirk like attrs that makes it difficult to adapt.
In principle I tend to agree. There's some stuff about attrs use of __post__init
that doesn't sit well with me, and it seems to me that it will be a problem when moving away from CONFIG.
Cc. @PgBiel
The thing that CONFIG does really nicely is it allows anyone to easily create derived classes with a few default values changed.
class myRedText(Text):
CONFIG = {
colour: "RED"
}
(or whatever the correct syntax is here) is a lot simpler than
class myRedText(Text):
def __init__(self, *args, **kwargs):
c = kwargs.pop("colour", "RED")
super().__init__(self, args, colour=c, kwargs)
or sth like that. (don't criticise my syntax in a github comment :)
My question is, how do dataclasses impact my ability to quickly and easily create such derived classes?
and maybe red text isn't the best example. another example might be TextMobjectFromPresetString
I don't know about dataclasses, but. The example you mention is indeed very convenient for a dev who is defining derived classes. However, this happens extremely rarely compared to the number of times that a user needs to use a class, or read the documentation, or would like to use autocompletion. CONFIG dictionaries make all of these almost impossible. So it's about the trade off of convenient for the dev or convenient for the user.
Also, the latest point brought up is that it may be better to not use either dataclasses or CONFIG. We're waiting for @PgBiel input.
this happens extremely rarely
As someone who learned python by learning how to make manim videos and reading 3b1b code, I naturally assumed that this happens all the time! Indeed I have been doing a lot of this :D
But I am starting to learn that the 3b1b code is somewhat idiosyncratic and may not be the best guide.
As someone who learned python by learning how to make manim videos and reading 3b1b code
yikes
My takeaway from #271 is that attrs don't fit our use case. Dataclasses might but we don't know what problems we might run into so it'd be safer to stick with vanilla python. If someone is willing to vouch for dataclasses then maybe it'd be worth going back and asking him about it, but my prediction is that it will have some quirk like attrs that makes it difficult to adapt.
What is this quirk you speak about?
But, vanilla classes could work fine if we do it right. If you have any ideas about this, you could make some model or prototype or something so that I can better understand what you have in mind
@PgBiel The issues at the top of #271 https://github.com/ManimCommunity/manim/pull/271#issue-466912315
Regarding the first issue, I'm yet to come upon it, so I'll take a look later
Regarding the second, I'm pretty sure there are ways to bypass that; specifying types again is only necessary because of how python handles types in class attrs: it adds them to clazz.__annotations__
, and, if you don't specify a type, the attribute is not stored there. However, if we don't use the automatic type to annotation feature for those cases, simply using a = attr.ib(b)
instead of the fancy a: fulltype = b
might have it automatically infer that the type is the same as that of the attribute in the superclass (I'm yet to test this, but I believe this could work).
Anyway, we could work with vanilla classes. However, I believe we should keep attrs for specific classes. We should use it where convenient, and maybe in important classes or something (to be discussed later).
It seems to me that a lot of the confusion here was moving from the current implementation using CONFIG
dicts directly to attrs/dataclasses.
Now I'm more inclined to first move to vanilla classes ASAP, and then decide which classes to implement using attrs. Now that #620 is merged, I can work on removing CONFIG
entirely and using vanilla classes. Once that's done we can revisit which classes need to move to attrs.
Yes, it's more work, but I'm willing to do it.
Now I'm more inclined to first move to vanilla classes ASAP
This is now done in PR #783 The plan is to merge that just after release 0.1.1 - so that it will be included in the subsequent 0.2.0 but we have a whole month to clean up.
However, once 783 is merged we have to address the question of how we want to refactor this going forward. dataclasses? fastcore? ...
We may also need a different approach for those CONFIGs that used to be part of mobjects that a user might instantiate vs the CONFIGS that were in Scenes that a user was meant to subclass (like GraphScene for example). The former only requires keyword arguments to the constructor, the latter might require a custom __init__()
.
...Of course, why a GraphScene is a scene at all, as opposed to a Graph being a mobject is another question entirely ...
we have to address the question of how we want to refactor this going forward. dataclasses? fastcore? ...
The question is: what do our classes need right now? I'm not certain we necessarily have a problem that needs to be fixed right now. (Other than the following point you make, of course...)
We may also need a different approach for those CONFIGs that used to be part of mobjects that a user might instantiate vs the CONFIGS that were in Scenes that a user was meant to subclass (like GraphScene for example). The former only requires keyword arguments to the constructor, the latter might require a custom init().
I'm fairly certain that most (if not all) of the CONFIG keys of GraphScene can just be replaced by setting attributes at the top of the construct function. The code
class MyScene(GraphScene):
CONFIG = {"x_min": -1}
def construct(self):
self.setup_axes()
Can be replaced with
class MyScene(GraphScene):
def construct(self):
self.x_min = -1
self.setup_axes()
In fact, we could encourage use of Scene.setup()
for this purpose.
...Of course, why a GraphScene is a scene at all, as opposed to a Graph being a mobject is another question entirely ...
I think we must answer this question before choosing if we need to migrate to any other class and/or how and when. What is the concrete problem that needs to be addressed after we remove CONFIG once and for all?
closed by PR #783
For discussions on future refactoring, please open new dedicated issues.
We have discussed about the variable
CONFIG
previously on discord. What should we do about it ?I personally think we should modify at least a little bit of its architecture. it alters the readability a lot. One problem with that would be that in changing
CONFIG
we would have to review the entire architecture of the code.What do you think?