Source code for pigauth._parser

"""Permission expression parser"""
from __future__ import annotations

import abc
import re
from typing import Iterable

from ._auth import PermissionGrant, PermissionGrants
from ._matcher import RegexMatcher, AnyMatcher, AllMatcher, ModifierMatcherFactory, RequiresMatcher

class PermissionMatcher:
    pass

class Parser:
    @abc.abstractmethod
    def __call__(self, expression: str) -> Iterable[PermissionMatcher]:
        """Parse expression into matchers"""

class PatternParser(Parser):
    """Parse permission pattern segment"""
    def __call__(self, expression: str) -> Iterable[PermissionMatcher]:
        regex = re.compile(expression.replace(".", "\\.").replace("*", ".*"))
        yield RegexMatcher(regex)

class ModifierParser(Parser):
    """Parse permission expression modifier segment"""
    MODIFIER_DELIMITER = ','
    MODIFIER_ALTERNATIVE_DELIMITER = '+'

    def __init__(self, modifier_matcher_factory=None):
        self.modifier_matcher_factory = modifier_matcher_factory or ModifierMatcherFactory()

    def __call__(self, expression: str) -> Iterable[PermissionMatcher]:
        modifier_names = expression.split(self.MODIFIER_DELIMITER)
        yield RequiresMatcher(modifier_names)
        for modifier_name in modifier_names:
            modifier_alternatives = modifier_name.split(self.MODIFIER_ALTERNATIVE_DELIMITER)
            matchers_for_alternatives = []
            for alternative in modifier_alternatives:
                matcher = self.modifier_matcher_factory(alternative)
                if matcher:
                    matchers_for_alternatives.append(matcher)
            if not matchers_for_alternatives:
                continue
            if len(matchers_for_alternatives) > 1:
                yield AnyMatcher(matchers_for_alternatives)
            else:
                yield matchers_for_alternatives[0]

class PermissionExpressionParser(Parser):
    """Parse permission expression into PermissionMatchers"""
    MODIFIER_SEPARATOR = '|'
    _pattern_parser: PatternParser
    _modifier_parser: ModifierParser

    def __init__(self, pattern_parser = None, modifier_parser = None):
        self._pattern_parser = pattern_parser or PatternParser()
        self._modifier_parser = modifier_parser or ModifierParser()

    def __call__(self, expression: str) -> Iterable[PermissionMatcher]:
        pattern, _, modifier = expression.partition(self.MODIFIER_SEPARATOR)
        yield from self._pattern_parser(pattern)
        yield from self._modifier_parser(modifier)

[docs]class PermissionGrantParser: """Parse permission grant into a single PermissionMatcher""" def __init__(self, expression_parser: Parser | None = None): self.expression_parser = expression_parser or PermissionExpressionParser() def __call__(self, grant: PermissionGrant) -> PermissionMatcher: matchers = list(self.expression_parser(grant)) if len(matchers) > 1: return AllMatcher(matchers) return matchers[0]
[docs]class PermissionGrantsParser: """Parse multiple permission grants into a single PermissionMatcher""" def __init__(self, permission_grant_parser: Parser | None = None): self.permission_grant_parser = permission_grant_parser or PermissionGrantParser() def __call__(self, grants: PermissionGrants): matchers = [self.permission_grant_parser(grant) for grant in grants] return AnyMatcher(matchers)