From 5d1155c08edf7f53eca804b2b6538636c2dfe711 Mon Sep 17 00:00:00 2001 From: Florent Xicluna Date: Fri, 28 Oct 2011 14:45:05 +0200 Subject: [PATCH] Closes #13258: Use callable() built-in in the standard library. --- Lib/argparse.py | 10 +++------- Lib/copyreg.py | 4 ++-- Lib/distutils/dist.py | 2 +- Lib/encodings/__init__.py | 11 +++++------ Lib/fileinput.py | 9 +++++---- Lib/hmac.py | 2 +- Lib/idlelib/rpc.py | 4 ++-- Lib/logging/config.py | 4 ++-- Lib/multiprocessing/managers.py | 4 ++-- Lib/multiprocessing/pool.py | 2 +- Lib/optparse.py | 2 +- Lib/pickle.py | 2 +- Lib/pydoc.py | 4 ++-- Lib/re.py | 2 +- Lib/rlcompleter.py | 2 +- Lib/shutil.py | 4 ++-- Lib/test/test_nntplib.py | 3 +-- Lib/timeit.py | 6 +++--- Lib/tkinter/__init__.py | 8 ++++---- Lib/tkinter/tix.py | 2 +- Lib/unittest/loader.py | 4 ++-- Lib/unittest/suite.py | 2 +- Lib/warnings.py | 2 +- Lib/xmlrpc/server.py | 2 +- Misc/NEWS | 2 ++ 25 files changed, 48 insertions(+), 51 deletions(-) diff --git a/Lib/argparse.py b/Lib/argparse.py index 63561f7cb12..2202b573202 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -92,10 +92,6 @@ import textwrap as _textwrap from gettext import gettext as _, ngettext -def _callable(obj): - return hasattr(obj, '__call__') or hasattr(obj, '__bases__') - - SUPPRESS = '==SUPPRESS==' OPTIONAL = '?' @@ -1286,13 +1282,13 @@ class _ActionsContainer(object): # create the action object, and add it to the parser action_class = self._pop_action_class(kwargs) - if not _callable(action_class): + if not callable(action_class): raise ValueError('unknown action "%s"' % (action_class,)) action = action_class(**kwargs) # raise an error if the action type is not callable type_func = self._registry_get('type', action.type, action.type) - if not _callable(type_func): + if not callable(type_func): raise ValueError('%r is not callable' % (type_func,)) # raise an error if the metavar does not match the type @@ -2240,7 +2236,7 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer): def _get_value(self, action, arg_string): type_func = self._registry_get('type', action.type, action.type) - if not _callable(type_func): + if not callable(type_func): msg = _('%r is not callable') raise ArgumentError(action, msg % type_func) diff --git a/Lib/copyreg.py b/Lib/copyreg.py index 81a1e7fefe0..66c0f8a64d6 100644 --- a/Lib/copyreg.py +++ b/Lib/copyreg.py @@ -10,7 +10,7 @@ __all__ = ["pickle", "constructor", dispatch_table = {} def pickle(ob_type, pickle_function, constructor_ob=None): - if not hasattr(pickle_function, '__call__'): + if not callable(pickle_function): raise TypeError("reduction functions must be callable") dispatch_table[ob_type] = pickle_function @@ -20,7 +20,7 @@ def pickle(ob_type, pickle_function, constructor_ob=None): constructor(constructor_ob) def constructor(object): - if not hasattr(object, '__call__'): + if not callable(object): raise TypeError("constructors must be callable") # Example: provide pickling support for complex numbers. diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py index 69825f206f2..a7025682781 100644 --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -537,7 +537,7 @@ Common commands: (see '--help-commands' for more) for (help_option, short, desc, func) in cmd_class.help_options: if hasattr(opts, parser.get_attr_name(help_option)): help_option_found=1 - if hasattr(func, '__call__'): + if callable(func): func() else: raise DistutilsClassError( diff --git a/Lib/encodings/__init__.py b/Lib/encodings/__init__.py index b189bd9793e..8dd713056ef 100644 --- a/Lib/encodings/__init__.py +++ b/Lib/encodings/__init__.py @@ -120,12 +120,11 @@ def search_function(encoding): if not 4 <= len(entry) <= 7: raise CodecRegistryError('module "%s" (%s) failed to register' % (mod.__name__, mod.__file__)) - if not hasattr(entry[0], '__call__') or \ - not hasattr(entry[1], '__call__') or \ - (entry[2] is not None and not hasattr(entry[2], '__call__')) or \ - (entry[3] is not None and not hasattr(entry[3], '__call__')) or \ - (len(entry) > 4 and entry[4] is not None and not hasattr(entry[4], '__call__')) or \ - (len(entry) > 5 and entry[5] is not None and not hasattr(entry[5], '__call__')): + if not callable(entry[0]) or not callable(entry[1]) or \ + (entry[2] is not None and not callable(entry[2])) or \ + (entry[3] is not None and not callable(entry[3])) or \ + (len(entry) > 4 and entry[4] is not None and not callable(entry[4])) or \ + (len(entry) > 5 and entry[5] is not None and not callable(entry[5])): raise CodecRegistryError('incompatible codecs in module "%s" (%s)' % (mod.__name__, mod.__file__)) if len(entry)<7 or entry[6] is None: diff --git a/Lib/fileinput.py b/Lib/fileinput.py index a25a021eb31..554beb2448c 100644 --- a/Lib/fileinput.py +++ b/Lib/fileinput.py @@ -225,10 +225,11 @@ class FileInput: raise ValueError("FileInput opening mode must be one of " "'r', 'rU', 'U' and 'rb'") self._mode = mode - if inplace and openhook: - raise ValueError("FileInput cannot use an opening hook in inplace mode") - elif openhook and not hasattr(openhook, '__call__'): - raise ValueError("FileInput openhook must be callable") + if openhook: + if inplace: + raise ValueError("FileInput cannot use an opening hook in inplace mode") + if not callable(openhook): + raise ValueError("FileInput openhook must be callable") self._openhook = openhook def __del__(self): diff --git a/Lib/hmac.py b/Lib/hmac.py index e878e1a8096..956fc65d2c0 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py @@ -39,7 +39,7 @@ class HMAC: import hashlib digestmod = hashlib.md5 - if hasattr(digestmod, '__call__'): + if callable(digestmod): self.digest_cons = digestmod else: self.digest_cons = lambda d=b'': digestmod.new(d) diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py index 0c56ccdcfe5..def43945aee 100644 --- a/Lib/idlelib/rpc.py +++ b/Lib/idlelib/rpc.py @@ -570,7 +570,7 @@ def _getmethods(obj, methods): # Adds names to dictionary argument 'methods' for name in dir(obj): attr = getattr(obj, name) - if hasattr(attr, '__call__'): + if callable(attr): methods[name] = 1 if isinstance(obj, type): for super in obj.__bases__: @@ -579,7 +579,7 @@ def _getmethods(obj, methods): def _getattributes(obj, attributes): for name in dir(obj): attr = getattr(obj, name) - if not hasattr(attr, '__call__'): + if not callable(attr): attributes[name] = 1 class MethodProxy(object): diff --git a/Lib/logging/config.py b/Lib/logging/config.py index c7359cabe90..373da2b0764 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -471,7 +471,7 @@ class BaseConfigurator(object): def configure_custom(self, config): """Configure an object with a user-supplied factory.""" c = config.pop('()') - if not hasattr(c, '__call__'): + if not callable(c): c = self.resolve(c) props = config.pop('.', None) # Check for valid identifiers @@ -690,7 +690,7 @@ class DictConfigurator(BaseConfigurator): filters = config.pop('filters', None) if '()' in config: c = config.pop('()') - if not hasattr(c, '__call__') and hasattr(types, 'ClassType') and type(c) != types.ClassType: + if not callable(c): c = self.resolve(c) factory = c else: diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py index 388bfe3c87c..5a57288caaf 100644 --- a/Lib/multiprocessing/managers.py +++ b/Lib/multiprocessing/managers.py @@ -134,7 +134,7 @@ def all_methods(obj): temp = [] for name in dir(obj): func = getattr(obj, name) - if hasattr(func, '__call__'): + if callable(func): temp.append(name) return temp @@ -510,7 +510,7 @@ class BaseManager(object): ''' assert self._state.value == State.INITIAL - if initializer is not None and not hasattr(initializer, '__call__'): + if initializer is not None and not callable(initializer): raise TypeError('initializer must be a callable') # pipe over which we will retrieve address of server diff --git a/Lib/multiprocessing/pool.py b/Lib/multiprocessing/pool.py index 04e7c447d17..0c29e644ffd 100644 --- a/Lib/multiprocessing/pool.py +++ b/Lib/multiprocessing/pool.py @@ -151,7 +151,7 @@ class Pool(object): if processes < 1: raise ValueError("Number of processes must be at least 1") - if initializer is not None and not hasattr(initializer, '__call__'): + if initializer is not None and not callable(initializer): raise TypeError('initializer must be a callable') self._processes = processes diff --git a/Lib/optparse.py b/Lib/optparse.py index cbd019afb7d..d97a1f7aca3 100644 --- a/Lib/optparse.py +++ b/Lib/optparse.py @@ -705,7 +705,7 @@ class Option: def _check_callback(self): if self.action == "callback": - if not hasattr(self.callback, '__call__'): + if not callable(self.callback): raise OptionError( "callback not callable: %r" % self.callback, self) if (self.callback_args is not None and diff --git a/Lib/pickle.py b/Lib/pickle.py index c770ff8bdf4..1f45f37d46c 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -364,7 +364,7 @@ class _Pickler: raise PicklingError("args from save_reduce() should be a tuple") # Assert that func is callable - if not hasattr(func, '__call__'): + if not callable(func): raise PicklingError("func from save_reduce() should be callable") save = self.save diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 1a5db1a66fa..d0c6f62148f 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -775,7 +775,7 @@ class HTMLDoc(Doc): push(msg) for name, kind, homecls, value in ok: base = self.docother(getattr(object, name), name, mod) - if hasattr(value, '__call__') or inspect.isdatadescriptor(value): + if callable(value) or inspect.isdatadescriptor(value): doc = getattr(value, "__doc__", None) else: doc = None @@ -1199,7 +1199,7 @@ location listed above. hr.maybe() push(msg) for name, kind, homecls, value in ok: - if hasattr(value, '__call__') or inspect.isdatadescriptor(value): + if callable(value) or inspect.isdatadescriptor(value): doc = getdoc(value) else: doc = None diff --git a/Lib/re.py b/Lib/re.py index abd7ea27b32..4fe3bd88ac7 100644 --- a/Lib/re.py +++ b/Lib/re.py @@ -326,7 +326,7 @@ class Scanner: if i == j: break action = self.lexicon[m.lastindex-1][1] - if hasattr(action, "__call__"): + if callable(action): self.match = m action = action(self, m.group()) if action is not None: diff --git a/Lib/rlcompleter.py b/Lib/rlcompleter.py index 6eb1b3d0e93..8b74ffaadda 100644 --- a/Lib/rlcompleter.py +++ b/Lib/rlcompleter.py @@ -87,7 +87,7 @@ class Completer: return None def _callable_postfix(self, val, word): - if hasattr(val, '__call__'): + if callable(val): word = word + "(" return word diff --git a/Lib/shutil.py b/Lib/shutil.py index a0d981b0c72..00bffe5f20f 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -523,7 +523,7 @@ def register_archive_format(name, function, extra_args=None, description=''): """ if extra_args is None: extra_args = [] - if not isinstance(function, collections.Callable): + if not callable(function): raise TypeError('The %s object is not callable' % function) if not isinstance(extra_args, (tuple, list)): raise TypeError('extra_args needs to be a sequence') @@ -616,7 +616,7 @@ def _check_unpack_options(extensions, function, extra_args): raise RegistryError(msg % (extension, existing_extensions[extension])) - if not isinstance(function, collections.Callable): + if not callable(function): raise TypeError('The registered function must be a callable') diff --git a/Lib/test/test_nntplib.py b/Lib/test/test_nntplib.py index a387f61f1e5..786b5f093bc 100644 --- a/Lib/test/test_nntplib.py +++ b/Lib/test/test_nntplib.py @@ -4,7 +4,6 @@ import textwrap import unittest import functools import contextlib -import collections from test import support from nntplib import NNTP, GroupInfo, _have_ssl import nntplib @@ -246,7 +245,7 @@ class NetworkedNNTPTestsMixin: if not name.startswith('test_'): continue meth = getattr(cls, name) - if not isinstance(meth, collections.Callable): + if not callable(meth): continue # Need to use a closure so that meth remains bound to its current # value diff --git a/Lib/timeit.py b/Lib/timeit.py index 461c8910702..1ae59e0cccd 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -127,7 +127,7 @@ class Timer: if isinstance(setup, str): setup = reindent(setup, 4) src = template % {'stmt': stmt, 'setup': setup} - elif hasattr(setup, '__call__'): + elif callable(setup): src = template % {'stmt': stmt, 'setup': '_setup()'} ns['_setup'] = setup else: @@ -136,13 +136,13 @@ class Timer: code = compile(src, dummy_src_name, "exec") exec(code, globals(), ns) self.inner = ns["inner"] - elif hasattr(stmt, '__call__'): + elif callable(stmt): self.src = None if isinstance(setup, str): _setup = setup def setup(): exec(_setup, globals(), ns) - elif not hasattr(setup, '__call__'): + elif not callable(setup): raise ValueError("setup is neither a string nor callable") self.inner = _template_func(setup, stmt) else: diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py index e54c53f18ee..8af506548a9 100644 --- a/Lib/tkinter/__init__.py +++ b/Lib/tkinter/__init__.py @@ -1039,7 +1039,7 @@ class Misc: for k, v in cnf.items(): if v is not None: if k[-1] == '_': k = k[:-1] - if hasattr(v, '__call__'): + if callable(v): v = self._register(v) elif isinstance(v, (tuple, list)): nv = [] @@ -1608,7 +1608,7 @@ class Wm: """Bind function FUNC to command NAME for this widget. Return the function bound to NAME if None is given. NAME could be e.g. "WM_SAVE_YOURSELF" or "WM_DELETE_WINDOW".""" - if hasattr(func, '__call__'): + if callable(func): command = self._register(func) else: command = func @@ -3178,7 +3178,7 @@ class Image: elif kw: cnf = kw options = () for k, v in cnf.items(): - if hasattr(v, '__call__'): + if callable(v): v = self._register(v) options = options + ('-'+k, v) self.tk.call(('image', 'create', imgtype, name,) + options) @@ -3201,7 +3201,7 @@ class Image: for k, v in _cnfmerge(kw).items(): if v is not None: if k[-1] == '_': k = k[:-1] - if hasattr(v, '__call__'): + if callable(v): v = self._register(v) res = res + ('-'+k, v) self.tk.call((self.name, 'config') + res) diff --git a/Lib/tkinter/tix.py b/Lib/tkinter/tix.py index 4884e2260b2..18866c432db 100644 --- a/Lib/tkinter/tix.py +++ b/Lib/tkinter/tix.py @@ -405,7 +405,7 @@ class TixWidget(tkinter.Widget): elif kw: cnf = kw options = () for k, v in cnf.items(): - if hasattr(v, '__call__'): + if callable(v): v = self._register(v) options = options + ('-'+k, v) return master.tk.call(('image', 'create', imgtype,) + options) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py index afdff671643..cb92fd29baf 100644 --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -113,7 +113,7 @@ class TestLoader(object): return self.suiteClass([inst]) elif isinstance(obj, suite.TestSuite): return obj - if hasattr(obj, '__call__'): + if callable(obj): test = obj() if isinstance(test, suite.TestSuite): return test @@ -138,7 +138,7 @@ class TestLoader(object): def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): return attrname.startswith(prefix) and \ - hasattr(getattr(testCaseClass, attrname), '__call__') + callable(getattr(testCaseClass, attrname)) testFnNames = testFnNames = list(filter(isTestMethod, dir(testCaseClass))) if self.sortTestMethodsUsing: diff --git a/Lib/unittest/suite.py b/Lib/unittest/suite.py index 38bd6b861df..cde5d385ed1 100644 --- a/Lib/unittest/suite.py +++ b/Lib/unittest/suite.py @@ -42,7 +42,7 @@ class BaseTestSuite(object): def addTest(self, test): # sanity checks - if not hasattr(test, '__call__'): + if not callable(test): raise TypeError("{} is not callable".format(repr(test))) if isinstance(test, type) and issubclass(test, (case.TestCase, TestSuite)): diff --git a/Lib/warnings.py b/Lib/warnings.py index 5b5821b1c3d..edbbb5eda4f 100644 --- a/Lib/warnings.py +++ b/Lib/warnings.py @@ -259,7 +259,7 @@ def warn_explicit(message, category, filename, lineno, raise RuntimeError( "Unrecognized action (%r) in warnings.filters:\n %s" % (action, item)) - if not hasattr(showwarning, "__call__"): + if not callable(showwarning): raise TypeError("warnings.showwarning() must be set to a " "function or method") # Print message and context diff --git a/Lib/xmlrpc/server.py b/Lib/xmlrpc/server.py index 94773096178..ac252f11d36 100644 --- a/Lib/xmlrpc/server.py +++ b/Lib/xmlrpc/server.py @@ -149,7 +149,7 @@ def list_public_methods(obj): return [member for member in dir(obj) if not member.startswith('_') and - hasattr(getattr(obj, member), '__call__')] + callable(getattr(obj, member))] class SimpleXMLRPCDispatcher: """Mix-in class that dispatches XML-RPC requests. diff --git a/Misc/NEWS b/Misc/NEWS index 6be52fbff95..b3c7fd18aff 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -61,6 +61,8 @@ Core and Builtins Library ------- +- Issue #13258: Use callable() built-in in the standard library. + - Issue #13273: fix a bug that prevented HTMLParser to properly detect some tags when strict=False.