exceptions.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. from __future__ import annotations
  2. import typing
  3. from ..utils import YoutubeDLError
  4. if typing.TYPE_CHECKING:
  5. from .common import RequestHandler, Response
  6. class RequestError(YoutubeDLError):
  7. def __init__(
  8. self,
  9. msg: str | None = None,
  10. cause: Exception | str | None = None,
  11. handler: RequestHandler = None,
  12. ):
  13. self.handler = handler
  14. self.cause = cause
  15. if not msg and cause:
  16. msg = str(cause)
  17. super().__init__(msg)
  18. class UnsupportedRequest(RequestError):
  19. """raised when a handler cannot handle a request"""
  20. pass
  21. class NoSupportingHandlers(RequestError):
  22. """raised when no handlers can support a request for various reasons"""
  23. def __init__(self, unsupported_errors: list[UnsupportedRequest], unexpected_errors: list[Exception]):
  24. self.unsupported_errors = unsupported_errors or []
  25. self.unexpected_errors = unexpected_errors or []
  26. # Print a quick summary of the errors
  27. err_handler_map = {}
  28. for err in unsupported_errors:
  29. err_handler_map.setdefault(err.msg, []).append(err.handler.RH_NAME)
  30. reason_str = ', '.join([f'{msg} ({", ".join(handlers)})' for msg, handlers in err_handler_map.items()])
  31. if unexpected_errors:
  32. reason_str = ' + '.join(filter(None, [reason_str, f'{len(unexpected_errors)} unexpected error(s)']))
  33. err_str = 'Unable to handle request'
  34. if reason_str:
  35. err_str += f': {reason_str}'
  36. super().__init__(msg=err_str)
  37. class TransportError(RequestError):
  38. """Network related errors"""
  39. class HTTPError(RequestError):
  40. def __init__(self, response: Response, redirect_loop=False):
  41. self.response = response
  42. self.status = response.status
  43. self.reason = response.reason
  44. self.redirect_loop = redirect_loop
  45. msg = f'HTTP Error {response.status}: {response.reason}'
  46. if redirect_loop:
  47. msg += ' (redirect loop detected)'
  48. super().__init__(msg=msg)
  49. def close(self):
  50. self.response.close()
  51. def __repr__(self):
  52. return f'<HTTPError {self.status}: {self.reason}>'
  53. class IncompleteRead(TransportError):
  54. def __init__(self, partial: int, expected: int | None = None, **kwargs):
  55. self.partial = partial
  56. self.expected = expected
  57. msg = f'{partial} bytes read'
  58. if expected is not None:
  59. msg += f', {expected} more expected'
  60. super().__init__(msg=msg, **kwargs)
  61. def __repr__(self):
  62. return f'<IncompleteRead: {self.msg}>'
  63. class SSLError(TransportError):
  64. pass
  65. class CertificateVerifyError(SSLError):
  66. """Raised when certificate validated has failed"""
  67. pass
  68. class ProxyError(TransportError):
  69. pass
  70. network_exceptions = (HTTPError, TransportError)