Skip to content

feature request: seamless import of Basilisp libraries in Python with implicit bootstrapping #1242

@ikappaki

Description

@ikappaki

Hi,

I'd like to request support for importing Basilisp libraries directly into Python applications like any standard Python library, without requiring explicit Basilisp bootstrapping or the user needing to know the library is written in Basilisp.

The goal is to enable writing Python packages in Basilisp that can be seamlessly imported into Python code, with Basilisp being implicitly bootstrapped as needed.

The Bootstrapping section of the Basilisp docs mentions basilisp.main.bootstrap and basilisp.main.init as bootstrapping methods, but it's unclear what happens when bootstrapping occurs multiple times, for example, if two Basilisp-based libraries each bootstrap themselves in their __init__.py.

The basilisp.main module also lists basilisp.main.bootstrap_python, but it's still unclear whether calling it multiple times is safe, or if the runtime will even be available without re-importing the module.

From reviewing the code, basilisp.main.init seems the most promising option

def init(opts: Optional[CompilerOpts] = None) -> None:
"""
Initialize the runtime environment for Basilisp code evaluation.
Basilisp only needs to be initialized once per Python VM invocation. Subsequent
imports of Basilisp namespaces will work using Python's standard ``import``
statement and :external:py:func:`importlib.import_module` function.
If you want to execute a Basilisp file which is stored in a well-formed package
or module structure, you probably want to use :py:func:`bootstrap`.
"""
logconfig.configure_root_logger()
runtime.init_ns_var()
runtime.bootstrap_core(opts if opts is not None else compiler_opts())
importer.hook_imports()
importlib.import_module("basilisp.core")

Possibly in combination with a runtime check, such as whether BasilispImporter is already present in sys.meta_path, as done here:

def hook_imports() -> None:
"""Hook into Python's import machinery with a custom Basilisp code
importer.
Once this is called, Basilisp code may be called from within Python code
using standard `import module.submodule` syntax."""
if any(isinstance(o, BasilispImporter) for o in sys.meta_path):
return
sys.meta_path.insert(0, BasilispImporter())

Could you please advise of whether any of the existing bootstrapping methods can safely be used in this way (i.e., called multiple times at runtime) or suggest what changes might be needed to support this use case?

thanks

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions