I, too, struggled with this – I ended up writing a series of functions to solve the problem of whether or not something is native, to cover the corner-cases:
import importlib
import importlib.machinery
import inspect
QUALIFIER = '.'
EXTENSION_SUFFIXES = tuple(suffix.lstrip(QUALIFIER) \
for suffix \
in importlib.machinery.EXTENSION_SUFFIXES)
moduleof = lambda thing: getattr(thing, '__module__', '')
isbuiltin = lambda thing: moduleof(thing) == 'builtins'
suffix = lambda filename: QUALIFIER in filename \
and filename.rpartition(QUALIFIER)[-1] \
or ''
def isnativemodule(module):
""" isnativemodule(thing) → boolean predicate, True if `module`
is a native-compiled (“extension”) module.
Q.v. this fine StackOverflow answer on this subject:
https://stackoverflow.com/a/39304199/298171
"""
# Step one: modules only beyond this point:
if not inspect.ismodule(module):
return False
# Step two: return truly when “__loader__” is set:
if isinstance(getattr(module, '__loader__', None),
importlib.machinery.ExtensionFileLoader):
return True
# Step three: in leu of either of those indicators,
# check the module path’s file suffix:
try:
ext = suffix(inspect.getfile(module))
except TypeError as exc:
return 'is a built-in' in str(exc)
return ext in EXTENSION_SUFFIXES
def isnative(thing):
""" isnative(thing) → boolean predicate, True if `thing`
comes from a native-compiled (“extension”) module.
"""
module = moduleof(thing)
# You can have this next line return “True”,
# if that covers your use-cases, and thus get rid
# of “isinspectable(…)”, below:
if module == 'builtins':
return False
return isnativemodule(
importlib.import_module(
module))
def isinspectable(thing):
""" isinspectable(thing) → boolean predicate, True
if `thing` is inspectable, through the “inspect”
modules’ myriad functions and types.
"""
return (not isbuiltin(thing)) \
and (not isnative(thing))
… As noted: the source for the isnativemodule(…)
function, above, originally came from this StackOverflow answer (which also may be of use to you). The code as written is adapted from CLU, my utility-drawer library package.
…I also have code that parses and displays function signatures, which, as you seek to do with your project, does leverage these predicate functions. Just like FYI