def _query_perms(self,
                     roles,
                     get_related_prefixes,
                     perms_name,
                     force_separate,
                     agent=ANY,
                     target=ANY):
        """
        This is an abstraction used by subclasses to query permissions.

        Roles will be normalized to a list of roles.

        force_separate is an optimization. If you know you are going
        to have multiple left joins, this will speed things up.

        Either agent or target can be provided. It's assumed that the
        queryset to be retrieved is the thing not provided.
        """
        # Normalize inputs
        roles = normalize_value(roles)
        agent = normalize_value(agent)
        target = normalize_value(target)

        # Get all possible related queries we're doing
        related_prefixes = (get_related_prefixes(self, perms_name, *roles)
                            if is_value(roles) else [perms_name])

        # Create a query for each related prefix
        queries = [
            self._get_query(roles, agent, target, prefix=prefix)
            for prefix in related_prefixes
        ]

        # Aggregate the queries. Query together if we don't have any
        # divergent left joins.
        query_together = (not force_separate and len(related_prefixes) <= 1
                          and perms_name in related_prefixes)

        if query_together:
            results = self._query_together(queries)
        else:
            results = self._query_separate(queries)

        return results
    def _validate_actions(self, actions):
        if not is_value(actions):
            return actions

        actions = normalize_value(actions)

        if [action for action in actions if "." not in action]:
            raise ValueError("Prefixes are required since target is optional.")

        return actions
    def for_role(self,
                 roles=ANY,
                 agent=ANY,
                 infer_agents=True,
                 force_separate=False):
        """
        This filters permission targets by the given agent.

        infer_agents is an optimization. If you know you don't need the
        authority of any related agents, set it to false.
        """
        return self._query_perms(
            roles=roles,
            get_related_prefixes=get_related_target_prefixes,
            perms_name='target_perms',
            force_separate=force_separate,
            agent=normalize_value(agent,
                                  normalize_agent,
                                  infer_agents=infer_agents))
 def test_normalize_value(self):
     self.assertEqual(13, normalize_value(3, lambda x, y: x + y, 10))