Skip to content

Commit ba87413

Browse files
committed
Support global configuration overrides with environment variables
1 parent 74521e3 commit ba87413

File tree

3 files changed

+325
-9
lines changed

3 files changed

+325
-9
lines changed

src/charonload/_config.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import base64
44
import getpass
55
import hashlib
6+
import os
67
import pathlib
78
import re
89
import site
@@ -24,9 +25,9 @@
2425
@dataclass(init=False) # Python 3.10+: Use "_: KW_ONLY"
2526
class Config:
2627
"""
27-
Set of user-specified configuration options required for the import logic of the :class:`JITCompileFinder`.
28+
Set of user-specified configuration options for setting up the import logic of :class:`JITCompileFinder`.
2829
29-
This will be resolved into :class:`ResolvedConfig`.
30+
This will be resolved into :class:`ResolvedConfig` before usage.
3031
"""
3132

3233
project_directory: pathlib.Path | str
@@ -44,6 +45,12 @@ class Config:
4445
Whether to remove all cached files of previous builds from the build directory.
4546
4647
This is useful to ensure consistent behavior after major changes in the CMake files of the project.
48+
49+
.. admonition:: Overrides
50+
:class: important
51+
52+
If the environment variable ``CHARONLOAD_FORCE_CLEAN_BUILD`` is set, it will replace this value in
53+
:class:`ResolvedConfig`.
4754
"""
4855

4956
build_type: str
@@ -62,13 +69,27 @@ class Config:
6269
"""
6370

6471
stubs_invalid_ok: bool
65-
"""Whether to accept invalid stubs and skip raising an error."""
72+
"""
73+
Whether to accept invalid stubs and skip raising an error.
74+
75+
.. admonition:: Overrides
76+
:class: important
77+
78+
If the environment variable ``CHARONLOAD_FORCE_STUBS_INVALID_OK`` is set, it will replace this value in
79+
:class:`ResolvedConfig`.
80+
"""
6681

6782
verbose: bool
6883
"""
6984
Whether to enable printing the full log of the JIT compilation.
7085
7186
This is useful for debugging.
87+
88+
.. admonition:: Overrides
89+
:class: important
90+
91+
If the environment variable ``CHARONLOAD_FORCE_VERBOSE`` is set, it will replace this value in
92+
:class:`ResolvedConfig`.
7293
"""
7394

7495
def __init__(
@@ -96,9 +117,9 @@ def __init__(
96117
@dataclass(init=False) # Python 3.10+: Use "kw_only=True"
97118
class ResolvedConfig:
98119
"""
99-
Set of resolved configuration options that are actually used for the import logic of the :class:`JITCompileFinder`.
120+
Set of resolved configuration options that is **actually used** in the import logic of :class:`JITCompileFinder`.
100121
101-
This has been resolved from :class:`Config`.
122+
This has been resolved from :class:`Config` and from the environment variables.
102123
"""
103124

104125
full_project_directory: pathlib.Path
@@ -219,17 +240,31 @@ def _resolve(self: Self, module_name: str, config: Config) -> ResolvedConfig:
219240
project_directory=config.project_directory,
220241
verbose=config.verbose,
221242
),
222-
clean_build=config.clean_build,
243+
clean_build=self._str_to_bool(os.environ.get("CHARONLOAD_FORCE_CLEAN_BUILD", default=config.clean_build)),
223244
build_type=config.build_type,
224245
cmake_options=config.cmake_options if config.cmake_options is not None else {},
225246
full_stubs_directory=self._find_stubs_directory(
226247
stubs_directory=config.stubs_directory,
227248
verbose=config.verbose,
228249
),
229-
stubs_invalid_ok=config.stubs_invalid_ok,
230-
verbose=config.verbose,
250+
stubs_invalid_ok=self._str_to_bool(
251+
os.environ.get("CHARONLOAD_FORCE_STUBS_INVALID_OK", default=config.stubs_invalid_ok)
252+
),
253+
verbose=self._str_to_bool(os.environ.get("CHARONLOAD_FORCE_VERBOSE", default=config.verbose)),
231254
)
232255

256+
def _str_to_bool(self: Self, s: str | bool) -> bool:
257+
if isinstance(s, bool):
258+
return s
259+
260+
if s.lower() in ["1", "on", "yes", "true", "y"]:
261+
return True
262+
if s.lower() in ["0", "off", "no", "false", "n"]:
263+
return False
264+
265+
msg = f'Cannot convert string "{s}" to bool'
266+
raise ValueError(msg)
267+
233268
def _find_build_directory(
234269
self: Self,
235270
*,

src/charonload/_errors.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,25 @@ def __init__(self: Self, step_name: str = "", log: str | None = None) -> None:
2727
self.log = log
2828
"""The full log from the underlying compiler."""
2929

30-
super().__init__(f"{self.step_name} failed:\n\n{self.log}" if log is not None else f"{self.step_name} failed.")
30+
msg = ""
31+
if self.log is not None:
32+
msg += f"{self.step_name} failed:\n"
33+
msg += "----------------------------------------------------------------\n"
34+
msg += "\n"
35+
msg += self.log
36+
msg += "\n"
37+
msg += "----------------------------------------------------------------\n"
38+
else:
39+
msg += f"{self.step_name} failed.\n"
40+
msg += "\n"
41+
msg += (
42+
"charonload might automatically run a clean build on the next call in order to try to resolve the error. "
43+
)
44+
msg += "If the issue persists, you can override charonload's behavior via these environment variables:\n"
45+
msg += " - CHARONLOAD_FORCE_CLEAN_BUILD=1 : Enforce clean builds for all JIT compiled projects.\n"
46+
msg += " - CHARONLOAD_FORCE_VERBOSE=1 : Always show full JIT compilation logs (for debugging).\n"
47+
48+
super().__init__(msg)
3149

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

0 commit comments

Comments
 (0)