-
-
Notifications
You must be signed in to change notification settings - Fork 367
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
Extend attrs by adding custom decorators to attributes #340
Comments
@benbovy: This request could use some more specifics… can you describe an actual problem that needs solving which isn't addressed by existing mechanisms? Why the wrappers around |
Yeah I’m pretty sure that’s already possible. Check out https:/hynek/environ_config/blob/master/src/environ/_environ_config.py for a practical example. |
@wsanchez happy to provide more details. Basically, I'm developing a package in which I want to create very succinct classes that will be used as components of numerical models (a model = a collection of such classes that I call "processes"). Each of these classes declare some variables (e.g., physical fields) + some methods that will be called during a simulation to get, set or update values for these variables. I think I think that the reasons why I add wrappers around |
Ah, you're basically asking for _CountingAttr to become public, so you could subclass it. It's not an unreasonable request I think. |
You can wrap attr.s and attr.ib today, and it's fine (except a little non-composable). I used to do it in cattrs until attrs got its own type metadata. |
Unfortunately, I didn't succeed in trying to add a custom decorator to The closer (though not working) solution I found is to subclass from attr._make import _CountingAttr
class CountinAttrExtended(_CountingAttr):
def custom_decorator(self, meth):
self._custom_decorator = meth import attr
def variable(dims, intent='input', description=''):
metadata = {'attr_type': AttrType.VARIABLE,
'intent': intent,
'description': description}
return CountinAttrExtended(
default=attr.NOTHING,
validator=None,
repr=False,
cmp=False,
hash=None,
init=False,
converter=None,
metadata=metadata,
type=None,
)
return a
def process():
# wrapper around attr.s The basic example below runs fine but won't fully work because the @process(time_dependent=False)
class Grid(object):
length = variable(intent='input', description='grid total length')
spacing = variable(intent='input')
x = variable('x', intent='output')
nnodes = variable((), intent='output')
@nnodes.custom_decorator
def get_nnodes(self):
return self.x.size
def initialize(self):
self.x = np.arange(0, self.length + self.spacing, self.spacing) Also, I can't add attributes dynamically to neither Is there any other way to achieve this? |
Yeah exactly! That's a much better way to expose the problem :) |
Yeah, the problem is _CountingAttr will get replaced, so what you want to do is: in the custom_decorator method, stick something on the function it's decorating. Then wrap attr.s and read the thing you've stuck on and do some extra work. I think that's the best you can do atm. |
Sounds like a reasonable workaround. However, in the example above Although |
Yeah, you're still going to need to subclass _CountingAttr to make the decorator available in the first place. It's private but the cops won't show up at your door if you do it :) |
OK, I see, thanks @Tinche |
So I finally refactored my project so that it now extends Thanks again for the help here! [slightly off-topic] The way Back to this issue, I'm still a bit worried about the fact that I had to use attrs' internals (i.e., subclass Feel free to close this issue if this is never going to happen. |
Any chance of eventually having The problem with my subclass of I certainly could maintain it, but it would be nice if a more stable solution exists. If you think this request is reasonable, I'd be happy to work on it! |
Hm off top of my head that seems like another huge backward compatibility headache? 🤔 |
Yes I agree, it is probably not worth this edge case. Instead of subclassing |
@benbovy I'm reading the above as you found a satisfactory solution, so I'm going to close. Holler if you think that was premature. |
I'm thinking about refactoring a project so that it uses
attrs
under the hood (for more info, see benbovy/xarray-simlab#19), and I'd like to be able to do something like this:In the example above,
process
wrapsattr.s
andvariable
wrapsattr.ib
. Custom decorators would be a very nice way of implementing operations like validating input value or setting default value, but here more domain-specific.The text was updated successfully, but these errors were encountered: