Skip to content
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

Allow to register new class/dataclass/attribute makers in attrs plugin #5406

Open
hynek opened this issue Jul 31, 2018 · 5 comments
Open

Allow to register new class/dataclass/attribute makers in attrs plugin #5406

hynek opened this issue Jul 31, 2018 · 5 comments

Comments

@hynek
Copy link
Member

hynek commented Jul 31, 2018

This is a feature request.

attrs is very much intended to be composable (e.g. https://github.com/hynek/environ_config) but currently the attrs plugin only works on the core library's functions:

# The names of the different functions that create classes or arguments.
attr_class_makers = {
'attr.s',
'attr.attrs',
'attr.attributes',
}
attr_dataclass_makers = {
'attr.dataclass',
}
attr_attrib_makers = {
'attr.ib',
'attr.attrib',
'attr.attr',
}

I would like to be able to signal somehow to mypy, that some function is a wrapper around @attr.s/@attr.ib/@attr.dataclass. Not only would third-party applications benefit, but I could really use it while experimenting on python-attrs/attrs#408.

Any ideas/plans how we could achieve that?

cc also @euresti & @chadrik

@euresti
Copy link
Contributor

euresti commented Jul 31, 2018

FYI in our code I literally append to these lists in a mypy plugin.

I did have a vision that the plugin could support an @class_maker(...) decorator that would do nothing at runtime but let the plugin know that this method (along with some default values) is a class_maker or attrib_maker.

So you'd do:

@class_maker(auto_attribs_default=True)
def my_class_maker(...):
   ...

Or something like that.

@ilevkivskyi
Copy link
Member

Another possible pattern we can support is:

if TYPE_CHECKING:
    custom_maker = attr.s
else:
    def custom_maker(cls):
        ...

@ilevkivskyi
Copy link
Member

The same problem exists for dataclasses, see #6239

@ilevkivskyi
Copy link
Member

Just FTR cross-posting the workaround that currently works:

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from attr import s as custom_maker
else:
    def custom_maker(cls):
        ...

but it is arguably worse than #5406 (comment), that currently doesn't work.

@euresti
Copy link
Contributor

euresti commented May 8, 2019

Heh. Here's what I did in our code base. I added a plugin that adds some methods when imported. (Did y'all wonder why I made those variables globals?)

from mypy.plugin import Plugin
from mypy.plugins.attrs import (
    attr_attrib_makers,
    attr_class_makers,
    attr_dataclass_makers,
)

# These work just like attr.dataclass
attr_dataclass_makers.add("my_module.method_looks_like_attr_dataclass")

# This work just like attr.s
attr_class_makers.add("my_module.method_looks_like_attr_s")

# These are our attr.ib makers.
attr_attrib_makers.add("my_module.method_looks_like_attrib")

class MyPlugin(Plugin):
    # Our plugin does nothing but it has to exist so this file gets loaded.
    pass


def plugin(version):
    return MyPlugin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants