Loads a turicreate toolkit module (a shared library) into the
    tc.extensions namespace.

    Toolkit module created via SDK can either be directly imported,
    e.g. ``import example`` or via this function, e.g. ``turicreate.ext_import("example.so")``.
    Use ``ext_import`` when you need more namespace control, or when
    the shared library is not local, e.g. in http, s3 or hdfs.

    Parameters
    ----------
    soname : string
        The filename of the shared library to load.
        This can be a URL, or a HDFS location. For instance if soname is
        somewhere/outthere/toolkit.so
        The functions in toolkit.so will appear in tc.extensions.toolkit.*

    module_subpath : string, optional
        Any additional module paths to prepend to the toolkit module after
        it is imported. For instance if soname is
        somewhere/outthere/toolkit.so, by default
        the functions in toolkit.so will appear in tc.extensions.toolkit.*.
        However, if I module_subpath="somewhere.outthere", the functions
        in toolkit.so will appear in tc.extensions.somewhere.outthere.toolkit.*

    Returns
    -------
    out : a list of functions and classes loaded.

    Examples
    --------
    For instance, given a module which implements the function "square_root",

    .. code-block:: c++

        #include <cmath>
        #include <turicreate/sdk/toolkit_function_macros.hpp>
        double square_root(double a) {
          return sqrt(a);
        }

        BEGIN_FUNCTION_REGISTRATION
        REGISTER_FUNCTION(square_root, "a");
        END_FUNCTION_REGISTRATION

    compiled into example.so

    >>> turicreate.ext_import('example1.so')
    ['example1.square_root']

    >>> turicreate.extensions.example1.square_root(9)
    3.0

    We can customize the import location with module_subpath which can be
    used to avoid namespace conflicts when you have multiple toolkits with the
    same filename.

    >>> turicreate.ext_import('example1.so', 'math')
    ['math.example1.square_root']
    >>> turicreate.extensions.math.example1.square_root(9)
    3.0

    The module can also be imported directly, but turicreate *must* be imported
    first. turicreate will intercept the module loading process to load the
    toolkit.

    >>> import turicreate
    >>> import example1 #searches for example1.so in all the python paths
    >>> example1.square_root(9)
    3.0

def ext_import(soname, module_subpath=""):
    """
    Loads a turicreate toolkit module (a shared library) into the
    tc.extensions namespace.

    Toolkit module created via SDK can either be directly imported,
    e.g. ``import example`` or via this function, e.g. ``turicreate.ext_import("example.so")``.
    Use ``ext_import`` when you need more namespace control, or when
    the shared library is not local, e.g. in http, s3 or hdfs.

    Parameters
    ----------
    soname : string
        The filename of the shared library to load.
        This can be a URL, or a HDFS location. For instance if soname is
        somewhere/outthere/toolkit.so
        The functions in toolkit.so will appear in tc.extensions.toolkit.*

    module_subpath : string, optional
        Any additional module paths to prepend to the toolkit module after
        it is imported. For instance if soname is
        somewhere/outthere/toolkit.so, by default
        the functions in toolkit.so will appear in tc.extensions.toolkit.*.
        However, if I module_subpath="somewhere.outthere", the functions
        in toolkit.so will appear in tc.extensions.somewhere.outthere.toolkit.*

    Returns
    -------
    out : a list of functions and classes loaded.

    Examples
    --------
    For instance, given a module which implements the function "square_root",

    .. code-block:: c++

        #include <cmath>
        #include <turicreate/sdk/toolkit_function_macros.hpp>
        double square_root(double a) {
          return sqrt(a);
        }

        BEGIN_FUNCTION_REGISTRATION
        REGISTER_FUNCTION(square_root, "a");
        END_FUNCTION_REGISTRATION

    compiled into example.so

    >>> turicreate.ext_import('example1.so')
    ['example1.square_root']

    >>> turicreate.extensions.example1.square_root(9)
    3.0

    We can customize the import location with module_subpath which can be
    used to avoid namespace conflicts when you have multiple toolkits with the
    same filename.

    >>> turicreate.ext_import('example1.so', 'math')
    ['math.example1.square_root']
    >>> turicreate.extensions.math.example1.square_root(9)
    3.0

    The module can also be imported directly, but turicreate *must* be imported
    first. turicreate will intercept the module loading process to load the
    toolkit.

    >>> import turicreate
    >>> import example1 #searches for example1.so in all the python paths
    >>> example1.square_root(9)
    3.0
    """
    unity = _get_unity()
    import os
    if os.path.exists(soname):
        soname = os.path.abspath(soname)
    else:
        soname = _make_internal_url(soname)
    ret = unity.load_toolkit(soname, module_subpath)
    if len(ret) > 0:
        raise RuntimeError(ret)
    _publish()
    # push the functions into the corresponding module namespace
    return unity.list_toolkit_functions_in_dynamic_module(soname) + unity.list_toolkit_classes_in_dynamic_module(soname)