Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions src/charonload/_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import base64
import getpass
import hashlib
import os
import pathlib
import re
import site
Expand All @@ -24,9 +25,9 @@
@dataclass(init=False) # Python 3.10+: Use "_: KW_ONLY"
class Config:
"""
Set of user-specified configuration options required for the import logic of the :class:`JITCompileFinder`.
Set of user-specified configuration options for setting up the import logic of :class:`JITCompileFinder`.

This will be resolved into :class:`ResolvedConfig`.
This will be resolved into :class:`ResolvedConfig` before usage.
"""

project_directory: pathlib.Path | str
Expand All @@ -44,6 +45,12 @@ class Config:
Whether to remove all cached files of previous builds from the build directory.

This is useful to ensure consistent behavior after major changes in the CMake files of the project.

.. admonition:: Overrides
:class: important

If the environment variable ``CHARONLOAD_FORCE_CLEAN_BUILD`` is set, it will replace this value in
:class:`ResolvedConfig`.
"""

build_type: str
Expand All @@ -62,13 +69,27 @@ class Config:
"""

stubs_invalid_ok: bool
"""Whether to accept invalid stubs and skip raising an error."""
"""
Whether to accept invalid stubs and skip raising an error.

.. admonition:: Overrides
:class: important

If the environment variable ``CHARONLOAD_FORCE_STUBS_INVALID_OK`` is set, it will replace this value in
:class:`ResolvedConfig`.
"""

verbose: bool
"""
Whether to enable printing the full log of the JIT compilation.

This is useful for debugging.

.. admonition:: Overrides
:class: important

If the environment variable ``CHARONLOAD_FORCE_VERBOSE`` is set, it will replace this value in
:class:`ResolvedConfig`.
"""

def __init__(
Expand Down Expand Up @@ -96,9 +117,9 @@ def __init__(
@dataclass(init=False) # Python 3.10+: Use "kw_only=True"
class ResolvedConfig:
"""
Set of resolved configuration options that are actually used for the import logic of the :class:`JITCompileFinder`.
Set of resolved configuration options that is **actually used** in the import logic of :class:`JITCompileFinder`.

This has been resolved from :class:`Config`.
This has been resolved from :class:`Config` and from the environment variables.
"""

full_project_directory: pathlib.Path
Expand Down Expand Up @@ -219,17 +240,31 @@ def _resolve(self: Self, module_name: str, config: Config) -> ResolvedConfig:
project_directory=config.project_directory,
verbose=config.verbose,
),
clean_build=config.clean_build,
clean_build=self._str_to_bool(os.environ.get("CHARONLOAD_FORCE_CLEAN_BUILD", default=config.clean_build)),
build_type=config.build_type,
cmake_options=config.cmake_options if config.cmake_options is not None else {},
full_stubs_directory=self._find_stubs_directory(
stubs_directory=config.stubs_directory,
verbose=config.verbose,
),
stubs_invalid_ok=config.stubs_invalid_ok,
verbose=config.verbose,
stubs_invalid_ok=self._str_to_bool(
os.environ.get("CHARONLOAD_FORCE_STUBS_INVALID_OK", default=config.stubs_invalid_ok)
),
verbose=self._str_to_bool(os.environ.get("CHARONLOAD_FORCE_VERBOSE", default=config.verbose)),
)

def _str_to_bool(self: Self, s: str | bool) -> bool:
if isinstance(s, bool):
return s

if s.lower() in ["1", "on", "yes", "true", "y"]:
return True
if s.lower() in ["0", "off", "no", "false", "n"]:
return False

msg = f'Cannot convert string "{s}" to bool'
raise ValueError(msg)

def _find_build_directory(
self: Self,
*,
Expand Down
20 changes: 19 additions & 1 deletion src/charonload/_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,25 @@ def __init__(self: Self, step_name: str = "", log: str | None = None) -> None:
self.log = log
"""The full log from the underlying compiler."""

super().__init__(f"{self.step_name} failed:\n\n{self.log}" if log is not None else f"{self.step_name} failed.")
msg = ""
if self.log is not None:
msg += f"{self.step_name} failed:\n"
msg += "----------------------------------------------------------------\n"
msg += "\n"
msg += self.log
msg += "\n"
msg += "----------------------------------------------------------------\n"
else:
msg += f"{self.step_name} failed.\n"
msg += "\n"
msg += (
"charonload might automatically run a clean build on the next call in order to try to resolve the error. "
)
msg += "If the issue persists, you can override charonload's behavior via these environment variables:\n"
msg += " - CHARONLOAD_FORCE_CLEAN_BUILD=1 : Enforce clean builds for all JIT compiled projects.\n"
msg += " - CHARONLOAD_FORCE_VERBOSE=1 : Always show full JIT compilation logs (for debugging).\n"

super().__init__(msg)

def __new__(cls: type[Self], *args: Any, **kwargs: Any) -> Self: # noqa: ANN401, ARG004
if cls is JITCompileError:
Expand Down
Loading