classification
Title: add user notification that parent init will not be called in dataclass init method
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: eric.smith Nosy List: Ricyteach, eric.smith
Priority: normal Keywords:

Created on 2018-05-09 20:50 by Ricyteach, last changed 2018-05-10 02:27 by Ricyteach.

Messages (3)
msg316331 - (view) Author: Rick Teachey (Ricyteach) * Date: 2018-05-09 20:50
The dataclasses module is incredibly easy to use. This is a good thing. BUT one downside is it will definitely be utilized by people who don't have a thorough understanding of how it does what it does.

Even for me, despite having a very good understanding of how it works, after heavily using it on a project for about 3 weeks now I made a mistake like the one below:

class ImportantMixin:
    def __init__(self):
        super().__init__()
        important_task()

@dataclass
class NaiveDClass(ImportantMixin):
  data1 = int
  data2 = int

I then went on along my merry way. Obviously, ImportantMixin.__init__ never gets called and I didn't realize this until it was a bigger problem than it should have been (should have written better tests! but I digress).

It would seem like a good idea for the dataclasses module to let the user know they did this, probably via the warning system. Seems like it would be relatively easy to do: if there is an init method being create, just inspect the MRO for any previously defined init methods that weren't created by dataclasses.

Thanks.
msg316340 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2018-05-09 22:38
I'm okay with the concept, but I don't know how to implement it. You need to not only know if a class has a __init__, but also if it's expected to be called.

For example, these don't normally get called, but if you inherit from them (and everyone does inherit from object) you don't want a warning.

>>> hasattr(int, '__init__')
True
>>> hasattr(object, '__init__')
True

I'm open to ideas.
msg316343 - (view) Author: Rick Teachey (Ricyteach) * Date: 2018-05-10 02:27
The init method that comes up for int, str, float, etc is just the object init:

assert int.__init__ is object.__init__

Probably the thing to do is grab any init methods that aren't the object.__init__ while stripping out the dataclass-created init methods? Maybe something like:

import warnings

if cls.__dataclass_params__.init:
    for pcls in cls.mro():
        if pcls.__init__ is not object.__init__:
            try:
                d_params = getattr(pcls, "__dataclass_params__")
            except AttributeError:
                warnings.warn('Found a not called init')
            else:
                if not d_params.init:
                    warnings.warn('Found a custom dataclass init')
History
Date User Action Args
2018-05-10 02:27:36Ricyteachsetmessages: + msg316343
2018-05-09 22:54:00eric.smithsetassignee: eric.smith
2018-05-09 22:38:47eric.smithsetmessages: + msg316340
2018-05-09 20:50:00Ricyteachcreate