1

Given a class object in Python, how can I determine if the class was defined in an extension module (e.g. c, c++, cython), as opposed to being defined in standard python?

inspect.isbuiltin returns True for functions defined in an extension module, and False for functions defined in python, but it unfortunately does not have the same behavior for classes -- it returns False for both kinds of classes.

(The larger goal here is that we've got a system that generates a command line API for a set of classes based on parsing the docstring and signature of their __init__ functions. This system fails for classes defined in cython because inspect.getargspec doesn't work correctly on these classes, so I'm trying to figure out a workaround)

fish2000
  • 4,289
  • 2
  • 37
  • 76
Robert T. McGibbon
  • 5,075
  • 3
  • 37
  • 45

2 Answers2

0

"This system fails for classes defined in cython because X"

Doesn't this mean that the answer you're looking for is X?

To know if a class is of the kind that crashes some function, like when you do inspect.getargspec(X.__init__), then just do inspect.getargspec(X.__init__) in a try: except block.

Armin Rigo
  • 12,048
  • 37
  • 48
0

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

fish2000
  • 4,289
  • 2
  • 37
  • 76