register api command with metaclass, add deprecated and flags decorators

This commit is contained in:
Jack Robison 2017-05-28 15:59:17 -04:00
parent 17b692d258
commit 0b4c4cf6ca
2 changed files with 95 additions and 18 deletions

View file

@ -990,6 +990,7 @@ class Daemon(AuthJSONRPCServer):
############################################################################ ############################################################################
@defer.inlineCallbacks @defer.inlineCallbacks
@AuthJSONRPCServer.flags(session_status="-s", dht_status="-d")
def jsonrpc_status(self, session_status=False, dht_status=False): def jsonrpc_status(self, session_status=False, dht_status=False):
""" """
Return daemon status Return daemon status
@ -1042,6 +1043,7 @@ class Daemon(AuthJSONRPCServer):
response['dht_status'] = self.session.dht_node.get_bandwidth_stats() response['dht_status'] = self.session.dht_node.get_bandwidth_stats()
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('status')
def jsonrpc_get_best_blockhash(self): def jsonrpc_get_best_blockhash(self):
""" """
DEPRECATED. Use `status blockchain_status=True` instead DEPRECATED. Use `status blockchain_status=True` instead
@ -1051,6 +1053,7 @@ class Daemon(AuthJSONRPCServer):
x['blockchain_status']['best_blockhash'])) x['blockchain_status']['best_blockhash']))
return d return d
@AuthJSONRPCServer.deprecated('status')
def jsonrpc_is_running(self): def jsonrpc_is_running(self):
""" """
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
@ -1059,6 +1062,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda x: self._render_response(x['is_running'])) d.addCallback(lambda x: self._render_response(x['is_running']))
return d return d
@AuthJSONRPCServer.deprecated('status')
def jsonrpc_daemon_status(self): def jsonrpc_daemon_status(self):
""" """
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
@ -1094,6 +1098,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda x: self._render_response(x)) # is this necessary? d.addCallback(lambda x: self._render_response(x)) # is this necessary?
return d return d
@AuthJSONRPCServer.deprecated('status')
def jsonrpc_is_first_run(self): def jsonrpc_is_first_run(self):
""" """
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
@ -1102,6 +1107,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda x: self._render_response(x['is_first_run'])) d.addCallback(lambda x: self._render_response(x['is_first_run']))
return d return d
@AuthJSONRPCServer.deprecated('status')
def jsonrpc_get_lbry_session_info(self): def jsonrpc_get_lbry_session_info(self):
""" """
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
@ -1115,6 +1121,7 @@ class Daemon(AuthJSONRPCServer):
})) }))
return d return d
@AuthJSONRPCServer.deprecated('status')
def jsonrpc_get_time_behind_blockchain(self): def jsonrpc_get_time_behind_blockchain(self):
""" """
DEPRECATED. Use `status` instead DEPRECATED. Use `status` instead
@ -1168,6 +1175,7 @@ class Daemon(AuthJSONRPCServer):
) )
return self._render_response(True) return self._render_response(True)
@AuthJSONRPCServer.deprecated('settings_get')
def jsonrpc_get_settings(self): def jsonrpc_get_settings(self):
""" """
DEPRECATED. Use `settings_get` instead. DEPRECATED. Use `settings_get` instead.
@ -1184,6 +1192,7 @@ class Daemon(AuthJSONRPCServer):
""" """
return self._render_response(conf.settings.get_adjustable_settings_dict()) return self._render_response(conf.settings.get_adjustable_settings_dict())
@AuthJSONRPCServer.deprecated('settings_set')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_set_settings(self, **kwargs): def jsonrpc_set_settings(self, **kwargs):
""" """
@ -1256,12 +1265,14 @@ class Daemon(AuthJSONRPCServer):
if 'DEPRECATED' not in getattr(self, "jsonrpc_" + command).__doc__] if 'DEPRECATED' not in getattr(self, "jsonrpc_" + command).__doc__]
)) ))
@AuthJSONRPCServer.deprecated('wallet_balance')
def jsonrpc_get_balance(self, address=None, include_unconfirmed=False): def jsonrpc_get_balance(self, address=None, include_unconfirmed=False):
""" """
DEPRECATED. Use `wallet_balance` instead. DEPRECATED. Use `wallet_balance` instead.
""" """
return self.jsonrpc_wallet_balance(address, include_unconfirmed) return self.jsonrpc_wallet_balance(address, include_unconfirmed)
@AuthJSONRPCServer.flags(include_unconfirmed='-u')
def jsonrpc_wallet_balance(self, address=None, include_unconfirmed=False): def jsonrpc_wallet_balance(self, address=None, include_unconfirmed=False):
""" """
Return the balance of the wallet Return the balance of the wallet
@ -1280,6 +1291,7 @@ class Daemon(AuthJSONRPCServer):
return self._render_response(float( return self._render_response(float(
self.session.wallet.get_address_balance(address, include_unconfirmed))) self.session.wallet.get_address_balance(address, include_unconfirmed)))
@AuthJSONRPCServer.deprecated('daemon_stop')
def jsonrpc_stop(self): def jsonrpc_stop(self):
""" """
DEPRECATED. Use `daemon_stop` instead. DEPRECATED. Use `daemon_stop` instead.
@ -1301,6 +1313,7 @@ class Daemon(AuthJSONRPCServer):
defer.returnValue(response) defer.returnValue(response)
@defer.inlineCallbacks @defer.inlineCallbacks
@AuthJSONRPCServer.flags(full_status='-f')
def jsonrpc_file_list(self, **kwargs): def jsonrpc_file_list(self, **kwargs):
""" """
List files limited by optional filters List files limited by optional filters
@ -1348,6 +1361,7 @@ class Daemon(AuthJSONRPCServer):
defer.returnValue(response) defer.returnValue(response)
@defer.inlineCallbacks @defer.inlineCallbacks
@AuthJSONRPCServer.flags(force='-f')
def jsonrpc_resolve_name(self, name, force=False): def jsonrpc_resolve_name(self, name, force=False):
""" """
Resolve stream info from a LBRY name Resolve stream info from a LBRY name
@ -1367,6 +1381,7 @@ class Daemon(AuthJSONRPCServer):
else: else:
defer.returnValue(metadata) defer.returnValue(metadata)
@AuthJSONRPCServer.deprecated('claim_show')
def jsonrpc_get_claim_info(self, **kwargs): def jsonrpc_get_claim_info(self, **kwargs):
""" """
DEPRECATED. Use `claim_show` instead. DEPRECATED. Use `claim_show` instead.
@ -1414,6 +1429,7 @@ class Daemon(AuthJSONRPCServer):
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
@AuthJSONRPCServer.flags(force='-f')
def jsonrpc_resolve(self, uri, force=False): def jsonrpc_resolve(self, uri, force=False):
""" """
Resolve a LBRY URI Resolve a LBRY URI
@ -1568,6 +1584,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(result) response = yield self._render_response(result)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('file_set_status')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_stop_lbry_file(self, **kwargs): def jsonrpc_stop_lbry_file(self, **kwargs):
""" """
@ -1575,6 +1592,7 @@ class Daemon(AuthJSONRPCServer):
""" """
return self.jsonrpc_file_set_status(status='stop', **kwargs) return self.jsonrpc_file_set_status(status='stop', **kwargs)
@AuthJSONRPCServer.deprecated('file_set_status')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_start_lbry_file(self, **kwargs): def jsonrpc_start_lbry_file(self, **kwargs):
""" """
@ -1618,6 +1636,7 @@ class Daemon(AuthJSONRPCServer):
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
@defer.inlineCallbacks @defer.inlineCallbacks
@AuthJSONRPCServer.flags(delete_target_file='-f', delete_all='-a')
def jsonrpc_file_delete(self, delete_target_file=True, delete_all=False, **kwargs): def jsonrpc_file_delete(self, delete_target_file=True, delete_all=False, **kwargs):
""" """
Delete a lbry file Delete a lbry file
@ -1663,6 +1682,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(result) response = yield self._render_response(result)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('stream_cost_estimate')
def jsonrpc_get_est_cost(self, **kwargs): def jsonrpc_get_est_cost(self, **kwargs):
""" """
DEPRECATED. Use `stream_cost_estimate` instead DEPRECATED. Use `stream_cost_estimate` instead
@ -1883,6 +1903,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(result) response = yield self._render_response(result)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('claim_abandon')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_abandon_claim(self, **kwargs): def jsonrpc_abandon_claim(self, **kwargs):
""" """
@ -1919,6 +1940,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(err) response = yield self._render_response(err)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('claim_abandon')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_abandon_name(self, **kwargs): def jsonrpc_abandon_name(self, **kwargs):
""" """
@ -1926,6 +1948,7 @@ class Daemon(AuthJSONRPCServer):
""" """
return self.jsonrpc_claim_abandon(**kwargs) return self.jsonrpc_claim_abandon(**kwargs)
@AuthJSONRPCServer.deprecated('claim_support_new')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_support_claim(self, **kwargs): def jsonrpc_support_claim(self, **kwargs):
""" """
@ -1957,6 +1980,7 @@ class Daemon(AuthJSONRPCServer):
defer.returnValue(result) defer.returnValue(result)
# TODO: merge this into claim_list # TODO: merge this into claim_list
@AuthJSONRPCServer.deprecated('claim_list_mine')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_my_claim(self, name): def jsonrpc_get_my_claim(self, name):
""" """
@ -1974,6 +1998,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.deprecated('claim_list_mine')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_name_claims(self): def jsonrpc_get_name_claims(self):
""" """
@ -2016,12 +2041,14 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda claims: self._render_response(claims)) d.addCallback(lambda claims: self._render_response(claims))
return d return d
@AuthJSONRPCServer.deprecated('claim_list')
def jsonrpc_get_claims_for_name(self, **kwargs): def jsonrpc_get_claims_for_name(self, **kwargs):
""" """
DEPRECATED. Use `claim_list` instead. DEPRECATED. Use `claim_list` instead.
""" """
return self.jsonrpc_claim_list(**kwargs) return self.jsonrpc_claim_list(**kwargs)
@AuthJSONRPCServer.deprecated('claim_list')
def jsonrpc_get_claims_for_tx(self, **kwargs): def jsonrpc_get_claims_for_tx(self, **kwargs):
""" """
DEPRECATED. Use `claim_list` instead. DEPRECATED. Use `claim_list` instead.
@ -2060,6 +2087,7 @@ class Daemon(AuthJSONRPCServer):
claims = yield self.session.wallet.get_claims_for_name(name) claims = yield self.session.wallet.get_claims_for_name(name)
defer.returnValue(claims) defer.returnValue(claims)
@AuthJSONRPCServer.deprecated('transaction_list')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_transaction_history(self): def jsonrpc_get_transaction_history(self):
""" """
@ -2082,6 +2110,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.deprecated('transaction_show')
def jsonrpc_get_transaction(self, txid): def jsonrpc_get_transaction(self, txid):
""" """
DEPRECATED. Use `transaction_show` instead DEPRECATED. Use `transaction_show` instead
@ -2102,6 +2131,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.deprecated('wallet_is_address_mine')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_address_is_mine(self, address): def jsonrpc_address_is_mine(self, address):
""" """
@ -2124,6 +2154,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda is_mine: self._render_response(is_mine)) d.addCallback(lambda is_mine: self._render_response(is_mine))
return d return d
@AuthJSONRPCServer.deprecated('wallet_public_key')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_public_key_from_wallet(self, wallet): def jsonrpc_get_public_key_from_wallet(self, wallet):
""" """
@ -2163,6 +2194,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(addresses) response = yield self._render_response(addresses)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('wallet_new_address')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_get_new_address(self): def jsonrpc_get_new_address(self):
""" """
@ -2231,6 +2263,7 @@ class Daemon(AuthJSONRPCServer):
self.analytics_manager.send_credits_sent() self.analytics_manager.send_credits_sent()
defer.returnValue(True) defer.returnValue(True)
@AuthJSONRPCServer.deprecated('block_show')
def jsonrpc_get_block(self, **kwargs): def jsonrpc_get_block(self, **kwargs):
""" """
DEPRECATED. Use `block_show` instead DEPRECATED. Use `block_show` instead
@ -2259,6 +2292,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.deprecated('descriptor_get')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_download_descriptor(self, **kwargs): def jsonrpc_download_descriptor(self, **kwargs):
""" """
@ -2266,6 +2300,7 @@ class Daemon(AuthJSONRPCServer):
""" """
return self.jsonrpc_descriptor_get(**kwargs) return self.jsonrpc_descriptor_get(**kwargs)
@AuthJSONRPCServer.deprecated('blob_get')
@AuthJSONRPCServer.auth_required @AuthJSONRPCServer.auth_required
def jsonrpc_descriptor_get(self, sd_hash, timeout=None, payment_rate_manager=None): def jsonrpc_descriptor_get(self, sd_hash, timeout=None, payment_rate_manager=None):
""" """
@ -2345,6 +2380,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response("Deleted %s" % blob_hash) response = yield self._render_response("Deleted %s" % blob_hash)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('peer_list')
def jsonrpc_get_peers_for_hash(self, blob_hash): def jsonrpc_get_peers_for_hash(self, blob_hash):
""" """
DEPRECATED. Use `peer_list` instead DEPRECATED. Use `peer_list` instead
@ -2369,6 +2405,7 @@ class Daemon(AuthJSONRPCServer):
d.addCallback(lambda r: self._render_response(r)) d.addCallback(lambda r: self._render_response(r))
return d return d
@AuthJSONRPCServer.deprecated('blob_announce_all')
def jsonrpc_announce_all_blobs_to_dht(self): def jsonrpc_announce_all_blobs_to_dht(self):
""" """
DEPRECATED. Use `blob_announce_all` instead. DEPRECATED. Use `blob_announce_all` instead.
@ -2406,6 +2443,7 @@ class Daemon(AuthJSONRPCServer):
yield reupload.reflect_stream(lbry_file) yield reupload.reflect_stream(lbry_file)
defer.returnValue("Reflect success") defer.returnValue("Reflect success")
@AuthJSONRPCServer.deprecated('blob_list')
def jsonrpc_get_blob_hashes(self): def jsonrpc_get_blob_hashes(self):
""" """
DEPRECATED. Use `blob_list` instead DEPRECATED. Use `blob_list` instead
@ -2461,6 +2499,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(blob_hashes_for_return) response = yield self._render_response(blob_hashes_for_return)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('blob_reflect_all')
def jsonrpc_reflect_all_blobs(self): def jsonrpc_reflect_all_blobs(self):
""" """
DEPRECATED. Use `blob_reflect_all` instead DEPRECATED. Use `blob_reflect_all` instead
@ -2554,6 +2593,7 @@ class Daemon(AuthJSONRPCServer):
response = yield self._render_response(mean_availability) response = yield self._render_response(mean_availability)
defer.returnValue(response) defer.returnValue(response)
@AuthJSONRPCServer.deprecated('status')
def jsonrpc_get_start_notice(self): def jsonrpc_get_start_notice(self):
""" """
DEPRECATED. DEPRECATED.

View file

@ -110,21 +110,30 @@ def jsonrpc_dumps_pretty(obj, **kwargs):
separators=(',', ': '), **kwargs) + "\n" separators=(',', ': '), **kwargs) + "\n"
class AuthorizedBase(object): class JSONRPCServerType(type):
def __init__(self): def __new__(mcs, name, bases, newattrs):
self.authorized_functions = [] klass = type.__new__(mcs, name, bases, newattrs)
self.callable_methods = {} klass.callable_methods = {}
self._call_lock = {} klass.deprecated_methods = {}
self._queued_methods = [] klass.authorized_functions = []
klass.queued_methods = []
for methodname in dir(self): for methodname in dir(klass):
if methodname.startswith("jsonrpc_"): if methodname.startswith("jsonrpc_"):
method = getattr(self, methodname) method = getattr(klass, methodname)
self.callable_methods.update({methodname.split("jsonrpc_")[1]: method}) if not hasattr(method, '_deprecated'):
if hasattr(method, '_auth_required'): klass.callable_methods.update({methodname.split("jsonrpc_")[1]: method})
self.authorized_functions.append(methodname.split("jsonrpc_")[1]) if hasattr(method, '_auth_required'):
if hasattr(method, '_queued'): klass.authorized_functions.append(methodname.split("jsonrpc_")[1])
self._queued_methods.append(methodname.split("jsonrpc_")[1]) if hasattr(method, '_queued'):
klass.queued_methods.append(methodname.split("jsonrpc_")[1])
else:
klass.deprecated_methods.update({methodname.split("jsonrpc_")[1]: method})
return klass
class AuthorizedBase(object):
__metaclass__ = JSONRPCServerType
@staticmethod @staticmethod
def auth_required(f): def auth_required(f):
@ -136,6 +145,23 @@ class AuthorizedBase(object):
f._queued = True f._queued = True
return f return f
@staticmethod
def deprecated(new_command=None):
def _deprecated_wrapper(f):
f._new_command = new_command
f._deprecated = True
return f
return _deprecated_wrapper
@staticmethod
def flags(**kwargs):
def _flag_wrapper(f):
f._flags = {}
for k, v in kwargs.iteritems():
f._flags[v] = k
return f
return _flag_wrapper
class AuthJSONRPCServer(AuthorizedBase): class AuthJSONRPCServer(AuthorizedBase):
"""Authorized JSONRPC server used as the base class for the LBRY API """Authorized JSONRPC server used as the base class for the LBRY API
@ -164,7 +190,7 @@ class AuthJSONRPCServer(AuthorizedBase):
isLeaf = True isLeaf = True
def __init__(self, use_authentication=None): def __init__(self, use_authentication=None):
AuthorizedBase.__init__(self) self._call_lock = {}
self._use_authentication = ( self._use_authentication = (
use_authentication if use_authentication is not None else conf.settings['use_auth_http'] use_authentication if use_authentication is not None else conf.settings['use_auth_http']
) )
@ -263,7 +289,7 @@ class AuthJSONRPCServer(AuthorizedBase):
id_ = None id_ = None
try: try:
function_name = parsed.get('method') function_name = parsed.get('method')
is_queued = function_name in self._queued_methods is_queued = function_name in self.queued_methods
args = parsed.get('params', {}) args = parsed.get('params', {})
id_ = parsed.get('id', None) id_ = parsed.get('id', None)
token = parsed.pop('hmac', None) token = parsed.pop('hmac', None)
@ -337,7 +363,7 @@ class AuthJSONRPCServer(AuthorizedBase):
if is_queued: if is_queued:
d_lock = self._call_lock.get(function_name, False) d_lock = self._call_lock.get(function_name, False)
if not d_lock: if not d_lock:
d = defer.maybeDeferred(function, **args_dict) d = defer.maybeDeferred(function, self, **args_dict)
self._call_lock[function_name] = finished_deferred self._call_lock[function_name] = finished_deferred
def _del_lock(*args): def _del_lock(*args):
@ -352,9 +378,9 @@ class AuthJSONRPCServer(AuthorizedBase):
log.info("queued %s", function_name) log.info("queued %s", function_name)
d = d_lock d = d_lock
d.addBoth(lambda _: log.info("running %s from queue", function_name)) d.addBoth(lambda _: log.info("running %s from queue", function_name))
d.addCallback(lambda _: defer.maybeDeferred(function, **args_dict)) d.addCallback(lambda _: defer.maybeDeferred(function, self, **args_dict))
else: else:
d = defer.maybeDeferred(function, **args_dict) d = defer.maybeDeferred(function, self, **args_dict)
# finished_deferred will callback when the request is finished # finished_deferred will callback when the request is finished
# and errback if something went wrong. If the errback is # and errback if something went wrong. If the errback is
@ -454,6 +480,16 @@ class AuthJSONRPCServer(AuthorizedBase):
else: else:
return server_port[0], 80 return server_port[0], 80
def _check_deprecated(self, function_path):
if function_path in self.deprecated_methods:
deprecated_fn = self.deprecated_methods[function_path]
deprecated_function_path = function_path
new_function_path = deprecated_fn._new_command
log.warning("\"%s\" is deprecated, please update to use \"%s\"",
deprecated_function_path, new_function_path)
return new_function_path
return function_path
def _verify_method_is_callable(self, function_path): def _verify_method_is_callable(self, function_path):
if function_path not in self.callable_methods: if function_path not in self.callable_methods:
raise UnknownAPIMethodError(function_path) raise UnknownAPIMethodError(function_path)
@ -462,6 +498,7 @@ class AuthJSONRPCServer(AuthorizedBase):
raise NotAllowedDuringStartupError(function_path) raise NotAllowedDuringStartupError(function_path)
def _get_jsonrpc_method(self, function_path): def _get_jsonrpc_method(self, function_path):
function_path = self._check_deprecated(function_path)
self._verify_method_is_callable(function_path) self._verify_method_is_callable(function_path)
return self.callable_methods.get(function_path) return self.callable_methods.get(function_path)