-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Declare property aliases in a single place #9475
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
Changes from 1 commit
ef7a035
413144a
7c40fdf
a7f698e
b442049
2c83bdb
473590c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2805,14 +2805,13 @@ def _str_lower_equal(obj, s): | |
return isinstance(obj, six.string_types) and obj.lower() == s | ||
|
||
|
||
def _define_aliases(local_d, alias_d): | ||
"""Define property aliases. | ||
def _define_aliases(alias_d, cls=None): | ||
"""Class decorator for defining property aliases. | ||
|
||
Use in a class definition as :: | ||
Use as :: | ||
|
||
cbook._define_aliases(locals(), { | ||
"property": ["alias", ...], ... | ||
}) | ||
@cbook._define_aliases({"property": ["alias", ...], ...}) | ||
class C: ... | ||
|
||
For each property, if the corresponding ``get_property`` is defined in the | ||
class so far, an alias named ``get_alias`` will be defined; the same will | ||
|
@@ -2822,6 +2821,8 @@ class so far, an alias named ``get_alias`` will be defined; the same will | |
The alias map is stored as the ``_alias_map`` attribute on the class and | ||
can be used by `~.normalize_kwargs`. | ||
""" | ||
if cls is None: | ||
return functools.partial(_define_aliases, alias_d) | ||
|
||
def make_alias(name): # Enfore a closure over *name*. | ||
def method(self, *args, **kwargs): | ||
|
@@ -2831,14 +2832,15 @@ def method(self, *args, **kwargs): | |
for prop, aliases in alias_d.items(): | ||
exists = False | ||
for prefix in ["get_", "set_"]: | ||
if prefix + prop in local_d: | ||
if prefix + prop in vars(cls): | ||
exists = True | ||
for alias in aliases: | ||
method = make_alias(prefix + prop) | ||
method.__name__ = prefix + alias | ||
method.__doc__ = "alias for `{}`".format(prefix + prop) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose setting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm mostly too lazy to add a dep on funcsigs for this PR (I actually do add such a dependency for the pyplot PR, so that'd also mean merge conflicts and sadness). |
||
local_d[prefix + alias] = method | ||
setattr(cls, prefix + alias, method) | ||
if not exists: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is more explicit than the |
||
raise ValueError("property {} does not exist".format(prop)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use a different word than 'property' here? They are not python There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about edit: or |
||
|
||
local_d["_alias_map"] = alias_d | ||
cls._alias_map = alias_d | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might be tempted to have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really would prefer the aliases to stay close to the decorator, at least. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer it this way, to keep the decorator and the alias map close together. Would it make sense to have the decorator also add a def normalize_kvwargs(self, kw):
return normalize_kwargs(kw, self._alias_map) ? Might also be better to check if the class already has an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What you really want here is a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or maybe @staticmethod
def _get_alias_map(self):
d = {}
for cls in self.mro():
for k, aliases in cls.__dict__.get('_alias_map',{}).items()
d.setdefault(k, []).extend(aliases) edit: updated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think ChainMap helps here, ex @_define_aliases({'linewidth': ['lw']})
class A:
...
@_define_aliases({'linewidth': ['linewidths', 'lws']})
class B(A):
... You would want There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point. Updated my other comment to reflect that |
||
return cls |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,13 @@ | |
CIRCLE_AREA_FACTOR = 1.0 / np.sqrt(np.pi) | ||
|
||
|
||
@cbook._define_aliases({ | ||
"antialiased": ["antialiaseds"], | ||
"edgecolor": ["edgecolors"], | ||
"facecolor": ["facecolors"], | ||
"linestyle": ["linestyles", "dashes"], | ||
"linewidth": ["linewidths", "lw"], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not sets, instead of lists? Duplicates wouldn't make any sense here. (edit: because |
||
}) | ||
class Collection(artist.Artist, cm.ScalarMappable): | ||
""" | ||
Base class for Collections. Must be subclassed to be usable. | ||
|
@@ -799,13 +806,6 @@ def update_from(self, other): | |
# self.update_dict = other.update_dict # do we need to copy this? -JJL | ||
self.stale = True | ||
|
||
cbook._define_aliases(locals(), { | ||
"antialiased": ["antialiaseds"], | ||
"edgecolor": ["edgecolors"], | ||
"facecolor": ["facecolors"], | ||
"linestyle": ["linestyles", "dashes"], | ||
"linewidth": ["linewidths", "lw"], | ||
}) | ||
|
||
# these are not available for the object inspector until after the | ||
# class is built so we define an initial set here for the init | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
enforce
?