From 57fd3c58013a136c4a30b1d7e7a3675ff2e42957 Mon Sep 17 00:00:00 2001 From: Lex Berezhny Date: Tue, 19 Nov 2019 13:57:14 -0500 Subject: [PATCH] updated code base to use generated errors --- lbry/lbry/error/README.md | 33 +- lbry/lbry/error/__init__.py | 583 +++++++++++++----- lbry/lbry/error/generate.py | 24 +- lbry/lbry/extras/daemon/ComponentManager.py | 4 +- lbry/lbry/extras/daemon/Daemon.py | 16 +- .../extras/daemon/exchange_rate_manager.py | 24 +- lbry/lbry/stream/downloader.py | 4 +- lbry/lbry/stream/managed_stream.py | 4 +- lbry/lbry/stream/stream_manager.py | 6 +- lbry/lbry/wallet/manager.py | 4 +- lbry/tests/integration/test_file_commands.py | 4 +- 11 files changed, 503 insertions(+), 203 deletions(-) diff --git a/lbry/lbry/error/README.md b/lbry/lbry/error/README.md index c401638f7..41cdc507f 100644 --- a/lbry/lbry/error/README.md +++ b/lbry/lbry/error/README.md @@ -1,12 +1,12 @@ Code | Name | Message | Comment ---:|---|---|--- -**1xx** | External | **Daemon `start` and other CLI command failures (non-recoverable)** -**10x** | Meta | Meta error codes not presented by `lbrynet` itself but from apps trying to interact with `lbrynet`. -104 | SDKConnectionError | Failed to establish HTTP connection to `lbrynet`. (Is it running?) -105 | SDKRPCUnresponsive | HTTP connection established but daemon is not responding to commands. -106 | SDKWebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?) -107 | SDKWebSocketConnectionError | WebSocket connection established but daemon is not responding to commands. -**11x** | System | Enough of `lbrynet` was able to start to determine external factors causing eventual failure. +**1xx** | Initialization | **Daemon `start` and other CLI command failures (non-recoverable)** +**10x** | Client | Error codes reported by clients connecting to `lbrynet` daemon. +101 | RPCConnection | Failed to establish HTTP connection to `lbrynet`. (Is it running?) +102 | RPCUnresponsive | HTTP connection established but daemon is not responding to commands. +103 | WebSocketConnection | WebSocket connection established but daemon is not responding to commands. +104 | WebSocketUnresponsive | Failed to establish WebSocket connection to `lbrynet`. (Is it running?) +**11x** | Hardware | Enough of `lbrynet` was able to start to determine external factors causing eventual failure. 110 | OutOfSpace | Out of disk space. 111 | OutOfRAM | Out of RAM. **12x** | Environment | Internal factors preventing `lbrynet` from bootstrapping itself. @@ -53,6 +53,9 @@ Code | Name | Message | Comment **32x** | ChannelSigning | Channel signing. 320 | ChannelKeyNotFound | Channel signing key not found. 321 | ChannelKeyInvalid | Channel signing key is out of date. | For example, channel was updated but you don't have the updated key. +**33x** | Resolve | Errors while resolving urls. +331 | ResolveError | Failed to resolve '{uri}'. +332 | ResolveTimeout | Failed to resolve '{uri}' within the timeout. **4xx** | Blob | **Blobs** **40x** | BlobAvailability | Blob availability. 400 | BlobNotFound | Blob not found. @@ -64,3 +67,19 @@ Code | Name | Message | Comment 411 | CorruptBlob | Blobs is corrupted. **42x** | BlobEncryption | Encrypting / Creating 420 | BlobFailedEncryption | Failed to encrypt blob. +**43x** | BlobRelated | Exceptions carried over from old error system. +431 | DownloadCancelled | Download was canceled. +432 | DownloadSDTimeout | Failed to download sd blob {download} within timeout. +433 | DownloadDataTimeout | Failed to download data blobs for sd hash {download} within timeout. +434 | InvalidStreamDescriptor | {message} +435 | InvalidData | {message} +436 | InvalidBlobHash | {message} +**5xx** | Component | **Components** +501 | ComponentStartConditionNotMet | Unresolved dependencies for: {components} +502 | ComponentsNotStarted | {message} +**6xx** | CurrencyExchange | **Currency Exchange** +601 | InvalidExchangeRateResponse | Failed to get exchange rate from {source}: {reason} +602 | CurrencyConversion | {message} +603 | InvalidCurrency | Invalid currency: {currency} is not a supported currency. +**7xx** | Purchase | Purchase process errors. +701 | KeyFeeAboveMaxAllowed | {message} \ No newline at end of file diff --git a/lbry/lbry/error/__init__.py b/lbry/lbry/error/__init__.py index a57252da0..471725e89 100644 --- a/lbry/lbry/error/__init__.py +++ b/lbry/lbry/error/__init__.py @@ -1,202 +1,473 @@ -class RPCError(Exception): - code = 0 +from .base import BaseError -class PriceDisagreementError(Exception): - pass +class InitializationError(BaseError): + """ + **Daemon `start` and other CLI command failures (non-recoverable)** + """ -class DuplicateStreamHashError(Exception): - pass +class ClientError(InitializationError): + """ + Error codes reported by clients connecting to `lbrynet` daemon. + """ -class DownloadCancelledError(Exception): - pass +class RPCConnectionError(ClientError): + def __init__(self): + super().__init__("Failed to establish HTTP connection to `lbrynet`. (Is it running?)") -class DownloadSDTimeout(Exception): - def __init__(self, download): - super().__init__(f'Failed to download sd blob {download} within timeout') - self.download = download +class RPCUnresponsiveError(ClientError): + def __init__(self): + super().__init__("HTTP connection established but daemon is not responding to commands.") -class DownloadTimeoutError(Exception): - def __init__(self, download): - super().__init__(f'Failed to download {download} within timeout') - self.download = download +class WebSocketConnectionError(ClientError): + def __init__(self): + super().__init__("WebSocket connection established but daemon is not responding to commands.") -class DownloadDataTimeout(Exception): - def __init__(self, download): - super().__init__(f'Failed to download data blobs for sd hash {download} within timeout') - self.download = download +class WebSocketUnresponsiveError(ClientError): + def __init__(self): + super().__init__("Failed to establish WebSocket connection to `lbrynet`. (Is it running?)") -class ResolveTimeout(Exception): +class HardwareError(InitializationError): + """ + Enough of `lbrynet` was able to start to determine external factors causing eventual failure. + """ + + +class OutOfSpaceError(HardwareError): + def __init__(self): + super().__init__("Out of disk space.") + + +class OutOfRAMError(HardwareError): + def __init__(self): + super().__init__("Out of RAM.") + + +class EnvironmentError(InitializationError): + """ + Internal factors preventing `lbrynet` from bootstrapping itself. + """ + + +class IncompatiblePythonError(EnvironmentError): + def __init__(self): + super().__init__("Incompatible version of Python.") + + +class IncompatibleDependencyError(EnvironmentError): + def __init__(self): + super().__init__("Incompatible version of some library.") + + +class ConfigurationError(InitializationError): + """ + Configuration errors. + """ + + +class CannotWriteConfigurationError(ConfigurationError): + """ + When writing the default config fails on startup, such as due to permission issues. + """ + def __init__(self, path): + super().__init__(f"Cannot write configuration file '{path}'.") + + +class CannotOpenConfigurationError(ConfigurationError): + """ + Can't open the config file user provided via command line args. + """ + def __init__(self, path): + super().__init__(f"Cannot find provided configuration file '{path}'.") + + +class CannotParseConfigurationError(ConfigurationError): + """ + Includes the syntax error / line number to help user fix it. + """ + def __init__(self, path): + super().__init__(f"Failed to parse the configuration file '{path}'.") + + +class ConfigurationMissingError(ConfigurationError): + def __init__(self, path): + super().__init__(f"Configuration file '{path}' is missing setting that has no default / fallback.") + + +class ConfigurationInvalidError(ConfigurationError): + def __init__(self, path): + super().__init__(f"Configuration file '{path}' has setting with invalid value.") + + +class CommandError(InitializationError): + """ + Errors preparing to execute commands. + """ + + +class CommandDoesNotExistError(CommandError): + def __init__(self, command): + super().__init__(f"Command '{command}' does not exist.") + + +class CommandDeprecatedError(CommandError): + def __init__(self, command): + super().__init__(f"Command '{command}' is deprecated.") + + +class CommandInvalidArgumentError(CommandError): + def __init__(self, command): + super().__init__(f"Invalid arguments for command '{command}'.") + + +class CommandTemporarilyUnavailableError(CommandError): + """ + Such as waiting for required components to start. + """ + def __init__(self, command): + super().__init__(f"Command '{command}' is temporarily unavailable.") + + +class CommandPermanentlyUnavailableError(CommandError): + """ + such as when required component was intentionally configured not to start. + """ + def __init__(self, command): + super().__init__(f"Command '{command}' is permanently unavailable.") + + +class NetworkingError(BaseError): + """ + **Networking** + """ + + +class ConnectivityError(NetworkingError): + """ + General connectivity. + """ + + +class NoInternetError(ConnectivityError): + def __init__(self): + super().__init__("No internet connection.") + + +class NoUPnPSupportError(ConnectivityError): + def __init__(self): + super().__init__("Router does not support UPnP.") + + +class WalletConnectivityError(NetworkingError): + """ + Wallet server connectivity. + """ + + +class WalletConnectionError(WalletConnectivityError): + """ + Should normally not need to be handled higher up as `lbrynet` will retry other servers. + """ + def __init__(self): + super().__init__("Failed connecting to a lbryumx server.") + + +class WalletConnectionsError(WalletConnectivityError): + """ + Will need to bubble up and require user to do something. + """ + def __init__(self): + super().__init__("Failed connecting to all known lbryumx servers.") + + +class WalletConnectionDroppedError(WalletConnectivityError): + """ + Maybe we were being bad? + """ + def __init__(self): + super().__init__("lbryumx droppped our connection.") + + +class WalletDisconnectedError(NetworkingError): + """ + Wallet connection dropped. + """ + + +class WalletServerSuspiciousError(WalletDisconnectedError): + def __init__(self): + super().__init__("Disconnected from lbryumx server due to suspicious responses. *generic*") + + +class WalletServerValidationError(WalletDisconnectedError): + def __init__(self): + super().__init__("Disconnected from lbryumx server due to SPV validation failure.") + + +class WalletServerHeaderError(WalletDisconnectedError): + def __init__(self): + super().__init__("Disconnected from lbryumx server due to incorrect header received.") + + +class WalletServerVersionError(WalletDisconnectedError): + def __init__(self): + super().__init__("Disconnected from lbryumx server due to incompatible protocol version.") + + +class WalletServerUnresponsiveError(WalletDisconnectedError): + def __init__(self): + super().__init__("Disconnected from lbryumx server due to unresponsiveness.") + + +class DataConnectivityError(NetworkingError): + """ + P2P connection errors. + """ + + +class DataNetworkError(NetworkingError): + """ + P2P download errors. + """ + + +class DataDownloadError(DataNetworkError): + def __init__(self): + super().__init__("Failed to download blob. *generic*") + + +class DataUploadError(NetworkingError): + """ + P2P upload errors. + """ + + +class DHTConnectivityError(NetworkingError): + """ + DHT connectivity issues. + """ + + +class DHTProtocolError(NetworkingError): + """ + DHT protocol issues. + """ + + +class BlockchainError(BaseError): + """ + **Blockchain** + """ + + +class TransactionRejectionError(BlockchainError): + """ + Transaction rejected. + """ + + +class TransactionRejectedError(TransactionRejectionError): + def __init__(self): + super().__init__("Transaction rejected, unknown reason.") + + +class TransactionFeeTooLowError(TransactionRejectionError): + def __init__(self): + super().__init__("Fee too low.") + + +class TransactionInvalidSignatureError(TransactionRejectionError): + def __init__(self): + super().__init__("Invalid signature.") + + +class InsufficientFundsError(BlockchainError): + """ + determined by wallet prior to attempting to broadcast a tx; this is different for example from a TX + being created and sent but then rejected by lbrycrd for unspendable utxos. + """ + + +class ChannelSigningError(BlockchainError): + """ + Channel signing. + """ + + +class ChannelKeyNotFoundError(ChannelSigningError): + def __init__(self): + super().__init__("Channel signing key not found.") + + +class ChannelKeyInvalidError(ChannelSigningError): + """ + For example, channel was updated but you don't have the updated key. + """ + def __init__(self): + super().__init__("Channel signing key is out of date.") + + +class ResolveError(BlockchainError): + """ + Errors while resolving urls. + """ + + +class ResolveErrorError(ResolveError): def __init__(self, uri): - super().__init__(f'Failed to resolve "{uri}" within the timeout') - self.uri = uri + super().__init__(f"Failed to resolve '{uri}'.") -class RequestCanceledError(Exception): - pass +class ResolveTimeoutError(ResolveError): + def __init__(self, uri): + super().__init__(f"Failed to resolve '{uri}' within the timeout.") -class NegativeFundsError(Exception): - pass +class BlobError(BaseError): + """ + **Blobs** + """ -class NullFundsError(Exception): - pass +class BlobAvailabilityError(BlobError): + """ + Blob availability. + """ -class InsufficientFundsError(RPCError): - code = -310 +class BlobNotFoundError(BlobAvailabilityError): + def __init__(self): + super().__init__("Blob not found.") -class CurrencyConversionError(Exception): - pass +class BlobPermissionDeniedError(BlobAvailabilityError): + def __init__(self): + super().__init__("Permission denied to read blob.") -class FileOpenError(ValueError): - # this extends ValueError because it is replacing a ValueError in EncryptedFileDownloader - # and I don't know where it might get caught upstream - pass +class BlobTooBigError(BlobAvailabilityError): + def __init__(self): + super().__init__("Blob is too big.") -class ResolveError(Exception): - pass +class BlobEmptyError(BlobAvailabilityError): + def __init__(self): + super().__init__("Blob is empty.") -class ConnectionClosedBeforeResponseError(Exception): - pass +class BlobDecryptionError(BlobError): + """ + Decryption / Assembly + """ -class KeyFeeAboveMaxAllowed(Exception): - pass +class BlobFailedDecryptionError(BlobDecryptionError): + def __init__(self): + super().__init__("Failed to decrypt blob.") -class InvalidExchangeRateResponse(Exception): +class CorruptBlobError(BlobDecryptionError): + def __init__(self): + super().__init__("Blobs is corrupted.") + + +class BlobEncryptionError(BlobError): + """ + Encrypting / Creating + """ + + +class BlobFailedEncryptionError(BlobEncryptionError): + def __init__(self): + super().__init__("Failed to encrypt blob.") + + +class BlobRelatedError(BlobError): + """ + Exceptions carried over from old error system. + """ + + +class DownloadCancelledError(BlobRelatedError): + def __init__(self): + super().__init__("Download was canceled.") + + +class DownloadSDTimeoutError(BlobRelatedError): + def __init__(self, download): + super().__init__(f"Failed to download sd blob {download} within timeout.") + + +class DownloadDataTimeoutError(BlobRelatedError): + def __init__(self, download): + super().__init__(f"Failed to download data blobs for sd hash {download} within timeout.") + + +class InvalidStreamDescriptorError(BlobRelatedError): + def __init__(self, message): + super().__init__(f"{message}") + + +class InvalidDataError(BlobRelatedError): + def __init__(self, message): + super().__init__(f"{message}") + + +class InvalidBlobHashError(BlobRelatedError): + def __init__(self, message): + super().__init__(f"{message}") + + +class ComponentError(BaseError): + """ + **Components** + """ + + +class ComponentStartConditionNotMetError(ComponentError): + def __init__(self, components): + super().__init__(f"Unresolved dependencies for: {components}") + + +class ComponentsNotStartedError(ComponentError): + def __init__(self, message): + super().__init__(f"{message}") + + +class CurrencyExchangeError(BaseError): + """ + **Currency Exchange** + """ + + +class InvalidExchangeRateResponseError(CurrencyExchangeError): def __init__(self, source, reason): - super().__init__(f'Failed to get exchange rate from {source}:{reason}') - self.source = source - self.reason = reason + super().__init__(f"Failed to get exchange rate from {source}: {reason}") -class UnknownNameError(Exception): - def __init__(self, name): - super().__init__(f'Name {name} is unknown') - self.name = name +class CurrencyConversionError(CurrencyExchangeError): + def __init__(self, message): + super().__init__(f"{message}") -class UnknownClaimID(Exception): - def __init__(self, claim_id): - super().__init__(f'Claim {claim_id} is unknown') - self.claim_id = claim_id - - -class UnknownURI(Exception): - def __init__(self, uri): - super().__init__(f'URI {uri} cannot be resolved') - self.name = uri - - -class UnknownOutpoint(Exception): - def __init__(self, outpoint): - super().__init__(f'Outpoint {outpoint} cannot be resolved') - self.outpoint = outpoint - - -class InvalidName(Exception): - def __init__(self, name, invalid_characters): - self.name = name - self.invalid_characters = invalid_characters - super().__init__( - 'URI contains invalid characters: {}'.format(','.join(invalid_characters))) - - -class UnknownStreamTypeError(Exception): - def __init__(self, stream_type): - self.stream_type = stream_type - - def __str__(self): - return repr(self.stream_type) - - -class InvalidStreamDescriptorError(Exception): - pass - - -class InvalidStreamInfoError(Exception): - def __init__(self, name, stream_info): - msg = f'{name} has claim with invalid stream info: {stream_info}' - super().__init__(msg) - self.name = name - self.stream_info = stream_info - - -class MisbehavingPeerError(Exception): - pass - - -class InvalidDataError(MisbehavingPeerError): - pass - - -class NoResponseError(MisbehavingPeerError): - pass - - -class InvalidResponseError(MisbehavingPeerError): - pass - - -class NoSuchBlobError(Exception): - pass - - -class NoSuchStreamHash(Exception): - pass - - -class NoSuchSDHash(Exception): - """ - Raised if sd hash is not known - """ - - -class InvalidBlobHashError(Exception): - pass - - -class InvalidHeaderError(Exception): - pass - - -class InvalidAuthenticationToken(Exception): - pass - - -class NegotiationError(Exception): - pass - - -class InvalidCurrencyError(Exception): +class InvalidCurrencyError(CurrencyExchangeError): def __init__(self, currency): - self.currency = currency - super().__init__( - f'Invalid currency: {currency} is not a supported currency.') + super().__init__(f"Invalid currency: {currency} is not a supported currency.") -class NoSuchDirectoryError(Exception): - def __init__(self, directory): - self.directory = directory - super().__init__(f'No such directory {directory}') +class PurchaseError(BaseError): + """ + Purchase process errors. + """ -class ComponentStartConditionNotMet(Exception): - pass +class KeyFeeAboveMaxAllowedError(PurchaseError): + def __init__(self, message): + super().__init__(f"{message}") - -class ComponentsNotStarted(Exception): - pass diff --git a/lbry/lbry/error/generate.py b/lbry/lbry/error/generate.py index 18cec88de..54ef4cf2b 100644 --- a/lbry/lbry/error/generate.py +++ b/lbry/lbry/error/generate.py @@ -1,11 +1,14 @@ import re +from textwrap import fill, indent CLASS = """ class {name}Error({parent}Error):{doc} +""" +INIT = """\ def __init__({args}): - super().__init__(f'{desc}') + super().__init__({format}"{desc}") """ INDENT = ' ' * 4 @@ -13,6 +16,7 @@ INDENT = ' ' * 4 def main(): with open('README.md', 'r') as readme: + print('from .base import BaseError\n') stack = {} started = False for line in readme.readlines(): @@ -25,19 +29,29 @@ def main(): columns = [c.strip() for c in line.split('|')] (h, code, desc), comment = columns[:3], "" if len(columns) == 4: - comment = columns[3] + comment = columns[3].strip() if h.startswith('**'): if h.count('x') == 1: parent = stack[h[2:3]][0] stack[h.replace('**', '').replace('x', '')] = (code, desc) - else: - parent = stack[h[:2]][0] + if h.count('x') == 2: + stack[h.replace('**', '').replace('x', '')+'0'] = (code, desc) + comment = f'\n{INDENT}"""\n{indent(fill(comment or desc, 100), INDENT)}\n{INDENT}"""' + print(CLASS.format(name=code, parent=parent, doc=comment)) + continue + parent = stack[h[:2]][0] args = ['self'] for arg in re.findall('{([a-z0-1]+)}', desc): args.append(arg) + fmt = "" + if len(args) > 1: + fmt = "f" if comment: comment = f'\n{INDENT}"""\n{INDENT}{comment}\n{INDENT}"""' - print(CLASS.format(name=code, parent=parent, args=', '.join(args), desc=desc, doc=comment)) + print((CLASS+INIT).format( + name=code, parent=parent, args=', '.join(args), + desc=desc, doc=comment, format=fmt + )) if __name__ == "__main__": diff --git a/lbry/lbry/extras/daemon/ComponentManager.py b/lbry/lbry/extras/daemon/ComponentManager.py index c9069a8b5..811f58561 100644 --- a/lbry/lbry/extras/daemon/ComponentManager.py +++ b/lbry/lbry/extras/daemon/ComponentManager.py @@ -1,7 +1,7 @@ import logging import asyncio from lbry.conf import Config -from lbry.error import ComponentStartConditionNotMet +from lbry.error import ComponentStartConditionNotMetError from lbry.dht.peer import PeerManager log = logging.getLogger(__name__) @@ -106,7 +106,7 @@ class ComponentManager: staged.update(to_stage) steps.append(step) elif components: - raise ComponentStartConditionNotMet("Unresolved dependencies for: %s" % components) + raise ComponentStartConditionNotMetError(components) if reverse: steps.reverse() return steps diff --git a/lbry/lbry/extras/daemon/Daemon.py b/lbry/lbry/extras/daemon/Daemon.py index d7c208e30..5c42e99f5 100644 --- a/lbry/lbry/extras/daemon/Daemon.py +++ b/lbry/lbry/extras/daemon/Daemon.py @@ -25,8 +25,7 @@ from lbry.conf import Config, Setting from lbry.blob.blob_file import is_valid_blobhash, BlobBuffer from lbry.blob_exchange.downloader import download_blob from lbry.dht.peer import make_kademlia_peer -from lbry.error import DownloadSDTimeout, ComponentsNotStarted -from lbry.error import NullFundsError, NegativeFundsError, ComponentStartConditionNotMet +from lbry.error import DownloadSDTimeoutError, ComponentsNotStartedError, ComponentStartConditionNotMetError from lbry.extras import system_info from lbry.extras.daemon import analytics from lbry.extras.daemon.Components import WALLET_COMPONENT, DATABASE_COMPONENT, DHT_COMPONENT, BLOB_COMPONENT @@ -68,10 +67,11 @@ def requires(*components, **conditions): for condition_name in condition_names: condition_result, err_msg = component_manager.evaluate_condition(condition_name) if not condition_result: - raise ComponentStartConditionNotMet(err_msg) + raise ComponentStartConditionNotMetError(err_msg) if not component_manager.all_components_running(*components): - raise ComponentsNotStarted("the following required components have not yet started: " - "%s" % json.dumps(components)) + raise ComponentsNotStartedError( + f"the following required components have not yet started: {json.dumps(components)}" + ) return fn(*args, **kwargs) return _inner @@ -962,7 +962,7 @@ class Daemon(metaclass=JSONRPCServerType): save_file=save_file, wallet=wallet ) if not stream: - raise DownloadSDTimeout(uri) + raise DownloadSDTimeoutError(uri) except Exception as e: log.warning("Error downloading %s: %s", uri, str(e)) return {"error": str(e)} @@ -1292,10 +1292,6 @@ class Daemon(metaclass=JSONRPCServerType): accounts = wallet.get_accounts_or_all(funding_account_ids) amount = self.get_dewies_or_error("amount", amount) - if not amount: - raise NullFundsError - if amount < 0: - raise NegativeFundsError() if addresses and not isinstance(addresses, list): addresses = [addresses] diff --git a/lbry/lbry/extras/daemon/exchange_rate_manager.py b/lbry/lbry/extras/daemon/exchange_rate_manager.py index 1b328e4d8..62dc4cab8 100644 --- a/lbry/lbry/extras/daemon/exchange_rate_manager.py +++ b/lbry/lbry/extras/daemon/exchange_rate_manager.py @@ -5,7 +5,7 @@ import json from decimal import Decimal from typing import Optional from aiohttp.client_exceptions import ClientError -from lbry.error import InvalidExchangeRateResponse, CurrencyConversionError +from lbry.error import InvalidExchangeRateResponseError, CurrencyConversionError from lbry.utils import aiohttp_request from lbry.wallet.dewies import lbc_to_dewies @@ -81,7 +81,7 @@ class MarketFeed: try: response = await asyncio.wait_for(self._make_request(), self.REQUESTS_TIMEOUT) self._save_price(self._subtract_fee(self._handle_response(response))) - except (asyncio.TimeoutError, InvalidExchangeRateResponse, ClientError) as err: + except (asyncio.TimeoutError, InvalidExchangeRateResponseError, ClientError) as err: self._on_error(err) await asyncio.sleep(self.EXCHANGE_RATE_UPDATE_RATE_SEC) @@ -108,14 +108,14 @@ class BittrexFeed(MarketFeed): def _handle_response(self, response): json_response = json.loads(response) if 'result' not in json_response: - raise InvalidExchangeRateResponse(self.name, 'result not found') + raise InvalidExchangeRateResponseError(self.name, 'result not found') trades = json_response['result'] if len(trades) == 0: - raise InvalidExchangeRateResponse(self.market, 'trades not found') + raise InvalidExchangeRateResponseError(self.market, 'trades not found') totals = sum([i['Total'] for i in trades]) qtys = sum([i['Quantity'] for i in trades]) if totals <= 0 or qtys <= 0: - raise InvalidExchangeRateResponse(self.market, 'quantities were not positive') + raise InvalidExchangeRateResponseError(self.market, 'quantities were not positive') vwap = totals / qtys return float(1.0 / vwap) @@ -133,7 +133,7 @@ class LBRYioFeed(MarketFeed): def _handle_response(self, response): json_response = json.loads(response) if 'data' not in json_response: - raise InvalidExchangeRateResponse(self.name, 'result not found') + raise InvalidExchangeRateResponseError(self.name, 'result not found') return 1.0 / json_response['data']['lbc_btc'] @@ -151,9 +151,9 @@ class LBRYioBTCFeed(MarketFeed): try: json_response = json.loads(response) except ValueError: - raise InvalidExchangeRateResponse(self.name, "invalid rate response : %s" % response) + raise InvalidExchangeRateResponseError(self.name, "invalid rate response : %s" % response) if 'data' not in json_response: - raise InvalidExchangeRateResponse(self.name, 'result not found') + raise InvalidExchangeRateResponseError(self.name, 'result not found') return 1.0 / json_response['data']['btc_usd'] @@ -171,10 +171,10 @@ class CryptonatorBTCFeed(MarketFeed): try: json_response = json.loads(response) except ValueError: - raise InvalidExchangeRateResponse(self.name, "invalid rate response") + raise InvalidExchangeRateResponseError(self.name, "invalid rate response") if 'ticker' not in json_response or len(json_response['ticker']) == 0 or \ 'success' not in json_response or json_response['success'] is not True: - raise InvalidExchangeRateResponse(self.name, 'result not found') + raise InvalidExchangeRateResponseError(self.name, 'result not found') return float(json_response['ticker']['price']) @@ -192,10 +192,10 @@ class CryptonatorFeed(MarketFeed): try: json_response = json.loads(response) except ValueError: - raise InvalidExchangeRateResponse(self.name, "invalid rate response") + raise InvalidExchangeRateResponseError(self.name, "invalid rate response") if 'ticker' not in json_response or len(json_response['ticker']) == 0 or \ 'success' not in json_response or json_response['success'] is not True: - raise InvalidExchangeRateResponse(self.name, 'result not found') + raise InvalidExchangeRateResponseError(self.name, 'result not found') return float(json_response['ticker']['price']) diff --git a/lbry/lbry/stream/downloader.py b/lbry/lbry/stream/downloader.py index fae884f6f..ea478b0ed 100644 --- a/lbry/lbry/stream/downloader.py +++ b/lbry/lbry/stream/downloader.py @@ -4,7 +4,7 @@ import logging import binascii from lbry.dht.peer import make_kademlia_peer -from lbry.error import DownloadSDTimeout +from lbry.error import DownloadSDTimeoutError from lbry.utils import resolve_host, lru_cache_concurrent from lbry.stream.descriptor import StreamDescriptor from lbry.blob_exchange.downloader import BlobDownloader @@ -82,7 +82,7 @@ class StreamDownloader: log.info("downloaded sd blob %s", self.sd_hash) self.time_to_descriptor = self.loop.time() - now except asyncio.TimeoutError: - raise DownloadSDTimeout(self.sd_hash) + raise DownloadSDTimeoutError(self.sd_hash) # parse the descriptor self.descriptor = await StreamDescriptor.from_stream_descriptor_blob( diff --git a/lbry/lbry/stream/managed_stream.py b/lbry/lbry/stream/managed_stream.py index 3a5de6f5d..5558d3370 100644 --- a/lbry/lbry/stream/managed_stream.py +++ b/lbry/lbry/stream/managed_stream.py @@ -6,7 +6,7 @@ import logging import binascii from aiohttp.web import Request, StreamResponse, HTTPRequestRangeNotSatisfiable from lbry.utils import generate_id -from lbry.error import DownloadSDTimeout +from lbry.error import DownloadSDTimeoutError from lbry.schema.mime_types import guess_media_type from lbry.stream.downloader import StreamDownloader from lbry.stream.descriptor import StreamDescriptor, sanitize_file_name @@ -253,7 +253,7 @@ class ManagedStream: await asyncio.wait_for(self.downloader.start(node), timeout, loop=self.loop) except asyncio.TimeoutError: self._running.clear() - raise DownloadSDTimeout(self.sd_hash) + raise DownloadSDTimeoutError(self.sd_hash) if self.delayed_stop_task and not self.delayed_stop_task.done(): self.delayed_stop_task.cancel() diff --git a/lbry/lbry/stream/stream_manager.py b/lbry/lbry/stream/stream_manager.py index 4ab4fb4d6..b38ab0a97 100644 --- a/lbry/lbry/stream/stream_manager.py +++ b/lbry/lbry/stream/stream_manager.py @@ -7,7 +7,7 @@ import typing from typing import Optional from aiohttp.web import Request from lbry.error import ResolveError, InvalidStreamDescriptorError -from lbry.error import ResolveTimeout, DownloadDataTimeout +from lbry.error import ResolveTimeoutError, DownloadDataTimeoutError from lbry.utils import cache_concurrent from lbry.stream.descriptor import StreamDescriptor from lbry.stream.managed_stream import ManagedStream @@ -371,7 +371,7 @@ class StreamManager: ) resolved_result = self._convert_to_old_resolve_output(manager, response) except asyncio.TimeoutError: - raise ResolveTimeout(uri) + raise ResolveTimeoutError(uri) except Exception as err: if isinstance(err, asyncio.CancelledError): raise @@ -437,7 +437,7 @@ class StreamManager: loop=self.loop) return stream except asyncio.TimeoutError: - error = DownloadDataTimeout(stream.sd_hash) + error = DownloadDataTimeoutError(stream.sd_hash) raise error except Exception as err: # forgive data timeout, don't delete stream log.exception("Unexpected error downloading stream:") diff --git a/lbry/lbry/wallet/manager.py b/lbry/lbry/wallet/manager.py index c936a2140..5a012d68a 100644 --- a/lbry/lbry/wallet/manager.py +++ b/lbry/lbry/wallet/manager.py @@ -9,7 +9,7 @@ from torba.client.basemanager import BaseWalletManager from torba.client.wallet import ENCRYPT_ON_DISK from torba.rpc.jsonrpc import CodeMessageError -from lbry.error import KeyFeeAboveMaxAllowed +from lbry.error import KeyFeeAboveMaxAllowedError from lbry.wallet.dewies import dewies_to_lbc from lbry.wallet.account import Account from lbry.wallet.ledger import MainNetLedger @@ -199,7 +199,7 @@ class LbryWalletManager(BaseWalletManager): error_max_fee = f"{dewies_to_lbc(max_fee_amount)} LBC" if max_fee['currency'] != 'LBC': error_max_fee += f" ({max_fee['amount']} {max_fee['currency']})" - raise KeyFeeAboveMaxAllowed( + raise KeyFeeAboveMaxAllowedError( f"Purchase price of {error_fee} exceeds maximum " f"configured price of {error_max_fee}." ) diff --git a/lbry/tests/integration/test_file_commands.py b/lbry/tests/integration/test_file_commands.py index 01579bb70..f324e803f 100644 --- a/lbry/tests/integration/test_file_commands.py +++ b/lbry/tests/integration/test_file_commands.py @@ -205,12 +205,12 @@ class FileCommands(CommandTestCase): await self.server.blob_manager.delete_blobs(all_except_sd) resp = await self.daemon.jsonrpc_get('lbry://foo', timeout=2, save_file=True) self.assertIn('error', resp) - self.assertEqual('Failed to download data blobs for sd hash %s within timeout' % sd_hash, resp['error']) + self.assertEqual('Failed to download data blobs for sd hash %s within timeout.' % sd_hash, resp['error']) self.assertTrue(await self.daemon.jsonrpc_file_delete(claim_name='foo'), "data timeout didn't create a file") await self.server.blob_manager.delete_blobs([sd_hash]) resp = await self.daemon.jsonrpc_get('lbry://foo', timeout=2, save_file=True) self.assertIn('error', resp) - self.assertEqual('Failed to download sd blob %s within timeout' % sd_hash, resp['error']) + self.assertEqual('Failed to download sd blob %s within timeout.' % sd_hash, resp['error']) async def wait_files_to_complete(self): while await self.file_list(status='running'):