[docs]defto_gare(error:AnyErrorDocumentType)->GARE|None:""" Converts a GlobusAPIError, ErrorSubdocument, or dict into a GARE by attempting to match to GARE (preferred) or legacy variants. .. note:: A GlobusAPIError may contain multiple errors, and in this case only a single GARE is returned for the first error that matches a known format. If the provided error does not match a known format, None is returned. :param error: The error to convert. """fromglobus_sdk.excimportErrorSubdocument,GlobusAPIError# GlobusAPIErrors may contain more than one error, so we consider all of them# even though we only return the first.ifisinstance(error,GlobusAPIError):# first, try to parse a GARE from the root document,# and if we can do so, return itauthreq_error=_lenient_dict2gare(error.raw_json)ifauthreq_errorisnotNone:returnauthreq_error# Iterate over ErrorSubdocumentsforsubdocinerror.errors:authreq_error=_lenient_dict2gare(subdoc.raw)ifauthreq_errorisnotNone:# Return only the first auth requirements error we encounterreturnauthreq_error# We failed to find a Globus Auth Requirements ErrorreturnNoneelifisinstance(error,ErrorSubdocument):return_lenient_dict2gare(error.raw)else:return_lenient_dict2gare(error)
[docs]defto_gares(errors:list[AnyErrorDocumentType])->list[GARE]:""" Converts a list of GlobusAPIErrors, ErrorSubdocuments, or dicts into a list of GAREs by attempting to match each error to GARE (preferred) or legacy variants. .. note:: A GlobusAPIError may contain multiple errors, so the result list could be longer than the provided list. If no errors match any known formats, an empty list is returned. :param errors: The errors to convert. """maybe_gares:list[GARE|None]=[]forerrorinerrors:# when handling an API error, avoid `to_gare(error)` because that will# only unpack a single resultifisinstance(error,exc.GlobusAPIError):# Use the ErrorSubdocuments when handling API error typesmaybe_gares.extend(to_gare(e)foreinerror.errors)# Also use the root document, but only if there is an `"errors"`# key inside of the error document# Why? Because the *default* for `.errors` when there is no inner# `"errors"` array is an array containing the root document as a# subdocumentifisinstance(error.raw_json,dict)and"errors"inerror.raw_json:# use dict parsing directly so that the native descent in 'to_gare'# to subdocuments does not apply in this casemaybe_gares.append(_lenient_dict2gare(error.raw_json))else:maybe_gares.append(to_gare(error))# Remove any errors that did not resolve to a Globus Auth Requirements Errorreturn[errorforerrorinmaybe_garesiferrorisnotNone]
def_lenient_dict2gare(error_dict:dict[str,t.Any]|None)->GARE|None:""" Parse a GARE from a dict, accepting legacy variants. If given ``None``, returns ``None``. This allows this to accept inputs which are themselves dict|None. :param error_dict: the error input :eturns: ``None`` on a failed parse """iferror_dictisNone:returnNone# Prefer a proper auth requirements error, if possibletry:returnGARE.from_dict(error_dict)exceptexc.ValidationErroraserr:log.debug(f"Failed to parse error as 'GARE' ({err})")supported_variants:list[type[LegacyAuthRequirementsErrorVariant]]=[LegacyAuthorizationParametersError,LegacyConsentRequiredTransferError,LegacyConsentRequiredAPError,]forvariantinsupported_variants:try:returnvariant.from_dict(error_dict).to_auth_requirements_error()exceptexc.ValidationErroraserr:log.debug(f"Failed to parse error as '{variant.__name__}' ({err})")returnNone
[docs]defis_gare(error:AnyErrorDocumentType)->bool:""" Return True if the provided error matches a known Globus Auth Requirements Error format. :param error: The error to check. """returnto_gare(error)isnotNone
[docs]defhas_gares(errors:list[AnyErrorDocumentType])->bool:""" Return True if any of the provided errors match a known Globus Auth Requirements Error format. :param errors: The errors to check. """returnany(is_gare(error)forerrorinerrors)