def test_error_code(self): a = lt.error_code() a = lt.error_code(10, lt.libtorrent_category()) self.assertEqual(a.category().name(), 'libtorrent') self.assertEqual(lt.libtorrent_category().name(), 'libtorrent') self.assertEqual(lt.upnp_category().name(), 'upnp') self.assertEqual(lt.http_category().name(), 'http') self.assertEqual(lt.socks_category().name(), 'socks') self.assertEqual(lt.bdecode_category().name(), 'bdecode') self.assertEqual(lt.generic_category().name(), 'generic') self.assertEqual(lt.system_category().name(), 'system')
def test_system_category_windows( instantiate: Callable[[lt.error_code], ltpy.Error], value: int, result_cls: type[ltpy.OSError], ) -> None: ec = lt.error_code(value, lt.system_category()) assert isinstance(instantiate(ec), result_cls)
def error_code_from_exception(exc: Exception) -> Optional[lt.error_code]: if not isinstance(exc, RuntimeError): return None msg = str(exc) lookup = _error_code_msg_lookup.get(msg) if not lookup: return None # I sampled messages in libtorrent 1.2.6 and found only collisions between # generic_category and system_category, and between deprecated # libtorrent_category values and their non-deprecated more specific # categories. # We prefer to use generic_category, as it is meant to contain portable # errno values. In particular, cpython's WinError-to-errno mapping is # fairly coarse, so mapping errno by message here will probably give better # results. # We de-prefer libtorrent_category, assuming that some error codes start # life as libtorrent_category errors then get specialized into other # categories. def cat_key(category) -> int: return { GENERIC_CATEGORY: 0, LIBTORRENT_CATEGORY: 2, }.get(category, 1) items = sorted(lookup.items(), key=lambda item: cat_key(item[0])) if not items: return None category, value = items[0] return lt.error_code(value, category)
def test_subtypes_libtorrenterror( instantiate: Callable[[lt.error_code], ltpy.Error], value: int, result_cls: type[ltpy.Error], ) -> None: ec = lt.error_code(value, lt.libtorrent_category()) assert isinstance(instantiate(ec), result_cls)
def test_subtypes_top_level( instantiate: Callable[[lt.error_code], ltpy.Error], category: lt.error_category, cls: type[ltpy.Error], ) -> None: # use a nonce value ec = lt.error_code(123, category) assert isinstance(instantiate(ec), cls)
def test_subtypes_oserror( instantiate: Callable[[lt.error_code], ltpy.Error], value: int, category: lt.error_category, result_cls: type[ltpy.OSError], ) -> None: ec = lt.error_code(value, category) assert isinstance(instantiate(ec), result_cls)
def test_from_orm(self) -> None: ec = lt.error_code() ec.assign(errno.ECANCELED, lt.generic_category()) value = ltmodels.ErrorCode.from_orm(ec) self.assertEqual( value, ltmodels.ErrorCode( category="generic", value=errno.ECANCELED, message="Operation canceled", ), )
def _init_error_code_msg_lookup() -> None: # There's no way to enumerate all error categories. Check all the ones we # know about. for category in ( GENERIC_CATEGORY, SYSTEM_CATEGORY, LIBTORRENT_CATEGORY, BDECODE_CATEGORY, HTTP_CATEGORY, I2P_CATEGORY, SOCKS_CATEGORY, UPNP_CATEGORY, ): # There's no way to enumerate all error codes covered by an # error_category. So our strategy is to get the message string for # error code #1, and keep incrementing the error code until the # messages all look the same. last_msg = None last_msg_count = 0 value = 1 while True: msg = lt.error_code(value, category).message() _error_code_msg_lookup.setdefault(msg, {}).setdefault(category, value) # At least http_category and upnp_category yield messages for # unknown error codes like "unknown code 123". We do map these # messages, but for stop condition testing we strip the decimal # value of the code. msg = msg.replace(str(value), "") if msg == last_msg: last_msg_count += 1 else: last_msg = msg last_msg_count = 1 # If error messages for the last N error codes were the same, we're # probably at the end if last_msg_count >= 1000: break # For sanity, stop after a large number of error codes if value >= 1000000: break value += 1
def test_clear(self) -> None: ec = lt.error_code(errno.ENOENT, lt.generic_category()) ec.clear() self.assertEqual(ec.value(), 0) self.assertEqual(ec.category(), lt.system_category())
def create(cls: type[_C]) -> _C: ec = lt.error_code( LibtorrentErrorValue.INVALID_TORRENT_HANDLE, lt.libtorrent_category(), ) return cls(ec)
def test_empty(self) -> None: ec = lt.error_code() self.assertEqual(ec.value(), 0)
def test_no_error() -> None: ec = lt.error_code(0, lt.generic_category()) assert ltpy.exception_from_error_code(ec) is None
def test_init(self) -> None: ec = lt.error_code(1, lt.generic_category()) self.assertEqual(ec.value(), 1) self.assertEqual(ec.category(), lt.generic_category())
def test_pickle(self) -> None: ec = lt.error_code(errno.ENOENT, lt.generic_category()) ec = pickle.loads(pickle.dumps(ec)) self.assertEqual(ec.value(), errno.ENOENT) self.assertEqual(ec.category(), lt.generic_category())
def test_assign(self) -> None: ec = lt.error_code(errno.ENOENT, lt.generic_category()) ec.assign(123, lt.libtorrent_category()) self.assertEqual(ec.value(), 123) self.assertEqual(ec.category(), lt.libtorrent_category())
def test_message(self) -> None: ec = lt.error_code(errno.ENOENT, lt.generic_category()) self.assertEqual(ec.message(), os.strerror(errno.ENOENT))
def test_value(self) -> None: ec = lt.error_code(errno.ENOENT, lt.generic_category()) self.assertEqual(ec.value(), errno.ENOENT)