# Path: rolemanagement/abc.py
# class MixinMeta(ABC):
#     """
#     Metaclass for well behaved type hint detection with composite class.
#     """
# 
#     # https://github.com/python/mypy/issues/1996
# 
#     qualified_name: str
# 
#     def __init__(self, *_args):
#         self.config: Config
#         self.bot: Red
# 
#     @abstractmethod
#     def strip_variations(self, s: str) -> str:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def wait_for_ready(self) -> None:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def is_self_assign_eligible(
#         self, who: discord.Member, role: discord.Role
#     ) -> List[discord.Role]:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def update_roles_atomically(
#         self,
#         *,
#         who: discord.Member,
#         give: Optional[List[discord.Role]] = None,
#         remove: Optional[List[discord.Role]] = None,
#     ):
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def all_are_valid_roles(self, ctx, *roles: discord.Role) -> bool:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def maybe_update_guilds(self, *guilds: discord.Guild) -> None:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     def get_top_role(self, member: discord.Member) -> discord.Role:
#         raise NotImplementedError()
# 
# Path: rolemanagement/exceptions.py
# class ConflictingRoleException(RoleManagementException):
#     def __init__(self, *, conflicts=None):
#         self.conflicts = conflicts or []
#         super().__init__()
# 
# class MissingRequirementsException(RoleManagementException):
#     def __init__(self, *, miss_any=None, miss_all=None):
#         self.miss_all = miss_all or []
#         self.miss_any = miss_any or []
#         super().__init__()
# 
# class PermissionOrHierarchyException(Exception):
#     pass
# 
# class RoleManagementException(Exception):
#     pass


import re
import discord
from typing import List
from .abc import MixinMeta
from .exceptions import (
    ConflictingRoleException,
    MissingRequirementsException,
    PermissionOrHierarchyException,
    RoleManagementException,
)
                if who._roles.has(idx):
                    req_any_fail = []
                    break

        req_all_fail = [
            idx
            for idx in await self.config.role(role).requires_all()
            if not who._roles.has(idx)
        ]

        if req_any_fail or req_all_fail:
            raise MissingRequirementsException(
                miss_all=req_all_fail, miss_any=req_any_fail
            )

        return None

    async def check_exclusivity(
        self, who: discord.Member, role: discord.Role
    ) -> List[discord.Role]:
        """
        Returns a list of roles to remove, or raises an error
        """

        data = await self.config.all_roles()
        ex = data.get(role.id, {}).get("exclusive_to", [])
        conflicts: List[discord.Role] = [r for r in who.roles if r.id in ex]

        for r in conflicts:
            if not data.get(r.id, {}).get("self_removable", False):

# Path: rolemanagement/abc.py
# class MixinMeta(ABC):
#     """
#     Metaclass for well behaved type hint detection with composite class.
#     """
# 
#     # https://github.com/python/mypy/issues/1996
# 
#     qualified_name: str
# 
#     def __init__(self, *_args):
#         self.config: Config
#         self.bot: Red
# 
#     @abstractmethod
#     def strip_variations(self, s: str) -> str:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def wait_for_ready(self) -> None:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def is_self_assign_eligible(
#         self, who: discord.Member, role: discord.Role
#     ) -> List[discord.Role]:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def update_roles_atomically(
#         self,
#         *,
#         who: discord.Member,
#         give: Optional[List[discord.Role]] = None,
#         remove: Optional[List[discord.Role]] = None,
#     ):
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def all_are_valid_roles(self, ctx, *roles: discord.Role) -> bool:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     async def maybe_update_guilds(self, *guilds: discord.Guild) -> None:
#         raise NotImplementedError()
# 
#     @abstractmethod
#     def get_top_role(self, member: discord.Member) -> discord.Role:
#         raise NotImplementedError()
# 
# Path: rolemanagement/exceptions.py
# class ConflictingRoleException(RoleManagementException):
#     def __init__(self, *, conflicts=None):
#         self.conflicts = conflicts or []
#         super().__init__()
# 
# class MissingRequirementsException(RoleManagementException):
#     def __init__(self, *, miss_any=None, miss_all=None):
#         self.miss_all = miss_all or []
#         self.miss_any = miss_any or []
#         super().__init__()
# 
# class PermissionOrHierarchyException(Exception):
#     pass
# 
# class RoleManagementException(Exception):
#     pass


# Path: rolemanagement/utils.py
import re
import discord
from typing import List
from .abc import MixinMeta
from .exceptions import (
    ConflictingRoleException,
    MissingRequirementsException,
    PermissionOrHierarchyException,
    RoleManagementException,
)

                if who._roles.has(idx):
                    req_any_fail = []
                    break

        req_all_fail = [
            idx
            for idx in await self.config.role(role).requires_all()
            if not who._roles.has(idx)
        ]

        if req_any_fail or req_all_fail:
            raise MissingRequirementsException(
                miss_all=req_all_fail, miss_any=req_any_fail
            )

        return None

    async def check_exclusivity(
        self, who: discord.Member, role: discord.Role
    ) -> List[discord.Role]:
        """
        Returns a list of roles to remove, or raises an error
        """

        data = await self.config.all_roles()
        ex = data.get(role.id, {}).get("exclusive_to", [])
        conflicts: List[discord.Role] = [r for r in who.roles if r.id in ex]

        for r in conflicts:
            if not data.get(r.id, {}).get("self_removable", False):

                raise ConflictingRoleException(conflicts=conflicts)