# SPDX-License-Identifier: MIT"""This module defines exceptions and error handling utilities. It is therecommend path to access ``ConfiguratonError``, ``ConfigurationWarning``, and``ExceptionGroup``. For backward compatibility, ``ConfigurationError`` isre-exported in the top-level package."""from__future__importannotationsimportbuiltinsimportcontextlibimportdataclassesimportsysimporttypingimportwarnings__all__=["ConfigurationError","ConfigurationWarning","ExceptionGroup",]def__dir__()->list[str]:return__all__
[docs]classConfigurationError(Exception):"""Error in the backend metadata. Has an optional key attribute, which will be non-None if the error is related to a single key in the pyproject.toml file."""def__init__(self,msg:str,*,key:str|None=None):super().__init__(msg)self._key=key@propertydefkey(self)->str|None:# pragma: no coverreturnself._key
[docs]classConfigurationWarning(UserWarning):"""Warnings about backend metadata."""
ifsys.version_info>=(3,11):ExceptionGroup=builtins.ExceptionGroupelse:classExceptionGroup(Exception):"""A minimal implementation of `ExceptionGroup` from Python 3.11. Users can replace this with a more complete implementation, such as from the exceptiongroup backport package, if better error messages and integration with tooling is desired and the addition of a dependency is acceptable. """message:strexceptions:list[Exception]def__init__(self,message:str,exceptions:list[Exception])->None:self.message=messageself.exceptions=exceptionsdef__repr__(self)->str:returnf"{self.__class__.__name__}({self.message!r}, {self.exceptions!r})"@dataclasses.dataclassclassErrorCollector:""" Collect errors and raise them as a group at the end (if collect_errors is True), otherwise raise them immediately. """collect_errors:boolerrors:list[Exception]=dataclasses.field(default_factory=list)defconfig_error(self,msg:str,*,key:str|None=None,got:typing.Any=None,got_type:type[typing.Any]|None=None,warn:bool=False,**kwargs:typing.Any,)->None:"""Raise a configuration error, or add it to the error list."""msg=msg.format(key=f'"{key}"',**kwargs)ifgotisnotNone:msg=f"{msg} (got {got!r})"ifgot_typeisnotNone:msg=f"{msg} (got {got_type.__name__})"ifwarn:warnings.warn(msg,ConfigurationWarning,stacklevel=3)elifself.collect_errors:self.errors.append(ConfigurationError(msg,key=key))else:raiseConfigurationError(msg,key=key)deffinalize(self,msg:str)->None:"""Raise a group exception if there are any errors."""ifself.errors:raiseExceptionGroup(msg,self.errors)@contextlib.contextmanagerdefcollect(self)->typing.Generator[None,None,None]:"""Support nesting; add any grouped errors to the error list."""ifself.collect_errors:try:yieldexceptExceptionGroupaserror:self.errors.extend(error.exceptions)else:yield