Add verbose_name for rules and permissions#154
Add verbose_name for rules and permissions#154jacklinke wants to merge 3 commits intodfunckt:masterfrom
verbose_name for rules and permissions#154Conversation
|
Great stuff! 👍 My only concern is we're changing the structure of the items stored in rule sets -- RuleSets used to be a map of strings to predicates, whereas now it is going to be a map of strings to dicts. This is technically a breaking change and can catch users by surprise. Maybe override Otherwise this looks like a great addition, thank you for that! |
|
Glad this is seen as something beneficial, and thanks for the advice/direction. I updated the code, returning the I figured following a similar approach as Django's If that sounds sensible, I'll add tests and docs this week to finish this out. |
dfunckt
left a comment
There was a problem hiding this comment.
@jacklinke apologies for the delayed review. Great stuff 👍
I left a few comments. There also seem to be a few lint/formatting issues highlighted by the checks -- can you please take a look at those too?
| for perm_type, predicate in perms.items(): | ||
| add_perm(new_class.get_perm(perm_type), predicate) | ||
| if isinstance(predicate, dict): | ||
| add_perm(new_class.get_perm(perm_type), predicate['pred'], verbose_name=predicate['verbose_name']) |
There was a problem hiding this comment.
Can you please rename the pred attribute to predicate?
|
|
||
| def add_rule(self, name, pred): | ||
| def rule_verbose_name(self, name): | ||
| return self["get_%s_display" % name] or name |
There was a problem hiding this comment.
| return self["get_%s_display" % name] or name | |
| return self["get_%s_display" % name] |
This must return None if no verbose name has been provided for the rule and callers can choose whether to fallback to name.
| if isfunction(pred): | ||
| # If a function as passed in (as might be done with legacy django-rules) | ||
| # convert the value to the dictionary form | ||
| pred = {'pred': predicate(pred), 'verbose_name': verbose_name} | ||
|
|
||
| if isinstance(pred, dict): | ||
| # Check if internal pred is already a Predicate, or an basic | ||
| # unwrapped function. Wrap as a Predicate if needed | ||
| if not isinstance(pred['pred'], Predicate): | ||
| pred['pred'] = predicate(pred['pred']) | ||
|
|
There was a problem hiding this comment.
All this can just be:
| if isfunction(pred): | |
| # If a function as passed in (as might be done with legacy django-rules) | |
| # convert the value to the dictionary form | |
| pred = {'pred': predicate(pred), 'verbose_name': verbose_name} | |
| if isinstance(pred, dict): | |
| # Check if internal pred is already a Predicate, or an basic | |
| # unwrapped function. Wrap as a Predicate if needed | |
| if not isinstance(pred['pred'], Predicate): | |
| pred['pred'] = predicate(pred['pred']) | |
| if isinstance(pred, dict): | |
| pred['pred'] = predicate(pred['pred']) | |
| else: | |
| pred = {'pred': predicate(pred), 'verbose_name': None} |
Or even:
| if isfunction(pred): | |
| # If a function as passed in (as might be done with legacy django-rules) | |
| # convert the value to the dictionary form | |
| pred = {'pred': predicate(pred), 'verbose_name': verbose_name} | |
| if isinstance(pred, dict): | |
| # Check if internal pred is already a Predicate, or an basic | |
| # unwrapped function. Wrap as a Predicate if needed | |
| if not isinstance(pred['pred'], Predicate): | |
| pred['pred'] = predicate(pred['pred']) | |
| if not isinstance(pred, dict): | |
| pred = {'pred': predicate(pred), 'verbose_name': None} |
if we assume anyone passing a dict know what they're doing.
| def _check_name(_name): | ||
| if (not super(RuleSet, self).__contains__(_name)): | ||
| raise KeyError("Provided name '`%s`' not found" % _name) | ||
|
|
||
| if name[0] != '_': | ||
| prefix = "get_" | ||
| suffix = "_display" | ||
| if name.startswith(prefix) and name.endswith(suffix): | ||
| _name = name[len(prefix):-len(suffix)] | ||
| _check_name(_name) | ||
| return super(RuleSet, self).__getitem__(_name)['verbose_name'] | ||
|
|
||
| _check_name(name) |
There was a problem hiding this comment.
All this can just be:
| def _check_name(_name): | |
| if (not super(RuleSet, self).__contains__(_name)): | |
| raise KeyError("Provided name '`%s`' not found" % _name) | |
| if name[0] != '_': | |
| prefix = "get_" | |
| suffix = "_display" | |
| if name.startswith(prefix) and name.endswith(suffix): | |
| _name = name[len(prefix):-len(suffix)] | |
| _check_name(_name) | |
| return super(RuleSet, self).__getitem__(_name)['verbose_name'] | |
| _check_name(name) | |
| prefix = "get_" | |
| suffix = "_display" | |
| if name.startswith(prefix) and name.endswith(suffix): | |
| _name = name[len(prefix):-len(suffix)] | |
| return super(RuleSet, self).__getitem__(_name)['verbose_name'] |
Right?
Adds
verbose_namefor rules and permissions, resolving #59.This change should be transparent to any existing users of django-rules, but adds the new capability to add and display verbose names for rules & permissions through the use of new/updated RuleSet instance methods and shortcuts for shared and permissions rule sets.
add_rule(name, predicate, verbose_name=None): Updated to allow optionalverbose_name.set_rule(name, predicate, verbose_name=None): Updated to allow optionalverbose_namerule_verbose_name(name): A new method which returns theverbose_nameif it was supplied when adding or setting the rule. Defaults tonameif noverbose_namewas supplied.permissions)Models can now also optionally add verbose names to permissions using the following conventions:
This would be equivalent to the following calls::
Tasks:
I welcome any feedback.