api: Use custom exceptions in API client.

This removes the use of RuntimeError, and replaces it with a custom
error class called ZulipError.  In a few places, we use a subclass to
make it easier for code to interact with the error type.
This commit is contained in:
Shivam Gera 2018-01-28 01:51:49 +05:30 committed by Tim Abbott
parent b7b083f094
commit fc1d134685
2 changed files with 24 additions and 18 deletions

View file

@ -7,7 +7,7 @@ import unittest
import zulip import zulip
from unittest import TestCase from unittest import TestCase
from zulip import ZulipError
if six.PY2: if six.PY2:
from mock import patch from mock import patch
else: else:
@ -38,7 +38,7 @@ Zulip API configuration:
parser = zulip.add_default_arguments(argparse.ArgumentParser(usage="lorem ipsum")) parser = zulip.add_default_arguments(argparse.ArgumentParser(usage="lorem ipsum"))
test_path = '~/zuliprc' test_path = '~/zuliprc'
args = parser.parse_args(['--config-file', test_path]) args = parser.parse_args(['--config-file', test_path])
with self.assertRaises(RuntimeError) as cm: with self.assertRaises(ZulipError) as cm:
zulip.init_from_options(args) zulip.init_from_options(args)
expanded_test_path = os.path.abspath(os.path.expanduser(test_path)) expanded_test_path = os.path.abspath(os.path.expanduser(test_path))
self.assertEqual(str(cm.exception), 'api_key or email not specified and ' self.assertEqual(str(cm.exception), 'api_key or email not specified and '

View file

@ -267,13 +267,19 @@ def get_default_config_filename():
config_file = os.path.join(os.environ["HOME"], ".zuliprc") config_file = os.path.join(os.environ["HOME"], ".zuliprc")
if (not os.path.exists(config_file) and if (not os.path.exists(config_file) and
os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))): os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))):
raise RuntimeError("The Zulip API configuration file is now ~/.zuliprc; please run:\n\n" raise ZulipError("The Zulip API configuration file is now ~/.zuliprc; please run:\n\n"
" mv ~/.humbugrc ~/.zuliprc\n") " mv ~/.humbugrc ~/.zuliprc\n")
return config_file return config_file
class ZulipError(Exception): class ZulipError(Exception):
pass pass
class ConfigNotFoundError(ZulipError):
pass
class MissingURLError(ZulipError):
pass
class Client(object): class Client(object):
def __init__(self, email=None, api_key=None, config_file=None, def __init__(self, email=None, api_key=None, config_file=None,
verbose=False, retry_on_errors=True, verbose=False, retry_on_errors=True,
@ -331,10 +337,10 @@ class Client(object):
elif insecure_setting == "false": elif insecure_setting == "false":
insecure = False insecure = False
else: else:
raise RuntimeError("insecure is set to '%s', it must be 'true' or 'false' if it is used in %s" raise ZulipError("insecure is set to '%s', it must be 'true' or 'false' if it is used in %s"
% (insecure_setting, config_file)) % (insecure_setting, config_file))
elif None in (api_key, email): elif None in (api_key, email):
raise RuntimeError("api_key or email not specified and file %s does not exist" raise ConfigNotFoundError("api_key or email not specified and file %s does not exist"
% (config_file,)) % (config_file,))
assert(api_key is not None and email is not None) assert(api_key is not None and email is not None)
@ -350,7 +356,7 @@ class Client(object):
site = site.rstrip("/") site = site.rstrip("/")
self.base_url = site self.base_url = site
else: else:
raise RuntimeError("Missing Zulip server URL; specify via --site or ~/.zuliprc.") raise MissingURLError("Missing Zulip server URL; specify via --site or ~/.zuliprc.")
if not self.base_url.endswith("/api"): if not self.base_url.endswith("/api"):
self.base_url += "/api" self.base_url += "/api"
@ -362,7 +368,7 @@ class Client(object):
self.tls_verification = False # type: Union[bool, str] self.tls_verification = False # type: Union[bool, str]
elif cert_bundle is not None: elif cert_bundle is not None:
if not os.path.isfile(cert_bundle): if not os.path.isfile(cert_bundle):
raise RuntimeError("tls bundle '%s' does not exist" raise ConfigNotFoundError("tls bundle '%s' does not exist"
% (cert_bundle,)) % (cert_bundle,))
self.tls_verification = cert_bundle self.tls_verification = cert_bundle
else: else:
@ -371,15 +377,15 @@ class Client(object):
if client_cert is None: if client_cert is None:
if client_cert_key is not None: if client_cert_key is not None:
raise RuntimeError("client cert key '%s' specified, but no client cert public part provided" raise ConfigNotFoundError("client cert key '%s' specified, but no client cert public part provided"
% (client_cert_key,)) % (client_cert_key,))
else: # we have a client cert else: # we have a client cert
if not os.path.isfile(client_cert): if not os.path.isfile(client_cert):
raise RuntimeError("client cert '%s' does not exist" raise ConfigNotFoundError("client cert '%s' does not exist"
% (client_cert,)) % (client_cert,))
if client_cert_key is not None: if client_cert_key is not None:
if not os.path.isfile(client_cert_key): if not os.path.isfile(client_cert_key):
raise RuntimeError("client cert key '%s' does not exist" raise ConfigNotFoundError("client cert key '%s' does not exist"
% (client_cert_key,)) % (client_cert_key,))
self.client_cert = client_cert self.client_cert = client_cert
self.client_cert_key = client_cert_key self.client_cert_key = client_cert_key
@ -398,7 +404,7 @@ class Client(object):
# Build a client cert object for requests # Build a client cert object for requests
if self.client_cert_key is not None: if self.client_cert_key is not None:
assert(self.client_cert is not None) # Otherwise RuntimeError near end of __init__ assert(self.client_cert is not None) # Otherwise ZulipError near end of __init__
client_cert = (self.client_cert, self.client_cert_key) # type: Union[None, str, Tuple[str, str]] client_cert = (self.client_cert, self.client_cert_key) # type: Union[None, str, Tuple[str, str]]
else: else:
client_cert = self.client_cert client_cert = self.client_cert