xsdata icon indicating copy to clipboard operation
xsdata copied to clipboard

Subclass's Meta should inherit from parent class's Meta

Open sashkent3 opened this issue 10 months ago • 8 comments

Every time the generated code contains a structure similar to:

class A:
  class Meta:
    pass

class B(A):
  class Meta:
    pass

I get a static type-checker warning about B.Meta being an incorrect override for A.Meta. To fix this, simply change the above to:

class A:
  class Meta:
    pass

class B(A):
  class Meta(A.Meta):
    pass

sashkent3 avatar Feb 15 '25 12:02 sashkent3

Can you give some more info about the type-checker you are using?

Unfortunately this isn't really an option as the Meta class must be final to avoid conflicts

tefra avatar Mar 01 '25 10:03 tefra

@tefra It's Pyright, take a look here.

sashkent3 avatar Mar 01 '25 10:03 sashkent3

Thanks @sashkent3 from quick look a lot of libraries suffer from that issue

https://github.com/microsoft/pyright/discussions/6570 https://github.com/typeddjango/django-stubs/issues/748

I am open to suggestions but inheritance between Meta classes is impossible

tefra avatar Mar 01 '25 11:03 tefra

@tefra could you kindly clarify what do you mean by:

Meta class must be final

Also, if xsdata intends to ignore this warning, maybe it's better to simply generate type: ignore alongside?

sashkent3 avatar Mar 01 '25 11:03 sashkent3

The parent class might not have a meta class, but the parent parent might, resolving the imports is very hard in these cases.

Maybe the type: ignore is the way to go let me think about it.

tefra avatar Mar 01 '25 11:03 tefra

Isn't it feasible to generate class Meta for every class? Even in cases where it's currently not needed.

sashkent3 avatar Mar 01 '25 11:03 sashkent3

If we create a Meta class for every model and include all the properties in each one, doesn’t that undermine the point of using inheritance, which is to share and build on common attributes efficiently?

I am not sure I like adding more code/noise just to satisfy pyright

tefra avatar Mar 02 '25 05:03 tefra

Well, that's fair, but I believe this is about more than satisfying Pyright. When you do:

class A:
  class Meta:
    pass

class B(A):
  pass

The B class inherits A.Meta whether you intend it or not. The following two pieces of code are exactly equivalent, because B.Meta is A.Meta:

class C(B):
    class Meta(B.Meta):
        pass

and

class C(B):
    class Meta(A.Meta):
        pass

sashkent3 avatar Mar 02 '25 11:03 sashkent3