Skip to content

Commit aa0e310

Browse files
committed
Synchronize basilisp.main.init to allow repeat invocations
1 parent 9869527 commit aa0e310

File tree

3 files changed

+37
-17
lines changed

3 files changed

+37
-17
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
* Removed implicit support for single-use iterables in sequences, and introduced `iterator-seq` to expliciltly handle them (#1192)
1717
* `basilisp.core/str` now delegates to the builtin Python `str` in all cases except for customizing the string output for builtin Python types (#1237)
1818
* Optimised mainstream seq-consuming functions by coercing their inputs into `seq` upfront (#1234)
19+
* `basilisp.main.init` will only initialize the runtime environment on the first invocation (#1242)
1920

2021
### Fixed
2122
* Fix a bug where protocols with methods with leading hyphens in the could not be defined (#1230)

src/basilisp/main.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import importlib
22
import os
33
import sysconfig
4+
import threading
45
from pathlib import Path
56
from typing import Optional
67

@@ -11,8 +12,11 @@
1112
from basilisp.lang.typing import CompilerOpts
1213
from basilisp.lang.util import munge
1314

15+
_INIT_LOCK = threading.Lock()
16+
_runtime_is_initialized = False
1417

15-
def init(opts: Optional[CompilerOpts] = None) -> None:
18+
19+
def init(opts: Optional[CompilerOpts] = None, force_reload: bool = False) -> None:
1620
"""
1721
Initialize the runtime environment for Basilisp code evaluation.
1822
@@ -22,12 +26,22 @@ def init(opts: Optional[CompilerOpts] = None) -> None:
2226
2327
If you want to execute a Basilisp file which is stored in a well-formed package
2428
or module structure, you probably want to use :py:func:`bootstrap`.
29+
30+
``init()`` may be called more than once. Only the first invocation will initialize
31+
the runtime unless ``force_reload=True``.
2532
"""
26-
logconfig.configure_root_logger()
27-
runtime.init_ns_var()
28-
runtime.bootstrap_core(opts if opts is not None else compiler_opts())
29-
importer.hook_imports()
30-
importlib.import_module("basilisp.core")
33+
global _runtime_is_initialized
34+
35+
with _INIT_LOCK:
36+
if _runtime_is_initialized and not force_reload:
37+
return
38+
39+
logconfig.configure_root_logger()
40+
runtime.init_ns_var()
41+
runtime.bootstrap_core(opts if opts is not None else compiler_opts())
42+
importer.hook_imports()
43+
importlib.import_module("basilisp.core")
44+
_runtime_is_initialized = True
3145

3246

3347
def bootstrap(

tests/basilisp/cli_test.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,25 @@ class CapturedIO:
8181

8282

8383
@pytest.fixture
84-
def run_cli(monkeypatch, capsys, cap_lisp_io):
84+
def run_cli(monkeypatch):
8585
def _run_cli(args: Sequence[str], input: Optional[str] = None):
8686
if input is not None:
8787
monkeypatch.setattr(
8888
"sys.stdin", io.TextIOWrapper(io.BytesIO(input.encode("utf-8")))
8989
)
90-
invoke_cli([*args])
91-
python_io = capsys.readouterr()
92-
lisp_out, lisp_err = cap_lisp_io
90+
process = subprocess.run(
91+
["basilisp", *args],
92+
stdin=io.StringIO(input) if input is not None else None,
93+
encoding="utf-8",
94+
capture_output=True,
95+
check=True,
96+
)
97+
9398
return CapturedIO(
94-
out=python_io.out,
95-
err=python_io.err,
96-
lisp_out=lisp_out.getvalue(),
97-
lisp_err=lisp_err.getvalue(),
99+
out=process.stdout,
100+
err=process.stderr,
101+
lisp_out=process.stdout,
102+
lisp_err=process.stderr,
98103
)
99104

100105
return _run_cli
@@ -204,7 +209,7 @@ def test_valid_flag(self, run_cli, val):
204209

205210
@pytest.mark.parametrize("val", ["maybe", "not-no", "4"])
206211
def test_invalid_flag(self, run_cli, val):
207-
with pytest.raises(SystemExit):
212+
with pytest.raises(subprocess.CalledProcessError):
208213
run_cli(["run", "--warn-on-var-indirection", val, "-c", "(+ 1 2)"])
209214

210215

@@ -355,7 +360,7 @@ def test_repl_include_extra_path(
355360

356361
class TestRun:
357362
def test_run_ns_and_code_mutually_exclusive(self, run_cli):
358-
with pytest.raises(SystemExit):
363+
with pytest.raises(subprocess.CalledProcessError):
359364
run_cli(["run", "-c", "-n"])
360365

361366
class TestRunCode:
@@ -550,7 +555,7 @@ def test_cannot_run_namespace_with_in_ns_arg(
550555
self, run_cli, namespace_name: str, namespace_file: pathlib.Path
551556
):
552557
namespace_file.write_text("(println (+ 1 2))")
553-
with pytest.raises(SystemExit):
558+
with pytest.raises(subprocess.CalledProcessError):
554559
run_cli(["run", "--in-ns", "otherpackage.core", "-n", namespace_name])
555560

556561
def test_run_namespace(

0 commit comments

Comments
 (0)