Skip to content

Commit

Permalink
feature: return built and skipped importables from build_all
Browse files Browse the repository at this point in the history
docs: improved docstrings for public API
  • Loading branch information
mityax committed Dec 3, 2024
1 parent 1ec3cc0 commit fd9c30b
Showing 1 changed file with 53 additions and 48 deletions.
101 changes: 53 additions & 48 deletions rustimport/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
For more information check the Readme on GitHub: https://github.com/mityax/rustimport
"""

from shutil import which
import logging as _logging
from shutil import which
from types import ModuleType

from rustimport import settings
Expand All @@ -43,19 +43,15 @@

def imp(fullname, opt_in: bool = False, force_rebuild: bool = settings.force_rebuild) -> ModuleType:
"""
`imp` is the explicit alternative to using rustimport.import_hook.
Parameters
----------
fullname : the name of the module to import.
opt_in : should we require rust files to opt in via adding "rustimport" to
the first line of the file? This is on by default for the
import hook, but is off by default for this function since the
intent to import a rust module is clearly specified.
Returns
-------
module : the compiled and loaded Python extension module
Explicit alternative to using rustimport.import_hook.
@param fullname: The name of the module to import.
@param opt_in: Whether to require rust sources to opt in via adding "rustimport" to the first line of the file/crate.
Default is False since the intent to import a Rust module is explicitly stated.
@param force_rebuild: Whether to force re-compilation of the extension, even if it hasn't changed. Default is
derived from settings.
@return: The compiled and loaded Python extension module.
"""
from rustimport.load import dlopen_flags

Expand All @@ -77,18 +73,16 @@ def imp(fullname, opt_in: bool = False, force_rebuild: bool = settings.force_reb

def imp_from_path(path, fullname=None, opt_in: bool = False, force_rebuild: bool = settings.force_rebuild) -> ModuleType:
"""
`imp_from_path` serves the same purpose as `imp` except allows
specifying the exact path of the rust file or crate.
Parameters
----------
filepath : the filepath to the C++ file to build and import.
fullname : the name of the module to import. This can be different from the
module name inferred from the filepath if desired.
Returns
-------
module : the compiled and loaded Python extension module
Imports a Rust module from a specified file path.
@param path: The path to the Rust file or crate.
@param fullname: The name of the module to import. Defaults to inferring from the file/crate path if not specified.
@param opt_in: Whether to require rust sources to opt in via adding "rustimport" to the first line of the file/crate.
Default is False since the intent to import a Rust module is explicitly stated.
@param force_rebuild: Whether to force re-compilation of the extension, even if it hasn't changed. Default is
derived from settings.
@return: The compiled and loaded Python extension module.
"""
from rustimport.load import dlopen_flags

Expand All @@ -110,40 +104,40 @@ def imp_from_path(path, fullname=None, opt_in: bool = False, force_rebuild: bool
def build(fullname, opt_in: bool = False, force_rebuild: bool = settings.force_rebuild,
release: bool = settings.compile_release_binaries):
"""
`build` builds a extension module like `imp` but does not import the
extension.
Builds a rust extension without importing it.
Parameters
----------
fullname : the name of the module to import.
@param fullname: The name of the rust file/crate to build.
@param opt_in: Whether to require rust sources to opt in via adding "rustimport" to the first line of the file/crate.
Default is False since the intent to import a Rust module is explicitly stated.
@param force_rebuild: Whether to force re-compilation of the extension, even if it hasn't changed. Default is
derived from settings.
@param release: Whether to build a release binary. Default is derived from settings.
Returns
-------
ext_path : the path to the compiled extension.
@return: An [Importable] instance for the given extension.
"""
from rustimport.find import find_module_importable
from rustimport.importable import should_rebuild

importable = find_module_importable(fullname, opt_in=opt_in)
if should_rebuild(importable, force_rebuild=force_rebuild, force_release=release):
importable.build(release=release)

return importable


def build_filepath(path, opt_in: bool = False, force_rebuild: bool = settings.force_rebuild,
release: bool = settings.compile_release_binaries):
"""
`build_filepath` builds a extension module like `build` but allows
to directly specify a file path.
Builds a rust extension module from a specified file path, without importing it.
Parameters
----------
filepath : the filepath to the C++ file to build.
fullname : the name of the module to build.
@param path: The file path to the rust file or crate.
@param opt_in: Whether to require rust sources to opt in via adding "rustimport" to the first line of the file/crate.
Default is False since the intent to import a Rust module is explicitly stated.
@param force_rebuild: Whether to force re-compilation of the extension, even if it hasn't changed. Default is
derived from settings.
@param release: Whether to build a release binary. Default is derived from settings.
Returns
-------
ext_path : the path to the compiled extension.
@return: An [Importable] instance for the given extension.
"""

from rustimport.importable import all_importables
Expand All @@ -159,12 +153,17 @@ def build_filepath(path, opt_in: bool = False, force_rebuild: bool = settings.fo
def build_all(root_directory, opt_in: bool = True, force_rebuild: bool = settings.force_rebuild,
release: bool = settings.compile_release_binaries):
"""
`build_all` builds a extension module like `build` for each eligible (that is,
containing the "rustimport" header) source file within the given `root_directory`.
Builds all eligible rust extensions modules in the specified directory.
@param root_directory: The root directory to recursively search for rust source files/crates.
@param opt_in: Whether to require rust sources to opt in via adding "rustimport" to the first line of the file/crate.
Default is True.
@param force_rebuild: Whether to force re-compilation of the extension, even if it hasn't changed. Default is
derived from settings.
@param release: Whether to build a release binary. Default is derived from settings.
Parameters
----------
root_directory : the root directory to search for cpp source files in.
@return: A tuple of two lists of [Importable]s, one with the built [Importable]s and one with those
skipped: `(built, not_built)`
"""
import os
from rustimport.importable import (
Expand All @@ -176,6 +175,7 @@ def build_all(root_directory, opt_in: bool = True, force_rebuild: bool = setting
importables = []

_logger.info(f"Collecting rust extensions in {root_directory}…")

for directory, subdirs, files in os.walk(root_directory, topdown=True):
if any(f.lower() == 'cargo.toml' for f in files):
if i := CrateImportable.try_create(directory, opt_in=opt_in):
Expand All @@ -190,6 +190,7 @@ def build_all(root_directory, opt_in: bool = True, force_rebuild: bool = setting
importables.append(i)

_logger.info(f"Found {len(importables)} {'extension' if len(importables) == 1 else 'extensions'}.")

not_built = []
for index, i in enumerate(importables):
if should_rebuild(i, force_rebuild=force_rebuild, force_release=release):
Expand All @@ -201,10 +202,14 @@ def build_all(root_directory, opt_in: bool = True, force_rebuild: bool = setting
if not_built:
_logger.info(f"Skipped building {len(not_built)} {'extension' if len(not_built) == 1 else 'extensions'} due"
f" to unchanged source files. Re-run with `--force` to rebuild everything.")

_logger.info("Completed successfully.")

return [i for i in importables if i not in not_built], not_built


def load_ipython_extension(ipython):
"""IPython magic entry point."""
rustc_is_installed = which("rustc") is not None
if not rustc_is_installed:
msg = "rustc must be installed to ust rustimport"
Expand Down

0 comments on commit fd9c30b

Please sign in to comment.