Skip to content

Commit 43769f5

Browse files
authored
Merge pull request #1942 from filmor/configless-coreclr
Config-less CoreCLR and improved runtime load message
2 parents 91d3e55 + fd8fd3b commit 43769f5

File tree

4 files changed

+50
-23
lines changed

4 files changed

+50
-23
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
graft src/runtime
22
prune src/runtime/obj
33
prune src/runtime/bin
4+
include src/pythonnet.snk
45
include Directory.Build.*
56
include pythonnet.sln
67
include version.txt

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ license = {text = "MIT"}
1010
readme = "README.rst"
1111

1212
dependencies = [
13-
"clr_loader>=0.1.7"
13+
"clr_loader>=0.2.2,<0.3.0"
1414
]
1515

1616
classifiers = [

pythonnet/__init__.py

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import sys
22
from pathlib import Path
3-
from typing import Dict, Optional, Union
3+
from typing import Dict, Optional, Union, Any
44
import clr_loader
55

66
__all__ = ["set_runtime", "set_runtime_from_env", "load"]
77

88
_RUNTIME: Optional[clr_loader.Runtime] = None
9-
_LOADER_ASSEMBLY: Optional[clr_loader.wrappers.Assembly] = None
9+
_LOADER_ASSEMBLY: Optional[clr_loader.Assembly] = None
1010
_LOADED: bool = False
1111

1212

@@ -27,6 +27,15 @@ def set_runtime(runtime: Union[clr_loader.Runtime, str], **params: str) -> None:
2727
_RUNTIME = runtime
2828

2929

30+
def get_runtime_info() -> Optional[clr_loader.RuntimeInfo]:
31+
"""Retrieve information on the configured runtime"""
32+
33+
if _RUNTIME is None:
34+
return None
35+
else:
36+
return _RUNTIME.info()
37+
38+
3039
def _get_params_from_env(prefix: str) -> Dict[str, str]:
3140
from os import environ
3241

@@ -43,24 +52,41 @@ def _get_params_from_env(prefix: str) -> Dict[str, str]:
4352

4453

4554
def _create_runtime_from_spec(
46-
spec: str, params: Optional[Dict[str, str]] = None
55+
spec: str, params: Optional[Dict[str, Any]] = None
4756
) -> clr_loader.Runtime:
57+
was_default = False
4858
if spec == "default":
59+
was_default = True
4960
if sys.platform == "win32":
5061
spec = "netfx"
5162
else:
5263
spec = "mono"
5364

5465
params = params or _get_params_from_env(spec)
5566

56-
if spec == "netfx":
57-
return clr_loader.get_netfx(**params)
58-
elif spec == "mono":
59-
return clr_loader.get_mono(**params)
60-
elif spec == "coreclr":
61-
return clr_loader.get_coreclr(**params)
62-
else:
63-
raise RuntimeError(f"Invalid runtime name: '{spec}'")
67+
try:
68+
if spec == "netfx":
69+
return clr_loader.get_netfx(**params)
70+
elif spec == "mono":
71+
return clr_loader.get_mono(**params)
72+
elif spec == "coreclr":
73+
return clr_loader.get_coreclr(**params)
74+
else:
75+
raise RuntimeError(f"Invalid runtime name: '{spec}'")
76+
except Exception as exc:
77+
if was_default:
78+
raise RuntimeError(
79+
f"""Failed to create a default .NET runtime, which would
80+
have been "{spec}" on this system. Either install a
81+
compatible runtime or configure it explicitly via
82+
`set_runtime` or the `PYTHONNET_*` environment variables
83+
(see set_runtime_from_env)."""
84+
) from exc
85+
else:
86+
raise RuntimeError(
87+
f"""Failed to create a .NET runtime ({spec}) using the
88+
parameters {params}."""
89+
) from exc
6490

6591

6692
def set_runtime_from_env() -> None:
@@ -85,9 +111,7 @@ def set_runtime_from_env() -> None:
85111
set_runtime(runtime)
86112

87113

88-
def load(
89-
runtime: Union[clr_loader.Runtime, str, None] = None, **params: str
90-
) -> None:
114+
def load(runtime: Union[clr_loader.Runtime, str, None] = None, **params: str) -> None:
91115
"""Load Python.NET in the specified runtime
92116
93117
The same parameters as for `set_runtime` can be used. By default,
@@ -109,9 +133,9 @@ def load(
109133

110134
dll_path = Path(__file__).parent / "runtime" / "Python.Runtime.dll"
111135

112-
_LOADER_ASSEMBLY = _RUNTIME.get_assembly(str(dll_path))
136+
_LOADER_ASSEMBLY = assembly = _RUNTIME.get_assembly(str(dll_path))
137+
func = assembly.get_function("Python.Runtime.Loader.Initialize")
113138

114-
func = _LOADER_ASSEMBLY["Python.Runtime.Loader.Initialize"]
115139
if func(b"") != 0:
116140
raise RuntimeError("Failed to initialize Python.Runtime.dll")
117141

@@ -125,12 +149,12 @@ def unload() -> None:
125149

126150
global _RUNTIME, _LOADER_ASSEMBLY
127151
if _LOADER_ASSEMBLY is not None:
128-
func = _LOADER_ASSEMBLY["Python.Runtime.Loader.Shutdown"]
152+
func = _LOADER_ASSEMBLY.get_function("Python.Runtime.Loader.Shutdown")
129153
if func(b"full_shutdown") != 0:
130154
raise RuntimeError("Failed to call Python.NET shutdown")
131155

132156
_LOADER_ASSEMBLY = None
133157

134158
if _RUNTIME is not None:
135-
# TODO: Add explicit `close` to clr_loader
159+
_RUNTIME.shutdown()
136160
_RUNTIME = None

tests/conftest.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ def pytest_configure(config):
5353
runtime_params = {}
5454

5555
if runtime_opt == "coreclr":
56-
fw = "net6.0"
57-
runtime_params["runtime_config"] = str(
58-
bin_path / "Python.Test.runtimeconfig.json"
59-
)
56+
# This is optional now:
57+
#
58+
# fw = "net6.0"
59+
# runtime_params["runtime_config"] = str(
60+
# bin_path / "Python.Test.runtimeconfig.json"
61+
# )
6062
collect_ignore.append("domain_tests/test_domain_reload.py")
6163
else:
6264
domain_tests_dir = cwd / "domain_tests"

0 commit comments

Comments
 (0)