1- import os
21import sys
2+ from pathlib import Path
3+ from typing import Generator , Tuple
34
45from .ffi import ffi , load_hostfxr
5- from .util import check_result , find_dotnet_root
6+ from .types import Runtime , RuntimeInfo , StrOrPath
7+ from .util import check_result
68
79__all__ = ["DotnetCoreRuntime" ]
810
11+ _IS_SHUTDOWN = False
912
10- class DotnetCoreRuntime :
11- def __init__ (self , runtime_config : str , dotnet_root : str ):
12- self ._dotnet_root = dotnet_root or find_dotnet_root ()
13+
14+ class DotnetCoreRuntime (Runtime ):
15+ def __init__ (self , runtime_config : Path , dotnet_root : Path , ** params : str ):
16+ if _IS_SHUTDOWN :
17+ raise RuntimeError ("Runtime can not be reinitialized" )
18+
19+ self ._dotnet_root = Path (dotnet_root )
1320 self ._dll = load_hostfxr (self ._dotnet_root )
14- self ._is_finalized = False
21+ self ._is_initialized = False
1522 self ._handle = _get_handle (self ._dll , self ._dotnet_root , runtime_config )
1623 self ._load_func = _get_load_func (self ._dll , self ._handle )
1724
25+ for key , value in params .items ():
26+ self [key ] = value
27+
28+ # TODO: Get version
29+ self ._version = "<undefined>"
30+
1831 @property
19- def dotnet_root (self ) -> str :
32+ def dotnet_root (self ) -> Path :
2033 return self ._dotnet_root
2134
2235 @property
23- def is_finalized (self ) -> bool :
24- return self ._is_finalized
36+ def is_initialized (self ) -> bool :
37+ return self ._is_initialized
38+
39+ @property
40+ def is_shutdown (self ) -> bool :
41+ return _IS_SHUTDOWN
2542
2643 def __getitem__ (self , key : str ) -> str :
44+ if self .is_shutdown :
45+ raise RuntimeError ("Runtime is shut down" )
2746 buf = ffi .new ("char_t**" )
2847 res = self ._dll .hostfxr_get_runtime_property_value (
2948 self ._handle , encode (key ), buf
@@ -34,15 +53,17 @@ def __getitem__(self, key: str) -> str:
3453 return decode (buf [0 ])
3554
3655 def __setitem__ (self , key : str , value : str ) -> None :
37- if self .is_finalized :
38- raise RuntimeError ("Already finalized " )
56+ if self .is_initialized :
57+ raise RuntimeError ("Already initialized " )
3958
4059 res = self ._dll .hostfxr_set_runtime_property_value (
4160 self ._handle , encode (key ), encode (value )
4261 )
4362 check_result (res )
4463
45- def __iter__ (self ):
64+ def __iter__ (self ) -> Generator [Tuple [str , str ], None , None ]:
65+ if self .is_shutdown :
66+ raise RuntimeError ("Runtime is shut down" )
4667 max_size = 100
4768 size_ptr = ffi .new ("size_t*" )
4869 size_ptr [0 ] = max_size
@@ -51,25 +72,26 @@ def __iter__(self):
5172 values_ptr = ffi .new ("char_t*[]" , max_size )
5273
5374 res = self ._dll .hostfxr_get_runtime_properties (
54- self ._dll . _handle , size_ptr , keys_ptr , values_ptr
75+ self ._handle , size_ptr , keys_ptr , values_ptr
5576 )
5677 check_result (res )
5778
5879 for i in range (size_ptr [0 ]):
5980 yield (decode (keys_ptr [i ]), decode (values_ptr [i ]))
6081
61- def get_callable (self , assembly_path : str , typename : str , function : str ):
82+ def get_callable (self , assembly_path : StrOrPath , typename : str , function : str ):
6283 # TODO: Maybe use coreclr_get_delegate as well, supported with newer API
6384 # versions of hostfxr
64- self ._is_finalized = True
85+ self ._is_initialized = True
6586
6687 # Append assembly name to typename
67- assembly_name , _ = os .path .splitext (os .path .basename (assembly_path ))
88+ assembly_path = Path (assembly_path )
89+ assembly_name = assembly_path .stem
6890 typename = f"{ typename } , { assembly_name } "
6991
7092 delegate_ptr = ffi .new ("void**" )
7193 res = self ._load_func (
72- encode (assembly_path ),
94+ encode (str ( assembly_path ) ),
7395 encode (typename ),
7496 encode (function ),
7597 ffi .NULL ,
@@ -79,27 +101,39 @@ def get_callable(self, assembly_path: str, typename: str, function: str):
79101 check_result (res )
80102 return ffi .cast ("component_entry_point_fn" , delegate_ptr [0 ])
81103
104+ def _check_initialized (self ) -> None :
105+ if self ._handle is None :
106+ raise RuntimeError ("Runtime is shut down" )
107+ elif not self ._is_initialized :
108+ raise RuntimeError ("Runtime is not initialized" )
109+
82110 def shutdown (self ) -> None :
83111 if self ._handle is not None :
84112 self ._dll .hostfxr_close (self ._handle )
85113 self ._handle = None
86114
87- def __del__ (self ):
88- self .shutdown ()
115+ def info (self ):
116+ return RuntimeInfo (
117+ kind = "CoreCLR" ,
118+ version = self ._version ,
119+ initialized = self ._handle is not None ,
120+ shutdown = self ._handle is None ,
121+ properties = dict (self ) if not _IS_SHUTDOWN else {},
122+ )
89123
90124
91- def _get_handle (dll , dotnet_root : str , runtime_config : str ):
125+ def _get_handle (dll , dotnet_root : StrOrPath , runtime_config : StrOrPath ):
92126 params = ffi .new ("hostfxr_initialize_parameters*" )
93127 params .size = ffi .sizeof ("hostfxr_initialize_parameters" )
94128 # params.host_path = ffi.new("char_t[]", encode(sys.executable))
95129 params .host_path = ffi .NULL
96- dotnet_root_p = ffi .new ("char_t[]" , encode (dotnet_root ))
130+ dotnet_root_p = ffi .new ("char_t[]" , encode (str ( Path ( dotnet_root )) ))
97131 params .dotnet_root = dotnet_root_p
98132
99133 handle_ptr = ffi .new ("hostfxr_handle*" )
100134
101135 res = dll .hostfxr_initialize_for_runtime_config (
102- encode (runtime_config ), params , handle_ptr
136+ encode (str ( Path ( runtime_config )) ), params , handle_ptr
103137 )
104138 check_result (res )
105139
@@ -119,16 +153,16 @@ def _get_load_func(dll, handle):
119153
120154if sys .platform == "win32" :
121155
122- def encode (string ):
156+ def encode (string : str ):
123157 return string
124158
125- def decode (char_ptr ):
159+ def decode (char_ptr ) -> str :
126160 return ffi .string (char_ptr )
127161
128162else :
129163
130- def encode (string ):
164+ def encode (string : str ):
131165 return string .encode ("utf8" )
132166
133- def decode (char_ptr ):
167+ def decode (char_ptr ) -> str :
134168 return ffi .string (char_ptr ).decode ("utf8" )
0 commit comments