def wrapFQPN(fqpn):
    """
    Given an FQPN, retrieve the object via the global Python module
    namespace and wrap it with a L{PythonModule} or a
    L{twisted.python.modules.PythonAttribute}.
    """
    # largely cribbed from t.p.reflect.namedAny

    if not fqpn:
        raise InvalidFQPN("FQPN was empty")

    components = collections.deque(fqpn.split('.'))

    if '' in components:
        raise InvalidFQPN(
            "name must be a string giving a '.'-separated list of Python "
            "identifiers, not %r" % (fqpn,))

    component = components.popleft()
    try:
        module = getModule(component)
    except KeyError:
        raise NoModule(component)

    # find the bottom-most module
    while components:
        component = components.popleft()
        try:
            module = module[component]
        except KeyError:
            components.appendleft(component)
            break
        else:
            module.load()
    else:
        return module

    # find the bottom-most attribute
    attribute = module
    for component in components:
        try:
            attribute = next(child for child in attribute.iterAttributes()
                             if child.name.rsplit('.', 1)[-1] == component)
        except StopIteration:
            raise NoObject('{}.{}'.format(attribute.name, component))

    return attribute

    Given an FQPN, retrieve the object via the global Python module
    namespace and wrap it with a L{PythonModule} or a
    L{twisted.python.modules.PythonAttribute}.
    
stackoverflow/venv/lib/python3.6/site-packages/automat/_discover.py