From 9b5914e3cfcd57bf4f5d4afc8d40c4733aedc4aa Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Thu, 12 Dec 2024 21:14:08 +0100 Subject: [PATCH 01/22] Workaround for setuptools bug #4759 --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 94857e4..c3ed5df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61", "setuptools_scm[toml]", "wheel"] +requires = ["setuptools>=75", "setuptools_scm[toml]"] build-backend = "setuptools.build_meta" [project] @@ -43,6 +43,7 @@ dev = [ [tool.setuptools] zip-safe = false package-data = {"clr_loader.ffi" = ["dlls/x86/*.dll", "dlls/amd64/*.dll"]} +license-files = [] [tool.setuptools.packages.find] include = ["clr_loader*"] From cbe765c35ecf8c1885be4f2eef4e9aea7d8ce406 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Thu, 12 Dec 2024 21:33:46 +0100 Subject: [PATCH 02/22] Use dependency group instead of optional deps --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c3ed5df..2c643e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ email = "filmor@gmail.com" Sources = "https://github.com/pythonnet/clr-loader" Documentation = "https://pythonnet.github.io/clr-loader/" -[optional-dependencies] +[dependency-groups] dev = [ "pytest" ] From 80e2385f5e1ba3ed2292948422514878b951793f Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Thu, 24 Jul 2025 19:55:34 +0200 Subject: [PATCH 03/22] Update CI actions (#79) * Update CI actions * Fix format --- .github/workflows/ci-arm.yml | 5 ++--- .github/workflows/ci.yml | 22 +++++++++++----------- .github/workflows/docs.yml | 2 +- clr_loader/types.py | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml index c451f0f..8f46757 100644 --- a/.github/workflows/ci-arm.yml +++ b/.github/workflows/ci-arm.yml @@ -2,7 +2,7 @@ name: ARM64 Tests on: push: - branches: master + branches: [master] pull_request: jobs: @@ -10,13 +10,12 @@ jobs: runs-on: [self-hosted, linux, ARM64] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v1 with: dotnet-version: | - 3.1.x 6.0.x - name: Create virtualenv diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae40be9..b83433d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,22 +2,22 @@ name: Python Tests on: push: - branches: master + branches: [master] pull_request: jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-dotnet@v1 - - uses: astral-sh/setup-uv@v4 + - uses: astral-sh/setup-uv@v6 - name: Build run: uv build - name: Upload source distribution - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: build-output path: "dist/*" @@ -26,10 +26,10 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depths: 0 - - uses: astral-sh/setup-uv@v4 + - uses: astral-sh/setup-uv@v6 - name: Install Ruff run: uv tool install ruff - name: Check format @@ -46,7 +46,7 @@ jobs: python: ['3.13', '3.12', '3.11', '3.10', '3.9', '3.8'] # pypy3 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v1 @@ -54,13 +54,13 @@ jobs: dotnet-version: '6.0.x' - name: Set up Python ${{ matrix.python }} - uses: astral-sh/setup-uv@v4 + uses: astral-sh/setup-uv@v6 with: python-version: ${{ matrix.python }} - name: Cache Mono if: runner.os == 'Windows' - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ env.TEMP }}\chocolatey key: ${{ runner.os }}-chocolatey-${{ matrix.python == 'pypy3' && '32' || '64' }} @@ -76,7 +76,7 @@ jobs: uv pip install pytest - name: Download wheel - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: build-output path: dist/ @@ -96,7 +96,7 @@ jobs: steps: - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: build-output path: dist/ diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index bce19d4..1fe8fee 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -14,7 +14,7 @@ jobs: - name: Upload artifact # Automatically uploads an artifact from the './_site' directory by default - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v3 with: path: doc/_build/html/ diff --git a/clr_loader/types.py b/clr_loader/types.py index 15c1e30..6b54030 100644 --- a/clr_loader/types.py +++ b/clr_loader/types.py @@ -141,6 +141,6 @@ def _truncate(string: str, length: int) -> str: if length <= 1: raise TypeError("length must be > 1") if len(string) > length - 1: - return f"{string[:length-1]}…" + return f"{string[: length - 1]}…" else: return string From f9e0544ff02c6fced35e47a3593d477dd17a4cb2 Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Mon, 28 Jul 2025 16:20:14 -0500 Subject: [PATCH 04/22] add trace options (#67) Co-authored-by: Mohamed Koubaa --- clr_loader/__init__.py | 2 ++ clr_loader/ffi/mono.py | 3 +++ clr_loader/mono.py | 12 ++++++++++++ tests/test_common.py | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/clr_loader/__init__.py b/clr_loader/__init__.py index 71eb09d..52ce603 100644 --- a/clr_loader/__init__.py +++ b/clr_loader/__init__.py @@ -33,6 +33,8 @@ def get_mono( assembly_dir: Optional[str] = None, config_dir: Optional[str] = None, set_signal_chaining: bool = False, + trace_mask: Optional[str] = None, + trace_level: Optional[str] = None, ) -> Runtime: """Get a Mono runtime instance diff --git a/clr_loader/ffi/mono.py b/clr_loader/ffi/mono.py index c194393..a3249a1 100644 --- a/clr_loader/ffi/mono.py +++ b/clr_loader/ffi/mono.py @@ -44,5 +44,8 @@ void mono_set_signal_chaining(bool chain_signals); +void mono_trace_set_level_string(const char* value); +void mono_trace_set_mask_string(const char* value); + """ ) diff --git a/clr_loader/mono.py b/clr_loader/mono.py index 1899ea3..f7f90e5 100644 --- a/clr_loader/mono.py +++ b/clr_loader/mono.py @@ -27,6 +27,8 @@ def __init__( assembly_dir: Optional[str] = None, config_dir: Optional[str] = None, set_signal_chaining: bool = False, + trace_mask: Optional[str] = None, + trace_level: Optional[str] = None, ): self._assemblies: Dict[Path, Any] = {} @@ -39,6 +41,8 @@ def __init__( assembly_dir=assembly_dir, config_dir=config_dir, set_signal_chaining=set_signal_chaining, + trace_mask=trace_mask, + trace_level=trace_level, ) if domain is None: @@ -131,11 +135,19 @@ def initialize( assembly_dir: Optional[str] = None, config_dir: Optional[str] = None, set_signal_chaining: bool = False, + trace_mask: Optional[str] = None, + trace_level: Optional[str] = None, ) -> str: global _MONO, _ROOT_DOMAIN if _MONO is None: _MONO = load_mono(libmono) + if trace_mask is not None: + _MONO.mono_trace_set_mask_string(trace_mask.encode("utf8")) + + if trace_level is not None: + _MONO.mono_trace_set_level_string(trace_level.encode("utf8")) + if assembly_dir is not None and config_dir is not None: _MONO.mono_set_dirs(assembly_dir.encode("utf8"), config_dir.encode("utf8")) diff --git a/tests/test_common.py b/tests/test_common.py index 139f192..3eaf215 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -56,6 +56,24 @@ def test_mono_signal_chaining(example_netstandard: Path): run_tests(asm) +def test_mono_trace_mask(example_netstandard: Path): + from clr_loader import get_mono + + mono = get_mono(trace_mask="all") + asm = mono.get_assembly(example_netstandard / "example.dll") + + run_tests(asm) + + +def test_mono_trace_level(example_netstandard: Path): + from clr_loader import get_mono + + mono = get_mono(trace_level="message") + asm = mono.get_assembly(example_netstandard / "example.dll") + + run_tests(asm) + + def test_mono_set_dir(example_netstandard: Path): from clr_loader import get_mono From 5dadf4cedbe8e68075d50e626f26a8fc556591af Mon Sep 17 00:00:00 2001 From: Mohamed Koubaa Date: Thu, 14 Aug 2025 16:44:40 -0500 Subject: [PATCH 05/22] Support pythonnet for AppDomain (#78) * load the assembly and get function address inside the domain When using domain.Load for an assembly, the assembly resolution rules are awkward Even if the full path is given to the AssemblyName, when the domain tries to load the assembly, it does not use that context and tries to resolve the assembly using normal domain resolution rules, which would require an assembly resolver to be installed. However, the assembly resolver that is actually used at runtime is the one installed to the main appdomain. This prevents a library like Python.Runtime.dll (used by pythonnet) which is not installed to the application base directory to be loaded by clr_loader. To fix this issue, the assembly resolver of the main appdomain is lazily extending to include paths needed for libraries passed into GetFunction, and GetFunction internally uses AppDomain.DoCallBack() to marshal the function pointer inside the target app domain, using global domain data to access the function pointer and return it to the user of clr_loader. * Add comment * PR review feedback --------- Co-authored-by: Mohamed Koubaa --- netfx_loader/ClrLoader.cs | 25 ++++++++-- netfx_loader/DomainData.cs | 99 ++++++++++++++++++++++++++++++-------- 2 files changed, 100 insertions(+), 24 deletions(-) diff --git a/netfx_loader/ClrLoader.cs b/netfx_loader/ClrLoader.cs index 32b4c01..2a065bb 100644 --- a/netfx_loader/ClrLoader.cs +++ b/netfx_loader/ClrLoader.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Reflection; using System.Runtime.InteropServices; using NXPorts.Attributes; @@ -21,6 +22,19 @@ public static void Initialize() } } + private static string AssemblyDirectory + { + get + { + // This is needed in case the DLL was shadow-copied + // (Otherwise .Location would work) + string codeBase = Assembly.GetExecutingAssembly().CodeBase; + UriBuilder uri = new UriBuilder(codeBase); + string path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path); + } + } + [DllExport("pyclr_create_appdomain", CallingConvention.Cdecl)] public static IntPtr CreateAppDomain( [MarshalAs(UnmanagedType.LPUTF8Str)] string name, @@ -28,16 +42,17 @@ public static IntPtr CreateAppDomain( ) { Print($"Creating AppDomain {name} with {configFile}"); + + var clrLoaderDir = AssemblyDirectory; if (!string.IsNullOrEmpty(name)) { var setup = new AppDomainSetup { - ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, + ApplicationBase = clrLoaderDir, ConfigurationFile = configFile }; - Print($"Base: {AppDomain.CurrentDomain.BaseDirectory}"); + Print($"Base: {clrLoaderDir}"); var domain = AppDomain.CreateDomain(name, null, setup); - Print($"Located domain {domain}"); var domainData = new DomainData(domain); @@ -61,8 +76,8 @@ public static IntPtr GetFunction( try { var domainData = _domains[(int)domain]; - var deleg = domainData.GetEntryPoint(assemblyPath, typeName, function); - return Marshal.GetFunctionPointerForDelegate(deleg); + Print($"Getting functor for function {function} of type {typeName} in assembly {assemblyPath}"); + return domainData.GetFunctor(assemblyPath, typeName, function); } catch (Exception exc) { diff --git a/netfx_loader/DomainData.cs b/netfx_loader/DomainData.cs index 3a17d7a..35c3363 100644 --- a/netfx_loader/DomainData.cs +++ b/netfx_loader/DomainData.cs @@ -1,54 +1,115 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Runtime.InteropServices; namespace ClrLoader { using static ClrLoader; - class DomainData : IDisposable + public static class DomainSetup { public delegate int EntryPoint(IntPtr buffer, int size); + public static void StoreFunctorFromDomainData() + { + var domain = AppDomain.CurrentDomain; + var assemblyPath = (string)domain.GetData("_assemblyPath"); + var typeName = (string)domain.GetData("_typeName"); + var function = (string)domain.GetData("_function"); + var deleg = GetDelegate(domain, assemblyPath, typeName, function); + var functor = Marshal.GetFunctionPointerForDelegate(deleg); + domain.SetData("_thisDelegate", deleg); + domain.SetData("_thisFunctor", functor); + } + + private static Delegate GetDelegate(AppDomain domain, string assemblyPath, string typeName, string function) + { + var assemblyName = AssemblyName.GetAssemblyName(assemblyPath); + var assembly = domain.Load(assemblyName); + var type = assembly.GetType(typeName, throwOnError: true); + var deleg = Delegate.CreateDelegate(typeof(EntryPoint), type, function); + return deleg; + } + } + + class DomainData : IDisposable + { bool _disposed = false; public AppDomain Domain { get; } - public Dictionary<(string, string, string), EntryPoint> _delegates; + public Dictionary<(string, string, string), IntPtr> _functors; + public HashSet _resolvedAssemblies; public DomainData(AppDomain domain) { Domain = domain; - _delegates = new Dictionary<(string, string, string), EntryPoint>(); + _functors = new Dictionary<(string, string, string), IntPtr>(); + _resolvedAssemblies = new HashSet(); } - public EntryPoint GetEntryPoint(string assemblyPath, string typeName, string function) + private void installResolver(string assemblyPath) { - if (_disposed) - throw new InvalidOperationException("Domain is already disposed"); - - var key = (assemblyPath, typeName, function); - - EntryPoint result; + var assemblyName = AssemblyName.GetAssemblyName(assemblyPath).Name; + if (_resolvedAssemblies.Contains(assemblyName)) + return; + _resolvedAssemblies.Add(assemblyName); - if (!_delegates.TryGetValue(key, out result)) + AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { - var assembly = Domain.Load(AssemblyName.GetAssemblyName(assemblyPath)); - var type = assembly.GetType(typeName, throwOnError: true); + if (args.Name.Contains(assemblyName)) + return Assembly.LoadFrom(assemblyPath); + return null; + }; + } - Print($"Loaded type {type}"); - result = (EntryPoint)Delegate.CreateDelegate(typeof(EntryPoint), type, function); + private static readonly object _lockObj = new object(); - _delegates[key] = result; - } + public IntPtr GetFunctor(string assemblyPath, string typeName, string function) + { + if (_disposed) + throw new InvalidOperationException("Domain is already disposed"); - return result; + // neither the domain data nor the _functors dictionary is threadsafe + lock (_lockObj) + { + installResolver(assemblyPath); + var assemblyName = AssemblyName.GetAssemblyName(assemblyPath).Name; + + var key = (assemblyName, typeName, function); + + IntPtr result; + if (!_functors.TryGetValue(key, out result)) + { + Domain.SetData("_assemblyPath", assemblyPath); + Domain.SetData("_typeName", typeName); + Domain.SetData("_function", function); + + Domain.DoCallBack(new CrossAppDomainDelegate(DomainSetup.StoreFunctorFromDomainData)); + result = (IntPtr)Domain.GetData("_thisFunctor"); + if (result == IntPtr.Zero) + throw new Exception($"Unable to get functor for {assemblyName}, {typeName}, {function}"); + + // set inputs to StoreFunctorFromDomainData to null. + // (There's no method to explicitly clear domain data) + Domain.SetData("_assemblyPath", null); + Domain.SetData("_typeName", null); + Domain.SetData("_function", null); + + // the result has to remain in the domain data because we don't know when the + // client of pyclr_get_function will actually invoke the functor, and if we + // remove it from the domain data after returning it may get collected too early. + _functors[key] = result; + } + return result; + } } public void Dispose() { if (!_disposed) { - _delegates.Clear(); + _functors.Clear(); if (Domain != AppDomain.CurrentDomain) AppDomain.Unload(Domain); From c3445ff0f5f7212154224717b29f64c48a81b88e Mon Sep 17 00:00:00 2001 From: Etienne Gaudrain Date: Thu, 14 Aug 2025 23:51:10 +0200 Subject: [PATCH 06/22] Added extra info about error when hostfxr not found or loaded properly. (#76) https://github.com/pythonnet/clr-loader/issues/75 --- clr_loader/ffi/__init__.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/clr_loader/ffi/__init__.py b/clr_loader/ffi/__init__.py index 23debae..289999d 100644 --- a/clr_loader/ffi/__init__.py +++ b/clr_loader/ffi/__init__.py @@ -23,18 +23,20 @@ def load_hostfxr(dotnet_root: Path): hostfxr_path = dotnet_root / "host" / "fxr" hostfxr_paths = hostfxr_path.glob(f"?.*/{hostfxr_name}") + error_report = list() + for hostfxr_path in reversed(sorted(hostfxr_paths, key=_path_to_version)): try: return ffi.dlopen(str(hostfxr_path)) - except Exception: - pass + except Exception as err: + error_report.append(f"Path {hostfxr_path} gave the following error:\n{err}") try: return ffi.dlopen(str(dotnet_root / hostfxr_name)) - except Exception: - pass + except Exception as err: + error_report.append(f"Path {hostfxr_path} gave the following error:\n{err}") - raise RuntimeError(f"Could not find a suitable hostfxr library in {dotnet_root}") + raise RuntimeError(f"Could not find a suitable hostfxr library in {dotnet_root}. The following paths were scanned:\n\n"+("\n\n".join(error_report))) def load_mono(path: Optional[Path] = None): From eeed6ec9ccc1be5222eb192beaef28570223a47e Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Thu, 14 Aug 2025 23:53:35 +0200 Subject: [PATCH 07/22] Fix format --- clr_loader/ffi/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clr_loader/ffi/__init__.py b/clr_loader/ffi/__init__.py index 289999d..7917af9 100644 --- a/clr_loader/ffi/__init__.py +++ b/clr_loader/ffi/__init__.py @@ -36,7 +36,10 @@ def load_hostfxr(dotnet_root: Path): except Exception as err: error_report.append(f"Path {hostfxr_path} gave the following error:\n{err}") - raise RuntimeError(f"Could not find a suitable hostfxr library in {dotnet_root}. The following paths were scanned:\n\n"+("\n\n".join(error_report))) + raise RuntimeError( + f"Could not find a suitable hostfxr library in {dotnet_root}. The following paths were scanned:\n\n" + + ("\n\n".join(error_report)) + ) def load_mono(path: Optional[Path] = None): From 8c123c6147b6b7094cd6a61031db47156bff5522 Mon Sep 17 00:00:00 2001 From: Steven Lovelock Date: Thu, 14 Aug 2025 23:01:30 +0100 Subject: [PATCH 08/22] Add get_coreclr_command_line which uses hostfxr_initialize_for_dotnet_command_line (#66) see https://github.com/dotnet/runtime/blob/main/docs/design/features/native-hosting.md#initializing-host-context --- clr_loader/__init__.py | 34 ++++++++++++++++++++++ clr_loader/hostfxr.py | 64 ++++++++++++++++++++++++++++++++++-------- tests/test_common.py | 13 +++++++++ 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/clr_loader/__init__.py b/clr_loader/__init__.py index 52ce603..2744cf0 100644 --- a/clr_loader/__init__.py +++ b/clr_loader/__init__.py @@ -11,6 +11,7 @@ "get_mono", "get_netfx", "get_coreclr", + "get_coreclr_command_line", "find_dotnet_root", "find_libmono", "find_runtimes", @@ -152,6 +153,39 @@ def get_coreclr( return impl +def get_coreclr_command_line( + *, + entry_dll: StrOrPath, + dotnet_root: Optional[StrOrPath] = None, + properties: Optional[Dict[str, str]] = None +) -> Runtime: + """Get a CoreCLR (.NET Core) runtime instance + The returned ``DotnetCoreRuntimeCommandLine`` also acts as a mapping of the config + properties. They can be retrieved using the index operator and can be + written until the runtime is initialized. The runtime is initialized when + the first function object is retrieved. + :param entry_dll: + The path to the entry dll. + :param dotnet_root: + The root directory of the .NET Core installation. If this is not + specified, we try to discover it using :py:func:`find_dotnet_root`. + :param properties: + Additional runtime properties. These can also be passed using the + ``configProperties`` section in the runtime config.""" + from .hostfxr import DotnetCoreCommandRuntime + + dotnet_root = _maybe_path(dotnet_root) + if dotnet_root is None: + dotnet_root = find_dotnet_root() + + impl = DotnetCoreCommandRuntime(entry_dll=_maybe_path(entry_dll), dotnet_root=dotnet_root) + if properties: + for key, value in properties.items(): + impl[key] = value + + return impl + + def get_netfx( *, domain: Optional[str] = None, config_file: Optional[StrOrPath] = None ) -> Runtime: diff --git a/clr_loader/hostfxr.py b/clr_loader/hostfxr.py index 225b4c7..7a159f3 100644 --- a/clr_loader/hostfxr.py +++ b/clr_loader/hostfxr.py @@ -6,13 +6,15 @@ from .types import Runtime, RuntimeInfo, StrOrPath from .util import check_result -__all__ = ["DotnetCoreRuntime"] +__all__ = ["DotnetCoreRuntime", "DotnetCoreCommandRuntime"] _IS_SHUTDOWN = False -class DotnetCoreRuntime(Runtime): - def __init__(self, runtime_config: Path, dotnet_root: Path, **params: str): +class DotnetCoreRuntimeBase(Runtime): + _version: str + + def __init__(self, dotnet_root: Path): self._handle = None if _IS_SHUTDOWN: @@ -20,15 +22,8 @@ def __init__(self, runtime_config: Path, dotnet_root: Path, **params: str): self._dotnet_root = Path(dotnet_root) self._dll = load_hostfxr(self._dotnet_root) - self._handle = _get_handle(self._dll, self._dotnet_root, runtime_config) self._load_func = None - for key, value in params.items(): - self[key] = value - - # TODO: Get version - self._version = "" - @property def dotnet_root(self) -> Path: return self._dotnet_root @@ -122,7 +117,31 @@ def info(self): ) -def _get_handle(dll, dotnet_root: StrOrPath, runtime_config: StrOrPath): +class DotnetCoreRuntime(DotnetCoreRuntimeBase): + def __init__(self, runtime_config: Path, dotnet_root: Path, **params: str): + super().__init__(dotnet_root) + self._handle = _get_handle_for_runtime_config(self._dll, self._dotnet_root, runtime_config) + + for key, value in params.items(): + self[key] = value + + # TODO: Get version + self._version = "" + + +class DotnetCoreCommandRuntime(DotnetCoreRuntimeBase): + def __init__(self, entry_dll: Path, dotnet_root: Path, **params: str): + super().__init__(dotnet_root) + self._handle = _get_handle_for_dotnet_command_line(self._dll, self._dotnet_root, entry_dll) + + for key, value in params.items(): + self[key] = value + + # TODO: Get version + self._version = "" + + +def _get_handle_for_runtime_config(dll, dotnet_root: StrOrPath, runtime_config: StrOrPath): params = ffi.new("hostfxr_initialize_parameters*") params.size = ffi.sizeof("hostfxr_initialize_parameters") # params.host_path = ffi.new("char_t[]", encode(sys.executable)) @@ -140,6 +159,29 @@ def _get_handle(dll, dotnet_root: StrOrPath, runtime_config: StrOrPath): return handle_ptr[0] +def _get_handle_for_dotnet_command_line(dll, dotnet_root: StrOrPath, entry_dll: StrOrPath): + params = ffi.new("hostfxr_initialize_parameters*") + params.size = ffi.sizeof("hostfxr_initialize_parameters") + params.host_path = ffi.NULL + dotnet_root_p = ffi.new("char_t[]", encode(str(Path(dotnet_root)))) + params.dotnet_root = dotnet_root_p + + handle_ptr = ffi.new("hostfxr_handle*") + + args_ptr = ffi.new("char_t*[1]") + arg_ptr = ffi.new("char_t[]", encode(str(Path(entry_dll)))) + args_ptr[0] = arg_ptr + res = dll.hostfxr_initialize_for_dotnet_command_line( + 1, + args_ptr, + params, handle_ptr + ) + + check_result(res) + + return handle_ptr[0] + + def _get_load_func(dll, handle): delegate_ptr = ffi.new("void**") diff --git a/tests/test_common.py b/tests/test_common.py index 3eaf215..b9b0597 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -92,6 +92,19 @@ def test_coreclr(example_netcore: Path): run_tests(asm) +def test_coreclr_command_line(example_netcore: Path): + run_in_subprocess(_do_test_coreclr_command_line, example_netcore) + + +def _do_test_coreclr_command_line(example_netcore): + from clr_loader import get_coreclr_command_line + + coreclr = get_coreclr_command_line(entry_dll=example_netcore / "example.dll") + asm = coreclr.get_assembly(example_netcore / "example.dll") + + run_tests(asm) + + def test_coreclr_properties(example_netcore: Path): run_in_subprocess( _do_test_coreclr_autogenerated_runtimeconfig, From bbdc3dad210d865f90a14797025989a73d48657a Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 6 Oct 2025 18:57:23 +0200 Subject: [PATCH 09/22] Fix format --- clr_loader/__init__.py | 6 ++++-- clr_loader/hostfxr.py | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/clr_loader/__init__.py b/clr_loader/__init__.py index 2744cf0..ce239a1 100644 --- a/clr_loader/__init__.py +++ b/clr_loader/__init__.py @@ -157,7 +157,7 @@ def get_coreclr_command_line( *, entry_dll: StrOrPath, dotnet_root: Optional[StrOrPath] = None, - properties: Optional[Dict[str, str]] = None + properties: Optional[Dict[str, str]] = None, ) -> Runtime: """Get a CoreCLR (.NET Core) runtime instance The returned ``DotnetCoreRuntimeCommandLine`` also acts as a mapping of the config @@ -178,7 +178,9 @@ def get_coreclr_command_line( if dotnet_root is None: dotnet_root = find_dotnet_root() - impl = DotnetCoreCommandRuntime(entry_dll=_maybe_path(entry_dll), dotnet_root=dotnet_root) + impl = DotnetCoreCommandRuntime( + entry_dll=_maybe_path(entry_dll), dotnet_root=dotnet_root + ) if properties: for key, value in properties.items(): impl[key] = value diff --git a/clr_loader/hostfxr.py b/clr_loader/hostfxr.py index 7a159f3..60ad6b6 100644 --- a/clr_loader/hostfxr.py +++ b/clr_loader/hostfxr.py @@ -120,7 +120,9 @@ def info(self): class DotnetCoreRuntime(DotnetCoreRuntimeBase): def __init__(self, runtime_config: Path, dotnet_root: Path, **params: str): super().__init__(dotnet_root) - self._handle = _get_handle_for_runtime_config(self._dll, self._dotnet_root, runtime_config) + self._handle = _get_handle_for_runtime_config( + self._dll, self._dotnet_root, runtime_config + ) for key, value in params.items(): self[key] = value @@ -132,7 +134,9 @@ def __init__(self, runtime_config: Path, dotnet_root: Path, **params: str): class DotnetCoreCommandRuntime(DotnetCoreRuntimeBase): def __init__(self, entry_dll: Path, dotnet_root: Path, **params: str): super().__init__(dotnet_root) - self._handle = _get_handle_for_dotnet_command_line(self._dll, self._dotnet_root, entry_dll) + self._handle = _get_handle_for_dotnet_command_line( + self._dll, self._dotnet_root, entry_dll + ) for key, value in params.items(): self[key] = value @@ -141,7 +145,9 @@ def __init__(self, entry_dll: Path, dotnet_root: Path, **params: str): self._version = "" -def _get_handle_for_runtime_config(dll, dotnet_root: StrOrPath, runtime_config: StrOrPath): +def _get_handle_for_runtime_config( + dll, dotnet_root: StrOrPath, runtime_config: StrOrPath +): params = ffi.new("hostfxr_initialize_parameters*") params.size = ffi.sizeof("hostfxr_initialize_parameters") # params.host_path = ffi.new("char_t[]", encode(sys.executable)) @@ -159,7 +165,9 @@ def _get_handle_for_runtime_config(dll, dotnet_root: StrOrPath, runtime_config: return handle_ptr[0] -def _get_handle_for_dotnet_command_line(dll, dotnet_root: StrOrPath, entry_dll: StrOrPath): +def _get_handle_for_dotnet_command_line( + dll, dotnet_root: StrOrPath, entry_dll: StrOrPath +): params = ffi.new("hostfxr_initialize_parameters*") params.size = ffi.sizeof("hostfxr_initialize_parameters") params.host_path = ffi.NULL @@ -172,9 +180,7 @@ def _get_handle_for_dotnet_command_line(dll, dotnet_root: StrOrPath, entry_dll: arg_ptr = ffi.new("char_t[]", encode(str(Path(entry_dll)))) args_ptr[0] = arg_ptr res = dll.hostfxr_initialize_for_dotnet_command_line( - 1, - args_ptr, - params, handle_ptr + 1, args_ptr, params, handle_ptr ) check_result(res) From cf0ba009af0ed04e8616a272440c0547239d6d15 Mon Sep 17 00:00:00 2001 From: Dmitriy Shepelev Date: Mon, 6 Oct 2025 13:02:37 -0400 Subject: [PATCH 10/22] Support finding .NET 10 and pre-release .NET versions (#82) * Support finding .NET 10 and pre-release .NET versions --- clr_loader/ffi/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clr_loader/ffi/__init__.py b/clr_loader/ffi/__init__.py index 7917af9..eb2b5ae 100644 --- a/clr_loader/ffi/__init__.py +++ b/clr_loader/ffi/__init__.py @@ -18,10 +18,9 @@ def load_hostfxr(dotnet_root: Path): hostfxr_name = _get_dll_name("hostfxr") dotnet_root = dotnet_root.absolute() - # This will fail as soon as .NET hits version 10, but hopefully by then - # we'll have a more robust way of finding the libhostfxr + # Find all hostfxr versions by looking for the library file in version subdirectories hostfxr_path = dotnet_root / "host" / "fxr" - hostfxr_paths = hostfxr_path.glob(f"?.*/{hostfxr_name}") + hostfxr_paths = hostfxr_path.glob(f"*/{hostfxr_name}") error_report = list() @@ -69,7 +68,9 @@ def load_netfx(): def _path_to_version(path: Path) -> Tuple[int, int, int]: name = path.parent.name try: - res = list(map(int, name.split("."))) + # Handle pre-release versions like "10.0.0-rc.1" by taking only the version part + version_part = name.split("-")[0] + res = list(map(int, version_part.split("."))) return tuple(res + [0, 0, 0])[:3] except Exception: return (0, 0, 0) From 816970c1fac2e240373fc129556e8efcb0a47b70 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 20 Oct 2025 21:58:50 +0200 Subject: [PATCH 11/22] Add dependabot file and update CI (#83) * Add dependabot file and update CI * Add typed marker * Type tests, use newer pytest tmp_path, use net8.0 * Adjust target images * Reorder and explicitly switch mono * Fix type hint and adjust test * Downgrade to last version that has mono installed * Remove currently not working platforms --- .github/workflows/ci-arm.yml | 41 ---- .github/workflows/ci.yml | 24 ++- clr_loader/py.typed | 0 clr_loader/util/find.py | 2 +- dependabot.yml | 16 ++ example/example.csproj | 2 +- netfx_loader/ClrLoader.csproj | 2 +- pyproject.toml | 2 +- tests/test_common.py | 18 +- uv.lock | 355 ++++++++++++++++++++++------------ 10 files changed, 283 insertions(+), 179 deletions(-) delete mode 100644 .github/workflows/ci-arm.yml create mode 100644 clr_loader/py.typed create mode 100644 dependabot.yml diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml deleted file mode 100644 index 8f46757..0000000 --- a/.github/workflows/ci-arm.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: ARM64 Tests - -on: - push: - branches: [master] - pull_request: - -jobs: - build: - runs-on: [self-hosted, linux, ARM64] - - steps: - - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: | - 6.0.x - - - name: Create virtualenv - run: | - virtualenv -p python3 venv - - - name: Install dependencies - run: | - source venv/bin/activate - python -m pip install --upgrade pip - pip install pytest cffi - - # Assumes recent Mono - - - name: Build - run: | - source venv/bin/activate - pip install -e . - - - name: Test with pytest - run: | - source venv/bin/activate - pytest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b83433d..9a1b5b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-dotnet@v1 + - uses: actions/setup-dotnet@v5 - uses: astral-sh/setup-uv@v6 - name: Build run: uv build @@ -41,17 +41,27 @@ jobs: runs-on: ${{ matrix.os }} needs: build strategy: + fail-fast: false matrix: - os: [ubuntu-22.04, windows-latest, macos-13] - python: ['3.13', '3.12', '3.11', '3.10', '3.9', '3.8'] # pypy3 + # macos-13-arm64, windows-11-arm + # TODO: + # - Install mono via install-package action + # - Update macos images to at least 14 as 13 is retired + # - Update ubuntu images + os: [ubuntu-22.04, ubuntu-22.04-arm, windows-latest, macos-13] + python: ['3.14', '3.13', '3.12', '3.11', '3.10', '3.9', '3.8'] # pypy3 steps: - - uses: actions/checkout@v4 + - name: Set Environment on macOS + uses: maxim-lobanov/setup-xamarin@v1 + if: ${{ matrix.os.category == 'macos' }} + with: + mono-version: latest - name: Setup .NET - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v5 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Set up Python ${{ matrix.python }} uses: astral-sh/setup-uv@v6 @@ -70,6 +80,8 @@ jobs: run: | choco install -y mono ${{ matrix.python == 'pypy3' && '--x86' || '' }} + - uses: actions/checkout@v4 + - name: Install dependencies run: | uv venv diff --git a/clr_loader/py.typed b/clr_loader/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/clr_loader/util/find.py b/clr_loader/util/find.py index 65bc7ac..ffae7c3 100644 --- a/clr_loader/util/find.py +++ b/clr_loader/util/find.py @@ -105,7 +105,7 @@ def find_runtimes() -> Iterator[DotnetCoreRuntimeSpec]: return find_runtimes_in_root(dotnet_root) -def find_libmono(*, assembly_dir: str = None, sgen: bool = True) -> Path: +def find_libmono(*, assembly_dir: Optional[str] = None, sgen: bool = True) -> Path: """Find a suitable libmono dynamic library On Windows and macOS, we check the default installation directories. diff --git a/dependabot.yml b/dependabot.yml new file mode 100644 index 0000000..f7a2baa --- /dev/null +++ b/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "pip" + directory: "/" + schedule: + interval: "weekly" + + - package-ecosystem: "nuget" + directory: "netfx_loader/" + schedule: + interval: "weekly" diff --git a/example/example.csproj b/example/example.csproj index fd6d566..ed76d15 100644 --- a/example/example.csproj +++ b/example/example.csproj @@ -1,6 +1,6 @@  - net60;netstandard20 + net8.0;netstandard2.0 true diff --git a/netfx_loader/ClrLoader.csproj b/netfx_loader/ClrLoader.csproj index f656e1e..28524c8 100644 --- a/netfx_loader/ClrLoader.csproj +++ b/netfx_loader/ClrLoader.csproj @@ -1,6 +1,6 @@  - net47 + net472 win-x86;win-x64 diff --git a/pyproject.toml b/pyproject.toml index 2c643e2..1427a77 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,7 +37,7 @@ Documentation = "https://pythonnet.github.io/clr-loader/" [dependency-groups] dev = [ - "pytest" + "pytest>=7.0" ] [tool.setuptools] diff --git a/tests/test_common.py b/tests/test_common.py index b9b0597..cf8f400 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -6,17 +6,17 @@ @pytest.fixture(scope="session") -def example_netstandard(tmpdir_factory): - return build_example(tmpdir_factory, "netstandard20") +def example_netstandard(tmp_path_factory: pytest.TempPathFactory) -> Path: + return build_example(tmp_path_factory, "netstandard2.0") @pytest.fixture(scope="session") -def example_netcore(tmpdir_factory): - return build_example(tmpdir_factory, "net60") +def example_netcore(tmp_path_factory: pytest.TempPathFactory) -> Path: + return build_example(tmp_path_factory, "net8.0") -def build_example(tmpdir_factory, framework): - out = Path(tmpdir_factory.mktemp(f"example-{framework}")) +def build_example(tmp_path_factory: pytest.TempPathFactory, framework: str) -> Path: + out = tmp_path_factory.mktemp(f"example-{framework}") proj_path = Path(__file__).parent.parent / "example" / "example.csproj" check_call(["dotnet", "build", str(proj_path), "-o", str(out), "-f", framework]) @@ -77,7 +77,7 @@ def test_mono_trace_level(example_netstandard: Path): def test_mono_set_dir(example_netstandard: Path): from clr_loader import get_mono - mono = get_mono(assembly_dir="/usr/lib", config_dir="/etc") + mono = get_mono(assembly_dir="/usr", config_dir="/etc") asm = mono.get_assembly(example_netstandard / "example.dll") run_tests(asm) @@ -96,7 +96,7 @@ def test_coreclr_command_line(example_netcore: Path): run_in_subprocess(_do_test_coreclr_command_line, example_netcore) -def _do_test_coreclr_command_line(example_netcore): +def _do_test_coreclr_command_line(example_netcore: Path): from clr_loader import get_coreclr_command_line coreclr = get_coreclr_command_line(entry_dll=example_netcore / "example.dll") @@ -118,7 +118,7 @@ def test_coreclr_autogenerated_runtimeconfig(example_netstandard: Path): def _do_test_coreclr_autogenerated_runtimeconfig( - example_netstandard: Path, **properties + example_netstandard: Path, **properties: str ): from clr_loader import get_coreclr diff --git a/uv.lock b/uv.lock index 60809e6..2f7d19a 100644 --- a/uv.lock +++ b/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 3 requires-python = ">=3.7" resolution-markers = [ "python_full_version < '3.8'", @@ -16,56 +17,56 @@ resolution-markers = [ dependencies = [ { name = "pycparser", marker = "python_full_version < '3.8'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2b/a8/050ab4f0c3d4c1b8aaa805f70e26e84d0e27004907c5b8ecc1d31815f92a/cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", size = 508501 } +sdist = { url = "https://files.pythonhosted.org/packages/2b/a8/050ab4f0c3d4c1b8aaa805f70e26e84d0e27004907c5b8ecc1d31815f92a/cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", size = 508501, upload-time = "2022-06-30T18:18:32.799Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/ff/c4b7a358526f231efa46a375c959506c87622fb4a2c5726e827c55e6adf2/cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", size = 179233 }, - { url = "https://files.pythonhosted.org/packages/ea/be/c4ad40ad441ac847b67c7a37284ae3c58f39f3e638c6b0f85fb662233825/cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", size = 174280 }, - { url = "https://files.pythonhosted.org/packages/ed/a3/c5f01988ddb70a187c3e6112152e01696188c9f8a4fa4c68aa330adbb179/cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", size = 421712 }, - { url = "https://files.pythonhosted.org/packages/ef/41/19da352d341963d29a33bdb28433ba94c05672fb16155f794fad3fd907b0/cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", size = 449886 }, - { url = "https://files.pythonhosted.org/packages/af/da/9441d56d7dd19d07dcc40a2a5031a1f51c82a27cee3705edf53dadcac398/cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", size = 450520 }, - { url = "https://files.pythonhosted.org/packages/aa/02/ab15b3aa572759df752491d5fa0f74128cd14e002e8e3257c1ab1587810b/cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", size = 446015 }, - { url = "https://files.pythonhosted.org/packages/88/89/c34caf63029fb7628ec2ebd5c88ae0c9bd17db98c812e4065a4d020ca41f/cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", size = 441830 }, - { url = "https://files.pythonhosted.org/packages/32/bd/d0809593f7976828f06a492716fbcbbfb62798bbf60ea1f65200b8d49901/cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", size = 434743 }, - { url = "https://files.pythonhosted.org/packages/0e/65/0d7b5dad821ced4dcd43f96a362905a68ce71e6b5f5cfd2fada867840582/cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", size = 464113 }, - { url = "https://files.pythonhosted.org/packages/9f/52/1e2b43cfdd7d9a39f48bc89fcaee8d8685b1295e205a4f1044909ac14d89/cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", size = 170412 }, - { url = "https://files.pythonhosted.org/packages/0e/e2/a23af3d81838c577571da4ff01b799b0c2bbde24bd924d97e228febae810/cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", size = 179060 }, - { url = "https://files.pythonhosted.org/packages/23/8b/2e8c2469eaf89f7273ac685164949a7e644cdfe5daf1c036564208c3d26b/cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", size = 179198 }, - { url = "https://files.pythonhosted.org/packages/f9/96/fc9e118c47b7adc45a0676f413b4a47554e5f3b6c99b8607ec9726466ef1/cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", size = 174221 }, - { url = "https://files.pythonhosted.org/packages/10/72/617ee266192223a38b67149c830bd9376b69cf3551e1477abc72ff23ef8e/cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", size = 441694 }, - { url = "https://files.pythonhosted.org/packages/91/bc/b7723c2fe7a22eee71d7edf2102cd43423d5f95ff3932ebaa2f82c7ec8d0/cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", size = 470613 }, - { url = "https://files.pythonhosted.org/packages/5d/4e/4e0bb5579b01fdbfd4388bd1eb9394a989e1336203a4b7f700d887b233c1/cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", size = 472199 }, - { url = "https://files.pythonhosted.org/packages/37/5a/c37631a86be838bdd84cc0259130942bf7e6e32f70f4cab95f479847fb91/cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", size = 462588 }, - { url = "https://files.pythonhosted.org/packages/71/d7/0fe0d91b0bbf610fb7254bb164fa8931596e660d62e90fb6289b7ee27b09/cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", size = 450543 }, - { url = "https://files.pythonhosted.org/packages/d3/56/3e94aa719ae96eeda8b68b3ec6e347e0a23168c6841dc276ccdcdadc9f32/cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", size = 474253 }, - { url = "https://files.pythonhosted.org/packages/87/ee/ddc23981fc0f5e7b5356e98884226bcb899f95ebaefc3e8e8b8742dd7e22/cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", size = 170313 }, - { url = "https://files.pythonhosted.org/packages/43/a0/cc7370ef72b6ee586369bacd3961089ab3d94ae712febf07a244f1448ffd/cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", size = 179001 }, - { url = "https://files.pythonhosted.org/packages/b5/7d/df6c088ef30e78a78b0c9cca6b904d5abb698afb5bc8f5191d529d83d667/cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", size = 178906 }, - { url = "https://files.pythonhosted.org/packages/c2/0b/3b09a755ddb977c167e6d209a7536f6ade43bb0654bad42e08df1406b8e4/cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", size = 405992 }, - { url = "https://files.pythonhosted.org/packages/5b/1a/e1ee5bed11d8b6540c05a8e3c32448832d775364d4461dd6497374533401/cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", size = 435560 }, - { url = "https://files.pythonhosted.org/packages/d3/e1/e55ca2e0dd446caa2cc8f73c2b98879c04a1f4064ac529e1836683ca58b8/cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", size = 435478 }, - { url = "https://files.pythonhosted.org/packages/2e/7a/68c35c151e5b7a12650ecc12fdfb85211aa1da43e9924598451c4a0a3839/cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", size = 430395 }, - { url = "https://files.pythonhosted.org/packages/93/d0/2e2b27ea2f69b0ec9e481647822f8f77f5fc23faca2dd00d1ff009940eb7/cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", size = 427911 }, - { url = "https://files.pythonhosted.org/packages/50/34/4cc590ad600869502c9838b4824982c122179089ed6791a8b1c95f0ff55e/cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", size = 169721 }, - { url = "https://files.pythonhosted.org/packages/32/2a/63cb8c07d151de92ff9d897b2eb27ba6a0e78dda8e4c5f70d7b8c16cd6a2/cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", size = 179301 }, - { url = "https://files.pythonhosted.org/packages/87/4b/64e8bd9d15d6b22b6cb11997094fbe61edf453ea0a97c8675cb7d1c3f06f/cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", size = 178940 }, - { url = "https://files.pythonhosted.org/packages/22/c6/df826563f55f7e9dd9a1d3617866282afa969fe0d57decffa1911f416ed8/cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", size = 421947 }, - { url = "https://files.pythonhosted.org/packages/c1/25/16a082701378170559bb1d0e9ef2d293cece8dc62913d79351beb34c5ddf/cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", size = 449906 }, - { url = "https://files.pythonhosted.org/packages/df/02/aef53d4aa43154b829e9707c8c60bab413cd21819c4a36b0d7aaa83e2a61/cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", size = 451028 }, - { url = "https://files.pythonhosted.org/packages/79/4b/33494eb0adbcd884656c48f6db0c98ad8a5c678fb8fb5ed41ab546b04d8c/cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", size = 446520 }, - { url = "https://files.pythonhosted.org/packages/b7/8b/06f30caa03b5b3ac006de4f93478dbd0239e2a16566d81a106c322dc4f79/cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", size = 442655 }, - { url = "https://files.pythonhosted.org/packages/47/97/137f0e3d2304df2060abb872a5830af809d7559a5a4b6a295afb02728e65/cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", size = 170236 }, - { url = "https://files.pythonhosted.org/packages/c9/e3/0a52838832408cfbbf3a59cb19bcd17e64eb33795c9710ca7d29ae10b5b7/cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", size = 178835 }, - { url = "https://files.pythonhosted.org/packages/18/8f/5ff70c7458d61fa8a9752e5ee9c9984c601b0060aae0c619316a1e1f1ee5/cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", size = 179249 }, - { url = "https://files.pythonhosted.org/packages/3a/75/a162315adeaf47e94a3b7f886a8e31d77b9e525a387eef2d6f0efc96a7c8/cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0", size = 174297 }, - { url = "https://files.pythonhosted.org/packages/85/1f/a3c533f8d377da5ca7edb4f580cc3edc1edbebc45fac8bb3ae60f1176629/cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", size = 420641 }, - { url = "https://files.pythonhosted.org/packages/77/b7/d3618d612be01e184033eab90006f8ca5b5edafd17bf247439ea4e167d8a/cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", size = 448814 }, - { url = "https://files.pythonhosted.org/packages/a9/ba/e082df21ebaa9cb29f2c4e1d7e49a29b90fcd667d43632c6674a16d65382/cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", size = 449647 }, - { url = "https://files.pythonhosted.org/packages/af/cb/53b7bba75a18372d57113ba934b27d0734206c283c1dfcc172347fbd9f76/cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", size = 445191 }, - { url = "https://files.pythonhosted.org/packages/2d/86/3ca57cddfa0419f6a95d1c8478f8f622ba597e3581fd501bbb915b20eb75/cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", size = 441236 }, - { url = "https://files.pythonhosted.org/packages/ad/26/7b3a73ab7d82a64664c7c4ea470e4ec4a3c73bb4f02575c543a41e272de5/cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", size = 433865 }, - { url = "https://files.pythonhosted.org/packages/da/ff/ab939e2c7b3f40d851c0f7192c876f1910f3442080c9c846532993ec3cef/cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", size = 463090 }, - { url = "https://files.pythonhosted.org/packages/c6/3d/dd085bb831b22ce4d0b7ba8550e6d78960f02f770bbd1314fea3580727f8/cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", size = 170382 }, - { url = "https://files.pythonhosted.org/packages/a8/16/06b84a7063a4c0a2b081030fdd976022086da9c14e80a9ed4ba0183a98a9/cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", size = 179079 }, + { url = "https://files.pythonhosted.org/packages/e8/ff/c4b7a358526f231efa46a375c959506c87622fb4a2c5726e827c55e6adf2/cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", size = 179233, upload-time = "2022-06-30T18:15:31.105Z" }, + { url = "https://files.pythonhosted.org/packages/ea/be/c4ad40ad441ac847b67c7a37284ae3c58f39f3e638c6b0f85fb662233825/cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", size = 174280, upload-time = "2022-06-30T18:15:34.397Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a3/c5f01988ddb70a187c3e6112152e01696188c9f8a4fa4c68aa330adbb179/cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", size = 421712, upload-time = "2022-06-30T18:15:37.367Z" }, + { url = "https://files.pythonhosted.org/packages/ef/41/19da352d341963d29a33bdb28433ba94c05672fb16155f794fad3fd907b0/cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", size = 449886, upload-time = "2022-06-30T18:15:40.823Z" }, + { url = "https://files.pythonhosted.org/packages/af/da/9441d56d7dd19d07dcc40a2a5031a1f51c82a27cee3705edf53dadcac398/cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", size = 450520, upload-time = "2022-06-30T18:15:43.967Z" }, + { url = "https://files.pythonhosted.org/packages/aa/02/ab15b3aa572759df752491d5fa0f74128cd14e002e8e3257c1ab1587810b/cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", size = 446015, upload-time = "2022-06-30T18:15:46.905Z" }, + { url = "https://files.pythonhosted.org/packages/88/89/c34caf63029fb7628ec2ebd5c88ae0c9bd17db98c812e4065a4d020ca41f/cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", size = 441830, upload-time = "2022-06-30T18:15:50.622Z" }, + { url = "https://files.pythonhosted.org/packages/32/bd/d0809593f7976828f06a492716fbcbbfb62798bbf60ea1f65200b8d49901/cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", size = 434743, upload-time = "2022-06-30T18:15:53.952Z" }, + { url = "https://files.pythonhosted.org/packages/0e/65/0d7b5dad821ced4dcd43f96a362905a68ce71e6b5f5cfd2fada867840582/cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", size = 464113, upload-time = "2022-06-30T18:15:57.459Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/1e2b43cfdd7d9a39f48bc89fcaee8d8685b1295e205a4f1044909ac14d89/cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", size = 170412, upload-time = "2022-06-30T18:16:00.728Z" }, + { url = "https://files.pythonhosted.org/packages/0e/e2/a23af3d81838c577571da4ff01b799b0c2bbde24bd924d97e228febae810/cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", size = 179060, upload-time = "2022-06-30T18:16:03.511Z" }, + { url = "https://files.pythonhosted.org/packages/23/8b/2e8c2469eaf89f7273ac685164949a7e644cdfe5daf1c036564208c3d26b/cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", size = 179198, upload-time = "2022-06-30T18:16:06.056Z" }, + { url = "https://files.pythonhosted.org/packages/f9/96/fc9e118c47b7adc45a0676f413b4a47554e5f3b6c99b8607ec9726466ef1/cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", size = 174221, upload-time = "2022-06-30T18:16:09.137Z" }, + { url = "https://files.pythonhosted.org/packages/10/72/617ee266192223a38b67149c830bd9376b69cf3551e1477abc72ff23ef8e/cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", size = 441694, upload-time = "2022-06-30T18:16:12.057Z" }, + { url = "https://files.pythonhosted.org/packages/91/bc/b7723c2fe7a22eee71d7edf2102cd43423d5f95ff3932ebaa2f82c7ec8d0/cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", size = 470613, upload-time = "2022-06-30T18:16:15.3Z" }, + { url = "https://files.pythonhosted.org/packages/5d/4e/4e0bb5579b01fdbfd4388bd1eb9394a989e1336203a4b7f700d887b233c1/cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", size = 472199, upload-time = "2022-06-30T18:16:18.027Z" }, + { url = "https://files.pythonhosted.org/packages/37/5a/c37631a86be838bdd84cc0259130942bf7e6e32f70f4cab95f479847fb91/cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", size = 462588, upload-time = "2022-06-30T18:16:21.148Z" }, + { url = "https://files.pythonhosted.org/packages/71/d7/0fe0d91b0bbf610fb7254bb164fa8931596e660d62e90fb6289b7ee27b09/cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", size = 450543, upload-time = "2022-06-30T18:16:24.497Z" }, + { url = "https://files.pythonhosted.org/packages/d3/56/3e94aa719ae96eeda8b68b3ec6e347e0a23168c6841dc276ccdcdadc9f32/cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", size = 474253, upload-time = "2022-06-30T18:16:27.156Z" }, + { url = "https://files.pythonhosted.org/packages/87/ee/ddc23981fc0f5e7b5356e98884226bcb899f95ebaefc3e8e8b8742dd7e22/cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", size = 170313, upload-time = "2022-06-30T18:16:29.939Z" }, + { url = "https://files.pythonhosted.org/packages/43/a0/cc7370ef72b6ee586369bacd3961089ab3d94ae712febf07a244f1448ffd/cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", size = 179001, upload-time = "2022-06-30T18:16:34.521Z" }, + { url = "https://files.pythonhosted.org/packages/b5/7d/df6c088ef30e78a78b0c9cca6b904d5abb698afb5bc8f5191d529d83d667/cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", size = 178906, upload-time = "2022-06-30T18:17:02.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/0b/3b09a755ddb977c167e6d209a7536f6ade43bb0654bad42e08df1406b8e4/cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", size = 405992, upload-time = "2022-06-30T18:17:05.658Z" }, + { url = "https://files.pythonhosted.org/packages/5b/1a/e1ee5bed11d8b6540c05a8e3c32448832d775364d4461dd6497374533401/cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", size = 435560, upload-time = "2022-06-30T18:17:08.894Z" }, + { url = "https://files.pythonhosted.org/packages/d3/e1/e55ca2e0dd446caa2cc8f73c2b98879c04a1f4064ac529e1836683ca58b8/cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", size = 435478, upload-time = "2022-06-30T18:17:11.637Z" }, + { url = "https://files.pythonhosted.org/packages/2e/7a/68c35c151e5b7a12650ecc12fdfb85211aa1da43e9924598451c4a0a3839/cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", size = 430395, upload-time = "2022-06-30T18:17:14.378Z" }, + { url = "https://files.pythonhosted.org/packages/93/d0/2e2b27ea2f69b0ec9e481647822f8f77f5fc23faca2dd00d1ff009940eb7/cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", size = 427911, upload-time = "2022-06-30T18:17:17.178Z" }, + { url = "https://files.pythonhosted.org/packages/50/34/4cc590ad600869502c9838b4824982c122179089ed6791a8b1c95f0ff55e/cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", size = 169721, upload-time = "2022-06-30T18:17:20.322Z" }, + { url = "https://files.pythonhosted.org/packages/32/2a/63cb8c07d151de92ff9d897b2eb27ba6a0e78dda8e4c5f70d7b8c16cd6a2/cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", size = 179301, upload-time = "2022-06-30T18:17:25.797Z" }, + { url = "https://files.pythonhosted.org/packages/87/4b/64e8bd9d15d6b22b6cb11997094fbe61edf453ea0a97c8675cb7d1c3f06f/cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", size = 178940, upload-time = "2022-06-30T18:17:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/22/c6/df826563f55f7e9dd9a1d3617866282afa969fe0d57decffa1911f416ed8/cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", size = 421947, upload-time = "2022-06-30T18:17:33.099Z" }, + { url = "https://files.pythonhosted.org/packages/c1/25/16a082701378170559bb1d0e9ef2d293cece8dc62913d79351beb34c5ddf/cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", size = 449906, upload-time = "2022-06-30T18:17:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/df/02/aef53d4aa43154b829e9707c8c60bab413cd21819c4a36b0d7aaa83e2a61/cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", size = 451028, upload-time = "2022-06-30T18:17:39.675Z" }, + { url = "https://files.pythonhosted.org/packages/79/4b/33494eb0adbcd884656c48f6db0c98ad8a5c678fb8fb5ed41ab546b04d8c/cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", size = 446520, upload-time = "2022-06-30T18:17:44.577Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8b/06f30caa03b5b3ac006de4f93478dbd0239e2a16566d81a106c322dc4f79/cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", size = 442655, upload-time = "2022-06-30T18:17:48.199Z" }, + { url = "https://files.pythonhosted.org/packages/47/97/137f0e3d2304df2060abb872a5830af809d7559a5a4b6a295afb02728e65/cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", size = 170236, upload-time = "2022-06-30T18:17:51.708Z" }, + { url = "https://files.pythonhosted.org/packages/c9/e3/0a52838832408cfbbf3a59cb19bcd17e64eb33795c9710ca7d29ae10b5b7/cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", size = 178835, upload-time = "2022-06-30T18:17:54.561Z" }, + { url = "https://files.pythonhosted.org/packages/18/8f/5ff70c7458d61fa8a9752e5ee9c9984c601b0060aae0c619316a1e1f1ee5/cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", size = 179249, upload-time = "2022-06-30T18:17:57.374Z" }, + { url = "https://files.pythonhosted.org/packages/3a/75/a162315adeaf47e94a3b7f886a8e31d77b9e525a387eef2d6f0efc96a7c8/cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0", size = 174297, upload-time = "2022-06-30T18:18:00.012Z" }, + { url = "https://files.pythonhosted.org/packages/85/1f/a3c533f8d377da5ca7edb4f580cc3edc1edbebc45fac8bb3ae60f1176629/cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", size = 420641, upload-time = "2022-06-30T18:18:03.635Z" }, + { url = "https://files.pythonhosted.org/packages/77/b7/d3618d612be01e184033eab90006f8ca5b5edafd17bf247439ea4e167d8a/cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", size = 448814, upload-time = "2022-06-30T18:18:07.53Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ba/e082df21ebaa9cb29f2c4e1d7e49a29b90fcd667d43632c6674a16d65382/cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", size = 449647, upload-time = "2022-06-30T18:18:11.38Z" }, + { url = "https://files.pythonhosted.org/packages/af/cb/53b7bba75a18372d57113ba934b27d0734206c283c1dfcc172347fbd9f76/cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", size = 445191, upload-time = "2022-06-30T18:18:14.46Z" }, + { url = "https://files.pythonhosted.org/packages/2d/86/3ca57cddfa0419f6a95d1c8478f8f622ba597e3581fd501bbb915b20eb75/cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", size = 441236, upload-time = "2022-06-30T18:18:17.433Z" }, + { url = "https://files.pythonhosted.org/packages/ad/26/7b3a73ab7d82a64664c7c4ea470e4ec4a3c73bb4f02575c543a41e272de5/cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", size = 433865, upload-time = "2022-06-30T18:18:20.607Z" }, + { url = "https://files.pythonhosted.org/packages/da/ff/ab939e2c7b3f40d851c0f7192c876f1910f3442080c9c846532993ec3cef/cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", size = 463090, upload-time = "2022-06-30T18:18:23.592Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3d/dd085bb831b22ce4d0b7ba8550e6d78960f02f770bbd1314fea3580727f8/cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", size = 170382, upload-time = "2022-06-30T18:18:26.229Z" }, + { url = "https://files.pythonhosted.org/packages/a8/16/06b84a7063a4c0a2b081030fdd976022086da9c14e80a9ed4ba0183a98a9/cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", size = 179079, upload-time = "2022-06-30T18:18:29.006Z" }, ] [[package]] @@ -79,96 +80,212 @@ resolution-markers = [ dependencies = [ { name = "pycparser", marker = "python_full_version >= '3.8'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, - { url = "https://files.pythonhosted.org/packages/48/08/15bf6b43ae9bd06f6b00ad8a91f5a8fe1069d4c9fab550a866755402724e/cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", size = 182457 }, - { url = "https://files.pythonhosted.org/packages/c2/5b/f1523dd545f92f7df468e5f653ffa4df30ac222f3c884e51e139878f1cb5/cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", size = 425932 }, - { url = "https://files.pythonhosted.org/packages/53/93/7e547ab4105969cc8c93b38a667b82a835dd2cc78f3a7dad6130cfd41e1d/cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", size = 448585 }, - { url = "https://files.pythonhosted.org/packages/56/c4/a308f2c332006206bb511de219efeff090e9d63529ba0a77aae72e82248b/cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", size = 456268 }, - { url = "https://files.pythonhosted.org/packages/ca/5b/b63681518265f2f4060d2b60755c1c77ec89e5e045fc3773b72735ddaad5/cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", size = 436592 }, - { url = "https://files.pythonhosted.org/packages/bb/19/b51af9f4a4faa4a8ac5a0e5d5c2522dcd9703d07fac69da34a36c4d960d3/cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", size = 446512 }, - { url = "https://files.pythonhosted.org/packages/e2/63/2bed8323890cb613bbecda807688a31ed11a7fe7afe31f8faaae0206a9a3/cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", size = 171576 }, - { url = "https://files.pythonhosted.org/packages/2f/70/80c33b044ebc79527447fd4fbc5455d514c3bb840dede4455de97da39b4d/cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", size = 181229 }, - { url = "https://files.pythonhosted.org/packages/b9/ea/8bb50596b8ffbc49ddd7a1ad305035daa770202a6b782fc164647c2673ad/cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", size = 182220 }, - { url = "https://files.pythonhosted.org/packages/ae/11/e77c8cd24f58285a82c23af484cf5b124a376b32644e445960d1a4654c3a/cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", size = 178605 }, - { url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910 }, - { url = "https://files.pythonhosted.org/packages/42/7a/9d086fab7c66bd7c4d0f27c57a1b6b068ced810afc498cc8c49e0088661c/cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", size = 447200 }, - { url = "https://files.pythonhosted.org/packages/da/63/1785ced118ce92a993b0ec9e0d0ac8dc3e5dbfbcaa81135be56c69cabbb6/cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", size = 454565 }, - { url = "https://files.pythonhosted.org/packages/74/06/90b8a44abf3556599cdec107f7290277ae8901a58f75e6fe8f970cd72418/cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", size = 435635 }, - { url = "https://files.pythonhosted.org/packages/bd/62/a1f468e5708a70b1d86ead5bab5520861d9c7eacce4a885ded9faa7729c3/cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", size = 445218 }, - { url = "https://files.pythonhosted.org/packages/5b/95/b34462f3ccb09c2594aa782d90a90b045de4ff1f70148ee79c69d37a0a5a/cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", size = 460486 }, - { url = "https://files.pythonhosted.org/packages/fc/fc/a1e4bebd8d680febd29cf6c8a40067182b64f00c7d105f8f26b5bc54317b/cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", size = 437911 }, - { url = "https://files.pythonhosted.org/packages/e6/c3/21cab7a6154b6a5ea330ae80de386e7665254835b9e98ecc1340b3a7de9a/cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", size = 460632 }, - { url = "https://files.pythonhosted.org/packages/cb/b5/fd9f8b5a84010ca169ee49f4e4ad6f8c05f4e3545b72ee041dbbcb159882/cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", size = 171820 }, - { url = "https://files.pythonhosted.org/packages/8c/52/b08750ce0bce45c143e1b5d7357ee8c55341b52bdef4b0f081af1eb248c2/cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", size = 181290 }, + { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191, upload-time = "2024-09-04T20:43:30.027Z" }, + { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592, upload-time = "2024-09-04T20:43:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024, upload-time = "2024-09-04T20:43:34.186Z" }, + { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188, upload-time = "2024-09-04T20:43:36.286Z" }, + { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571, upload-time = "2024-09-04T20:43:38.586Z" }, + { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687, upload-time = "2024-09-04T20:43:40.084Z" }, + { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211, upload-time = "2024-09-04T20:43:41.526Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325, upload-time = "2024-09-04T20:43:43.117Z" }, + { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784, upload-time = "2024-09-04T20:43:45.256Z" }, + { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564, upload-time = "2024-09-04T20:43:46.779Z" }, + { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804, upload-time = "2024-09-04T20:43:48.186Z" }, + { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299, upload-time = "2024-09-04T20:43:49.812Z" }, + { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, + { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, + { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, + { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, + { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, + { url = "https://files.pythonhosted.org/packages/48/08/15bf6b43ae9bd06f6b00ad8a91f5a8fe1069d4c9fab550a866755402724e/cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", size = 182457, upload-time = "2024-09-04T20:44:47.892Z" }, + { url = "https://files.pythonhosted.org/packages/c2/5b/f1523dd545f92f7df468e5f653ffa4df30ac222f3c884e51e139878f1cb5/cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", size = 425932, upload-time = "2024-09-04T20:44:49.491Z" }, + { url = "https://files.pythonhosted.org/packages/53/93/7e547ab4105969cc8c93b38a667b82a835dd2cc78f3a7dad6130cfd41e1d/cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", size = 448585, upload-time = "2024-09-04T20:44:51.671Z" }, + { url = "https://files.pythonhosted.org/packages/56/c4/a308f2c332006206bb511de219efeff090e9d63529ba0a77aae72e82248b/cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", size = 456268, upload-time = "2024-09-04T20:44:53.51Z" }, + { url = "https://files.pythonhosted.org/packages/ca/5b/b63681518265f2f4060d2b60755c1c77ec89e5e045fc3773b72735ddaad5/cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", size = 436592, upload-time = "2024-09-04T20:44:55.085Z" }, + { url = "https://files.pythonhosted.org/packages/bb/19/b51af9f4a4faa4a8ac5a0e5d5c2522dcd9703d07fac69da34a36c4d960d3/cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", size = 446512, upload-time = "2024-09-04T20:44:57.135Z" }, + { url = "https://files.pythonhosted.org/packages/e2/63/2bed8323890cb613bbecda807688a31ed11a7fe7afe31f8faaae0206a9a3/cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", size = 171576, upload-time = "2024-09-04T20:44:58.535Z" }, + { url = "https://files.pythonhosted.org/packages/2f/70/80c33b044ebc79527447fd4fbc5455d514c3bb840dede4455de97da39b4d/cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", size = 181229, upload-time = "2024-09-04T20:44:59.963Z" }, + { url = "https://files.pythonhosted.org/packages/b9/ea/8bb50596b8ffbc49ddd7a1ad305035daa770202a6b782fc164647c2673ad/cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", size = 182220, upload-time = "2024-09-04T20:45:01.577Z" }, + { url = "https://files.pythonhosted.org/packages/ae/11/e77c8cd24f58285a82c23af484cf5b124a376b32644e445960d1a4654c3a/cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", size = 178605, upload-time = "2024-09-04T20:45:03.837Z" }, + { url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910, upload-time = "2024-09-04T20:45:05.315Z" }, + { url = "https://files.pythonhosted.org/packages/42/7a/9d086fab7c66bd7c4d0f27c57a1b6b068ced810afc498cc8c49e0088661c/cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", size = 447200, upload-time = "2024-09-04T20:45:06.903Z" }, + { url = "https://files.pythonhosted.org/packages/da/63/1785ced118ce92a993b0ec9e0d0ac8dc3e5dbfbcaa81135be56c69cabbb6/cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", size = 454565, upload-time = "2024-09-04T20:45:08.975Z" }, + { url = "https://files.pythonhosted.org/packages/74/06/90b8a44abf3556599cdec107f7290277ae8901a58f75e6fe8f970cd72418/cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", size = 435635, upload-time = "2024-09-04T20:45:10.64Z" }, + { url = "https://files.pythonhosted.org/packages/bd/62/a1f468e5708a70b1d86ead5bab5520861d9c7eacce4a885ded9faa7729c3/cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", size = 445218, upload-time = "2024-09-04T20:45:12.366Z" }, + { url = "https://files.pythonhosted.org/packages/5b/95/b34462f3ccb09c2594aa782d90a90b045de4ff1f70148ee79c69d37a0a5a/cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", size = 460486, upload-time = "2024-09-04T20:45:13.935Z" }, + { url = "https://files.pythonhosted.org/packages/fc/fc/a1e4bebd8d680febd29cf6c8a40067182b64f00c7d105f8f26b5bc54317b/cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", size = 437911, upload-time = "2024-09-04T20:45:15.696Z" }, + { url = "https://files.pythonhosted.org/packages/e6/c3/21cab7a6154b6a5ea330ae80de386e7665254835b9e98ecc1340b3a7de9a/cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", size = 460632, upload-time = "2024-09-04T20:45:17.284Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b5/fd9f8b5a84010ca169ee49f4e4ad6f8c05f4e3545b72ee041dbbcb159882/cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", size = 171820, upload-time = "2024-09-04T20:45:18.762Z" }, + { url = "https://files.pythonhosted.org/packages/8c/52/b08750ce0bce45c143e1b5d7357ee8c55341b52bdef4b0f081af1eb248c2/cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", size = 181290, upload-time = "2024-09-04T20:45:20.226Z" }, ] [[package]] name = "clr-loader" -version = "0.2.7.dev2+g3e2dff0.d20241212" source = { editable = "." } dependencies = [ { name = "cffi", version = "1.15.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.8'" }, { name = "cffi", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8'" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + [package.metadata] requires-dist = [ { name = "cffi", marker = "python_full_version >= '3.8'", specifier = ">=1.17" }, { name = "cffi", marker = "python_full_version < '3.9'", specifier = ">=1.13" }, ] +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=7.0" }] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "6.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.8'" }, + { name = "zipp", marker = "python_full_version < '3.8'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/82/f6e29c8d5c098b6be61460371c2c5591f4a335923639edec43b3830650a4/importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4", size = 53569, upload-time = "2023-06-18T21:44:35.024Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/94/64287b38c7de4c90683630338cf28f129decbba0a44f0c6db35a873c73c4/importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5", size = 22934, upload-time = "2023-06-18T21:44:33.441Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646, upload-time = "2023-01-07T11:08:11.254Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892, upload-time = "2023-01-07T11:08:09.864Z" }, +] + +[[package]] +name = "packaging" +version = "24.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/b5/b43a27ac7472e1818c4bafd44430e69605baefe1f34440593e0332ec8b4d/packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9", size = 147882, upload-time = "2024-03-10T09:39:28.33Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", size = 53488, upload-time = "2024-03-10T09:39:25.947Z" }, +] + +[[package]] +name = "pluggy" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata", marker = "python_full_version < '3.8'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/42/8f2833655a29c4e9cb52ee8a2be04ceac61bcff4a680fb338cbd3d1e322d/pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3", size = 61613, upload-time = "2023-06-21T09:12:28.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/32/4a79112b8b87b21450b066e102d6608907f4c885ed7b04c3fdb085d4d6ae/pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849", size = 17695, upload-time = "2023-06-21T09:12:27.397Z" }, +] + [[package]] name = "pycparser" version = "2.21" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/0b/95d387f5f4433cb0f53ff7ad859bd2c6051051cebbb564f139a999ab46de/pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206", size = 170877 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/0b/95d387f5f4433cb0f53ff7ad859bd2c6051051cebbb564f139a999ab46de/pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206", size = 170877, upload-time = "2021-11-06T12:48:46.095Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/d5/5f610ebe421e85889f2e55e33b7f9a6795bd982198517d912eb1c76e1a53/pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", size = 118697, upload-time = "2021-11-06T12:50:13.61Z" }, +] + +[[package]] +name = "pytest" +version = "7.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "importlib-metadata", marker = "python_full_version < '3.8'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/1f/9d8e98e4133ffb16c90f3b405c43e38d3abb715bb5d7a63a5a684f7e46a3/pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280", size = 1357116, upload-time = "2023-12-31T12:00:18.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/ff/f6e8b8f39e08547faece4bd80f89d5a8de68a38b2d179cc1c4490ffa3286/pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8", size = 325287, upload-time = "2023-12-31T12:00:13.963Z" }, +] + +[[package]] +name = "tomli" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/3f/d7af728f075fb08564c5949a9c95e44352e23dee646869fa104a3b2060a3/tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f", size = 15164, upload-time = "2022-02-08T10:54:04.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", size = 12757, upload-time = "2022-02-08T10:54:02.017Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3c/8b/0111dd7d6c1478bf83baa1cab85c686426c7a6274119aceb2bd9d35395ad/typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2", size = 72876, upload-time = "2023-07-02T14:20:55.045Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/6b/63cc3df74987c36fe26157ee12e09e8f9db4de771e0f3404263117e75b95/typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36", size = 33232, upload-time = "2023-07-02T14:20:53.275Z" }, +] + +[[package]] +name = "zipp" +version = "3.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/27/f0ac6b846684cecce1ee93d32450c45ab607f65c2e0255f0092032d91f07/zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b", size = 18454, upload-time = "2023-02-25T02:17:22.503Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/d5/5f610ebe421e85889f2e55e33b7f9a6795bd982198517d912eb1c76e1a53/pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", size = 118697 }, + { url = "https://files.pythonhosted.org/packages/5b/fa/c9e82bbe1af6266adf08afb563905eb87cab83fde00a0a08963510621047/zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556", size = 6758, upload-time = "2023-02-25T02:17:20.807Z" }, ] From 8bcb1a306ed3dc15391ef55472fd16301a9a156d Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 20 Oct 2025 22:01:51 +0200 Subject: [PATCH 12/22] Move dependabot file to the right location --- dependabot.yml => .github/dependabot.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename dependabot.yml => .github/dependabot.yml (100%) diff --git a/dependabot.yml b/.github/dependabot.yml similarity index 100% rename from dependabot.yml rename to .github/dependabot.yml From c313494e93667f54a170da69e452713aaaeb199f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:03:16 +0200 Subject: [PATCH 13/22] Bump actions/deploy-pages from 1 to 4 (#88) Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 1 to 4. - [Release notes](https://github.com/actions/deploy-pages/releases) - [Commits](https://github.com/actions/deploy-pages/compare/v1...v4) --- updated-dependencies: - dependency-name: actions/deploy-pages dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 1fe8fee..67bd95a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -32,4 +32,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v1 + uses: actions/deploy-pages@v4 From 3bc1d82b59a81bac4c3217036f4f1ad9e522030f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:03:39 +0200 Subject: [PATCH 14/22] Bump actions/download-artifact from 4 to 5 (#87) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9a1b5b1..9846d2b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,7 +88,7 @@ jobs: uv pip install pytest - name: Download wheel - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: build-output path: dist/ @@ -108,7 +108,7 @@ jobs: steps: - name: Download artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: build-output path: dist/ From 18cb1192947891de29ba658f0529537568ef7e8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:03:47 +0200 Subject: [PATCH 15/22] Bump astral-sh/setup-uv from 6 to 7 (#86) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6 to 7. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/v6...v7) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9846d2b..7343d1c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: with: fetch-depth: 0 - uses: actions/setup-dotnet@v5 - - uses: astral-sh/setup-uv@v6 + - uses: astral-sh/setup-uv@v7 - name: Build run: uv build - name: Upload source distribution @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v4 with: fetch-depths: 0 - - uses: astral-sh/setup-uv@v6 + - uses: astral-sh/setup-uv@v7 - name: Install Ruff run: uv tool install ruff - name: Check format @@ -64,7 +64,7 @@ jobs: dotnet-version: '8.0.x' - name: Set up Python ${{ matrix.python }} - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v7 with: python-version: ${{ matrix.python }} From 11b59c53c43579097c936db602ffb660ae6efe4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:03:55 +0200 Subject: [PATCH 16/22] Bump actions/checkout from 1 to 5 (#85) Bumps [actions/checkout](https://github.com/actions/checkout) from 1 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v1...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 6 +++--- .github/workflows/docs.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7343d1c..86582a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 - uses: actions/setup-dotnet@v5 @@ -26,7 +26,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depths: 0 - uses: astral-sh/setup-uv@v7 @@ -80,7 +80,7 @@ jobs: run: | choco install -y mono ${{ matrix.python == 'pypy3' && '--x86' || '' }} - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install dependencies run: | diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 67bd95a..d22fa17 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,7 +6,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v5 - name: Build Sphinx documentation run: | pip install -r doc/requirements.txt From 94d2583559198c6602c717901c1e28f7029b3322 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:04:03 +0200 Subject: [PATCH 17/22] Bump softprops/action-gh-release from 1 to 2 (#84) Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2. - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: '2' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86582a3..2d5e995 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,7 +121,7 @@ jobs: repository_url: https://test.pypi.org/legacy/ - name: Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 if: startsWith(github.ref, 'refs/tags/v') with: files: dist/* From f0cf11dc1165e90069578dd60ecebe2f80c5abff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:04:25 +0200 Subject: [PATCH 18/22] Bump Microsoft.NETFramework.ReferenceAssemblies from 1.0.0 to 1.0.3 (#89) --- updated-dependencies: - dependency-name: Microsoft.NETFramework.ReferenceAssemblies dependency-version: 1.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- netfx_loader/ClrLoader.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netfx_loader/ClrLoader.csproj b/netfx_loader/ClrLoader.csproj index 28524c8..9f0e83a 100644 --- a/netfx_loader/ClrLoader.csproj +++ b/netfx_loader/ClrLoader.csproj @@ -7,7 +7,7 @@ - 1.0.0 + 1.0.3 all runtime; build; native; contentfiles; analyzers From d804f5942b4257ce66fbf00a5973886b3c1d0457 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:08:22 +0200 Subject: [PATCH 19/22] Bump NXPorts from 1.0.0 to 1.1.0 (#90) --- updated-dependencies: - dependency-name: NXPorts dependency-version: 1.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- netfx_loader/ClrLoader.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netfx_loader/ClrLoader.csproj b/netfx_loader/ClrLoader.csproj index 9f0e83a..42f5ef8 100644 --- a/netfx_loader/ClrLoader.csproj +++ b/netfx_loader/ClrLoader.csproj @@ -5,7 +5,7 @@ - + 1.0.3 all From 961d1e10888a1cdcea32822734da9af18de4daa5 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 20 Oct 2025 22:47:08 +0200 Subject: [PATCH 20/22] Fix docstring --- clr_loader/__init__.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/clr_loader/__init__.py b/clr_loader/__init__.py index ce239a1..43bbba3 100644 --- a/clr_loader/__init__.py +++ b/clr_loader/__init__.py @@ -62,11 +62,13 @@ def get_mono( Whether to enable signal chaining, passed to ``mono_set_signal_chaining``. If it is enabled, the runtime saves the original signal handlers before installing its own, and calls the original ones in the following cases: - - SIGSEGV/SIGABRT while executing native code - - SIGPROF - - SIGFPE - - SIGQUIT - - SIGUSR2 + + - SIGSEGV/SIGABRT while executing native code + - SIGPROF + - SIGFPE + - SIGQUIT + - SIGUSR2 + This currently only works on POSIX platforms """ from .mono import Mono From 718fc4893d3ad254f128102e4edcaca516439c8d Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 20 Oct 2025 22:47:42 +0200 Subject: [PATCH 21/22] Add a few more type hints (#91) --- clr_loader/mono.py | 12 +++++++----- clr_loader/netfx.py | 6 +++--- clr_loader/types.py | 17 ++++++++++------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/clr_loader/mono.py b/clr_loader/mono.py index f7f90e5..638c601 100644 --- a/clr_loader/mono.py +++ b/clr_loader/mono.py @@ -4,7 +4,7 @@ from typing import Any, Dict, Optional, Sequence from .ffi import ffi, load_mono -from .types import Runtime, RuntimeInfo +from .types import Runtime, RuntimeInfo, StrOrPath from .util import optional_path_as_string, path_as_string __all__ = ["Mono"] @@ -32,7 +32,7 @@ def __init__( ): self._assemblies: Dict[Path, Any] = {} - self._version = initialize( + self._version: str = initialize( config_file=optional_path_as_string(config_file), debug=debug, jit_options=jit_options, @@ -50,7 +50,9 @@ def __init__( else: raise NotImplementedError - def _get_callable(self, assembly_path, typename, function): + def _get_callable( + self, assembly_path: StrOrPath, typename: str, function: str + ) -> "MonoMethod": assembly_path = Path(assembly_path) assembly = self._assemblies.get(assembly_path) if not assembly: @@ -87,14 +89,14 @@ def shutdown(self) -> None: class MethodDesc: - def __init__(self, typename, function): + def __init__(self, typename: str, function: str): self._desc = f"{typename}:{function}" self._ptr = _MONO.mono_method_desc_new( self._desc.encode("utf8"), 1, # include_namespace ) - def search(self, image): + def search(self, image: str): return _MONO.mono_method_desc_search_in_image(self._ptr, image) def __del__(self): diff --git a/clr_loader/netfx.py b/clr_loader/netfx.py index 4d46b37..ac3fdec 100644 --- a/clr_loader/netfx.py +++ b/clr_loader/netfx.py @@ -12,7 +12,7 @@ class NetFx(Runtime): def __init__( self, domain: Optional[str] = None, config_file: Optional[Path] = None ): - self._domain = None + self._domain: Optional[str] = None initialize() if config_file is not None: @@ -22,8 +22,8 @@ def __init__( domain_s = domain.encode("utf8") if domain else ffi.NULL - self._domain_name = domain - self._config_file = config_file + self._domain_name: Optional[str] = domain + self._config_file: Optional[Path] = config_file self._domain = _FW.pyclr_create_appdomain(domain_s, config_file_s) def info(self) -> RuntimeInfo: diff --git a/clr_loader/types.py b/clr_loader/types.py index 6b54030..f7b47c1 100644 --- a/clr_loader/types.py +++ b/clr_loader/types.py @@ -5,7 +5,10 @@ __all__ = ["StrOrPath"] -StrOrPath = Union[str, PathLike] +try: + StrOrPath = Union[str, PathLike[str]] +except TypeError: + StrOrPath = Union[str, PathLike] @dataclass @@ -34,7 +37,7 @@ class RuntimeInfo: def __str__(self) -> str: return ( - f"Runtime: {self.kind}\n" + f"Runtime: {self.kind}\n" # pyright: ignore[reportImplicitStringConcatenation] "=============\n" f" Version: {self.version}\n" f" Initialized: {self.initialized}\n" @@ -51,9 +54,9 @@ class ClrFunction: def __init__( self, runtime: "Runtime", assembly: StrOrPath, typename: str, func_name: str ): - self._assembly = assembly - self._class = typename - self._name = func_name + self._assembly: StrOrPath = assembly + self._class: str = typename + self._name: str = func_name self._callable = runtime._get_callable(assembly, typename, func_name) @@ -69,8 +72,8 @@ def __repr__(self) -> str: class Assembly: def __init__(self, runtime: "Runtime", path: StrOrPath): - self._runtime = runtime - self._path = path + self._runtime: "Runtime" = runtime + self._path: StrOrPath = path def get_function(self, name: str, func: Optional[str] = None) -> ClrFunction: """Get a wrapped .NET function instance From 604264869e87ae3ff731c22f9c5eaa7de9d92257 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 20 Oct 2025 22:54:40 +0200 Subject: [PATCH 22/22] Use the same API for command line and runtimeconfig hosting (#92) --- clr_loader/__init__.py | 55 +++++++++++--------------------------- clr_loader/hostfxr.py | 60 ++++++++++++++++++++---------------------- tests/test_common.py | 4 +-- 3 files changed, 46 insertions(+), 73 deletions(-) diff --git a/clr_loader/__init__.py b/clr_loader/__init__.py index 43bbba3..e5fca2a 100644 --- a/clr_loader/__init__.py +++ b/clr_loader/__init__.py @@ -11,7 +11,6 @@ "get_mono", "get_netfx", "get_coreclr", - "get_coreclr_command_line", "find_dotnet_root", "find_libmono", "find_runtimes", @@ -94,6 +93,7 @@ def get_mono( def get_coreclr( *, runtime_config: Optional[StrOrPath] = None, + entry_dll: Optional[StrOrPath] = None, dotnet_root: Optional[StrOrPath] = None, properties: Optional[Dict[str, str]] = None, runtime_spec: Optional[DotnetCoreRuntimeSpec] = None, @@ -106,9 +106,13 @@ def get_coreclr( the first function object is retrieved. :param runtime_config: - Pass to a ``runtimeconfig.json`` as generated by + Path to a ``runtimeconfig.json`` as generated by ``dotnet publish``. If this parameter is not given, a temporary runtime config will be generated. + :param entry_dll: + The path to the entry dll. If this parameter is given, the runtime will + be initialized using the command line hosting API instead of using the + runtime config. :param dotnet_root: The root directory of the .NET Core installation. If this is not specified, we try to discover it using :py:func:`find_dotnet_root`. @@ -119,6 +123,7 @@ def get_coreclr( If the ``runtime_config`` is not specified, the concrete runtime to use can be controlled by passing this parameter. Possible values can be retrieved using :py:func:`find_runtimes`.""" + from .hostfxr import DotnetCoreRuntime dotnet_root = _maybe_path(dotnet_root) @@ -127,7 +132,9 @@ def get_coreclr( temp_dir = None runtime_config = _maybe_path(runtime_config) - if runtime_config is None: + entry_dll = _maybe_path(entry_dll) + + if runtime_config is None and entry_dll is None: if runtime_spec is None: candidates = [ rt for rt in find_runtimes() if rt.name == "Microsoft.NETCore.App" @@ -144,7 +151,12 @@ def get_coreclr( with open(runtime_config, "w") as f: runtime_spec.write_config(f) - impl = DotnetCoreRuntime(runtime_config=runtime_config, dotnet_root=dotnet_root) + if entry_dll is not None: + entry_dll = _maybe_path(entry_dll) + impl = DotnetCoreRuntime(entry_dll=entry_dll, dotnet_root=dotnet_root) + else: + impl = DotnetCoreRuntime(runtime_config=runtime_config, dotnet_root=dotnet_root) + if properties: for key, value in properties.items(): impl[key] = value @@ -155,41 +167,6 @@ def get_coreclr( return impl -def get_coreclr_command_line( - *, - entry_dll: StrOrPath, - dotnet_root: Optional[StrOrPath] = None, - properties: Optional[Dict[str, str]] = None, -) -> Runtime: - """Get a CoreCLR (.NET Core) runtime instance - The returned ``DotnetCoreRuntimeCommandLine`` also acts as a mapping of the config - properties. They can be retrieved using the index operator and can be - written until the runtime is initialized. The runtime is initialized when - the first function object is retrieved. - :param entry_dll: - The path to the entry dll. - :param dotnet_root: - The root directory of the .NET Core installation. If this is not - specified, we try to discover it using :py:func:`find_dotnet_root`. - :param properties: - Additional runtime properties. These can also be passed using the - ``configProperties`` section in the runtime config.""" - from .hostfxr import DotnetCoreCommandRuntime - - dotnet_root = _maybe_path(dotnet_root) - if dotnet_root is None: - dotnet_root = find_dotnet_root() - - impl = DotnetCoreCommandRuntime( - entry_dll=_maybe_path(entry_dll), dotnet_root=dotnet_root - ) - if properties: - for key, value in properties.items(): - impl[key] = value - - return impl - - def get_netfx( *, domain: Optional[str] = None, config_file: Optional[StrOrPath] = None ) -> Runtime: diff --git a/clr_loader/hostfxr.py b/clr_loader/hostfxr.py index 60ad6b6..e32423c 100644 --- a/clr_loader/hostfxr.py +++ b/clr_loader/hostfxr.py @@ -1,20 +1,27 @@ import sys from pathlib import Path -from typing import Generator, Tuple +from typing import Generator, Tuple, Optional from .ffi import ffi, load_hostfxr from .types import Runtime, RuntimeInfo, StrOrPath from .util import check_result -__all__ = ["DotnetCoreRuntime", "DotnetCoreCommandRuntime"] +__all__ = ["DotnetCoreRuntime"] _IS_SHUTDOWN = False -class DotnetCoreRuntimeBase(Runtime): +class DotnetCoreRuntime(Runtime): _version: str - def __init__(self, dotnet_root: Path): + def __init__( + self, + *, + dotnet_root: Path, + runtime_config: Optional[Path] = None, + entry_dll: Optional[Path] = None, + **params: str, + ): self._handle = None if _IS_SHUTDOWN: @@ -24,6 +31,23 @@ def __init__(self, dotnet_root: Path): self._dll = load_hostfxr(self._dotnet_root) self._load_func = None + if runtime_config is not None: + self._handle = _get_handle_for_runtime_config( + self._dll, self._dotnet_root, runtime_config + ) + elif entry_dll is not None: + self._handle = _get_handle_for_dotnet_command_line( + self._dll, self._dotnet_root, entry_dll + ) + else: + raise ValueError("Either runtime_config or entry_dll must be provided") + + for key, value in params.items(): + self[key] = value + + # TODO: Get version + self._version: str = "" + @property def dotnet_root(self) -> Path: return self._dotnet_root @@ -117,34 +141,6 @@ def info(self): ) -class DotnetCoreRuntime(DotnetCoreRuntimeBase): - def __init__(self, runtime_config: Path, dotnet_root: Path, **params: str): - super().__init__(dotnet_root) - self._handle = _get_handle_for_runtime_config( - self._dll, self._dotnet_root, runtime_config - ) - - for key, value in params.items(): - self[key] = value - - # TODO: Get version - self._version = "" - - -class DotnetCoreCommandRuntime(DotnetCoreRuntimeBase): - def __init__(self, entry_dll: Path, dotnet_root: Path, **params: str): - super().__init__(dotnet_root) - self._handle = _get_handle_for_dotnet_command_line( - self._dll, self._dotnet_root, entry_dll - ) - - for key, value in params.items(): - self[key] = value - - # TODO: Get version - self._version = "" - - def _get_handle_for_runtime_config( dll, dotnet_root: StrOrPath, runtime_config: StrOrPath ): diff --git a/tests/test_common.py b/tests/test_common.py index cf8f400..6561650 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -97,9 +97,9 @@ def test_coreclr_command_line(example_netcore: Path): def _do_test_coreclr_command_line(example_netcore: Path): - from clr_loader import get_coreclr_command_line + from clr_loader import get_coreclr - coreclr = get_coreclr_command_line(entry_dll=example_netcore / "example.dll") + coreclr = get_coreclr(entry_dll=example_netcore / "example.dll") asm = coreclr.get_assembly(example_netcore / "example.dll") run_tests(asm)