diff --git a/.editorconfig b/.editorconfig index d64f74bc1..2261004d2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -25,10 +25,11 @@ dotnet_sort_system_directives_first = true dotnet_separate_import_directive_groups = true [*.cs] -csharp_new_line_before_open_brace = all -csharp_new_line_before_else = true -csharp_new_line_before_catch = true -csharp_new_line_before_finally = true +csharp_new_line_before_open_brace = all:suggestion +csharp_new_line_before_else = true:suggestion +csharp_new_line_before_catch = true:suggestion +csharp_new_line_before_finally = true:suggesion +csharp_prefer_braces = true:suggestion # Solution [*.sln] diff --git a/.github/workflows/build+test.yml b/.github/workflows/build+test.yml new file mode 100644 index 000000000..c1c5dbef3 --- /dev/null +++ b/.github/workflows/build+test.yml @@ -0,0 +1,32 @@ +name: Build + Test + +on: + push: + branches: + - losttech/master + pull_request: + branches: + - losttech/master + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.5, 3.7] + steps: + - uses: actions/checkout@v2 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: 3.1.101 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v1 + with: + python-version: ${{ matrix.python-version }} + - name: Build + run: dotnet build src/runtime/Python.Runtime.15.csproj --configuration Release + - name: Test + run: dotnet test src/embed_tests/Python.EmbeddingTest.15.csproj --configuration Release + env: + PYTHON_VERSION: ${{ matrix.python-version }} diff --git a/AUTHORS.md b/AUTHORS.md index 5dbf1e1ce..3b9d5534b 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -71,6 +71,8 @@ - ([@OneBlue](https://github.com/OneBlue)) - ([@rico-chet](https://github.com/rico-chet)) - ([@rmadsen-ks](https://github.com/rmadsen-ks)) +- ([@SnGmng](https://github.com/SnGmng)) - ([@stonebig](https://github.com/stonebig)) - ([@testrunner123](https://github.com/testrunner123)) +- ([@DanBarzilian](https://github.com/DanBarzilian)) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad4016450..afb2badbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][]. ### Fixed +- Fix incorrect dereference of wrapper object in tp_repr, which may result in a program crash + ## [2.5.0][] - 2020-06-14 This version improves performance on benchmarks significantly compared to 2.3. diff --git a/LICENSE b/LICENSE index 19c31a12f..788160102 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,9 @@ -MIT License +You must have a license for LostTech.TensorFlow +(see https://losttech.software/gradient.html) to use this software. -Copyright (c) 2006-2020 the contributors of the Python.NET project +If you wish to obtain a version of this sofware with a more liberal +license, refer to https://github.com/pythonnet/pythonnet. -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +This fork contains substantial parts of the original project, which are +distributed under MIT License: +https://github.com/pythonnet/pythonnet/blob/master/LICENSE diff --git a/NuGet.config b/NuGet.config index 5210cd6c9..ed9d41057 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,6 @@ - \ No newline at end of file diff --git a/README.rst b/README.rst index 55f0e50a1..e8a55f95e 100644 --- a/README.rst +++ b/README.rst @@ -3,12 +3,15 @@ pythonnet - Python.NET |Join the chat at https://gitter.im/pythonnet/pythonnet| -|appveyor shield| |travis shield| |codecov shield| +|github test shield| -|license shield| |pypi package version| |conda-forge version| |python supported shield| +|nuget version| |stackexchange shield| -Python.NET is a package that gives Python programmers nearly +This fork is part of `Gradient `_ and has a `different +license `_. + +Python for .NET is a package that gives Python programmers nearly seamless integration with the .NET Common Language Runtime (CLR) and provides a powerful application scripting tool for .NET developers. It allows Python code to interact with the CLR, and may also be used to @@ -126,3 +129,6 @@ This project is supported by the `.NET Foundation :target: http://stackoverflow.com/questions/tagged/python.net .. |conda-forge version| image:: https://img.shields.io/conda/vn/conda-forge/pythonnet.svg :target: https://anaconda.org/conda-forge/pythonnet +.. |github test shield| image:: https://github.com/losttech/pythonnet/workflows/Build%20%2B%20Test/badge.svg +.. |nuget version| image:: https://img.shields.io/nuget/vpre/LostTech.Python.Runtime + :target: https://www.nuget.org/packages/LostTech.Python.Runtime/ diff --git a/global.json b/global.json new file mode 100644 index 000000000..73fa45c8d --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "msbuild-sdks": { + "MSBuild.Sdk.Extras": "1.6.65" + } +} diff --git a/pythonnet.15.sln b/pythonnet.15.sln index ce863817f..82b70fb09 100644 --- a/pythonnet.15.sln +++ b/pythonnet.15.sln @@ -19,7 +19,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Repo", "Repo", "{441A0123-F .editorconfig = .editorconfig .gitignore = .gitignore CHANGELOG.md = CHANGELOG.md + LICENSE = LICENSE README.rst = README.rst + src\SharedAssemblyInfo.cs = src\SharedAssemblyInfo.cs EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI", "CI", "{D301657F-5EAF-4534-B280-B858D651B2E5}" @@ -28,6 +30,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI", "CI", "{D301657F-5EAF- appveyor.yml = appveyor.yml ci\appveyor_build_recipe.ps1 = ci\appveyor_build_recipe.ps1 ci\appveyor_run_tests.ps1 = ci\appveyor_run_tests.ps1 + .github\workflows\build+test.yml = .github\workflows\build+test.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{57F5D701-F265-4736-A5A2-07249E7A4DA3}" @@ -45,349 +48,33 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - DebugMono|Any CPU = DebugMono|Any CPU - DebugMono|x64 = DebugMono|x64 - DebugMono|x86 = DebugMono|x86 - DebugMonoPY3|Any CPU = DebugMonoPY3|Any CPU - DebugMonoPY3|x64 = DebugMonoPY3|x64 - DebugMonoPY3|x86 = DebugMonoPY3|x86 - DebugWin|Any CPU = DebugWin|Any CPU - DebugWin|x64 = DebugWin|x64 - DebugWin|x86 = DebugWin|x86 - DebugWinPY3|Any CPU = DebugWinPY3|Any CPU - DebugWinPY3|x64 = DebugWinPY3|x64 - DebugWinPY3|x86 = DebugWinPY3|x86 Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - ReleaseMono|Any CPU = ReleaseMono|Any CPU - ReleaseMono|x64 = ReleaseMono|x64 - ReleaseMono|x86 = ReleaseMono|x86 - ReleaseMonoPY3|Any CPU = ReleaseMonoPY3|Any CPU - ReleaseMonoPY3|x64 = ReleaseMonoPY3|x64 - ReleaseMonoPY3|x86 = ReleaseMonoPY3|x86 - ReleaseWin|Any CPU = ReleaseWin|Any CPU - ReleaseWin|x64 = ReleaseWin|x64 - ReleaseWin|x86 = ReleaseWin|x86 - ReleaseWinPY3|Any CPU = ReleaseWinPY3|Any CPU - ReleaseWinPY3|x64 = ReleaseWinPY3|x64 - ReleaseWinPY3|x86 = ReleaseWinPY3|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|Any CPU.ActiveCfg = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|Any CPU.Build.0 = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|x64.ActiveCfg = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|x64.Build.0 = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|x86.ActiveCfg = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|x86.Build.0 = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|Any CPU.ActiveCfg = DebugMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|Any CPU.Build.0 = DebugMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x64.ActiveCfg = DebugMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x64.Build.0 = DebugMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x86.ActiveCfg = DebugMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMono|x86.Build.0 = DebugMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|Any CPU.ActiveCfg = DebugMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|Any CPU.Build.0 = DebugMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|Any CPU.ActiveCfg = DebugWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|Any CPU.Build.0 = DebugWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x64.Build.0 = DebugWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWin|x86.Build.0 = DebugWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|Any CPU.ActiveCfg = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|Any CPU.Build.0 = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x64.Build.0 = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.DebugWinPY3|x86.Build.0 = DebugWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|Any CPU.ActiveCfg = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|Any CPU.Build.0 = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|x64.ActiveCfg = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|x64.Build.0 = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|x86.ActiveCfg = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|x86.Build.0 = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|Any CPU.ActiveCfg = ReleaseMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|Any CPU.Build.0 = ReleaseMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x64.ActiveCfg = ReleaseMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x64.Build.0 = ReleaseMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x86.ActiveCfg = ReleaseMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMono|x86.Build.0 = ReleaseMono|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|Any CPU.ActiveCfg = ReleaseMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|Any CPU.Build.0 = ReleaseMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|Any CPU.ActiveCfg = ReleaseWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|Any CPU.Build.0 = ReleaseWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|Any CPU.ActiveCfg = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|Any CPU.Build.0 = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|Any CPU - {2759F4FF-716B-4828-916F-50FA86613DFC}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|Any CPU - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|Any CPU.Build.0 = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|x64.ActiveCfg = DebugWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|x64.Build.0 = DebugWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|x86.ActiveCfg = DebugWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|x86.Build.0 = DebugWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|Any CPU.ActiveCfg = DebugMono|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x64.Build.0 = DebugMono|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMono|x86.Build.0 = DebugMono|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|Any CPU.ActiveCfg = DebugMonoPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|Any CPU.ActiveCfg = DebugWin|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x64.Build.0 = DebugWin|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWin|x86.Build.0 = DebugWin|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|Any CPU.ActiveCfg = DebugWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|Any CPU.Build.0 = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|x64.ActiveCfg = ReleaseWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|x64.Build.0 = ReleaseWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|x86.ActiveCfg = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|x86.Build.0 = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|Any CPU.ActiveCfg = ReleaseMono|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|Any CPU.ActiveCfg = ReleaseMonoPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|Any CPU.ActiveCfg = ReleaseWin|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {66B8D01A-9906-452A-B09E-BF75EA76468F}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|Any CPU.Build.0 = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|x64.ActiveCfg = DebugWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|x64.Build.0 = DebugWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|x86.ActiveCfg = DebugWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|x86.Build.0 = DebugWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMono|Any CPU.ActiveCfg = DebugMono|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMonoPY3|Any CPU.ActiveCfg = DebugMonoPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|Any CPU.ActiveCfg = DebugWin|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x64.Build.0 = DebugWin|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWin|x86.Build.0 = DebugWin|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|Any CPU.ActiveCfg = DebugWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|Any CPU.Build.0 = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|x64.ActiveCfg = ReleaseWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|x64.Build.0 = ReleaseWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|x86.ActiveCfg = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|x86.Build.0 = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMono|Any CPU.ActiveCfg = ReleaseMono|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMonoPY3|Any CPU.ActiveCfg = ReleaseMonoPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|Any CPU.ActiveCfg = ReleaseWin|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|Any CPU.Build.0 = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|x64.ActiveCfg = DebugWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|x64.Build.0 = DebugWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|x86.ActiveCfg = DebugWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|x86.Build.0 = DebugWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|Any CPU.ActiveCfg = DebugMono|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x64.Build.0 = DebugMono|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMono|x86.Build.0 = DebugMono|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|Any CPU.ActiveCfg = DebugMonoPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|Any CPU.ActiveCfg = DebugWin|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x64.Build.0 = DebugWin|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWin|x86.Build.0 = DebugWin|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|Any CPU.ActiveCfg = DebugWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|Any CPU.Build.0 = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|x64.ActiveCfg = ReleaseWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|x64.Build.0 = ReleaseWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|x86.ActiveCfg = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|x86.Build.0 = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|Any CPU.ActiveCfg = ReleaseMono|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|Any CPU.ActiveCfg = ReleaseMonoPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|Any CPU.ActiveCfg = ReleaseWin|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {CDAD305F-8E72-492C-A314-64CF58D472A0}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|Any CPU.Build.0 = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|x64.ActiveCfg = DebugWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|x64.Build.0 = DebugWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|x86.ActiveCfg = DebugWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|x86.Build.0 = DebugWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|Any CPU.ActiveCfg = DebugMono|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x64.Build.0 = DebugMono|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMono|x86.Build.0 = DebugMono|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|Any CPU.ActiveCfg = DebugMonoPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|Any CPU.ActiveCfg = DebugWin|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x64.Build.0 = DebugWin|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWin|x86.Build.0 = DebugWin|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|Any CPU.ActiveCfg = DebugWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|Any CPU.Build.0 = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|x64.ActiveCfg = ReleaseWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|x64.Build.0 = ReleaseWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|x86.ActiveCfg = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|x86.Build.0 = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|Any CPU.ActiveCfg = ReleaseMono|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|Any CPU.ActiveCfg = ReleaseMonoPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|Any CPU.ActiveCfg = ReleaseWin|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {F94B547A-E97E-4500-8D53-B4D64D076E5F}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|Any CPU.ActiveCfg = ReleaseWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|Any CPU.Build.0 = ReleaseWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|x64.ActiveCfg = DebugWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|x64.Build.0 = DebugWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|x86.ActiveCfg = DebugWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|x86.Build.0 = DebugWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMono|Any CPU.ActiveCfg = DebugMono|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMono|x64.Build.0 = DebugMono|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMono|x86.Build.0 = DebugMono|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMonoPY3|Any CPU.ActiveCfg = DebugMonoPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWin|Any CPU.ActiveCfg = DebugWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWin|x64.Build.0 = DebugWin|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWin|x86.Build.0 = DebugWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWinPY3|Any CPU.ActiveCfg = DebugWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|Any CPU.ActiveCfg = ReleaseWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|Any CPU.Build.0 = ReleaseWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|x64.ActiveCfg = ReleaseWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|x64.Build.0 = ReleaseWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|x86.ActiveCfg = ReleaseWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|x86.Build.0 = ReleaseWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMono|Any CPU.ActiveCfg = ReleaseMono|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMonoPY3|Any CPU.ActiveCfg = ReleaseMonoPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWin|Any CPU.ActiveCfg = ReleaseWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWinPY3|Any CPU.ActiveCfg = ReleaseWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 + {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2759F4FF-716B-4828-916F-50FA86613DFC}.Release|Any CPU.Build.0 = Release|Any CPU + {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.Debug|Any CPU.Build.0 = Debug|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|Any CPU.ActiveCfg = Release|x64 + {66B8D01A-9906-452A-B09E-BF75EA76468F}.Release|Any CPU.Build.0 = Release|x64 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|Any CPU.ActiveCfg = Debug|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Debug|Any CPU.Build.0 = Debug|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|Any CPU.ActiveCfg = Release|x86 + {E08678D4-9A52-4AD5-B63D-8EBC7399981B}.Release|Any CPU.Build.0 = Release|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|Any CPU.ActiveCfg = Debug|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.Debug|Any CPU.Build.0 = Debug|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|Any CPU.ActiveCfg = Release|x86 + {CDAD305F-8E72-492C-A314-64CF58D472A0}.Release|Any CPU.Build.0 = Release|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|Any CPU.ActiveCfg = Debug|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Debug|Any CPU.Build.0 = Debug|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|Any CPU.ActiveCfg = Release|x86 + {F94B547A-E97E-4500-8D53-B4D64D076E5F}.Release|Any CPU.Build.0 = Release|x86 + {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|Any CPU.ActiveCfg = DebugWin|x86 + {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Debug|Any CPU.Build.0 = DebugWin|x86 + {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|Any CPU.ActiveCfg = DebugWin|x86 + {6FB0D091-9CEC-4DCC-8701-C40F9BFC9EDE}.Release|Any CPU.Build.0 = DebugWin|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/pythonnet.sln b/pythonnet.sln deleted file mode 100644 index c5afd66c3..000000000 --- a/pythonnet.sln +++ /dev/null @@ -1,202 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Runtime", "src\runtime\Python.Runtime.csproj", "{097B4AC0-74E9-4C58-BCF8-C69746EC8271}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Test", "src\testing\Python.Test.csproj", "{6F401A34-273B-450F-9A4C-13550BE0767B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.EmbeddingTest", "src\embed_tests\Python.EmbeddingTest.csproj", "{4165C59D-2822-499F-A6DB-EACA4C331EB5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "src\console\Console.csproj", "{E29DCF0A-5114-4A98-B1DD-71264B6EA349}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "clrmodule", "src\clrmodule\clrmodule.csproj", "{86E834DE-1139-4511-96CC-69636A56E7AC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - DebugMono|x64 = DebugMono|x64 - DebugMono|x86 = DebugMono|x86 - DebugMonoPY3|x64 = DebugMonoPY3|x64 - DebugMonoPY3|x86 = DebugMonoPY3|x86 - DebugWin|x64 = DebugWin|x64 - DebugWin|x86 = DebugWin|x86 - DebugWinPY3|x64 = DebugWinPY3|x64 - DebugWinPY3|x86 = DebugWinPY3|x86 - ReleaseMono|x64 = ReleaseMono|x64 - ReleaseMono|x86 = ReleaseMono|x86 - ReleaseMonoPY3|x64 = ReleaseMonoPY3|x64 - ReleaseMonoPY3|x86 = ReleaseMonoPY3|x86 - ReleaseWin|x64 = ReleaseWin|x64 - ReleaseWin|x86 = ReleaseWin|x86 - ReleaseWinPY3|x64 = ReleaseWinPY3|x64 - ReleaseWinPY3|x86 = ReleaseWinPY3|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.Build.0 = DebugMono|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.Build.0 = DebugMono|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.Build.0 = DebugWin|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.Build.0 = DebugWin|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.Build.0 = DebugMono|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x86.Build.0 = DebugMono|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x64.Build.0 = DebugWin|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x86.Build.0 = DebugWin|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x64.Build.0 = DebugMono|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x86.Build.0 = DebugMono|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x64.Build.0 = DebugWin|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x86.Build.0 = DebugWin|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.Build.0 = DebugMono|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.Build.0 = DebugMono|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.Build.0 = DebugWin|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.Build.0 = DebugWin|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMono|x64.ActiveCfg = DebugMono|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMono|x86.ActiveCfg = DebugMono|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x64.ActiveCfg = DebugWin|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x64.Build.0 = DebugWin|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x86.ActiveCfg = DebugWin|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x86.Build.0 = DebugWin|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 - {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(MonoDevelopProperties) = preSolution - StartupItem = src\console\Console.csproj - Policies = $0 - $0.VersionControlPolicy = $1 - $1.inheritsSet = Mono - $0.ChangeLogPolicy = $2 - $2.UpdateMode = None - $2.MessageStyle = $3 - $3.LineAlign = 0 - $2.inheritsSet = Mono - EndGlobalSection -EndGlobal diff --git a/src/SharedAssemblyInfo.cs b/src/SharedAssemblyInfo.cs index dd057b144..071360e55 100644 --- a/src/SharedAssemblyInfo.cs +++ b/src/SharedAssemblyInfo.cs @@ -7,9 +7,9 @@ // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("pythonnet")] -[assembly: AssemblyProduct("Python.NET")] -[assembly: AssemblyCopyright("Copyright (c) 2006-2020 the contributors of the Python.NET project")] +[assembly: AssemblyCompany("Lost Tech LLC")] +[assembly: AssemblyProduct("LostTech.Python.Runtime")] +[assembly: AssemblyCopyright("Copyright (c) 2006-2020 Lost Tech and the contributors of the Python.NET project")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -25,4 +25,4 @@ // Version Information. Keeping it simple. May need to revisit for Nuget // See: https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/ // AssemblyVersion can only be numeric -[assembly: AssemblyVersion("2.5.0")] +[assembly: AssemblyVersion("3.0.0")] diff --git a/src/clrmodule/ClrModule.cs b/src/clrmodule/ClrModule.cs index 377be66d1..e0a0f67c8 100644 --- a/src/clrmodule/ClrModule.cs +++ b/src/clrmodule/ClrModule.cs @@ -28,15 +28,10 @@ using System.Runtime.InteropServices; using RGiesecke.DllExport; -public class clrModule +public static class clrModule { -#if PYTHON3 [DllExport("PyInit_clr", CallingConvention.StdCall)] public static IntPtr PyInit_clr() -#elif PYTHON2 - [DllExport("initclr", CallingConvention.StdCall)] - public static void initclr() -#endif { DebugPrint("Attempting to load 'Python.Runtime' using standard binding rules."); #if USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN @@ -95,11 +90,7 @@ public static void initclr() catch (InvalidOperationException) { DebugPrint("Could not load 'Python.Runtime'."); -#if PYTHON3 return IntPtr.Zero; -#elif PYTHON2 - return; -#endif } } @@ -107,11 +98,7 @@ public static void initclr() // So now we get the PythonEngine and execute the InitExt method on it. Type pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine"); -#if PYTHON3 return (IntPtr)pythonEngineType.InvokeMember("InitExt", BindingFlags.InvokeMethod, null, null, null); -#elif PYTHON2 - pythonEngineType.InvokeMember("InitExt", BindingFlags.InvokeMethod, null, null, null); -#endif } /// diff --git a/src/clrmodule/clrmodule.15.csproj b/src/clrmodule/clrmodule.15.csproj index 7fc9c2dda..5f80a1698 100644 --- a/src/clrmodule/clrmodule.15.csproj +++ b/src/clrmodule/clrmodule.15.csproj @@ -5,7 +5,6 @@ net40 x64;x86 - DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 clrmodule clrmodule clrmodule diff --git a/src/clrmodule/clrmodule.csproj b/src/clrmodule/clrmodule.csproj deleted file mode 100644 index 6e5ff4966..000000000 --- a/src/clrmodule/clrmodule.csproj +++ /dev/null @@ -1,95 +0,0 @@ - - - - Debug - AnyCPU - {86E834DE-1139-4511-96CC-69636A56E7AC} - Library - clrmodule - clrmodule - bin\clrmodule.xml - bin\ - v4.0 - - 1591 - ..\..\ - $(SolutionDir)\bin\ - Properties - 6 - true - prompt - - - x86 - - - x64 - - - true - PYTHON2;TRACE;DEBUG - full - - - PYTHON2 - true - pdbonly - - - true - PYTHON2;TRACE;DEBUG - full - - - PYTHON2 - true - pdbonly - - - true - PYTHON3;TRACE;DEBUG - full - - - PYTHON3 - true - pdbonly - - - true - PYTHON3;TRACE;DEBUG - full - - - PYTHON3 - true - pdbonly - - - - ..\..\packages\UnmanagedExports.1.2.7\lib\net\RGiesecke.DllExport.Metadata.dll - False - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - $(TargetPath) - $(TargetDir)$(TargetName).pdb - - - - - - - diff --git a/src/console/Console.15.csproj b/src/console/Console.15.csproj index 3c51caa31..4dcd1c32f 100644 --- a/src/console/Console.15.csproj +++ b/src/console/Console.15.csproj @@ -1,9 +1,8 @@ - net40;netcoreapp2.0 + netcoreapp2.0 x64;x86 - DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 Exe nPython Python.Runtime diff --git a/src/console/Console.csproj b/src/console/Console.csproj deleted file mode 100644 index ea88b6356..000000000 --- a/src/console/Console.csproj +++ /dev/null @@ -1,101 +0,0 @@ - - - - Debug - AnyCPU - {E29DCF0A-5114-4A98-B1DD-71264B6EA349} - Exe - nPython - Python.Runtime - bin\nPython.xml - bin\ - v4.0 - - 1591 - ..\..\ - $(SolutionDir)\bin\ - Properties - 6 - python-clear.ico - prompt - - - x86 - - - x64 - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - $(PythonManifest) - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - Python.Runtime.dll - - - - - {097b4ac0-74e9-4c58-bcf8-c69746ec8271} - Python.Runtime - - - - - - - diff --git a/src/embed_tests/Arrays.cs b/src/embed_tests/Arrays.cs new file mode 100644 index 000000000..f71a87f9c --- /dev/null +++ b/src/embed_tests/Arrays.cs @@ -0,0 +1,32 @@ +namespace Python.EmbeddingTest { + using System; + using System.Linq; + + using NUnit.Framework; + + using Python.Runtime; + + public class Arrays { + [Test] + public void Enumerate() { + var objArray = new[] { new Uri("http://a"), new Uri("http://b") }; + using var scope = Py.CreateScope(); + scope.Set("arr", objArray); + scope.Set("s", ""); + scope.Exec("for item in arr: s += str(item)"); + var result = scope.Eval("s"); + Assert.AreEqual(string.Concat(args: objArray), result); + } + + + [OneTimeSetUp] + public void SetUp() { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() { + PythonEngine.Shutdown(); + } + } +} diff --git a/src/embed_tests/CallableObject.cs b/src/embed_tests/CallableObject.cs new file mode 100644 index 000000000..553a666e6 --- /dev/null +++ b/src/embed_tests/CallableObject.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; + +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest { + class CallableObject { + [OneTimeSetUp] + public void SetUp() { + PythonEngine.Initialize(); + using (Py.GIL()) { + using var locals = new PyDict(); + PythonEngine.Exec(CallViaInheritance.BaseClassSource, locals: locals.Handle); + CustomBaseTypeProvider.BaseClass = locals[CallViaInheritance.BaseClassName]; + PythonEngine.InteropConfiguration.PythonBaseTypeProviders.Add(new CustomBaseTypeProvider()); + } + } + + [OneTimeTearDown] + public void Dispose() { + PythonEngine.Shutdown(); + } + [Test] + public void CallMethodMakesObjectCallable() { + var doubler = new DerivedDoubler(); + using (Py.GIL()) { + dynamic applyObjectTo21 = PythonEngine.Eval("lambda o: o(21)"); + Assert.AreEqual(doubler.__call__(21), (int)applyObjectTo21(doubler.ToPython())); + } + } + [Test] + public void CallMethodCanBeInheritedFromPython() { + var callViaInheritance = new CallViaInheritance(); + using (Py.GIL()) { + dynamic applyObjectTo14 = PythonEngine.Eval("lambda o: o(14)"); + Assert.AreEqual(callViaInheritance.Call(14), (int)applyObjectTo14(callViaInheritance.ToPython())); + } + } + + [Test] + public void CanOverwriteCall() { + var callViaInheritance = new CallViaInheritance(); + using var _ = Py.GIL(); + using var scope = Py.CreateScope(); + scope.Set("o", callViaInheritance); + scope.Exec("orig_call = o.Call"); + scope.Exec("o.Call = lambda a: orig_call(a*7)"); + int result = scope.Eval("o.Call(5)"); + Assert.AreEqual(105, result); + } + + class Doubler { + public int __call__(int arg) => 2 * arg; + } + + class DerivedDoubler : Doubler { } + + class CallViaInheritance { + public const string BaseClassName = "Forwarder"; + public static readonly string BaseClassSource = $@" +class MyCallableBase: + def __call__(self, val): + return self.Call(val) + +class {BaseClassName}(MyCallableBase): pass +"; + public int Call(int arg) => 3 * arg; + } + + class CustomBaseTypeProvider : IPythonBaseTypeProvider { + internal static PyObject BaseClass; + + public IEnumerable GetBaseTypes(Type type, IList existingBases) { + Assert.Greater(BaseClass.Refcount, 0); + return type != typeof(CallViaInheritance) + ? existingBases + : new []{BaseClass}; + } + } + } +} diff --git a/src/embed_tests/Codecs.cs b/src/embed_tests/Codecs.cs index 18fcd32d1..aa7627847 100644 --- a/src/embed_tests/Codecs.cs +++ b/src/embed_tests/Codecs.cs @@ -5,6 +5,7 @@ namespace Python.EmbeddingTest { using NUnit.Framework; using Python.Runtime; using Python.Runtime.Codecs; + using static Python.Runtime.PyObjectConversions; public class Codecs { [SetUp] @@ -82,6 +83,163 @@ static void TupleRoundtripGeneric() { Assert.AreEqual(expected: tuple, actual: restored); } } + + [Test] + public void EnumEncoded() { + var enumEncoder = new FakeEncoder(); + RegisterEncoder(enumEncoder); + ConsoleModifiers.Alt.ToPython(); + Assert.AreEqual(ConsoleModifiers.Alt, enumEncoder.LastObject); + } + + [Test] + public void EnumDecoded() { + var enumDecoder = new DecoderReturningPredefinedValue( + objectType: PythonEngine.Eval("list"), + decodeResult: ConsoleModifiers.Alt); + RegisterDecoder(enumDecoder); + var decoded = PythonEngine.Eval("[]").As(); + Assert.AreEqual(ConsoleModifiers.Alt, decoded); + } + + const string TestExceptionMessage = "Hello World!"; + [Test] + public void ExceptionEncoded() { + RegisterEncoder(new ValueErrorCodec()); + void CallMe() => throw new ValueErrorWrapper(TestExceptionMessage); + var callMeAction = new Action(CallMe); + using var _ = Py.GIL(); + using var scope = Py.CreateScope(); + scope.Exec(@" +def call(func): + try: + func() + except ValueError as e: + return str(e) +"); + var callFunc = scope.Get("call"); + string message = callFunc.Invoke(callMeAction.ToPython()).As(); + Assert.AreEqual(TestExceptionMessage, message); + } + + [Test] + public void ExceptionDecoded() { + RegisterDecoder(new ValueErrorCodec()); + using var _ = Py.GIL(); + using var scope = Py.CreateScope(); + var error = Assert.Throws(() => PythonEngine.Exec( + $"raise ValueError('{TestExceptionMessage}')")); + Assert.AreEqual(TestExceptionMessage, error.Message); + } + + [Test] + public void ExceptionDecodedNoInstance() { + using var _ = Py.GIL(); + RegisterDecoder(new InstancelessExceptionDecoder()); + using var scope = Py.CreateScope(); + var error = Assert.Throws(() => PythonEngine.Exec( + $"[].__iter__().__next__()")); + Assert.AreEqual(TestExceptionMessage, error.Message); + } + + [Test] + public void ExceptionStringValue() { + RegisterDecoder(new AttributeErrorDecoder()); + using var _ = Py.GIL(); + using var scope = Py.CreateScope(); + var error = Assert.Throws(() => "hi".ToPython().GetAttr("blah")); + StringAssert.Contains("blah", error.Message); + } + + [Test] + public void OutParameterEncoded() + { + var enumEncoder = new FakeEncoder(); + RegisterEncoder(enumEncoder); + + using var scope = Py.CreateScope(); + scope.Set("func", new Codecs().ToPython().GetAttr(nameof(GetModifiers))); + scope.Set("dummy", PyObject.FromManagedObject(ConsoleModifiers.Shift)); + var evalResult = scope.Eval("func(dummy)").As(); + Assert.AreSame(enumEncoder, evalResult); + Assert.AreEqual(ConsoleModifiers.Control, enumEncoder.LastObject); + } + + public void GetModifiers(out ConsoleModifiers result) => result = ConsoleModifiers.Control; + + class ValueErrorWrapper : Exception { + public ValueErrorWrapper(string message) : base(message) { } + } + + class ValueErrorCodec : IPyObjectEncoder, IPyObjectDecoder { + public bool CanDecode(PyObject objectType, Type targetType) + => this.CanEncode(targetType) + && PythonReferenceComparer.Instance.Equals(objectType, PythonEngine.Eval("ValueError")); + + public bool CanEncode(Type type) => type == typeof(ValueErrorWrapper) + || typeof(ValueErrorWrapper).IsSubclassOf(type); + + public bool TryDecode(PyObject pyObj, out T value) { + var message = pyObj.GetAttr("args")[0].As(); + value = (T)(object)new ValueErrorWrapper(message); + return true; + } + + public PyObject TryEncode(object value) { + var error = (ValueErrorWrapper)value; + return PythonEngine.Eval("ValueError").Invoke(error.Message.ToPython()); + } + } + + class AttributeErrorWrapper : Exception { + public AttributeErrorWrapper(string message) : base(message) { } + } + + class AttributeErrorDecoder : IPyObjectDecoder { + public bool CanDecode(PyObject objectType, Type targetType) + => this.SupportsTargetType(targetType) + && PythonReferenceComparer.Instance.Equals(objectType, PythonEngine.Eval("AttributeError")); + + bool SupportsTargetType(Type type) => type == typeof(AttributeErrorWrapper) + || typeof(AttributeErrorWrapper).IsSubclassOf(type); + + public bool TryDecode(PyObject pyObj, out T value) { + var message = pyObj.GetAttr("args")[0].As(); + value = (T)(object)new AttributeErrorWrapper(message); + return true; + } + } + + class InstancelessExceptionDecoder : IPyObjectDecoder + { + readonly PyObject PyErr = Py.Import("clr.interop").GetAttr("PyErr"); + + public bool CanDecode(PyObject objectType, Type targetType) + => PythonReferenceComparer.Instance.Equals(PyErr, objectType); + + public bool TryDecode(PyObject pyObj, out T value) + { + if (pyObj.HasAttr("value")) + { + value = default; + return false; + } + + value = (T)(object)new ValueErrorWrapper(TestExceptionMessage); + return true; + } + } + } + + class FakeEncoder : IPyObjectEncoder + { + public T LastObject { get; private set; } + public bool CanEncode(Type type) => type == typeof(T); + public PyObject TryEncode(object value) + { + this.LastObject = (T)value; + return PyObject.FromManagedObject(this); + } } /// @@ -94,25 +252,40 @@ class ObjectToEncoderInstanceEncoder : IPyObjectEncoder public PyObject TryEncode(object value) => PyObject.FromManagedObject(this); } + abstract class SingleTypeDecoder : IPyObjectDecoder + { + public PyObject LastSourceType { get; private set; } + public PyObject TheOnlySupportedSourceType { get; } + + public virtual bool CanDecode(PyObject objectType, Type targetType) + { + this.LastSourceType = objectType; + return objectType.Handle == this.TheOnlySupportedSourceType.Handle; + } + + public abstract bool TryDecode(PyObject pyObj, out T value); + + protected SingleTypeDecoder(PyObject objectType) { + this.TheOnlySupportedSourceType = objectType; + } + } + /// /// Decodes object of specified Python type to the predefined value /// /// Type of the - class DecoderReturningPredefinedValue : IPyObjectDecoder + class DecoderReturningPredefinedValue : SingleTypeDecoder { - public PyObject TheOnlySupportedSourceType { get; } public TTarget DecodeResult { get; } - public DecoderReturningPredefinedValue(PyObject objectType, TTarget decodeResult) + public DecoderReturningPredefinedValue(PyObject objectType, TTarget decodeResult) : base(objectType) { - this.TheOnlySupportedSourceType = objectType; this.DecodeResult = decodeResult; } - public bool CanDecode(PyObject objectType, Type targetType) - => objectType.Handle == TheOnlySupportedSourceType.Handle - && targetType == typeof(TTarget); - public bool TryDecode(PyObject pyObj, out T value) + public override bool CanDecode(PyObject objectType, Type targetType) + => base.CanDecode(objectType, targetType) && targetType == typeof(TTarget); + public override bool TryDecode(PyObject pyObj, out T value) { if (typeof(T) != typeof(TTarget)) throw new ArgumentException(nameof(T)); diff --git a/src/embed_tests/CollectionsMixins.cs b/src/embed_tests/CollectionsMixins.cs new file mode 100644 index 000000000..33bde1876 --- /dev/null +++ b/src/embed_tests/CollectionsMixins.cs @@ -0,0 +1,56 @@ +namespace Python.EmbeddingTest { + using System; + using System.Collections.Generic; + using System.Linq; + using NUnit.Framework; + + using Python.Runtime; + + public class CollectionsMixins { + [Test] + public void Enumerables_Iterable() { + var iterable = Enumerable.Repeat(42, 5).ToPython(); + var iterator = iterable.InvokeMethod("__iter__"); + int first = iterator.InvokeMethod("__next__").As(); + Assert.AreEqual(42, first); + } + [Test] + public void Dict_Items_Iterable() { + var pyDict = MakeDict().ToPython(); + var items = pyDict.InvokeMethod("items"); + using var scope = Py.CreateScope(); + scope.Set("iterator", this.Iter.Invoke(items)); + scope.Set("s", ""); + scope.Exec("for i in iterator: s += str(i)"); + scope.Get("s"); + } + + [Test] + public void Dict() + { + var dict = MakeDict(); + var pyDict = dict.ToPython(); + Assert.IsTrue(pyDict.InvokeMethod("__contains__", "42".ToPython()).As()); + Assert.IsFalse(pyDict.InvokeMethod("__contains__", "21".ToPython()).As()); + Assert.AreEqual("12", pyDict.InvokeMethod("get", "21".ToPython(), "12".ToPython()).As()); + Assert.AreEqual(null, pyDict.InvokeMethod("get", "21".ToPython()).As()); + Assert.AreEqual("1", pyDict.InvokeMethod("pop", "10".ToPython(), "1".ToPython()).As()); + } + + static Dictionary MakeDict() => new Dictionary { + ["42"] = new object(), + [new object()] = "21", + }; + PyObject Iter => PythonEngine.Eval("iter"); + + [OneTimeSetUp] + public void SetUp() { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() { + PythonEngine.Shutdown(); + } + } +} diff --git a/src/embed_tests/GlobalTestsSetup.cs b/src/embed_tests/GlobalTestsSetup.cs index 458ab6a99..8f4981476 100644 --- a/src/embed_tests/GlobalTestsSetup.cs +++ b/src/embed_tests/GlobalTestsSetup.cs @@ -1,14 +1,75 @@ -using NUnit.Framework; -using Python.Runtime; - namespace Python.EmbeddingTest { + using System; + using System.IO; + using System.Runtime.InteropServices; + + using NUnit.Framework; + using Python.Runtime; // As the SetUpFixture, the OneTimeTearDown of this class is executed after // all tests have run. [SetUpFixture] - public class GlobalTestsSetup + public partial class GlobalTestsSetup { + [OneTimeSetUp] + public void ConfigureRuntime() + { + if (Path.IsPathFullyQualified(Runtime.PythonDLL)) return; + + string pyDll = Environment.GetEnvironmentVariable("PYTHON_DLL_PATH"); + if (!string.IsNullOrEmpty(pyDll)) + { + Runtime.PythonDLL = pyDll; + } + + string pyVer = Environment.GetEnvironmentVariable("PYTHON_VERSION"); + if (!string.IsNullOrEmpty(pyVer)) + { + Runtime.PythonVersion = Version.Parse(pyVer); + } + + string pyHome = Environment.GetEnvironmentVariable("PYTHON_HOME") + // defined in GitHub action setup-python + ?? Environment.GetEnvironmentVariable("pythonLocation"); + if (!string.IsNullOrEmpty(pyHome) && !Path.IsPathFullyQualified(Runtime.PythonDLL)) + { + string dll = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? Path.Combine(pyHome, Runtime.PythonDLL) + : Path.Combine(pyHome, "lib", Runtime.PythonDLL); + if (File.Exists(dll)) + { + Runtime.PythonDLL = dll; + } + } + + if (!Path.IsPathFullyQualified(Runtime.PythonDLL)) + { + string[] paths = Environment.GetEnvironmentVariable("PATH") + .Split(Path.PathSeparator, StringSplitOptions.RemoveEmptyEntries); + foreach (string pathDir in paths) + { + string dll = Path.Combine(pathDir, Runtime.PythonDLL); + if (File.Exists(dll)) + { + Runtime.PythonDLL = dll; + if (string.IsNullOrEmpty(pyHome)) + { + pyHome = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + // on Windows, paths is PYTHON_HOME/dll + ? Path.GetDirectoryName(dll) + // on *nix the path is HOME/lib/dll + : Path.GetDirectoryName(Path.GetDirectoryName(dll)); + } + + break; + } + } + } + + Environment.SetEnvironmentVariable("PYTHON_HOME", pyHome); + } + [OneTimeTearDown] public void FinalCleanup() { diff --git a/src/embed_tests/Inheritance.cs b/src/embed_tests/Inheritance.cs new file mode 100644 index 000000000..15ba44a1b --- /dev/null +++ b/src/embed_tests/Inheritance.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest { + public class Inheritance { + [OneTimeSetUp] + public void SetUp() { + PythonEngine.Initialize(); + using (Py.GIL()) { + var locals = new PyDict(); + PythonEngine.Exec(InheritanceTestBaseClassWrapper.ClassSourceCode, locals: locals.Handle); + CustomBaseTypeProvider.BaseClass = locals[InheritanceTestBaseClassWrapper.ClassName]; + var baseTypeProviders = PythonEngine.InteropConfiguration.PythonBaseTypeProviders; + baseTypeProviders.Add(new CustomBaseTypeProvider()); + baseTypeProviders.Add(new NoEffectBaseTypeProvider()); + } + } + + [OneTimeTearDown] + public void Dispose() { + PythonEngine.Shutdown(); + } + + [Test] + public void IsInstance() { + using (Py.GIL()) { + var inherited = new Inherited(); + bool properlyInherited = PyIsInstance(inherited, CustomBaseTypeProvider.BaseClass); + Assert.IsTrue(properlyInherited); + } + } + + static dynamic PyIsInstance => PythonEngine.Eval("isinstance"); + + [Test] + public void InheritedClassIsNew() { + using (Py.GIL()) { + PyObject a = CustomBaseTypeProvider.BaseClass; + var inherited = new Inherited(); + dynamic getClass = PythonEngine.Eval("lambda o: o.__class__"); + PyObject inheritedClass = getClass(inherited); + Assert.IsFalse(PythonReferenceComparer.Instance.Equals(a, inheritedClass)); + } + } + + [Test] + public void InheritedFromInheritedClassIsSelf() { + using (Py.GIL()) + using (var scope = Py.CreateScope()) { + scope.Exec($"from {typeof(Inherited).Namespace} import {nameof(Inherited)}"); + scope.Exec($"class B({nameof(Inherited)}): pass"); + PyObject b = scope.Eval("B"); + PyObject bInst = ((dynamic)b)(scope); + dynamic getClass = scope.Eval("lambda o: o.__class__"); + PyObject inheritedClass = getClass(bInst); + Assert.IsTrue(PythonReferenceComparer.Instance.Equals(b, inheritedClass)); + } + } + + [Test] + public void InheritedFromInheritedIsInstance() { + using (Py.GIL()) + using (var scope = Py.CreateScope()) { + scope.Exec($"from {typeof(Inherited).Namespace} import {nameof(Inherited)}"); + scope.Exec($"class B({nameof(Inherited)}): pass"); + PyObject b = scope.Eval("B"); + PyObject bInst = ((dynamic)b)(scope); + bool properlyInherited = PyIsInstance(bInst, CustomBaseTypeProvider.BaseClass); + Assert.IsTrue(properlyInherited); + } + } + + [Test] + public void CanCallInheritedMethodWithPythonBase() { + var instance = new Inherited(); + using (Py.GIL()) { + dynamic callBase = PythonEngine.Eval($"lambda o: o.{nameof(PythonWrapperBase.WrapperBaseMethod)}()"); + string result = (string)callBase(instance); + Assert.AreEqual(result, nameof(PythonWrapperBase.WrapperBaseMethod)); + } + } + + [Test] + public void PythonCanCallOverridenMethod() { + var instance = new Inherited(); + using (Py.GIL()) + using (var scope = Py.CreateScope()){ + scope.Set(nameof(instance), instance); + int actual = scope.Eval($"{nameof(instance)}.callVirt()"); + Assert.AreEqual(expected: Inherited.OverridenVirtValue, actual); + } + } + + [Test] + public void PythonCanSetAdHocAttributes() { + var instance = new Inherited(); + using (Py.GIL()) + using (var scope = Py.CreateScope()) { + scope.Set(nameof(instance), instance); + scope.Exec($"super({nameof(instance)}.__class__, {nameof(instance)}).set_x_to_42()"); + int actual = scope.Eval($"{nameof(instance)}.{nameof(Inherited.XProp)}"); + Assert.AreEqual(expected: Inherited.X, actual); + } + } + + [Test] + public void FromException() { + using var _ = Py.GIL(); + var runtimeError = PythonEngine.Eval("RuntimeError"); + PythonEngine.InteropConfiguration.PythonBaseTypeProviders.Add( + new TestRuntimeError.BaseProvdier()); + var instance = new TestRuntimeError().ToPython(); + bool isRuntimeError = PyIsInstance(instance, runtimeError); + Assert.IsTrue(isRuntimeError); + } + } + + public class TestRuntimeError: Exception { + internal class BaseProvdier: IPythonBaseTypeProvider { + public IEnumerable GetBaseTypes(Type type, IList existingBases) + => type != typeof(TestRuntimeError) + ? existingBases + : new[] { PythonEngine.Eval("RuntimeError") }; + } + } + + class CustomBaseTypeProvider : IPythonBaseTypeProvider { + internal static PyObject BaseClass; + public IEnumerable GetBaseTypes(Type type, IList existingBases) + => type != typeof(InheritanceTestBaseClassWrapper) + ? existingBases + : new []{ PyType.Get(type.BaseType), BaseClass }; + } + + class NoEffectBaseTypeProvider : IPythonBaseTypeProvider + { + public IEnumerable GetBaseTypes(Type type, IList existingBases) + => existingBases; + } + + public class PythonWrapperBase { + public string WrapperBaseMethod() => nameof(WrapperBaseMethod); + } + + public class InheritanceTestBaseClassWrapper : PythonWrapperBase { + public const string ClassName = "InheritanceTestBaseClass"; + public const string ClassSourceCode = "class " + ClassName + +@": + def virt(self): + return 42 + def set_x_to_42(self): + self.XProp = 42 + def callVirt(self): + return self.virt() + def __getattr__(self, name): + return '__getattr__:' + name + def __setattr__(self, name, value): + value[name] = name +" + ClassName + " = " + ClassName + "\n"; + } + + public class Inherited : InheritanceTestBaseClassWrapper { + public const int OverridenVirtValue = -42; + public const int X = 42; + readonly Dictionary extras = new Dictionary(); + public int virt() => OverridenVirtValue; + public int XProp { + get { + using (var scope = Py.CreateScope()) { + scope.Set("this", this); + try { + return scope.Eval($"super(this.__class__, this).{nameof(XProp)}"); + } catch (PythonException ex) when (ex.PyType == Exceptions.AttributeError) { + if (this.extras.TryGetValue(nameof(this.XProp), out object value)) + return (int)value; + throw; + } + } + } + set => this.extras[nameof(this.XProp)] = value; + } + } +} diff --git a/src/embed_tests/Inspect.cs b/src/embed_tests/Inspect.cs new file mode 100644 index 000000000..83fb923e1 --- /dev/null +++ b/src/embed_tests/Inspect.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; + +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest { + public class Inspect { + [OneTimeSetUp] + public void SetUp() { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() { + PythonEngine.Shutdown(); + } + + [Test] + public void BoundMethodsAreInspectable() { + var obj = new Class(); + using (var scope = Py.CreateScope()) { + scope.Import("inspect"); + scope.Set(nameof(obj), obj); + var spec = scope.Eval($"inspect.getfullargspec({nameof(obj)}.{nameof(Class.Method)})"); + } + } + + [Test] + public void InstancePropertiesVisibleOnClass() { + var uri = new Uri("http://example.org").ToPython(); + var uriClass = uri.GetPythonType(); + var property = uriClass.GetAttr(nameof(Uri.AbsoluteUri)); + var pyProp = ExtensionType.GetManagedObject(property.Reference); + Assert.AreEqual(nameof(Uri.AbsoluteUri), pyProp.info.Name); + } + + class Class { + public void Method(int a, int b = 10) { } + public void Method(int a, object b) { } + } + } +} diff --git a/src/embed_tests/NumPyTests.cs b/src/embed_tests/NumPyTests.cs new file mode 100644 index 000000000..7c7779ce9 --- /dev/null +++ b/src/embed_tests/NumPyTests.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Python.Runtime; +using Python.Runtime.Codecs; + +namespace Python.EmbeddingTest +{ + public class NumPyTests + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + TupleCodec.Register(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + static PyObject GetNumPy() { + PyObject np; + try { + np = Py.Import("numpy"); + } catch (PythonException) { + Assert.Inconclusive("Numpy or dependency not installed"); + throw; + } + return np; + } + + [Test] + public void TestReadme() + { + dynamic np = GetNumPy(); + + Assert.AreEqual("1.0", np.cos(np.pi * 2).ToString()); + + dynamic sin = np.sin; + StringAssert.StartsWith("-0.95892", sin(5).ToString()); + + double c = np.cos(5) + sin(5); + Assert.AreEqual(-0.675262, c, 0.01); + + dynamic a = np.array(new List { 1, 2, 3 }); + Assert.AreEqual("float64", a.dtype.ToString()); + + dynamic b = np.array(new List { 6, 5, 4 }, Py.kw("dtype", np.int32)); + Assert.AreEqual("int32", b.dtype.ToString()); + + Assert.AreEqual("[ 6. 10. 12.]", (a * b).ToString().Replace(" ", " ")); + } + + [Test] + public void MultidimensionalNumPyArray() + { + PyObject np = GetNumPy(); + + var array = new[,] { { 1, 2 }, { 3, 4 } }; + var ndarray = np.InvokeMethod("asarray", array.ToPython()); + Assert.AreEqual((2,2), ndarray.GetAttr("shape").As<(int,int)>()); + Assert.AreEqual(1, ndarray[(0, 0).ToPython()].As()); + Assert.AreEqual(array[1, 0], ndarray[(1, 0).ToPython()].As()); + } + + [Test] + public void Iterate() + { + PyObject np = GetNumPy(); + + var size = new[] { 3, 2 }; + var ndarray = np.InvokeMethod("zeros", size.ToPython()); + var iterator = ndarray.GetIterator(); + Assert.True(iterator.MoveNext()); + Assert.True(iterator.MoveNext()); + Assert.True(iterator.MoveNext()); + Assert.False(iterator.MoveNext()); + } + } +} diff --git a/src/embed_tests/Python.EmbeddingTest.15.csproj b/src/embed_tests/Python.EmbeddingTest.15.csproj index eb6957656..256b2fb90 100644 --- a/src/embed_tests/Python.EmbeddingTest.15.csproj +++ b/src/embed_tests/Python.EmbeddingTest.15.csproj @@ -1,10 +1,8 @@ - - + - net40;netcoreapp2.0 + netcoreapp3.1 x64;x86 - DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 Exe false Python.EmbeddingTest @@ -23,7 +21,7 @@ ..\..\ $(SolutionDir)\bin\ $(OutputPath)\$(TargetFramework)_publish - 7.3 + 8.0 prompt $(PYTHONNET_DEFINE_CONSTANTS) XPLAT @@ -79,6 +77,7 @@ + @@ -87,35 +86,17 @@ - - - - - - - - - - - - - $(TargetPath) $(TargetDir)$(TargetName).pdb - - - - - diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj deleted file mode 100644 index 5dee66e64..000000000 --- a/src/embed_tests/Python.EmbeddingTest.csproj +++ /dev/null @@ -1,142 +0,0 @@ - - - - Debug - AnyCPU - {4165C59D-2822-499F-A6DB-EACA4C331EB5} - Library - Python.EmbeddingTest - Python.EmbeddingTest - bin\Python.EmbeddingTest.xml - bin\ - v4.0 - - 1591 - ..\..\ - $(SolutionDir)\bin\ - 7.3 - true - prompt - - - x86 - - - x64 - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - - - ..\..\packages\NUnit.3.12.0\lib\net40\nunit.framework.dll - - - ..\..\packages\System.ValueTuple.4.5.0\lib\portable-net40+sl4+win8+wp8\System.ValueTuple.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {097B4AC0-74E9-4C58-BCF8-C69746EC8271} - Python.Runtime - - - - - - - - $(TargetPath) - $(TargetDir)$(TargetName).pdb - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - diff --git a/src/embed_tests/TestCallbacks.cs b/src/embed_tests/TestCallbacks.cs index 220b0a86a..7c20b1c22 100644 --- a/src/embed_tests/TestCallbacks.cs +++ b/src/embed_tests/TestCallbacks.cs @@ -4,8 +4,6 @@ using Python.Runtime; namespace Python.EmbeddingTest { - using Runtime = Python.Runtime.Runtime; - public class TestCallbacks { [OneTimeSetUp] public void SetUp() { @@ -17,6 +15,33 @@ public void Dispose() { PythonEngine.Shutdown(); } + [Test] + public void TestSimpleCallback() { + int passed = 0; + var aFunctionThatCallsIntoPython = new Action(value => passed = value); + using (Py.GIL()) { + dynamic callWith42 = PythonEngine.Eval("lambda f: f(42)"); + callWith42(aFunctionThatCallsIntoPython.ToPython()); + } + Assert.AreEqual(expected: 42, actual: passed); + } + + // regression test for https://github.com/pythonnet/pythonnet/issues/795 + [Test] + public void TestReentry() { + int passed = 0; + var aFunctionThatCallsIntoPython = new Action(value => { + using (Py.GIL()) { + passed = (int)(dynamic)PythonEngine.Eval("42"); + } + }); + using (Py.GIL()) { + dynamic callWith42 = PythonEngine.Eval("lambda f: f(42)"); + callWith42(aFunctionThatCallsIntoPython.ToPython()); + } + Assert.AreEqual(expected: 42, actual: passed); + } + [Test] public void TestNoOverloadException() { int passed = 0; @@ -25,11 +50,48 @@ public void TestNoOverloadException() { dynamic callWith42 = PythonEngine.Eval("lambda f: f([42])"); var error = Assert.Throws(() => callWith42(aFunctionThatCallsIntoPython.ToPython())); Assert.AreEqual("TypeError", error.PythonTypeName); - string expectedArgTypes = Runtime.IsPython2 - ? "()" - : "()"; - StringAssert.EndsWith(expectedArgTypes, error.Message); + StringAssert.EndsWith("()", error.Message); } } + + [Test] + public void TestNoInstanceOverloadException() { + var instance = new FunctionContainer(); + using (Py.GIL()) { + dynamic callWith42 = PythonEngine.Eval($"lambda f: f.{nameof(FunctionContainer.Instance)}([42])"); + var error = Assert.Throws(() => callWith42(instance.ToPython())); + Assert.AreEqual("TypeError", error.PythonTypeName); + string expectedMessageEnd = + $"{nameof(FunctionContainer)}.{nameof(FunctionContainer.Instance)}: ()"; + StringAssert.EndsWith(expectedMessageEnd, error.Message); + } + } + + [Test] + public void TestNoStaticOverloadException() { + using (Py.GIL()) { + var type = ((dynamic)new FunctionContainer().ToPython()).__class__; + dynamic callWith42 = PythonEngine.Eval($"lambda t: t.{nameof(FunctionContainer.Static)}([42])"); + var error = Assert.Throws(() => callWith42(type)); + Assert.AreEqual("TypeError", error.PythonTypeName); + string expectedMessageEnd = + $"{nameof(FunctionContainer)}::{nameof(FunctionContainer.Static)}: ()"; + StringAssert.EndsWith(expectedMessageEnd, error.Message); + } + } + + [Test] + public void TestExceptionInCallback() { + var dotnetFunction = new Action(_ => throw new ArgumentOutOfRangeException()); + using (Py.GIL()) { + dynamic callWith42 = PythonEngine.Eval("lambda f: f(42)"); + Assert.Throws(() => callWith42(dotnetFunction.ToPython())); + } + } + + class FunctionContainer { + public void Instance(int arg) { } + public static void Static(int arg) { } + } } } diff --git a/src/embed_tests/TestDomainReload.cs b/src/embed_tests/TestDomainReload.cs index b162d4eb0..a1362a426 100644 --- a/src/embed_tests/TestDomainReload.cs +++ b/src/embed_tests/TestDomainReload.cs @@ -14,7 +14,7 @@ #if !NETSTANDARD && !NETCOREAPP namespace Python.EmbeddingTest { - class TestDomainReload + static class TestDomainReload { /// /// Test that the python runtime can survive a C# domain reload without crashing. diff --git a/src/embed_tests/TestExample.cs b/src/embed_tests/TestExample.cs deleted file mode 100644 index 671f9e33d..000000000 --- a/src/embed_tests/TestExample.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using NUnit.Framework; -using Python.Runtime; - -namespace Python.EmbeddingTest -{ - public class TestExample - { - [OneTimeSetUp] - public void SetUp() - { - PythonEngine.Initialize(); - } - - [OneTimeTearDown] - public void Dispose() - { - PythonEngine.Shutdown(); - } - - [Test] - public void TestReadme() - { - dynamic np; - try - { - np = Py.Import("numpy"); - } - catch (PythonException) - { - Assert.Inconclusive("Numpy or dependency not installed"); - return; - } - - Assert.AreEqual("1.0", np.cos(np.pi * 2).ToString()); - - dynamic sin = np.sin; - StringAssert.StartsWith("-0.95892", sin(5).ToString()); - - double c = np.cos(5) + sin(5); - Assert.AreEqual(-0.675262, c, 0.01); - - dynamic a = np.array(new List { 1, 2, 3 }); - Assert.AreEqual("float64", a.dtype.ToString()); - - dynamic b = np.array(new List { 6, 5, 4 }, Py.kw("dtype", np.int32)); - Assert.AreEqual("int32", b.dtype.ToString()); - - Assert.AreEqual("[ 6. 10. 12.]", (a * b).ToString().Replace(" ", " ")); - } - } -} diff --git a/src/embed_tests/TestFinalizer.cs b/src/embed_tests/TestFinalizer.cs index f82767af1..219f3a566 100644 --- a/src/embed_tests/TestFinalizer.cs +++ b/src/embed_tests/TestFinalizer.cs @@ -34,8 +34,6 @@ private static void FullGCCollect() [Test] public void CollectBasicObject() { - Assert.IsTrue(Finalizer.Instance.Enable); - Finalizer.Instance.Threshold = 1; bool called = false; var objectCount = 0; @@ -95,64 +93,6 @@ private static void MakeAGarbage(out WeakReference shortWeak, out WeakReference obj = null; } - private static long CompareWithFinalizerOn(PyObject pyCollect, bool enbale) - { - // Must larger than 512 bytes make sure Python use - string str = new string('1', 1024); - Finalizer.Instance.Enable = true; - FullGCCollect(); - FullGCCollect(); - pyCollect.Invoke(); - Finalizer.Instance.Collect(); - Finalizer.Instance.Enable = enbale; - - // Estimate unmanaged memory size - long before = Environment.WorkingSet - GC.GetTotalMemory(true); - for (int i = 0; i < 10000; i++) - { - // Memory will leak when disable Finalizer - new PyString(str); - } - FullGCCollect(); - FullGCCollect(); - pyCollect.Invoke(); - if (enbale) - { - Finalizer.Instance.Collect(); - } - - FullGCCollect(); - FullGCCollect(); - long after = Environment.WorkingSet - GC.GetTotalMemory(true); - return after - before; - - } - - /// - /// Because of two vms both have their memory manager, - /// this test only prove the finalizer has take effect. - /// - [Test] - [Ignore("Too many uncertainties, only manual on when debugging")] - public void SimpleTestMemory() - { - bool oldState = Finalizer.Instance.Enable; - try - { - using (PyObject gcModule = PythonEngine.ImportModule("gc")) - using (PyObject pyCollect = gcModule.GetAttr("collect")) - { - long span1 = CompareWithFinalizerOn(pyCollect, false); - long span2 = CompareWithFinalizerOn(pyCollect, true); - Assert.Less(span2, span1); - } - } - finally - { - Finalizer.Instance.Enable = oldState; - } - } - class MyPyObject : PyObject { public MyPyObject(IntPtr op) : base(op) diff --git a/src/embed_tests/TestInstanceWrapping.cs b/src/embed_tests/TestInstanceWrapping.cs index 8be207c00..7c6be134b 100644 --- a/src/embed_tests/TestInstanceWrapping.cs +++ b/src/embed_tests/TestInstanceWrapping.cs @@ -1,43 +1,150 @@ -using System; using System.Globalization; + using NUnit.Framework; using Python.Runtime; +using Python.Runtime.Slots; -namespace Python.EmbeddingTest -{ - public class TestInstanceWrapping - { +namespace Python.EmbeddingTest { + public class TestInstanceWrapping { [OneTimeSetUp] - public void SetUp() - { + public void SetUp() { PythonEngine.Initialize(); + using (Py.GIL()) { + var locals = new PyDict(); + PythonEngine.Exec(InheritanceTestBaseClassWrapper.ClassSourceCode, locals: locals.Handle); + CustomBaseTypeProvider.BaseClass = locals[InheritanceTestBaseClassWrapper.ClassName]; + var baseTypeProviders = PythonEngine.InteropConfiguration.PythonBaseTypeProviders; + baseTypeProviders.Add(new CustomBaseTypeProvider()); + } } [OneTimeTearDown] - public void Dispose() - { + public void Dispose() { PythonEngine.Shutdown(); } + [Test] + public void OverloadResolution_IntOrStr() { + var overloaded = new Overloaded(); + using (Py.GIL()) { + var o = overloaded.ToPython(); + + dynamic callWithInt = PythonEngine.Eval("lambda o: o.IntOrStr(42)"); + callWithInt(o); + Assert.AreEqual(42, overloaded.Value); + + dynamic callWithStr = PythonEngine.Eval("lambda o: o.IntOrStr('43')"); + callWithStr(o); + Assert.AreEqual(43, overloaded.Value); + } + } + + [Test] + public void OverloadResolution_ParamsOmitted() { + var overloaded = new Overloaded(); + using (Py.GIL()) { + var o = overloaded.ToPython(); + + dynamic callWithInt = PythonEngine.Eval($"lambda o: o.{nameof(Overloaded.ArgPlusParams)}(42)"); + callWithInt(o); + Assert.AreEqual(42, overloaded.Value); + } + } + + [Test] + public void OverloadResolution_ParamsTypeMatch() { + var overloaded = new Overloaded(); + using (Py.GIL()) { + var o = overloaded.ToPython(); + + var callWithInts = PythonEngine.Eval($"lambda o: o.{nameof(Overloaded.ArgPlusParams)}(42, 43)"); + callWithInts.Invoke(o); + Assert.AreEqual(42, overloaded.Value); + } + } + + [Test] + public void OverloadResolution_ParamsTypeMisMatch() { + var overloaded = new Overloaded(); + using (Py.GIL()) { + var o = overloaded.ToPython(); + + var callWithIntAndStr = PythonEngine.Eval($"lambda o: o.{nameof(Overloaded.ArgPlusParams)}(42, object())"); + var error = Assert.Throws(() => callWithIntAndStr.Invoke(o), "Should have thrown PythonException"); + Assert.AreEqual(expected: Exceptions.TypeError, actual: error.PyType, "Should have thrown TypeError"); + } + } + + [Test] + public void OverloadResolution_ObjOrClass() { + var overloaded = new Overloaded(); + using (Py.GIL()) { + var o = overloaded.ToPython(); + + dynamic callWithConcrete = PythonEngine.Eval("lambda o: o.ObjOrClass(o)"); + callWithConcrete(o); + Assert.AreEqual(Overloaded.ConcreteClass, overloaded.Value); + + dynamic callWithUnknown = PythonEngine.Eval("lambda o: o.ObjOrClass([])"); + callWithUnknown(o); + Assert.AreEqual(Overloaded.Object, overloaded.Value); + } + } + + [Test] + [Ignore("Overload resolution does not correctly choose from base vs derived class")] + public void OverloadResolution_BaseOrDerived() { + var overloaded = new Overloaded(); + using (Py.GIL()) { + var o = overloaded.ToPython(); + + dynamic callWithSelf = PythonEngine.Eval("lambda o: o.BaseOrDerived(o)"); + callWithSelf(o); + Assert.AreEqual(Overloaded.Derived, overloaded.Value); + } + } + // regression test for https://github.com/pythonnet/pythonnet/issues/811 [Test] - public void OverloadResolution_UnknownToObject() - { + public void OverloadResolution_UnknownToObject() { var overloaded = new Overloaded(); - using (Py.GIL()) - { + using (Py.GIL()) { var o = overloaded.ToPython(); - dynamic callWithSelf = PythonEngine.Eval("lambda o: o.ObjOrClass(object())"); + dynamic callWithSelf = PythonEngine.Eval("lambda o: o.ObjOrClass(KeyError())"); callWithSelf(o); Assert.AreEqual(Overloaded.Object, overloaded.Value); } } + [Test] + public void GetAttrCanBeOverriden() { + var overloaded = new Overloaded(); + using (Py.GIL()) { + var o = overloaded.ToPython(); + dynamic getNonexistingAttr = PythonEngine.Eval("lambda o: o.non_existing_attr"); + string nonexistentAttrValue = getNonexistingAttr(o); + Assert.AreEqual(GetAttrFallbackValue, nonexistentAttrValue); + } + } + + [Test] + public void GetAttrCanCallBase() { + var obj = new GetSetAttrDoubleInherited(); + using (Py.GIL()) { + var pyObj = obj.ToPython(); + dynamic getNonexistingAttr = PythonEngine.Eval("lambda o: o.non_existing_attr"); + string nonexistentAttrValue = getNonexistingAttr(pyObj); + Assert.AreEqual("__getattr__:non_existing_attr", nonexistentAttrValue); + } + } + + const string GetAttrFallbackValue = "undefined"; + class Base {} class Derived: Base { } - class Overloaded: Derived + class Overloaded: Derived, IGetAttr { public int Value { get; set; } public void IntOrStr(int arg) => this.Value = arg; @@ -53,6 +160,32 @@ public void IntOrStr(string arg) => public const int Derived = Base + 1; public void BaseOrDerived(Base _) => this.Value = Base; public void BaseOrDerived(Derived _) => this.Value = Derived; + + public void ArgPlusParams(int arg0, params double[] floats) => this.Value = arg0; + + public bool TryGetAttr(string name, out PyObject value) { + using (var self = this.ToPython()) { + if (GetAttr.TryGetBaseAttr(self, name, out value) + || GetAttr.GenericGetAttr(self, name, out value)) + return true; + } + + value = GetAttrFallbackValue.ToPython(); + return true; + } + } + + class GetSetAttrInherited : InheritanceTestBaseClassWrapper, IGetAttr { + public bool TryGetAttr(string name, out PyObject value) { + if (name == "NonInherited") { + value = "NonInherited".ToPython(); + return true; + } + + return GetAttr.TryGetBaseAttr(this.ToPython(), name, out value); + } } + + class GetSetAttrDoubleInherited: GetSetAttrInherited { } } } diff --git a/src/embed_tests/TestPassDynamic.cs b/src/embed_tests/TestPassDynamic.cs new file mode 100644 index 000000000..2e0c8ba8b --- /dev/null +++ b/src/embed_tests/TestPassDynamic.cs @@ -0,0 +1,34 @@ +namespace Python.EmbeddingTest { + using System; + using System.Collections.Generic; + using System.Dynamic; + using System.Text; + using NUnit.Framework; + using Python.Runtime; + + public class TestPassDynamic { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + [Ignore("Passing dynamic objects is no implemented. https://github.com/pythonnet/pythonnet/issues/952")] + public void ExpandoProperties() { + dynamic expando = new ExpandoObject(); + expando.test = 42; + using (Py.GIL()) { + dynamic getTest = PythonEngine.Eval("lambda o: o.test"); + int read = getTest(expando); + Assert.AreEqual(42, read); + } + } + } +} diff --git a/src/embed_tests/TestPyBuffer.cs b/src/embed_tests/TestPyBuffer.cs new file mode 100644 index 000000000..82e325269 --- /dev/null +++ b/src/embed_tests/TestPyBuffer.cs @@ -0,0 +1,94 @@ +using System; +using System.Text; +using NUnit.Framework; +using Python.Runtime; +using Python.Runtime.Codecs; + +namespace Python.EmbeddingTest { + public class TestPyBuffer + { + [OneTimeSetUp] + public void SetUp() + { + PythonEngine.Initialize(); + TupleCodec.Register(); + } + + [OneTimeTearDown] + public void Dispose() + { + PythonEngine.Shutdown(); + } + + [Test] + public void TestBufferWrite() + { + if (Runtime.Runtime.PythonVersion < new Version(3,5)) return; + + string bufferTestString = "hello world! !$%&/()=?"; + + using (Py.GIL()) + { + using (var scope = Py.CreateScope()) + { + scope.Exec($"arr = bytearray({bufferTestString.Length})"); + PyObject pythonArray = scope.Get("arr"); + byte[] managedArray = new UTF8Encoding().GetBytes(bufferTestString); + + using (PyBuffer buf = pythonArray.GetBuffer()) + { + buf.Write(managedArray, 0, managedArray.Length); + } + + string result = scope.Eval("arr.decode('utf-8')").ToString(); + Assert.IsTrue(result == bufferTestString); + } + } + } + + [Test] + public void TestBufferRead() + { + if (Runtime.Runtime.PythonVersion < new Version(3, 5)) return; + + string bufferTestString = "hello world! !$%&/()=?"; + + using (Py.GIL()) + { + using (var scope = Py.CreateScope()) + { + scope.Exec($"arr = b'{bufferTestString}'"); + PyObject pythonArray = scope.Get("arr"); + byte[] managedArray = new byte[bufferTestString.Length]; + + using (PyBuffer buf = pythonArray.GetBuffer()) + { + buf.Read(managedArray, 0, managedArray.Length); + } + + string result = new UTF8Encoding().GetString(managedArray); + Assert.IsTrue(result == bufferTestString); + } + } + } + + [Test] + public void ArrayHasBuffer() + { + var array = new[,] {{1, 2}, {3,4}}; + var memoryView = PythonEngine.Eval("memoryview"); + var mem = memoryView.Invoke(array.ToPython()); + Assert.AreEqual(1, mem[(0, 0).ToPython()].As()); + Assert.AreEqual(array[1,0], mem[(1, 0).ToPython()].As()); + } + + [Test] + public void ReferenceTypeArrayHasNoBuffer() + { + var array = new[] {new object()}; + var memoryView = PythonEngine.Eval("memoryview"); + var error = Assert.Throws(() => memoryView.Invoke(array.ToPython())); + Assert.AreEqual("TypeError", error.PythonTypeName); + } + } +} diff --git a/src/embed_tests/TestPyFloat.cs b/src/embed_tests/TestPyFloat.cs index 94e7026c7..28a3c53bb 100644 --- a/src/embed_tests/TestPyFloat.cs +++ b/src/embed_tests/TestPyFloat.cs @@ -4,9 +4,7 @@ namespace Python.EmbeddingTest { - /// - /// PyFloat implementation isn't complete, thus tests aren't complete. - /// + // PyFloat implementation isn't complete, thus tests aren't complete. public class TestPyFloat { [OneTimeSetUp] diff --git a/src/embed_tests/TestPyList.cs b/src/embed_tests/TestPyList.cs index e9acfbb45..f3f9242fe 100644 --- a/src/embed_tests/TestPyList.cs +++ b/src/embed_tests/TestPyList.cs @@ -78,22 +78,22 @@ public void TestPyObjectArrayCtor() } [Test] - public void TestPyObjectCtor() + public void TestWrap() { var a = new PyList(); - var s = new PyList(a); + var s = PyList.Wrap(a); Assert.IsInstanceOf(typeof(PyList), s); Assert.AreEqual(0, s.Length()); } [Test] - public void TestBadPyObjectCtor() + public void TestBadWrapArgument() { var i = new PyInt(5); PyList t = null; - var ex = Assert.Throws(() => t = new PyList(i)); + var ex = Assert.Throws(() => t = PyList.Wrap(i)); Assert.AreEqual("object is not a list", ex.Message); Assert.IsNull(t); diff --git a/src/embed_tests/TestPyTuple.cs b/src/embed_tests/TestPyTuple.cs index 362251049..79a1d90f2 100644 --- a/src/embed_tests/TestPyTuple.cs +++ b/src/embed_tests/TestPyTuple.cs @@ -153,9 +153,7 @@ public void TestNewPyTupleFromPyTuple() Assert.IsInstanceOf(typeof(PyTuple), t); } - /// - /// TODO: Should this throw ArgumentError instead? - /// + // TODO: Should this throw ArgumentError instead? [Test] public void TestInvalidAsTuple() { diff --git a/src/embed_tests/TestPythonException.cs b/src/embed_tests/TestPythonException.cs index 000c32ca3..56c328d46 100644 --- a/src/embed_tests/TestPythonException.cs +++ b/src/embed_tests/TestPythonException.cs @@ -37,7 +37,7 @@ public void TestMessage() [Test] public void TestNoError() { - var e = new PythonException(); // There is no PyErr to fetch + var e = PythonException.FromPyErr(); // There is no PyErr to fetch Assert.AreEqual("", e.Message); } @@ -55,6 +55,33 @@ public void TestPythonErrorTypeName() } } + [Test] + public void TestNestedExceptions() + { + try { + PythonEngine.Exec(@" +try: + raise Exception('inner') +except Exception as ex: + raise Exception('outer') from ex +"); + } catch (PythonException ex) { + Assert.That(ex.InnerException, Is.InstanceOf()); + Assert.That(ex.InnerException.Message, Is.EqualTo("Exception : inner")); + } + } + + [Test] + public void InnerIsEmptyWithNoCause() + { + var list = new PyList(); + PyObject foo = null; + + var ex = Assert.Throws(() => foo = list[0]); + + Assert.IsNull(ex.InnerException); + } + [Test] public void TestPythonExceptionFormat() { diff --git a/src/embed_tests/TestRuntime.cs b/src/embed_tests/TestRuntime.cs index 4129d3df3..2c268cf73 100644 --- a/src/embed_tests/TestRuntime.cs +++ b/src/embed_tests/TestRuntime.cs @@ -83,19 +83,23 @@ public static void PyCheck_Iter_PyObject_IsIterable_Test() Runtime.Runtime.Py_Initialize(); // Tests that a python list is an iterable, but not an iterator - var pyList = Runtime.Runtime.PyList_New(0); - Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyList)); - Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyList)); + using (var pyList = NewReference.DangerousFromPointer(Runtime.Runtime.PyList_New(0))) + { + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyList)); + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyList)); - // Tests that a python list iterator is both an iterable and an iterator - var pyListIter = Runtime.Runtime.PyObject_GetIter(pyList); - Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyListIter)); - Assert.IsTrue(Runtime.Runtime.PyIter_Check(pyListIter)); + // Tests that a python list iterator is both an iterable and an iterator + using var pyListIter = Runtime.Runtime.PyObject_GetIter(pyList); + Assert.IsTrue(Runtime.Runtime.PyObject_IsIterable(pyListIter)); + Assert.IsTrue(Runtime.Runtime.PyIter_Check(pyListIter)); + } // Tests that a python float is neither an iterable nor an iterator - var pyFloat = Runtime.Runtime.PyFloat_FromDouble(2.73); - Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(pyFloat)); - Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyFloat)); + using (var pyFloat = NewReference.DangerousFromPointer(Runtime.Runtime.PyFloat_FromDouble(2.73))) + { + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(pyFloat)); + Assert.IsFalse(Runtime.Runtime.PyIter_Check(pyFloat)); + } Runtime.Runtime.Py_Finalize(); } @@ -115,11 +119,32 @@ public static void PyCheck_Iter_PyObject_IsIterable_ThreadingLock_Test() if (lockType == IntPtr.Zero) throw new KeyNotFoundException("class 'Lock' was not found in 'threading'"); - var lockInstance = Runtime.Runtime.PyObject_CallObject(lockType, Runtime.Runtime.PyTuple_New(0)); - Exceptions.ErrorCheck(lockInstance); + using (var lockInstance = NewReference.DangerousFromPointer( + Runtime.Runtime.PyObject_CallObject(lockType, Runtime.Runtime.PyTuple_New(0)))) + { + Exceptions.ErrorCheck(lockInstance); + + Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance)); + Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance)); + } - Assert.IsFalse(Runtime.Runtime.PyObject_IsIterable(lockInstance)); - Assert.IsFalse(Runtime.Runtime.PyIter_Check(lockInstance)); + Runtime.Runtime.Py_Finalize(); + } + + [Test] + public static void PyType_Check_Sanity() + { + Runtime.Runtime.Py_Initialize(); + var builtins = Runtime.Runtime.GetBuiltins(); + var obj = Runtime.Runtime.PyObject_GetAttrString(builtins, "object"); + var t = Runtime.Runtime.PyObject_GetAttrString(builtins, "True"); + var none = Runtime.Runtime.PyObject_GetAttrString(builtins, "None"); + var noneType = Runtime.Runtime.PyObject_TYPE(none); + var type = Runtime.Runtime.PyObject_TYPE(noneType); + + Assert.IsTrue(Runtime.Runtime.PyType_Check(new BorrowedReference(obj))); + Assert.IsTrue(Runtime.Runtime.PyType_Check(new BorrowedReference(type))); + Assert.IsFalse(Runtime.Runtime.PyType_Check(new BorrowedReference(t))); Runtime.Runtime.Py_Finalize(); } diff --git a/src/embed_tests/TestTypeManager.cs b/src/embed_tests/TestTypeManager.cs index 931c44236..be2bc813e 100644 --- a/src/embed_tests/TestTypeManager.cs +++ b/src/embed_tests/TestTypeManager.cs @@ -4,7 +4,7 @@ namespace Python.EmbeddingTest { - class TestTypeManager + static class TestTypeManager { [SetUp] public static void Init() diff --git a/src/embed_tests/pyinitialize.cs b/src/embed_tests/pyinitialize.cs index ea1d8d023..e2aaf89db 100644 --- a/src/embed_tests/pyinitialize.cs +++ b/src/embed_tests/pyinitialize.cs @@ -43,13 +43,9 @@ public static void LoadSpecificArgs() } /// - /// Failing test demonstrating current issue with OverflowException (#376) - /// and ArgumentException issue after that one is fixed. - /// More complex version of StartAndStopTwice test + /// Regression test for https://github.com/pythonnet/pythonnet/pull/376 /// [Test] - [Ignore("GH#376: System.OverflowException : Arithmetic operation resulted in an overflow")] - //[Ignore("System.ArgumentException : Cannot pass a GCHandle across AppDomains")] public void ReInitialize() { var code = "from System import Int32\n"; diff --git a/src/perf_tests/Python.PerformanceTests.csproj b/src/perf_tests/Python.PerformanceTests.csproj index 25af89db0..01328c4f9 100644 --- a/src/perf_tests/Python.PerformanceTests.csproj +++ b/src/perf_tests/Python.PerformanceTests.csproj @@ -21,7 +21,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + compile diff --git a/src/runtime/BorrowedReference.cs b/src/runtime/BorrowedReference.cs index a3bf29056..5cff10512 100644 --- a/src/runtime/BorrowedReference.cs +++ b/src/runtime/BorrowedReference.cs @@ -21,5 +21,21 @@ public BorrowedReference(IntPtr pointer) { this.pointer = pointer; } + + public bool Equals(BorrowedReference other) => this.pointer == other.pointer; + + public static bool operator==(BorrowedReference reference, BorrowedReference other) + => reference.pointer == other.pointer; + public static bool operator!=(BorrowedReference reference, BorrowedReference other) + => reference.pointer != other.pointer; + public static bool operator==(BorrowedReference reference, IntPtr rawPointer) + => reference.pointer == rawPointer; + public static bool operator!=(BorrowedReference reference, IntPtr rawPointer) + => reference.pointer != rawPointer; + } + + static class BorrowedReferenceExtensions { + public static IntPtr DangerousIncRefOrNull(this in BorrowedReference reference) + => reference.IsNull ? IntPtr.Zero : Runtime.SelfIncRef(reference.DangerousGetAddress()); } } diff --git a/src/runtime/Codecs/DecoderGroup.cs b/src/runtime/Codecs/DecoderGroup.cs index 8a290d5d4..cc511ed50 100644 --- a/src/runtime/Codecs/DecoderGroup.cs +++ b/src/runtime/Codecs/DecoderGroup.cs @@ -8,7 +8,6 @@ namespace Python.Runtime.Codecs /// /// Represents a group of s. Useful to group them by priority. /// - [Obsolete(Util.UnstableApiMessage)] public sealed class DecoderGroup: IPyObjectDecoder, IEnumerable { readonly List decoders = new List(); @@ -49,7 +48,6 @@ public bool TryDecode(PyObject pyObj, out T value) IEnumerator IEnumerable.GetEnumerator() => this.decoders.GetEnumerator(); } - [Obsolete(Util.UnstableApiMessage)] public static class DecoderGroupExtensions { /// @@ -58,7 +56,6 @@ public static class DecoderGroupExtensions /// that can decode from to , /// or null if a matching decoder can not be found. /// - [Obsolete(Util.UnstableApiMessage)] public static IPyObjectDecoder GetDecoder( this IPyObjectDecoder decoder, PyObject objectType, Type targetType) diff --git a/src/runtime/Codecs/EncoderGroup.cs b/src/runtime/Codecs/EncoderGroup.cs index a5708c0bb..4f776a669 100644 --- a/src/runtime/Codecs/EncoderGroup.cs +++ b/src/runtime/Codecs/EncoderGroup.cs @@ -8,7 +8,6 @@ namespace Python.Runtime.Codecs /// /// Represents a group of s. Useful to group them by priority. /// - [Obsolete(Util.UnstableApiMessage)] public sealed class EncoderGroup: IPyObjectEncoder, IEnumerable { readonly List encoders = new List(); @@ -50,7 +49,6 @@ public PyObject TryEncode(object value) IEnumerator IEnumerable.GetEnumerator() => this.encoders.GetEnumerator(); } - [Obsolete(Util.UnstableApiMessage)] public static class EncoderGroupExtensions { /// @@ -58,7 +56,6 @@ public static class EncoderGroupExtensions /// (potentially selecting one from a collection), /// that can encode the specified . /// - [Obsolete(Util.UnstableApiMessage)] public static IEnumerable GetEncoders(this IPyObjectEncoder decoder, Type type) { if (decoder is null) throw new ArgumentNullException(nameof(decoder)); diff --git a/src/runtime/Codecs/RawProxyEncoder.cs b/src/runtime/Codecs/RawProxyEncoder.cs index a1b6c52b3..37ad0487b 100644 --- a/src/runtime/Codecs/RawProxyEncoder.cs +++ b/src/runtime/Codecs/RawProxyEncoder.cs @@ -6,7 +6,6 @@ namespace Python.Runtime.Codecs /// A .NET object encoder, that returns raw proxies (e.g. no conversion to Python types). /// You must inherit from this class and override . /// - [Obsolete(Util.UnstableApiMessage)] public class RawProxyEncoder: IPyObjectEncoder { public PyObject TryEncode(object value) diff --git a/src/runtime/Codecs/TupleCodecs.cs b/src/runtime/Codecs/TupleCodecs.cs index a9ae33fe0..0ed0f6674 100644 --- a/src/runtime/Codecs/TupleCodecs.cs +++ b/src/runtime/Codecs/TupleCodecs.cs @@ -5,7 +5,6 @@ namespace Python.Runtime.Codecs using System.Linq; using System.Reflection; - [Obsolete(Util.UnstableApiMessage)] public sealed class TupleCodec : IPyObjectEncoder, IPyObjectDecoder { TupleCodec() { } @@ -74,6 +73,11 @@ public bool TryDecode(PyObject pyObj, out T value) value = (T)EmptyTuple; return true; } + if (itemCount >= tupleCreate.Length) + { + value = default; + return false; + } var elements = new object[itemCount]; for (int itemIndex = 0; itemIndex < itemTypes.Length; itemIndex++) @@ -98,6 +102,11 @@ static bool Decode(PyObject tuple, out object value) value = EmptyTuple; return true; } + if (itemCount >= tupleCreate.Length) + { + value = default; + return false; + } var elements = new object[itemCount]; var itemTypes = new Type[itemCount]; value = null; diff --git a/src/runtime/CoreBaseTypeProvider.cs b/src/runtime/CoreBaseTypeProvider.cs new file mode 100644 index 000000000..0df6e877b --- /dev/null +++ b/src/runtime/CoreBaseTypeProvider.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; + +namespace Python.Runtime +{ + /// + /// Minimal Python base type provider + /// + public sealed class CoreBaseTypeProvider : IPythonBaseTypeProvider + { + public IEnumerable GetBaseTypes(Type type, IList existingBases) + { + if (type is null) + throw new ArgumentNullException(nameof(type)); + if (existingBases is null) + throw new ArgumentNullException(nameof(existingBases)); + if (existingBases.Count > 0) + throw new ArgumentException("To avoid confusion, this type provider requires the initial set of base types to be empty"); + + return new[] { new PyObject(GetBaseType(type)) }; + } + + static BorrowedReference GetBaseType(Type type) + { + if (type == typeof(Exception)) + return new BorrowedReference(Exceptions.Exception); + + return type.BaseType != null + ? ClassManager.GetClass(type.BaseType).Instance + : new BorrowedReference(Runtime.PyBaseObjectType); + } + + CoreBaseTypeProvider(){} + public static CoreBaseTypeProvider Instance { get; } = new CoreBaseTypeProvider(); + } +} diff --git a/src/runtime/CustomMarshaler.cs b/src/runtime/CustomMarshaler.cs index b51911816..8f50e2c3f 100644 --- a/src/runtime/CustomMarshaler.cs +++ b/src/runtime/CustomMarshaler.cs @@ -91,13 +91,13 @@ public static int GetUnicodeByteLength(IntPtr p) var len = 0; while (true) { - int c = Runtime._UCS == 2 + int c = Runtime.UCS == 2 ? Marshal.ReadInt16(p, len * 2) : Marshal.ReadInt32(p, len * 4); if (c == 0) { - return len * Runtime._UCS; + return len * Runtime.UCS; } checked { @@ -120,9 +120,7 @@ public static int GetUnicodeByteLength(IntPtr p) /// public static IntPtr Py3UnicodePy2StringtoPtr(string s) { - return Runtime.IsPython3 - ? Instance.MarshalManagedToNative(s) - : Marshal.StringToHGlobalAnsi(s); + return Instance.MarshalManagedToNative(s); } /// @@ -137,9 +135,7 @@ public static IntPtr Py3UnicodePy2StringtoPtr(string s) /// public static string PtrToPy3UnicodePy2String(IntPtr p) { - return Runtime.IsPython3 - ? PtrToStringUni(p) - : Marshal.PtrToStringAnsi(p); + return PtrToStringUni(p); } } @@ -163,7 +159,7 @@ public override IntPtr MarshalManagedToNative(object managedObj) } int totalStrLength = argv.Sum(arg => arg.Length + 1); - int memSize = argv.Length * IntPtr.Size + totalStrLength * Runtime._UCS; + int memSize = argv.Length * IntPtr.Size + totalStrLength * Runtime.UCS; IntPtr mem = Marshal.AllocHGlobal(memSize); try diff --git a/src/runtime/IPythonBaseTypeProvider.cs b/src/runtime/IPythonBaseTypeProvider.cs new file mode 100644 index 000000000..e7f641201 --- /dev/null +++ b/src/runtime/IPythonBaseTypeProvider.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace Python.Runtime +{ + public interface IPythonBaseTypeProvider + { + /// + /// Get Python types, that should be presented to Python as the base types + /// for the specified .NET type. + /// + IEnumerable GetBaseTypes(Type type, IList existingBases); + } +} diff --git a/src/runtime/InteropConfiguration.cs b/src/runtime/InteropConfiguration.cs new file mode 100644 index 000000000..2924f776c --- /dev/null +++ b/src/runtime/InteropConfiguration.cs @@ -0,0 +1,22 @@ +namespace Python.Runtime +{ + using System; + using System.Collections.Generic; + using Python.Runtime.Mixins; + + public sealed class InteropConfiguration + { + internal readonly PythonBaseTypeProviderGroup pythonBaseTypeProviders + = new PythonBaseTypeProviderGroup(); + public IList PythonBaseTypeProviders => this.pythonBaseTypeProviders; + + public static InteropConfiguration MakeDefault() => new InteropConfiguration + { + PythonBaseTypeProviders = + { + CoreBaseTypeProvider.Instance, + new CollectionMixinsProvider(new Lazy(() => Py.Import("clr._extras.collections"))), + }, + }; + } +} diff --git a/src/runtime/Mixins/CollectionMixinsProvider.cs b/src/runtime/Mixins/CollectionMixinsProvider.cs new file mode 100644 index 000000000..3a5d4e283 --- /dev/null +++ b/src/runtime/Mixins/CollectionMixinsProvider.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Python.Runtime.Mixins +{ + class CollectionMixinsProvider: IPythonBaseTypeProvider + { + readonly Lazy mixinsModule; + public CollectionMixinsProvider(Lazy mixinsModule) + { + this.mixinsModule = mixinsModule ?? throw new ArgumentNullException(nameof(mixinsModule)); + } + + public PyObject Mixins => this.mixinsModule.Value; + + public IEnumerable GetBaseTypes(Type type, IList existingBases) + { + if (type is null) + throw new ArgumentNullException(nameof(type)); + + if (existingBases is null) + throw new ArgumentNullException(nameof(existingBases)); + + foreach (PyObject existingBase in existingBases) + yield return existingBase; + + var interfaces = NewInterfaces(type).Select(GetDefinition).ToArray(); + + // dictionaries + if (interfaces.Contains(typeof(IDictionary<,>))) + { + yield return this.Mixins.GetAttr("MutableMappingMixin"); +#if NETSTANDARD + } else if (interfaces.Contains(typeof(IReadOnlyDictionary<,>))) + { + yield return this.Mixins.GetAttr("MappingMixin"); +#endif + } + + // item collections + if (interfaces.Contains(typeof(IList<>)) + || interfaces.Contains(typeof(System.Collections.IList))) + { + yield return this.Mixins.GetAttr("MutableSequenceMixin"); +#if NETSTANDARD + } else if (interfaces.Contains(typeof(IReadOnlyList<>))) + { + yield return this.Mixins.GetAttr("SequenceMixin"); +#endif + } else if (interfaces.Contains(typeof(ICollection<>)) + || interfaces.Contains(typeof(System.Collections.ICollection))) + { + yield return this.Mixins.GetAttr("CollectionMixin"); + } else if (interfaces.Contains(typeof(System.Collections.IEnumerable))) + { + yield return this.Mixins.GetAttr("IterableMixin"); + } + + // enumerators + if (interfaces.Contains(typeof(System.Collections.IEnumerator))) + { + yield return this.Mixins.GetAttr("IteratorMixin"); + } + } + + static Type[] NewInterfaces(Type type) + { + var result = type.GetInterfaces(); + return type.BaseType != null + ? result.Except(type.BaseType.GetInterfaces()).ToArray() + : result; + } + + static Type GetDefinition(Type type) + => type.IsGenericType ? type.GetGenericTypeDefinition() : type; + } +} diff --git a/src/runtime/Mixins/collections.py b/src/runtime/Mixins/collections.py new file mode 100644 index 000000000..a82032472 --- /dev/null +++ b/src/runtime/Mixins/collections.py @@ -0,0 +1,82 @@ +""" +Implements collections.abc for common .NET types +https://docs.python.org/3.6/library/collections.abc.html +""" + +import collections.abc as col + +class IteratorMixin(col.Iterator): + def close(self): + self.Dispose() + +class IterableMixin(col.Iterable): + pass + +class SizedMixin(col.Sized): + def __len__(self): return self.Count + +class ContainerMixin(col.Container): + def __contains__(self, item): return self.Contains(item) + +try: + abc_Collection = col.Collection +except AttributeError: + # Python 3.5- does not have collections.abc.Collection + abc_Collection = col.Container + +class CollectionMixin(SizedMixin, IterableMixin, ContainerMixin, abc_Collection): + pass + +class SequenceMixin(CollectionMixin, col.Sequence): + pass + +class MutableSequenceMixin(SequenceMixin, col.MutableSequence): + pass + +class MappingMixin(CollectionMixin, col.Mapping): + def __contains__(self, item): return self.ContainsKey(item) + def keys(self): return self.Keys + def items(self): return [(k,self.get(k)) for k in self.Keys] + def values(self): return self.Values + def __iter__(self): return self.Keys.__iter__() + def get(self, key, default=None): + existed, item = self.TryGetValue(key, None) + return item if existed else default + +class MutableMappingMixin(MappingMixin, col.MutableMapping): + _UNSET_ = object() + + def __delitem__(self, key): + self.Remove(key) + + def clear(self): + self.Clear() + + def pop(self, key, default=_UNSET_): + existed, item = self.TryGetValue(key, None) + if existed: + self.Remove(key) + return item + elif default == self._UNSET_: + raise KeyError(key) + else: + return default + + def setdefault(self, key, value=None): + existed, item = self.TryGetValue(key, None) + if existed: + return item + else: + self[key] = value + return value + + def update(self, items, **kwargs): + if isinstance(items, col.Mapping): + for key, value in items.items(): + self[key] = value + else: + for key, value in items: + self[key] = value + + for key, value in kwargs.items(): + self[key] = value diff --git a/src/runtime/NewReference.cs b/src/runtime/NewReference.cs index 6e66232d0..85ebe3244 100644 --- a/src/runtime/NewReference.cs +++ b/src/runtime/NewReference.cs @@ -15,6 +15,20 @@ ref struct NewReference public static implicit operator BorrowedReference(in NewReference reference) => new BorrowedReference(reference.pointer); + /// + /// Creates from a nullable . + /// Increments the reference count accordingly. + /// + [Pure] + public static NewReference FromNullable(BorrowedReference reference) + { + if (reference.IsNull) return default; + + IntPtr address = reference.DangerousGetAddress(); + Runtime.XIncref(address); + return DangerousFromPointer(address); + } + /// /// Returns wrapper around this reference, which now owns /// the pointer. Sets the original reference to null, as it no longer owns it. @@ -44,12 +58,41 @@ public void Dispose() public static NewReference DangerousFromPointer(IntPtr pointer) => new NewReference {pointer = pointer}; + /// + /// Creates from a raw pointer + /// and writes null to the original location. + /// + [Pure] + public static NewReference DangerousMoveFromPointer(ref IntPtr pointer) + { + var pointerValue = pointer; + pointer = IntPtr.Zero; + return DangerousFromPointer(pointerValue); + } + + public IntPtr DangerousMoveToPointer() + { + if (this.IsNull()) throw new NullReferenceException(); + + var result = this.pointer; + this.pointer = IntPtr.Zero; + return result; + } + [Pure] internal static IntPtr DangerousGetAddress(in NewReference reference) => IsNull(reference) ? throw new NullReferenceException() : reference.pointer; [Pure] internal static bool IsNull(in NewReference reference) => reference.pointer == IntPtr.Zero; + + // TODO: return some static type + internal StealingReference Steal() + { + var result = this.pointer; + this.pointer = IntPtr.Zero; + return StealingReference.DangerousFromPointer(result); + } } /// diff --git a/src/runtime/Platforms/INativeLibraryLoader.cs b/src/runtime/Platforms/INativeLibraryLoader.cs new file mode 100644 index 000000000..83393f128 --- /dev/null +++ b/src/runtime/Platforms/INativeLibraryLoader.cs @@ -0,0 +1,9 @@ +namespace Python.Runtime.Platforms { + using System; + + interface INativeLibraryLoader { + IntPtr LoadLibrary(string path); + IntPtr GetProcAddress(IntPtr library, string functionName); + void FreeLibrary(IntPtr library); + } +} diff --git a/src/runtime/Platforms/LinuxLibraryLoader.cs b/src/runtime/Platforms/LinuxLibraryLoader.cs new file mode 100644 index 000000000..1f7aea1ff --- /dev/null +++ b/src/runtime/Platforms/LinuxLibraryLoader.cs @@ -0,0 +1,40 @@ +namespace Python.Runtime.Platforms { + using System; + using System.IO; + using System.Runtime.InteropServices; + + sealed class LinuxLibraryLoader: UnixLibraryLoader { + public static LinuxLibraryLoader Instance { get; } = new LinuxLibraryLoader(); + + const int RTLD_GLOBAL = 0x100; + const string LinuxNativeDll = "libdl.so"; + public override IntPtr LoadLibrary(string path) { + path = File.Exists(path) ? path : $"lib{path}.so"; + return Linux.dlopen(path, RTLD_NOW | RTLD_GLOBAL); + } + + public override void FreeLibrary(IntPtr library) => Linux.dlclose(library); + + protected override IntPtr dlerror() => Linux.dlerror(); + + protected override IntPtr dlsym(IntPtr libraryHandle, string name) => Linux.dlsym(libraryHandle, name); + + protected override IntPtr RTLD_DEFAULT => IntPtr.Zero; + + static class Linux { + [DllImport(LinuxNativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + public static extern IntPtr dlopen(string fileName, int flags); + + [DllImport(LinuxNativeDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int dlclose(IntPtr handle); + + [DllImport(LinuxNativeDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr dlerror(); + + [DllImport(LinuxNativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IntPtr dlsym(IntPtr handle, string symbol); + } + + private LinuxLibraryLoader() { } + } +} diff --git a/src/runtime/Platforms/MacLibraryLoader.cs b/src/runtime/Platforms/MacLibraryLoader.cs new file mode 100644 index 000000000..dc1dce90d --- /dev/null +++ b/src/runtime/Platforms/MacLibraryLoader.cs @@ -0,0 +1,39 @@ +namespace Python.Runtime.Platforms { + using System; + using System.IO; + using System.Runtime.InteropServices; + + class MacLibraryLoader: UnixLibraryLoader { + public static MacLibraryLoader Instance { get; } = new MacLibraryLoader(); + const int RTLD_GLOBAL = 0x8; + public override IntPtr LoadLibrary(string path) { + path = File.Exists(path) ? path : $"lib{path}.dylib"; + return Mac.dlopen(path, RTLD_NOW | RTLD_GLOBAL); + } + + public override void FreeLibrary(IntPtr library) => Mac.dlclose(library); + + protected override IntPtr dlerror() => Mac.dlerror(); + + protected override IntPtr dlsym(IntPtr libraryHandle, string name) => Mac.dlsym(libraryHandle, name); + + protected override IntPtr RTLD_DEFAULT => new IntPtr(-2); + + static class Mac { + const string MacNativeDll = "/usr/lib/libSystem.dylib"; + [DllImport(MacNativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + public static extern IntPtr dlopen(String fileName, int flags); + + [DllImport(MacNativeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal static extern IntPtr dlsym(IntPtr handle, String symbol); + + [DllImport(MacNativeDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern int dlclose(IntPtr handle); + + [DllImport(MacNativeDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr dlerror(); + } + + private MacLibraryLoader() { } + } +} diff --git a/src/runtime/Platforms/UnixLibraryLoader.cs b/src/runtime/Platforms/UnixLibraryLoader.cs new file mode 100644 index 000000000..b7f11aaf1 --- /dev/null +++ b/src/runtime/Platforms/UnixLibraryLoader.cs @@ -0,0 +1,33 @@ +namespace Python.Runtime.Platforms { + using System; + using System.Runtime.InteropServices; + + abstract class UnixLibraryLoader: INativeLibraryLoader { + protected const int RTLD_NOW = 0x2; + public abstract IntPtr LoadLibrary(string path); + + public IntPtr GetProcAddress(IntPtr libraryHandle, string functionName) { + // look in the exe if dllHandle is NULL + if (libraryHandle == IntPtr.Zero) { + libraryHandle = RTLD_DEFAULT; + } + + // clear previous errors if any + IntPtr res, errPtr; + this.dlerror(); + res = this.dlsym(libraryHandle, functionName); + errPtr = this.dlerror(); + + if (errPtr != IntPtr.Zero) { + throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr)); + } + return res; + } + + protected abstract IntPtr dlerror(); + protected abstract IntPtr dlsym(IntPtr libraryHandle, string name); + protected abstract IntPtr RTLD_DEFAULT { get; } + + public abstract void FreeLibrary(IntPtr library); + } +} diff --git a/src/runtime/Platforms/WindowsLibraryLoader.cs b/src/runtime/Platforms/WindowsLibraryLoader.cs new file mode 100644 index 000000000..30905b776 --- /dev/null +++ b/src/runtime/Platforms/WindowsLibraryLoader.cs @@ -0,0 +1,22 @@ +namespace Python.Runtime.Platforms { + using System; + using System.Runtime.InteropServices; + + class WindowsLibraryLoader : INativeLibraryLoader { + public static WindowsLibraryLoader Instance { get; } = new WindowsLibraryLoader(); + public void FreeLibrary(IntPtr library) => WinFreeLibrary(library); + public IntPtr GetProcAddress(IntPtr library, string functionName) => WinGetProcAddress(library, functionName); + public IntPtr LoadLibrary(string path) => WinLoadLibrary(path); + + private const string WinNativeDll = "kernel32.dll"; + + [DllImport(WinNativeDll, EntryPoint = "LoadLibrary")] + public static extern IntPtr WinLoadLibrary(string dllToLoad); + [DllImport(WinNativeDll, EntryPoint = "GetProcAddress")] + public static extern IntPtr WinGetProcAddress(IntPtr hModule, string procedureName); + [DllImport(WinNativeDll, EntryPoint = "FreeLibrary")] + public static extern bool WinFreeLibrary(IntPtr hModule); + + private WindowsLibraryLoader() { } + } +} diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj index d753a5dff..cd181c982 100644 --- a/src/runtime/Python.Runtime.15.csproj +++ b/src/runtime/Python.Runtime.15.csproj @@ -1,154 +1,91 @@ - - + - net40;netstandard2.0 + netstandard2.0;net40 AnyCPU - DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 - net45 Python.Runtime Python.Runtime - pythonnet - 2.5.0 - true - false - Python.NET - Copyright (c) 2006-2020 the contributors of the Python.NET project - Python and CLR (.NET and Mono) cross-platform language interop - pythonnet - https://github.com/pythonnet/pythonnet/blob/master/LICENSE - https://github.com/pythonnet/pythonnet - git - - python interop dynamic dlr Mono pinvoke - https://raw.githubusercontent.com/pythonnet/pythonnet/master/src/console/python-clear.ico - https://pythonnet.github.io/ + LostTech.Python.Runtime + LICENSE + true + true + This software is part of Gradient: https://losttech.software/gradient.html + 3.0.5 + true + true + snupkg + false + false + false + false + false + false bin\ - false - $(OutputPath)\$(AssemblyName).xml - $(OutputPath)\$(TargetFramework)\$(AssemblyName).xml + $(OutputPath)\$(TargetFramework)\$(AssemblyName).xml 1591;NU1701 ..\..\ $(SolutionDir)\bin\ - $(PythonBuildDir)\$(TargetFramework)\ - 7.3 + $(PythonBuildDir)\$(TargetFramework)\ + 8.0 True ..\pythonnet.snk $(PYTHONNET_DEFINE_CONSTANTS) XPLAT $(DefineConstants);$(CustomDefineConstants);$(BaseDefineConstants); + $(DefineConstants);NETFX $(DefineConstants);NETSTANDARD $(DefineConstants);TRACE;DEBUG - $(NuGetPackageRoot)\microsoft.targetingpack.netframework.v4.5\1.0.1\lib\net45\ - $(PYTHONNET_PY2_VERSION) - PYTHON27 - $(PYTHONNET_PY3_VERSION) - PYTHON38 - $(PYTHONNET_WIN_DEFINE_CONSTANTS) - UCS2 - $(PYTHONNET_MONO_DEFINE_CONSTANTS) - UCS4;MONO_LINUX;PYTHON_WITH_PYMALLOC - $(PYTHONNET_INTEROP_FILE) - - - false - full - - - true - pdbonly - - - true - false - full - - - true - true - portable - - - $(DefineConstants);PYTHON2;$(Python2Version);$(PythonMonoDefineConstants) + $(PYTHONNET_MULTIRUNTIME_DEFINE_CONSTANTS) - - $(DefineConstants);PYTHON3;$(Python3Version);$(PythonMonoDefineConstants) - - - $(DefineConstants);PYTHON2;$(Python2Version);$(PythonMonoDefineConstants);FINALIZER_CHECK;TRACE;DEBUG - - - $(DefineConstants);PYTHON3;$(Python3Version);$(PythonMonoDefineConstants);FINALIZER_CHECK;TRACE;DEBUG - - - $(DefineConstants);PYTHON2;$(Python2Version);$(PythonWinDefineConstants) - - - $(DefineConstants);PYTHON3;$(Python3Version);$(PythonWinDefineConstants) - - - $(DefineConstants);PYTHON2;$(Python2Version);$(PythonWinDefineConstants);FINALIZER_CHECK;TRACE;DEBUG + + + $(DefineConstants);$(PythonMultiRuntimeDefineConstants);TRACE;DEBUG - - $(DefineConstants);PYTHON3;$(Python3Version);$(PythonWinDefineConstants);FINALIZER_CHECK;TRACE;DEBUG + + $(DefineConstants);$(PythonMultiRuntimeDefineConstants) - - - - - - + - + - + clr.py + + interop.py + + - - - - - - - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive + - - $(TargetPath) $(TargetDir)$(TargetName).pdb - - - - - - - - - diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj deleted file mode 100644 index 75f5e2fab..000000000 --- a/src/runtime/Python.Runtime.csproj +++ /dev/null @@ -1,186 +0,0 @@ - - - - Debug - AnyCPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271} - Library - Python.Runtime - Python.Runtime - bin\Python.Runtime.xml - bin\ - v4.0 - - 1591 - ..\..\ - $(SolutionDir)\bin\ - Properties - 7.3 - true - false - ..\pythonnet.snk - - - - - - PYTHON2;PYTHON27;UCS4 - true - pdbonly - - - PYTHON3;PYTHON38;UCS4 - true - pdbonly - - - true - PYTHON2;PYTHON27;UCS4;TRACE;DEBUG - false - full - - - true - PYTHON3;PYTHON38;UCS4;TRACE;DEBUG - false - full - - - PYTHON2;PYTHON27;UCS2 - true - pdbonly - - - PYTHON3;PYTHON38;UCS2 - true - pdbonly - - - true - PYTHON2;PYTHON27;UCS2;TRACE;DEBUG - false - full - - - true - PYTHON3;PYTHON38;UCS2;TRACE;DEBUG - false - full - - - - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - clr.py - - - - - $(TargetPath) - $(TargetDir)$(TargetName).pdb - - - - - - \ No newline at end of file diff --git a/src/runtime/PythonBaseTypeProviderGroup.cs b/src/runtime/PythonBaseTypeProviderGroup.cs new file mode 100644 index 000000000..201960f89 --- /dev/null +++ b/src/runtime/PythonBaseTypeProviderGroup.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Python.Runtime +{ + class PythonBaseTypeProviderGroup : List, IPythonBaseTypeProvider + { + public IEnumerable GetBaseTypes(Type type, IList existingBases) + { + if (type is null) + throw new ArgumentNullException(nameof(type)); + if (existingBases is null) + throw new ArgumentNullException(nameof(existingBases)); + + foreach (var provider in this) + { + existingBases = provider.GetBaseTypes(type, existingBases).ToList(); + } + + return existingBases; + } + } +} diff --git a/src/runtime/PythonEngineException.cs b/src/runtime/PythonEngineException.cs new file mode 100644 index 000000000..22059002a --- /dev/null +++ b/src/runtime/PythonEngineException.cs @@ -0,0 +1,15 @@ +namespace Python.Runtime { + using System; + using System.Runtime.Serialization; + + [Serializable] + public class PythonEngineException: Exception { + public PythonEngineException() : base() { } + + public PythonEngineException(string message) : base(message) { } + + public PythonEngineException(string message, Exception innerException) : base(message, innerException) { } + + protected PythonEngineException(SerializationInfo info, StreamingContext context):base(info, context) { } + } +} diff --git a/src/runtime/PythonReferenceComparer.cs b/src/runtime/PythonReferenceComparer.cs new file mode 100644 index 000000000..d1ef9611f --- /dev/null +++ b/src/runtime/PythonReferenceComparer.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; + +namespace Python.Runtime { + /// + /// Compares Python object wrappers by Python object references. + /// Similar to but for Python objects + /// + public sealed class PythonReferenceComparer : IEqualityComparer + { + public static PythonReferenceComparer Instance { get; } = new PythonReferenceComparer(); + public bool Equals(PyObject x, PyObject y) + { + return x?.Handle == y?.Handle; + } + + public int GetHashCode(PyObject obj) => obj.Handle.GetHashCode(); + + private PythonReferenceComparer() { } + } +} diff --git a/src/runtime/StealingReference.cs b/src/runtime/StealingReference.cs new file mode 100644 index 000000000..da4b67fda --- /dev/null +++ b/src/runtime/StealingReference.cs @@ -0,0 +1,23 @@ +namespace Python.Runtime +{ + using System; + using System.Diagnostics.Contracts; + + /// + /// Represents a reference to a Python object, that is being stolen by a C API. + /// + [NonCopyable] + ref struct StealingReference + { + IntPtr pointer; + + /// + /// Creates from a raw pointer + /// + [Pure] + public static StealingReference DangerousFromPointer(IntPtr pointer) + => new StealingReference { pointer = pointer}; + + public IntPtr DangerousGetAddressOrNull() => this.pointer; + } +} diff --git a/src/runtime/Util.cs b/src/runtime/Util.cs index eb21cddbb..d82f7693e 100644 --- a/src/runtime/Util.cs +++ b/src/runtime/Util.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Runtime.InteropServices; namespace Python.Runtime @@ -8,6 +9,9 @@ internal static class Util internal const string UnstableApiMessage = "This API is unstable, and might be changed or removed in the next minor release"; + internal const string UseOverloadWithReferenceTypes = + "This API is unsafe, and will be removed in the future. Use overloads working with *Reference types"; + internal static Int64 ReadCLong(IntPtr tp, int offset) { // On Windows, a C long is always 32 bits. @@ -39,5 +43,17 @@ internal static void WriteCLong(IntPtr type, int offset, Int64 flags) /// internal static IntPtr Coalesce(this IntPtr primary, IntPtr fallback) => primary == IntPtr.Zero ? fallback : primary; + + /// + /// Gets substring after last occurrence of + /// + internal static string AfterLast(this string str, char symbol) + { + if (str is null) + throw new ArgumentNullException(nameof(str)); + + int last = str.LastIndexOf(symbol); + return last >= 0 ? str.Substring(last + 1) : null; + } } } diff --git a/src/runtime/arrayobject.cs b/src/runtime/arrayobject.cs index 1ef318473..42a394cad 100644 --- a/src/runtime/arrayobject.cs +++ b/src/runtime/arrayobject.cs @@ -1,5 +1,7 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; namespace Python.Runtime { @@ -82,7 +84,7 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) return IntPtr.Zero; } - return Converter.ToPython(value, itemType); + return Converter.ToPython(value); } // Multi-dimensional arrays can be indexed a la: list[1, 2, 3]. @@ -125,7 +127,7 @@ public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) return IntPtr.Zero; } - return Converter.ToPython(value, itemType); + return Converter.ToPython(value); } @@ -244,5 +246,156 @@ public static int sq_contains(IntPtr ob, IntPtr v) return 0; } + + #region Buffer protocol + static int GetBuffer(BorrowedReference obj, out Py_buffer buffer, PyBUF flags) + { + buffer = default; + + if (flags == PyBUF.SIMPLE) + { + Exceptions.SetError(Exceptions.BufferError, "SIMPLE not implemented"); + return -1; + } + if ((flags & PyBUF.F_CONTIGUOUS) == PyBUF.F_CONTIGUOUS) + { + Exceptions.SetError(Exceptions.BufferError, "only C-contiguous supported"); + return -1; + } + var self = (Array)((CLRObject)GetManagedObject(obj)).inst; + Type itemType = self.GetType().GetElementType(); + + bool formatRequested = (flags & PyBUF.FORMATS) != 0; + string format = formatRequested ? GetFormat(itemType) : null; + if (formatRequested && format is null) + { + Exceptions.SetError(Exceptions.BufferError, "unsupported element type: " + itemType.Name); + return -1; + } + var gcHandle = GCHandle.Alloc(self, GCHandleType.Pinned); + + int itemSize = Marshal.SizeOf(itemType); + IntPtr[] shape = GetShape(self); + IntPtr[] strides = GetStrides(shape, itemSize); + buffer = new Py_buffer + { + buf = gcHandle.AddrOfPinnedObject(), + obj = Runtime.SelfIncRef(obj.DangerousGetAddress()), + len = (IntPtr)(self.LongLength*itemSize), + itemsize = (IntPtr)itemSize, + _readonly = false, + ndim = self.Rank, + format = format, + shape = ToUnmanaged(shape), + strides = (flags & PyBUF.STRIDES) == PyBUF.STRIDES ? ToUnmanaged(strides) : IntPtr.Zero, + suboffsets = IntPtr.Zero, + _internal = (IntPtr)gcHandle, + }; + + return 0; + } + static void ReleaseBuffer(BorrowedReference obj, ref Py_buffer buffer) + { + if (buffer._internal == IntPtr.Zero) return; + + UnmanagedFree(ref buffer.shape); + UnmanagedFree(ref buffer.strides); + UnmanagedFree(ref buffer.suboffsets); + + var gcHandle = (GCHandle)buffer._internal; + gcHandle.Free(); + buffer._internal = IntPtr.Zero; + } + + static IntPtr[] GetStrides(IntPtr[] shape, long itemSize) + { + var result = new IntPtr[shape.Length]; + result[shape.Length - 1] = new IntPtr(itemSize); + for (int dim = shape.Length - 2; dim >= 0; dim--) + { + itemSize *= shape[dim + 1].ToInt64(); + result[dim] = new IntPtr(itemSize); + } + return result; + } + static IntPtr[] GetShape(Array array) + { + var result = new IntPtr[array.Rank]; + for (int i = 0; i < result.Length; i++) + result[i] = (IntPtr)array.GetLongLength(i); + return result; + } + + static void UnmanagedFree(ref IntPtr address) + { + if (address == IntPtr.Zero) return; + + Marshal.FreeHGlobal(address); + address = IntPtr.Zero; + } + static unsafe IntPtr ToUnmanaged(T[] array) where T : unmanaged + { + IntPtr result = Marshal.AllocHGlobal(checked(Marshal.SizeOf(typeof(T)) * array.Length)); + fixed (T* ptr = array) + { + var @out = (T*)result; + for (int i = 0; i < array.Length; i++) + @out[i] = ptr[i]; + } + return result; + } + + static readonly Dictionary ItemFormats = new Dictionary + { + [typeof(byte)] = "B", + [typeof(sbyte)] = "b", + + [typeof(bool)] = "?", + + [typeof(short)] = "h", + [typeof(ushort)] = "H", + [typeof(int)] = "i", + [typeof(uint)] = "I", + [typeof(long)] = "q", + [typeof(ulong)] = "Q", + + [typeof(IntPtr)] = "n", + [typeof(UIntPtr)] = "N", + + // TODO: half = "e" + [typeof(float)] = "f", + [typeof(double)] = "d", + }; + + static string GetFormat(Type elementType) + => ItemFormats.TryGetValue(elementType, out string result) ? result : null; + + static readonly GetBufferProc getBufferProc = GetBuffer; + static readonly ReleaseBufferProc releaseBufferProc = ReleaseBuffer; + static readonly IntPtr BufferProcsAddress = AllocateBufferProcs(); + static IntPtr AllocateBufferProcs() + { + var procs = new PyBufferProcs + { + Get = Marshal.GetFunctionPointerForDelegate(getBufferProc), + Release = Marshal.GetFunctionPointerForDelegate(releaseBufferProc), + }; + IntPtr result = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PyBufferProcs))); + Marshal.StructureToPtr(procs, result, fDeleteOld: false); + return result; + } + #endregion + + public static void InitializeSlots(IntPtr type, ISet initialized) + { + var gcHandle = (GCHandle)Marshal.ReadIntPtr(type, TypeOffset.magic()); + var self = (ArrayObject)gcHandle.Target; + if (ItemFormats.ContainsKey(self.type.GetElementType()) + && initialized.Add(nameof(TypeOffset.tp_as_buffer))) + { + // TODO: only for unmanaged arrays + TypeManager.InitializeSlot(type, BufferProcsAddress, nameof(TypeOffset.tp_as_buffer)); + } + } } } diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs index 46909a370..335ec04d1 100644 --- a/src/runtime/assemblymanager.cs +++ b/src/runtime/assemblymanager.cs @@ -204,8 +204,10 @@ public static Assembly LoadAssembly(string name) { assembly = Assembly.Load(name); } - catch (Exception) + catch (FileNotFoundException) { } + catch (Exception e) { + Trace.WriteLine($"{nameof(AssemblyManager)} failed to load assembly {name}: {e}"); //if (!(e is System.IO.FileNotFoundException)) //{ // throw; @@ -228,8 +230,10 @@ public static Assembly LoadAssemblyPath(string name) { assembly = Assembly.LoadFrom(path); } - catch (Exception) + catch (FileNotFoundException) { } + catch (Exception e) { + Trace.WriteLine($"{nameof(AssemblyManager)} failed to load assembly {name}: {e}"); } } return assembly; @@ -255,8 +259,9 @@ public static Assembly LoadAssemblyFullPath(string name) { assembly = Assembly.LoadFrom(name); } - catch (Exception) + catch (Exception e) { + Trace.WriteLine($"{nameof(AssemblyManager)} failed to load assembly {name}: {e}"); } } } diff --git a/src/runtime/bufferinterface.cs b/src/runtime/bufferinterface.cs new file mode 100644 index 000000000..f744acf7d --- /dev/null +++ b/src/runtime/bufferinterface.cs @@ -0,0 +1,118 @@ +using System; +using System.Runtime.InteropServices; + +namespace Python.Runtime +{ + /* buffer interface */ + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct Py_buffer { + public IntPtr buf; + public IntPtr obj; /* owned reference */ + [MarshalAs(UnmanagedType.SysInt)] + public IntPtr len; + [MarshalAs(UnmanagedType.SysInt)] + public IntPtr itemsize; /* This is Py_ssize_t so it can be + pointed to by strides in simple case.*/ + [MarshalAs(UnmanagedType.Bool)] + public bool _readonly; + public int ndim; + [MarshalAs(UnmanagedType.LPStr)] + public string format; + public IntPtr shape; + public IntPtr strides; + public IntPtr suboffsets; + public IntPtr _internal; + } + + public enum BufferOrderStyle: byte + { + C = (byte)'C', + Fortran = (byte)'F', + EitherOne = (byte)'A', + } + + /* Flags for getting buffers */ + [Flags] + public enum PyBUF: int + { + /// + /// Simple buffer without shape strides and suboffsets + /// + SIMPLE = 0, + /// + /// Controls the field. If set, the exporter MUST provide a writable buffer or else report failure. Otherwise, the exporter MAY provide either a read-only or writable buffer, but the choice MUST be consistent for all consumers. + /// + WRITABLE = 0x0001, + /// + /// Controls the field. If set, this field MUST be filled in correctly. Otherwise, this field MUST be NULL. + /// + FORMATS = 0x0004, + /// + /// N-Dimensional buffer with shape + /// + ND = 0x0008, + /// + /// Buffer with strides and shape + /// + STRIDES = (0x0010 | ND), + /// + /// C-Contigous buffer with strides and shape + /// + C_CONTIGUOUS = (0x0020 | STRIDES), + /// + /// F-Contigous buffer with strides and shape + /// + F_CONTIGUOUS = (0x0040 | STRIDES), + /// + /// C or Fortran contigous buffer with strides and shape + /// + ANY_CONTIGUOUS = (0x0080 | STRIDES), + /// + /// Buffer with suboffsets (if needed) + /// + INDIRECT = (0x0100 | STRIDES), + /// + /// Writable C-Contigous buffer with shape + /// + CONTIG = (ND | WRITABLE), + /// + /// Readonly C-Contigous buffer with shape + /// + CONTIG_RO = (ND), + /// + /// Writable buffer with shape and strides + /// + STRIDED = (STRIDES | WRITABLE), + /// + /// Readonly buffer with shape and strides + /// + STRIDED_RO = (STRIDES), + /// + /// Writable buffer with shape, strides and format + /// + RECORDS = (STRIDES | WRITABLE | FORMATS), + /// + /// Readonly buffer with shape, strides and format + /// + RECORDS_RO = (STRIDES | FORMATS), + /// + /// Writable indirect buffer with shape, strides, format and suboffsets (if needed) + /// + FULL = (INDIRECT | WRITABLE | FORMATS), + /// + /// Readonly indirect buffer with shape, strides, format and suboffsets (if needed) + /// + FULL_RO = (INDIRECT | FORMATS), + } + + internal struct PyBufferProcs + { + public IntPtr Get; + public IntPtr Release; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + delegate int GetBufferProc(BorrowedReference obj, out Py_buffer buffer, PyBUF flags); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + delegate void ReleaseBufferProc(BorrowedReference obj, ref Py_buffer buffer); +} diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index 144bac9d3..3e11b3d3e 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -266,6 +266,7 @@ public static IntPtr tp_repr(IntPtr ob) //otherwise use the standard object.__repr__(inst) IntPtr args = Runtime.PyTuple_New(1); + Runtime.XIncref(ob); Runtime.PyTuple_SetItem(args, 0, ob); IntPtr reprFunc = Runtime.PyObject_GetAttrString(Runtime.PyBaseObjectType, "__repr__"); var output = Runtime.PyObject_Call(reprFunc, args, IntPtr.Zero); @@ -290,8 +291,9 @@ public static IntPtr tp_repr(IntPtr ob) /// public static void tp_dealloc(IntPtr ob) { - ManagedType self = GetManagedObject(ob); - IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.TypeDictOffset(self.tpHandle)); + var reference = new BorrowedReference(ob); + var self = GetManagedObject(reference, ObjectOffset.ReflectedObjectGCHandle(reference)); + IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.TypeDictOffset(self.Type)); if (dict != IntPtr.Zero) { Runtime.XDecref(dict); diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs index af16b1359..fc81591b9 100644 --- a/src/runtime/classderived.cs +++ b/src/runtime/classderived.cs @@ -59,7 +59,7 @@ internal ClassDerivedObject(Type tp) : base(tp) // return the pointer to the python object // (this indirectly calls ClassDerivedObject.ToPython) - return Converter.ToPython(obj, cls.GetType()); + return Converter.ToPython(obj); } public new static void tp_dealloc(IntPtr ob) @@ -74,7 +74,7 @@ internal ClassDerivedObject(Type tp) : base(tp) // So we don't call PyObject_GC_Del here and instead we set the python // reference to a weak reference so that the C# object can be collected. GCHandle gc = GCHandle.Alloc(self, GCHandleType.Weak); - Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc); + Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.InstanceGCHandle(self.Type), (IntPtr)gc); self.gcHandle.Free(); self.gcHandle = gc; } @@ -100,7 +100,7 @@ internal static IntPtr ToPython(IPythonDerivedType obj) if (Runtime.Refcount(self.pyHandle) == 1) { GCHandle gc = GCHandle.Alloc(self, GCHandleType.Normal); - Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc); + Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.InstanceGCHandle(self.Type), (IntPtr)gc); self.gcHandle.Free(); self.gcHandle = gc; @@ -248,7 +248,7 @@ internal static Type CreateDerivedType(string name, MethodAttributes.HideBySig, CallingConventions.Standard, typeof(void), - Type.EmptyTypes); + System.Type.EmptyTypes); ILGenerator il = methodBuilder.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("Finalize")); @@ -621,7 +621,7 @@ private static ModuleBuilder GetModuleBuilder(string assemblyName, string module /// This has to be public as it's called from methods on dynamically built classes /// potentially in other assemblies. /// - public class PythonDerivedType + public static class PythonDerivedType { /// /// This is the implementation of the overridden methods in the derived @@ -660,7 +660,7 @@ public static T InvokeMethod(IPythonDerivedType obj, string methodName, strin var pyargs = new PyObject[args.Length]; for (var i = 0; i < args.Length; ++i) { - pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i])); + pyargs[i] = new PyObject(Converter.ToPython(args[i])); disposeList.Add(pyargs[i]); } @@ -722,7 +722,7 @@ public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, s var pyargs = new PyObject[args.Length]; for (var i = 0; i < args.Length; ++i) { - pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i])); + pyargs[i] = new PyObject(Converter.ToPython(args[i])); disposeList.Add(pyargs[i]); } @@ -795,7 +795,7 @@ public static void InvokeSetProperty(IPythonDerivedType obj, string propertyN { Runtime.XIncref(self.pyHandle); using (var pyself = new PyObject(self.pyHandle)) - using (var pyvalue = new PyObject(Converter.ToPythonImplicit(value))) + using (var pyvalue = new PyObject(Converter.ToPython(value))) { pyself.SetAttr(propertyName, pyvalue); } @@ -820,7 +820,7 @@ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, objec try { // create the python object - IntPtr type = TypeManager.GetTypeHandle(obj.GetType()); + BorrowedReference type = TypeManager.GetTypeHandle(obj.GetType()); self = new CLRObject(obj, type); // set __pyobj__ to self and deref the python object which will allow this @@ -877,7 +877,7 @@ public static void Finalize(IPythonDerivedType obj) // the C# object is being destroyed which must mean there are no more // references to the Python object as well so now we can dealloc the // python object. - IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.TypeDictOffset(self.tpHandle)); + IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.TypeDictOffset(self.Type)); if (dict != IntPtr.Zero) { Runtime.XDecref(dict); diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs index 0b084a49d..43168e598 100644 --- a/src/runtime/classmanager.cs +++ b/src/runtime/classmanager.cs @@ -132,12 +132,13 @@ private static void InitClassBase(Type type, ClassBase impl) // managed type, filling the Python type slots with thunks that // point to the managed methods providing the implementation. - - IntPtr tp = TypeManager.GetTypeHandle(impl, type); - impl.tpHandle = tp; + BorrowedReference tp = TypeManager.GetTypeHandle(impl, type); + Exceptions.ErrorCheck(tp); + #warning this overwrites existing value when type == typeof(object). Why ? Lifetimes ??? + impl.tpHandle = tp.DangerousGetAddress(); // Finally, initialize the class __dict__ and return the object. - IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict); + IntPtr dict = Marshal.ReadIntPtr(tp.DangerousGetAddress(), TypeOffset.tp_dict); IDictionaryEnumerator iter = info.members.GetEnumerator(); diff --git a/src/runtime/classobject.cs b/src/runtime/classobject.cs index 83d761fd0..0003066d9 100644 --- a/src/runtime/classobject.cs +++ b/src/runtime/classobject.cs @@ -1,5 +1,9 @@ using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; namespace Python.Runtime { @@ -294,6 +298,30 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) if (cb.type != typeof(Delegate)) { + var calls = cb.type.GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(m => m.Name == "__call__") + .ToList(); + if (calls.Count > 0) { + var callBinder = new MethodBinder(); + foreach (MethodInfo call in calls) { + callBinder.AddMethod(call); + } + return callBinder.Invoke(ob, args, kw); + } + + using var super = new PyObject(new BorrowedReference(Runtime.PySuper_Type)); + using var self = new PyObject(new BorrowedReference(ob)); + using var none = new PyObject(new BorrowedReference(Runtime.PyNone)); + foreach (IntPtr rawTypePointer in GetTypesWithPythonBasesInHierarchy(tp)) { + using var managedTypeDerivingFromPython = new PyObject(new BorrowedReference(rawTypePointer)); + using var @base = super.Invoke(managedTypeDerivingFromPython, self); + using var call = @base.GetAttrOrElse("__call__", none); + + if (call.Handle == Runtime.PyNone) continue; + + return Runtime.PyObject_Call(call.Handle, args, kw); + } + Exceptions.SetError(Exceptions.TypeError, "object is not callable"); return IntPtr.Zero; } @@ -309,5 +337,62 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) var binder = new MethodBinder(method); return binder.Invoke(ob, args, kw); } + + /// + /// Enumerate Python base types of the specified .NET type in mro order. + /// + internal static IEnumerable GetPythonBases(IntPtr tp) { + Debug.Assert(IsManagedType(tp)); + do { + IntPtr bases = Marshal.ReadIntPtr(tp, TypeOffset.tp_bases); + if (bases != IntPtr.Zero) { + long baseCount = Runtime.PyTuple_Size(bases); + for (long baseIndex = 0; baseIndex < baseCount; baseIndex++) { + IntPtr @base = Runtime.PyTuple_GetItem(bases, baseIndex); + if (IsManagedType(@base)) { + foreach (IntPtr innerBase in GetPythonBases(@base)) { + yield return innerBase; + } + } else { + yield return @base; + } + } + yield break; + } + + tp = Marshal.ReadIntPtr(tp, TypeOffset.tp_base); + } while (IsManagedType(tp)); + + yield return tp; + } + + internal static IEnumerable GetTypesWithPythonBasesInHierarchy(IntPtr tp) { + Debug.Assert(IsManagedType(tp)); + + var candidateQueue = new Queue(); + candidateQueue.Enqueue(tp); + while (candidateQueue.Count > 0) { + tp = candidateQueue.Dequeue(); + IntPtr bases = Marshal.ReadIntPtr(tp, TypeOffset.tp_bases); + if (bases != IntPtr.Zero) { + long baseCount = Runtime.PyTuple_Size(bases); + bool hasPythonBase = false; + for (long baseIndex = 0; baseIndex < baseCount; baseIndex++) { + IntPtr @base = Runtime.PyTuple_GetItem(bases, baseIndex); + if (IsManagedType(@base)) { + candidateQueue.Enqueue(@base); + } else { + hasPythonBase = true; + } + } + + if (hasPythonBase) yield return tp; + } else { + tp = Marshal.ReadIntPtr(tp, TypeOffset.tp_base); + if (tp != IntPtr.Zero && IsManagedType(tp)) + candidateQueue.Enqueue(tp); + } + } + } } } diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs index 5c7ad7891..058e042b1 100644 --- a/src/runtime/clrobject.cs +++ b/src/runtime/clrobject.cs @@ -1,43 +1,47 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; namespace Python.Runtime { + [DebuggerDisplay("clrO: {inst}")] internal class CLRObject : ManagedType { internal object inst; - internal CLRObject(object ob, IntPtr tp) + internal CLRObject(object ob, BorrowedReference tp) { - IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); + NewReference py = Runtime.PyType_GenericAlloc(tp, 0); - long flags = Util.ReadCLong(tp, TypeOffset.tp_flags); + var flags = (TypeFlags)Util.ReadCLong(tp.DangerousGetAddress(), TypeOffset.tp_flags); if ((flags & TypeFlags.Subclass) != 0) { - IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.TypeDictOffset(tp)); + IntPtr dict = Marshal.ReadIntPtr(py.DangerousGetAddress(), ObjectOffset.TypeDictOffset(tp)); if (dict == IntPtr.Zero) { dict = Runtime.PyDict_New(); - Marshal.WriteIntPtr(py, ObjectOffset.TypeDictOffset(tp), dict); + Marshal.WriteIntPtr(py.DangerousGetAddress(), ObjectOffset.TypeDictOffset(tp), dict); } } + // it is safe to "borrow" type pointer, because we also own a reference to an instance + tpHandle = tp.DangerousGetAddress(); + pyHandle = py.DangerousMoveToPointer(); GCHandle gc = GCHandle.Alloc(this); - Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc); - tpHandle = tp; - pyHandle = py; + int gcHandleOffset = ObjectOffset.ReflectedObjectGCHandle(this.Instance); + Marshal.WriteIntPtr(pyHandle, gcHandleOffset, (IntPtr)gc); gcHandle = gc; inst = ob; // Fix the BaseException args (and __cause__ in case of Python 3) // slot if wrapping a CLR exception - Exceptions.SetArgsAndCause(py); + Exceptions.SetArgsAndCause(pyHandle); } static CLRObject GetInstance(object ob, IntPtr pyType) { - return new CLRObject(ob, pyType); + return new CLRObject(ob, new BorrowedReference(pyType)); } @@ -68,5 +72,19 @@ internal static IntPtr GetInstHandle(object ob) CLRObject co = GetInstance(ob); return co.pyHandle; } + + /// + /// Creates proxy for the given object, + /// and returns a to it. + /// + internal static NewReference MakeNewReference(object obj) + { + if (obj is null) throw new ArgumentNullException(nameof(obj)); + + // TODO: CLRObject currently does not have Dispose or finalizer which might change in the future + IntPtr handle = GetInstHandle(obj); + DebugUtil.AssertRefcount(handle); + return NewReference.DangerousFromPointer(handle); + } } } diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs index 3908628b9..c052a0078 100644 --- a/src/runtime/constructorbinding.cs +++ b/src/runtime/constructorbinding.cs @@ -26,11 +26,10 @@ internal class ConstructorBinding : ExtensionType private ConstructorBinder ctorBinder; private IntPtr repr; - public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) + public ConstructorBinding(Type type, BorrowedReference pyTypeHndl, ConstructorBinder ctorBinder) { this.type = type; - Runtime.XIncref(pyTypeHndl); - this.pyTypeHndl = pyTypeHndl; + this.pyTypeHndl = pyTypeHndl.DangerousIncRefOrNull(); this.ctorBinder = ctorBinder; repr = IntPtr.Zero; } @@ -41,7 +40,7 @@ public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBi /// of a .Overloads[pyTypeOrType...] syntax to allow explicit ctor overload /// selection. /// - /// PyObject* to a Constructors wrapper + /// PyObject* to a Constructors wrapper /// /// the instance that the attribute was accessed through, /// or None when the attribute is accessed through the owner @@ -60,9 +59,10 @@ public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBi /// the attribute was accessed through, or None when the attribute is accessed through the owner. /// This method should return the (computed) attribute value or raise an AttributeError exception. /// - public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) + public static IntPtr tp_descr_get(IntPtr opRaw, IntPtr instance, IntPtr owner) { - var self = (ConstructorBinding)GetManagedObject(op); + var op = new BorrowedReference(opRaw); + var self = GetManagedObject(op); if (self == null) { return IntPtr.Zero; @@ -87,9 +87,10 @@ public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) /// Return element of o corresponding to the object key or NULL on failure. /// This is the equivalent of the Python expression o[key]. /// - public static IntPtr mp_subscript(IntPtr op, IntPtr key) + public static IntPtr mp_subscript(IntPtr opRaw, IntPtr key) { - var self = (ConstructorBinding)GetManagedObject(op); + var op = new BorrowedReference(opRaw); + var self = GetManagedObject(op); Type[] types = Runtime.PythonArgsToTypeArray(key); if (types == null) @@ -111,9 +112,10 @@ public static IntPtr mp_subscript(IntPtr op, IntPtr key) /// /// ConstructorBinding __repr__ implementation [borrowed from MethodObject]. /// - public static IntPtr tp_repr(IntPtr ob) + public static IntPtr tp_repr(IntPtr obRaw) { - var self = (ConstructorBinding)GetManagedObject(ob); + var ob = new BorrowedReference(obRaw); + var self = GetManagedObject(ob); if (self.repr != IntPtr.Zero) { Runtime.XIncref(self.repr); @@ -140,9 +142,10 @@ public static IntPtr tp_repr(IntPtr ob) /// /// ConstructorBinding dealloc implementation. /// - public new static void tp_dealloc(IntPtr ob) + public new static void tp_dealloc(IntPtr obRaw) { - var self = (ConstructorBinding)GetManagedObject(ob); + var ob = new BorrowedReference(obRaw); + var self = GetManagedObject(ob); Runtime.XDecref(self.repr); Runtime.XDecref(self.pyTypeHndl); ExtensionType.FinalizeObject(self); diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index 3add8aba0..7e6e84d7a 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -1,11 +1,11 @@ using System; using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; -using System.Reflection; using System.Runtime.InteropServices; using System.Security; -using System.ComponentModel; namespace Python.Runtime { @@ -19,18 +19,18 @@ private Converter() { } - private static NumberFormatInfo nfi; - private static Type objectType; - private static Type stringType; - private static Type singleType; - private static Type doubleType; - private static Type decimalType; - private static Type int16Type; - private static Type int32Type; - private static Type int64Type; - private static Type flagsType; - private static Type boolType; - private static Type typeType; + private static readonly NumberFormatInfo nfi; + private static readonly Type objectType; + private static readonly Type stringType; + private static readonly Type singleType; + private static readonly Type doubleType; + private static readonly Type decimalType; + private static readonly Type int16Type; + private static readonly Type int32Type; + private static readonly Type int64Type; + private static readonly Type flagsType; + private static readonly Type boolType; + private static readonly Type typeType; static Converter() { @@ -49,6 +49,11 @@ static Converter() } + /// + /// Given a builtin Python type, return the corresponding CLR type. + /// + internal static Type GetTypeByAlias(BorrowedReference type) + => GetTypeByAlias(type.DangerousGetAddress()); /// /// Given a builtin Python type, return the corresponding CLR type. /// @@ -75,7 +80,9 @@ internal static Type GetTypeByAlias(IntPtr op) return null; } - internal static IntPtr GetPythonTypeByAlias(Type op) + internal static BorrowedReference GetPythonTypeByAlias(Type type) + => new BorrowedReference(GetPythonTypeByAliasUnsafe(type)); + static IntPtr GetPythonTypeByAliasUnsafe(Type op) { if (op == stringType) return Runtime.PyUnicodeType; @@ -86,9 +93,6 @@ internal static IntPtr GetPythonTypeByAlias(Type op) if (op == int32Type) return Runtime.PyIntType; - if (op == int64Type && Runtime.IsPython2) - return Runtime.PyLongType; - if (op == int64Type) return Runtime.PyIntType; @@ -104,27 +108,22 @@ internal static IntPtr GetPythonTypeByAlias(Type op) return IntPtr.Zero; } - /// /// Return a Python object for the given native object, converting /// basic types (string, int, etc.) into equivalent Python objects. /// This always returns a new reference. Note that the System.Decimal /// type has no Python equivalent and converts to a managed instance. /// - internal static IntPtr ToPython(T value) - { - return ToPython(value, typeof(T)); - } - - internal static IntPtr ToPython(object value, Type type) + internal static IntPtr ToPython(object? value) { - if (value is PyObject) + if (value is PyObject pyObject) { - IntPtr handle = ((PyObject)value).Handle; + IntPtr handle = pyObject.Handle; Runtime.XIncref(handle); return handle; } - IntPtr result = IntPtr.Zero; + + IntPtr result; // Null always converts to None in Python. @@ -135,7 +134,8 @@ internal static IntPtr ToPython(object value, Type type) return result; } - if (Type.GetTypeCode(type) == TypeCode.Object && value.GetType() != typeof(object)) { + var type = value.GetType(); + if (EncodersAllowed(type)) { var encoded = PyObjectConversions.TryEncode(value, type); if (encoded != null) { result = encoded.Handle; @@ -144,22 +144,6 @@ internal static IntPtr ToPython(object value, Type type) } } - if (value is IList && !(value is INotifyPropertyChanged) && value.GetType().IsGenericType) - { - using (var resultlist = new PyList()) - { - foreach (object o in (IEnumerable)value) - { - using (var p = new PyObject(ToPython(o, o?.GetType()))) - { - resultlist.Append(p); - } - } - Runtime.XIncref(resultlist.Handle); - return resultlist.Handle; - } - } - // it the type is a python subclass of a managed type then return the // underlying python object rather than construct a new wrapper object. var pyderived = value as IPythonDerivedType; @@ -176,12 +160,6 @@ internal static IntPtr ToPython(object value, Type type) #endif } - // hmm - from Python, we almost never care what the declared - // type is. we'd rather have the object bound to the actual - // implementing class. - - type = value.GetType(); - TypeCode tc = Type.GetTypeCode(type); switch (tc) @@ -240,21 +218,6 @@ internal static IntPtr ToPython(object value, Type type) return Runtime.PyLong_FromUnsignedLongLong((ulong)value); default: - if (value is IEnumerable) - { - using (var resultlist = new PyList()) - { - foreach (object o in (IEnumerable)value) - { - using (var p = new PyObject(ToPython(o, o?.GetType()))) - { - resultlist.Append(p); - } - } - Runtime.XIncref(resultlist.Handle); - return resultlist.Handle; - } - } result = CLRObject.GetInstHandle(value, type); return result; } @@ -262,22 +225,11 @@ internal static IntPtr ToPython(object value, Type type) /// - /// In a few situations, we don't have any advisory type information - /// when we want to convert an object to Python. + /// Return a managed object for the given Python object, taking funny + /// byref types into account. /// - internal static IntPtr ToPythonImplicit(object value) - { - if (value == null) - { - IntPtr result = Runtime.PyNone; - Runtime.XIncref(result); - return result; - } - - return ToPython(value, objectType); - } - - + internal static bool ToManaged(BorrowedReference value, Type type, out object result, bool setError) + => ToManaged(value.DangerousGetAddress(), type: type, out result, setError: setError); /// /// Return a managed object for the given Python object, taking funny /// byref types into account. @@ -352,11 +304,6 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return ToArray(value, obType, out result, setError); } - if (obType.IsEnum) - { - return ToEnum(value, obType, out result, setError); - } - // Conversion to 'Object' is done based on some reasonable default // conversions (Python string -> managed string, Python int -> Int32 etc.). if (obType == objectType) @@ -387,17 +334,12 @@ internal static bool ToManagedValue(IntPtr value, Type obType, } // give custom codecs a chance to take over conversion of sequences - IntPtr pyType = Runtime.PyObject_TYPE(value); - if (PyObjectConversions.TryDecode(value, pyType, obType, out result)) + var pyType = new BorrowedReference(Runtime.PyObject_TYPE(value)); + if (PyObjectConversions.TryDecode(new BorrowedReference(value), pyType, obType, out result)) { return true; } - if (Runtime.PySequence_Check(value)) - { - return ToArray(value, typeof(object[]), out result, setError); - } - Runtime.XIncref(value); // PyObject() assumes ownership result = new PyObject(value); return true; @@ -436,12 +378,6 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return true; } - if (value == Runtime.PyListType || value == Runtime.PyTupleType) - { - result = typeof(object[]); - return true; - } - if (setError) { Exceptions.SetError(Exceptions.TypeError, "value cannot be converted to Type"); @@ -450,20 +386,26 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return false; } - TypeCode typeCode = Type.GetTypeCode(obType); - if (typeCode == TypeCode.Object) + if (EncodersAllowed(obType)) { - IntPtr pyType = Runtime.PyObject_TYPE(value); - if (PyObjectConversions.TryDecode(value, pyType, obType, out result)) + var pyType = new BorrowedReference(Runtime.PyObject_TYPE(value)); + if (PyObjectConversions.TryDecode(new BorrowedReference(value), pyType, obType, out result)) { return true; } } + if (obType.IsEnum) + { + return ToEnum(value, obType, out result, setError); + } + return ToPrimitive(value, obType, out result, setError); } - internal delegate bool TryConvertFromPythonDelegate(IntPtr pyObj, out object result); + static bool EncodersAllowed(Type type) => !type.IsPrimitive && type != typeof(string); + + internal delegate bool TryConvertFromPythonDelegate(BorrowedReference pyObj, out object result); /// /// Convert a Python value to an instance of a primitive managed type. @@ -489,62 +431,34 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo case TypeCode.Int32: // Trickery to support 64-bit platforms. - if (Runtime.IsPython2 && Runtime.Is32Bit) + op = Runtime.PyNumber_Long(value); + if (op == IntPtr.Zero) { - op = Runtime.PyNumber_Int(value); - - // As of Python 2.3, large ints magically convert :( - if (Runtime.PyLong_Check(op)) + Exceptions.Clear(); + if (Exceptions.ExceptionMatches(overflow)) { - Runtime.XDecref(op); goto overflow; } - - if (op == IntPtr.Zero) - { - if (Exceptions.ExceptionMatches(overflow)) - { - goto overflow; - } - goto type_error; - } - ival = (int)Runtime.PyInt_AsLong(op); - Runtime.XDecref(op); - result = ival; - return true; + goto type_error; } - else // Python3 always use PyLong API + long ll = (long)Runtime.PyLong_AsLongLong(op); + Runtime.XDecref(op); + if (ll == -1 && Exceptions.ErrorOccurred()) { - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) - { - Exceptions.Clear(); - if (Exceptions.ExceptionMatches(overflow)) - { - goto overflow; - } - goto type_error; - } - long ll = (long)Runtime.PyLong_AsLongLong(op); - Runtime.XDecref(op); - if (ll == -1 && Exceptions.ErrorOccurred()) - { - goto overflow; - } - if (ll > Int32.MaxValue || ll < Int32.MinValue) - { - goto overflow; - } - result = (int)ll; - return true; + goto overflow; + } + if (ll > Int32.MaxValue || ll < Int32.MinValue) + { + goto overflow; } + result = (int)ll; + return true; case TypeCode.Boolean: result = Runtime.PyObject_IsTrue(value) != 0; return true; case TypeCode.Byte: -#if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) @@ -555,18 +469,6 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo } goto type_error; } -#elif PYTHON2 - if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) - { - if (Runtime.PyString_Size(value) == 1) - { - op = Runtime.PyString_AsString(value); - result = (byte)Marshal.ReadByte(op); - return true; - } - goto type_error; - } -#endif op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) @@ -589,7 +491,6 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo return true; case TypeCode.SByte: -#if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) @@ -600,18 +501,6 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo } goto type_error; } -#elif PYTHON2 - if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) - { - if (Runtime.PyString_Size(value) == 1) - { - op = Runtime.PyString_AsString(value); - result = (sbyte)Marshal.ReadByte(op); - return true; - } - goto type_error; - } -#endif op = Runtime.PyNumber_Int(value); if (op == IntPtr.Zero) @@ -634,7 +523,6 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo return true; case TypeCode.Char: -#if PYTHON3 if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) { if (Runtime.PyBytes_Size(value) == 1) @@ -645,18 +533,6 @@ private static bool ToPrimitive(IntPtr value, Type obType, out object result, bo } goto type_error; } -#elif PYTHON2 - if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) - { - if (Runtime.PyString_Size(value) == 1) - { - op = Runtime.PyString_AsString(value); - result = (char)Marshal.ReadByte(op); - return true; - } - goto type_error; - } -#endif else if (Runtime.PyObject_TypeCheck(value, Runtime.PyUnicodeType)) { if (Runtime.PyUnicode_GetSize(value) == 1) @@ -885,10 +761,15 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s bool IsSeqObj = Runtime.PySequence_Check(value); var len = IsSeqObj ? Runtime.PySequence_Size(value) : -1; + if (IsSeqObj && len < 0) + { + // for the sequences, that explicitly deny calling __len__() + Exceptions.Clear(); + } - IntPtr IterObject = Runtime.PyObject_GetIter(value); + var IterObject = Runtime.PyObject_GetIter(new BorrowedReference(value)); - if(IterObject==IntPtr.Zero) { + if(IterObject.IsNull()) { if (setError) { SetConversionError(value, obType); @@ -900,24 +781,27 @@ private static bool ToArray(IntPtr value, Type obType, out object result, bool s var listType = typeof(List<>); var constructedListType = listType.MakeGenericType(elementType); - IList list = IsSeqObj ? (IList) Activator.CreateInstance(constructedListType, new Object[] {(int) len}) : - (IList) Activator.CreateInstance(constructedListType); - IntPtr item; + IList list = IsSeqObj && len > 0 + ? (IList) Activator.CreateInstance(constructedListType, args: (int)len) + : (IList) Activator.CreateInstance(constructedListType); + NewReference item; - while ((item = Runtime.PyIter_Next(IterObject)) != IntPtr.Zero) + while (!(item = Runtime.PyIter_Next(IterObject)).IsNull()) { - object obj = null; + try + { + if (!ToManaged(item.DangerousGetAddress(), elementType, out object obj, true)) + { + return false; + } - if (!Converter.ToManaged(item, elementType, out obj, true)) + list.Add(obj); + } finally { - Runtime.XDecref(item); - return false; + item.Dispose(); } - - list.Add(obj); - Runtime.XDecref(item); } - Runtime.XDecref(IterObject); + IterObject.Dispose(); items = Array.CreateInstance(elementType, list.Count); list.CopyTo(items, 0); @@ -965,7 +849,7 @@ public static class ConverterExtension { public static PyObject ToPython(this object o) { - return new PyObject(Converter.ToPython(o, o?.GetType())); + return new PyObject(Converter.ToPython(o)); } } } diff --git a/src/runtime/converterextensions.cs b/src/runtime/converterextensions.cs index 667fc6f00..7f911966b 100644 --- a/src/runtime/converterextensions.cs +++ b/src/runtime/converterextensions.cs @@ -5,12 +5,13 @@ namespace Python.Runtime using System.Collections.Generic; using System.Linq; using System.Reflection; + using System.Runtime.CompilerServices; + using Python.Runtime.Codecs; /// /// Defines conversion to CLR types (unmarshalling) /// - [Obsolete(Util.UnstableApiMessage)] public interface IPyObjectDecoder { /// @@ -30,7 +31,6 @@ public interface IPyObjectDecoder /// /// Defines conversion from CLR objects into Python objects (e.g. ) (marshalling) /// - [Obsolete(Util.UnstableApiMessage)] public interface IPyObjectEncoder { /// @@ -47,7 +47,6 @@ public interface IPyObjectEncoder /// This class allows to register additional marshalling codecs. /// Python.NET will pick suitable encoder/decoder registered first /// - [Obsolete(Util.UnstableApiMessage)] public static class PyObjectConversions { static readonly DecoderGroup decoders = new DecoderGroup(); @@ -110,37 +109,51 @@ static IPyObjectEncoder[] GetEncoders(Type type) #region Decoding static readonly ConcurrentDictionary pythonToClr = new ConcurrentDictionary(); - internal static bool TryDecode(IntPtr pyHandle, IntPtr pyType, Type targetType, out object result) + internal static bool TryDecode(BorrowedReference obj, BorrowedReference objType, Type targetType, out object result) { - if (pyHandle == IntPtr.Zero) throw new ArgumentNullException(nameof(pyHandle)); - if (pyType == IntPtr.Zero) throw new ArgumentNullException(nameof(pyType)); + if (obj.IsNull) throw new ArgumentNullException(nameof(obj)); + if (objType.IsNull) throw new ArgumentNullException(nameof(objType)); if (targetType == null) throw new ArgumentNullException(nameof(targetType)); - var decoder = pythonToClr.GetOrAdd(new TypePair(pyType, targetType), pair => GetDecoder(pair.PyType, pair.ClrType)); + var decoder = pythonToClr.GetOrAdd(new TypePair(objType.DangerousGetAddress(), targetType), pair => GetDecoder(pair.PyType, pair.ClrType)); result = null; if (decoder == null) return false; - return decoder.Invoke(pyHandle, out result); + try + { + return decoder.Invoke(obj, out result); + } catch (TargetInvocationException invocationException) + { + throw invocationException.InnerException.Rethrow(); + } } static Converter.TryConvertFromPythonDelegate GetDecoder(IntPtr sourceType, Type targetType) { + RuntimeHelpers.EnsureSufficientExecutionStack(); + IPyObjectDecoder decoder; - using (var pyType = new PyObject(Runtime.SelfIncRef(sourceType))) + var pyType = new PyObject(Runtime.SelfIncRef(sourceType)); + lock (decoders) { - lock (decoders) - { - decoder = decoders.GetDecoder(pyType, targetType); - if (decoder == null) return null; - } + decoder = decoders.GetDecoder(pyType, targetType); + if (decoder == null) return null; } var decode = genericDecode.MakeGenericMethod(targetType); - bool TryDecode(IntPtr pyHandle, out object result) + bool TryDecode(BorrowedReference pyHandle, out object result) { - var pyObj = new PyObject(Runtime.SelfIncRef(pyHandle)); + var pyObj = new PyObject(pyHandle); var @params = new object[] { pyObj, null }; - bool success = (bool)decode.Invoke(decoder, @params); + bool success = false; + try + { + success = (bool)decode.Invoke(decoder, @params); + } catch (TargetInvocationException invocationException) + { + throw invocationException.InnerException.Rethrow(); + } + if (!success) { pyObj.Dispose(); diff --git a/src/runtime/debughelper.cs b/src/runtime/debughelper.cs index 3fe9ee5bb..89bdd23f9 100644 --- a/src/runtime/debughelper.cs +++ b/src/runtime/debughelper.cs @@ -11,7 +11,7 @@ namespace Python.Runtime /// The methods are only executed when the DEBUG flag is set. Otherwise /// they are automagically hidden by the compiler and silently suppressed. /// - internal class DebugUtil + internal static class DebugUtil { [Conditional("DEBUG")] public static void Print(string msg, params IntPtr[] args) @@ -137,5 +137,27 @@ public static void PrintHexBytes(byte[] bytes) Console.WriteLine(); } } + + [Conditional("DEBUG")] + public static void EnsureGIL() + { + Debug.Assert(HaveInterpreterLock() != false, "GIL must be acquired"); + } + + public static bool? HaveInterpreterLock() + { + // not supported on older version + if (Runtime.PythonVersion < new Version(3, 4)) + return null; + + return Runtime.PyGILState_Check() == 1; + } + + [Conditional("DEBUG")] + public static void AssertRefcount(IntPtr ob, long expected = 1) { + long refcount = Runtime.Refcount(ob); + if (refcount != expected) + throw new InvalidProgramException(); + } } } diff --git a/src/runtime/delegatemanager.cs b/src/runtime/delegatemanager.cs index bd8f1ee4c..7e518bfcf 100644 --- a/src/runtime/delegatemanager.cs +++ b/src/runtime/delegatemanager.cs @@ -185,11 +185,10 @@ public class Dispatcher : IPyDisposable { public IntPtr target; public Type dtype; - private bool _disposed = false; - private bool _finalized = false; public Dispatcher(IntPtr target, Type dtype) { + if (target == IntPtr.Zero) throw new ArgumentNullException(nameof(target)); Runtime.XIncref(target); this.target = target; this.dtype = dtype; @@ -197,21 +196,20 @@ public Dispatcher(IntPtr target, Type dtype) ~Dispatcher() { - if (_finalized || _disposed) + if (this.target == IntPtr.Zero) { return; } - _finalized = true; Finalizer.Instance.AddFinalizedObject(this); } public void Dispose() { - if (_disposed) + DebugUtil.EnsureGIL(); + if (this.target == IntPtr.Zero) { return; } - _disposed = true; Runtime.XDecref(target); target = IntPtr.Zero; dtype = null; @@ -221,20 +219,15 @@ public void Dispose() public object Dispatch(ArrayList args) { IntPtr gs = PythonEngine.AcquireLock(); - object ob = null; try { - ob = TrueDispatch(args); + return TrueDispatch(args); } - catch (Exception e) + finally { PythonEngine.ReleaseLock(gs); - throw e; } - - PythonEngine.ReleaseLock(gs); - return ob; } public object TrueDispatch(ArrayList args) @@ -248,7 +241,7 @@ public object TrueDispatch(ArrayList args) { // Here we own the reference to the Python value, and we // give the ownership to the arg tuple. - IntPtr arg = Converter.ToPython(args[i], pi[i].ParameterType); + IntPtr arg = Converter.ToPython(args[i]); Runtime.PyTuple_SetItem(pyargs, i, arg); } @@ -257,8 +250,7 @@ public object TrueDispatch(ArrayList args) if (op == IntPtr.Zero) { - var e = new PythonException(); - throw e; + throw PythonException.ThrowLastAsClrException(); } if (rtype == typeof(void)) @@ -293,5 +285,7 @@ public ConversionException() public ConversionException(string msg) : base(msg) { } + + public ConversionException(string message, Exception innerException):base(message, innerException) { } } } diff --git a/src/runtime/delegateobject.cs b/src/runtime/delegateobject.cs index e1103cbc7..c9aad9898 100644 --- a/src/runtime/delegateobject.cs +++ b/src/runtime/delegateobject.cs @@ -96,7 +96,6 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) /// /// Implements __cmp__ for reflected delegate types. /// -#if PYTHON3 // TODO: Doesn't PY2 implement tp_richcompare too? public new static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) { if (op != Runtime.Py_EQ && op != Runtime.Py_NE) @@ -126,13 +125,5 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) Runtime.XIncref(pyfalse); return pyfalse; } -#elif PYTHON2 - public static int tp_compare(IntPtr ob, IntPtr other) - { - Delegate d1 = GetTrueDelegate(ob); - Delegate d2 = GetTrueDelegate(other); - return d1 == d2 ? 0 : -1; - } -#endif } } diff --git a/src/runtime/eventbinding.cs b/src/runtime/eventbinding.cs index b8b4c82ad..8b3f6ee43 100644 --- a/src/runtime/eventbinding.cs +++ b/src/runtime/eventbinding.cs @@ -9,6 +9,7 @@ internal class EventBinding : ExtensionType { private EventObject e; private IntPtr target; + internal BorrowedReference Target => new BorrowedReference(target); public EventBinding(EventObject e, IntPtr target) { @@ -31,7 +32,7 @@ public static IntPtr nb_inplace_add(IntPtr ob, IntPtr arg) return IntPtr.Zero; } - if (!self.e.AddEventHandler(self.target, arg)) + if (!self.e.AddEventHandler(self.Target, arg)) { return IntPtr.Zero; } @@ -54,7 +55,7 @@ public static IntPtr nb_inplace_subtract(IntPtr ob, IntPtr arg) return IntPtr.Zero; } - if (!self.e.RemoveEventHandler(self.target, arg)) + if (!self.e.RemoveEventHandler(self.Target, arg)) { return IntPtr.Zero; } diff --git a/src/runtime/eventobject.cs b/src/runtime/eventobject.cs index 5f18c4609..6d6bb59f0 100644 --- a/src/runtime/eventobject.cs +++ b/src/runtime/eventobject.cs @@ -24,12 +24,12 @@ public EventObject(EventInfo info) /// /// Register a new Python object event handler with the event. /// - internal bool AddEventHandler(IntPtr target, IntPtr handler) + internal bool AddEventHandler(BorrowedReference target, IntPtr handler) { object obj = null; if (target != IntPtr.Zero) { - var co = (CLRObject)GetManagedObject(target); + var co = (CLRObject)ManagedType.GetManagedObject(target); obj = co.inst; } @@ -69,12 +69,12 @@ internal bool AddEventHandler(IntPtr target, IntPtr handler) /// /// Remove the given Python object event handler. /// - internal bool RemoveEventHandler(IntPtr target, IntPtr handler) + internal bool RemoveEventHandler(BorrowedReference target, IntPtr handler) { object obj = null; if (target != IntPtr.Zero) { - var co = (CLRObject)GetManagedObject(target); + var co = (CLRObject)ManagedType.GetManagedObject(target); obj = co.inst; } diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs index 31c367eb2..03f5b4e18 100644 --- a/src/runtime/exceptions.cs +++ b/src/runtime/exceptions.cs @@ -103,7 +103,7 @@ private Exceptions() /// internal static void Initialize() { - string exceptionsModuleName = Runtime.IsPython3 ? "builtins" : "exceptions"; + string exceptionsModuleName = "builtins"; exceptions_module = Runtime.PyImport_ImportModule(exceptionsModuleName); Exceptions.ErrorCheck(exceptions_module); @@ -180,36 +180,40 @@ internal static void SetArgsAndCause(IntPtr ob) Marshal.WriteIntPtr(ob, ExceptionOffset.args, args); -#if PYTHON3 if (e.InnerException != null) { IntPtr cause = CLRObject.GetInstHandle(e.InnerException); Marshal.WriteIntPtr(ob, ExceptionOffset.cause, cause); } -#endif } /// /// Shortcut for (pointer == NULL) -> throw PythonException /// /// Pointer to a Python object - internal static void ErrorCheck(IntPtr pointer) + internal static IntPtr ErrorCheck(IntPtr pointer) { if (pointer == IntPtr.Zero) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } + + return pointer; } + internal static BorrowedReference ErrorCheck(BorrowedReference reference) + => reference.IsNull ? throw PythonException.ThrowLastAsClrException() : reference; /// /// Shortcut for (pointer == NULL or ErrorOccurred()) -> throw PythonException /// - internal static void ErrorOccurredCheck(IntPtr pointer) + internal static IntPtr ErrorOccurredCheck(IntPtr pointer) { if (pointer == IntPtr.Zero || ErrorOccurred()) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } + + return pointer; } /// @@ -279,14 +283,14 @@ public static void SetError(Exception e) var pe = e as PythonException; if (pe != null) { - Runtime.XIncref(pe.PyType); - Runtime.XIncref(pe.PyValue); - Runtime.XIncref(pe.PyTB); - Runtime.PyErr_Restore(pe.PyType, pe.PyValue, pe.PyTB); + Runtime.PyErr_Restore( + NewReference.FromNullable(pe.PythonType).Steal(), + NewReference.FromNullable(pe.Value).Steal(), + NewReference.FromNullable(pe.Traceback).Steal()); return; } - IntPtr op = CLRObject.GetInstHandle(e); + IntPtr op = Converter.ToPython(e); IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__"); Runtime.PyErr_SetObject(etype, op); Runtime.XDecref(etype); @@ -386,14 +390,12 @@ puplic static variables on the Exceptions class filled in from public static IntPtr Exception; public static IntPtr StopIteration; public static IntPtr GeneratorExit; -#if PYTHON2 - public static IntPtr StandardError; -#endif public static IntPtr ArithmeticError; public static IntPtr LookupError; public static IntPtr AssertionError; public static IntPtr AttributeError; + public static IntPtr BufferError; public static IntPtr EOFError; public static IntPtr FloatingPointError; public static IntPtr EnvironmentError; diff --git a/src/runtime/extensiontype.cs b/src/runtime/extensiontype.cs index 6585180c1..77e09762c 100644 --- a/src/runtime/extensiontype.cs +++ b/src/runtime/extensiontype.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Runtime.InteropServices; namespace Python.Runtime @@ -17,7 +18,7 @@ public ExtensionType() // The Python instance object is related to an instance of a // particular concrete subclass with a hidden CLR gchandle. - IntPtr tp = TypeManager.GetTypeHandle(GetType()); + BorrowedReference tp = TypeManager.GetTypeHandle(GetType()); //int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt); //if (rc > 1050) @@ -26,32 +27,53 @@ public ExtensionType() // DebugUtil.DumpType(tp); //} - IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); + using var py = Runtime.PyType_GenericAlloc(tp, 0); GCHandle gc = GCHandle.Alloc(this); - Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc); + Marshal.WriteIntPtr(py.DangerousGetAddress(), ObjectOffset.GetDefaultGCHandleOffset(), (IntPtr)gc); + + // It is safe to store the reference to the type without incref, + // because we also hold an instance of that type. + tpHandle = tp.DangerousGetAddress(); + pyHandle = py.DangerousMoveToPointer(); + gcHandle = gc; // We have to support gc because the type machinery makes it very // hard not to - but we really don't have a need for it in most // concrete extension types, so untrack the object to save calls // from Python into the managed runtime that are pure overhead. + Runtime.PyObject_GC_UnTrack(pyHandle); + } - Runtime.PyObject_GC_UnTrack(py); - // Steals a ref to tpHandle. - tpHandle = tp; - pyHandle = py; - gcHandle = gc; - } + internal static T GetManagedObject(BorrowedReference ob) + where T : ExtensionType + => (T)GetManagedObject(ob, ObjectOffset.GetDefaultGCHandleOffset()); + [Obsolete] + internal static new ExtensionType GetManagedObject(IntPtr ob) + => (ExtensionType)GetManagedObject(new BorrowedReference(ob), ObjectOffset.GetDefaultGCHandleOffset()); + [Obsolete] + internal static new ExtensionType GetManagedObject(BorrowedReference ob) + => (ExtensionType)GetManagedObject(ob, ObjectOffset.GetDefaultGCHandleOffset()); + internal static bool IsExtensionType(BorrowedReference tp) + { + if (!IsManagedType(tp)) return false; + var metaType = Runtime.PyObject_TYPE(tp); + return metaType == Runtime.PyTypeType; + } /// /// Common finalization code to support custom tp_deallocs. /// - public static void FinalizeObject(ManagedType self) + public static void FinalizeObject(ExtensionType self) { + Debug.Assert(self.pyHandle != IntPtr.Zero); Runtime.PyObject_GC_Del(self.pyHandle); - // Not necessary for decref of `tpHandle`. + self.pyHandle = IntPtr.Zero; + + self.tpHandle = IntPtr.Zero; + self.gcHandle.Free(); } @@ -71,17 +93,6 @@ public static int tp_setattro(IntPtr ob, IntPtr key, IntPtr val) } - /// - /// Default __set__ implementation - this prevents descriptor instances - /// being silently replaced in a type __dict__ by default __setattr__. - /// - public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) - { - Exceptions.SetError(Exceptions.AttributeError, "attribute is read-only"); - return -1; - } - - /// /// Default dealloc implementation. /// @@ -89,7 +100,7 @@ public static void tp_dealloc(IntPtr ob) { // Clean up a Python instance of this extension type. This // frees the allocated Python object and decrefs the type. - ManagedType self = GetManagedObject(ob); + var self = GetManagedObject(new BorrowedReference(ob)); FinalizeObject(self); } } diff --git a/src/runtime/fieldobject.cs b/src/runtime/fieldobject.cs index 7c9a466d5..e7910b044 100644 --- a/src/runtime/fieldobject.cs +++ b/src/runtime/fieldobject.cs @@ -20,8 +20,9 @@ public FieldObject(FieldInfo info) /// value of the field on the given object. The returned value /// is converted to an appropriately typed Python object. /// - public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) + public static IntPtr tp_descr_get(IntPtr ds, IntPtr obRaw, IntPtr tp) { + var ob = new BorrowedReference(obRaw); var self = (FieldObject)GetManagedObject(ds); object result; @@ -43,7 +44,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) try { result = info.GetValue(null); - return Converter.ToPython(result, info.FieldType); + return Converter.ToPython(result); } catch (Exception e) { @@ -54,9 +55,9 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) try { - var co = (CLRObject)GetManagedObject(ob); + var co = (CLRObject)ManagedType.GetManagedObject(ob); result = info.GetValue(co.inst); - return Converter.ToPython(result, info.FieldType); + return Converter.ToPython(result); } catch (Exception e) { @@ -70,8 +71,9 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) /// a field based on the given Python value. The Python value must be /// convertible to the type of the field. /// - public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) + public new static int tp_descr_set(IntPtr ds, IntPtr obRaw, IntPtr val) { + var ob = new BorrowedReference(obRaw); var self = (FieldObject)GetManagedObject(ds); object newval; @@ -114,7 +116,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { if (!is_static) { - var co = (CLRObject)GetManagedObject(ob); + var co = (CLRObject)ManagedType.GetManagedObject(ob); info.SetValue(co.inst, newval); } else diff --git a/src/runtime/finalizer.cs b/src/runtime/finalizer.cs index ba562cc26..59c208b7e 100644 --- a/src/runtime/finalizer.cs +++ b/src/runtime/finalizer.cs @@ -24,8 +24,7 @@ public class ErrorArgs : EventArgs public event EventHandler CollectOnce; public event EventHandler ErrorHandler; - public int Threshold { get; set; } - public bool Enable { get; set; } + public int Threshold { get; set; } = 200; private ConcurrentQueue _objQueue = new ConcurrentQueue(); private int _throttled; @@ -67,11 +66,7 @@ public IncorrectRefCountException(IntPtr ptr) #endregion - private Finalizer() - { - Enable = true; - Threshold = 200; - } + private Finalizer() { } [Obsolete("forceDispose parameter is unused. All objects are disposed regardless.")] public void Collect(bool forceDispose) => this.DisposeAll(); @@ -80,7 +75,7 @@ private Finalizer() internal void ThrottledCollect() { _throttled = unchecked(this._throttled + 1); - if (!Enable || _throttled < Threshold) return; + if (_throttled < Threshold) return; _throttled = 0; this.Collect(); } @@ -92,11 +87,6 @@ public List GetCollectedObjects() internal void AddFinalizedObject(IPyDisposable obj) { - if (!Enable) - { - return; - } - #if FINALIZER_CHECK lock (_queueLock) #endif diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs index aa3bbab6d..043cf4de1 100644 --- a/src/runtime/importhook.cs +++ b/src/runtime/importhook.cs @@ -12,8 +12,8 @@ internal class ImportHook private static CLRModule root; private static MethodWrapper hook; private static IntPtr py_clr_module; + public static BorrowedReference ClrModule => new BorrowedReference(py_clr_module); -#if PYTHON3 private static IntPtr module_def = IntPtr.Zero; internal static void InitializeModuleDef() @@ -33,7 +33,6 @@ internal static void ReleaseModuleDef() ModuleDefOffset.FreeModuleDef(module_def); module_def = IntPtr.Zero; } -#endif /// /// Initialize just the __import__ hook itself. @@ -82,7 +81,6 @@ internal static void Initialize() // Initialize the clr module and tell Python about it. root = new CLRModule(); -#if PYTHON3 // create a python module with the same methods as the clr module-like object InitializeModuleDef(); py_clr_module = Runtime.PyModule_Create2(module_def, 3); @@ -93,10 +91,6 @@ internal static void Initialize() clr_dict = (IntPtr)Marshal.PtrToStructure(clr_dict, typeof(IntPtr)); Runtime.PyDict_Update(mod_dict, clr_dict); -#elif PYTHON2 - Runtime.XIncref(root.pyHandle); // we are using the module two times - py_clr_module = root.pyHandle; // Alias handle for PY2/PY3 -#endif IntPtr dict = Runtime.PyImport_GetModuleDict(); Runtime.PyDict_SetItemString(dict, "CLR", py_clr_module); Runtime.PyDict_SetItemString(dict, "clr", py_clr_module); @@ -118,12 +112,11 @@ internal static void Shutdown() bool shouldFreeDef = Runtime.Refcount(py_clr_module) == 1; Runtime.XDecref(py_clr_module); py_clr_module = IntPtr.Zero; -#if PYTHON3 + if (shouldFreeDef) { ReleaseModuleDef(); } -#endif Runtime.XDecref(root.pyHandle); root = null; @@ -137,12 +130,6 @@ public static IntPtr GetCLRModule(IntPtr? fromList = null) { root.InitializePreload(); - if (Runtime.IsPython2) - { - Runtime.XIncref(py_clr_module); - return py_clr_module; - } - // Python 3 // update the module dictionary with the contents of the root dictionary root.LoadNames(); diff --git a/src/runtime/indexer.cs b/src/runtime/indexer.cs index 71f7e7aa1..26e028172 100644 --- a/src/runtime/indexer.cs +++ b/src/runtime/indexer.cs @@ -109,7 +109,7 @@ internal IntPtr GetDefaultArgs(IntPtr args) { continue; } - IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType); + IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue); Runtime.PyTuple_SetItem(defaultArgs, i, arg); } return defaultArgs; diff --git a/src/runtime/interfaceobject.cs b/src/runtime/interfaceobject.cs index 616ced6bd..acae39650 100644 --- a/src/runtime/interfaceobject.cs +++ b/src/runtime/interfaceobject.cs @@ -19,7 +19,7 @@ internal InterfaceObject(Type tp) : base(tp) var coclass = (CoClassAttribute)Attribute.GetCustomAttribute(tp, cc_attr); if (coclass != null) { - ctor = coclass.CoClass.GetConstructor(Type.EmptyTypes); + ctor = coclass.CoClass.GetConstructor(System.Type.EmptyTypes); } } diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs index 039feddc7..1084bf39d 100644 --- a/src/runtime/interop.cs +++ b/src/runtime/interop.cs @@ -1,14 +1,12 @@ using System; using System.Collections; -using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using System.Reflection; using System.Text; using System.Collections.Generic; -namespace Python.Runtime -{ +namespace Python.Runtime { /// /// This file defines objects to support binary interop with the Python /// runtime. Generally, the definitions here need to be kept up to date @@ -16,15 +14,12 @@ namespace Python.Runtime /// [Serializable] [AttributeUsage(AttributeTargets.All)] - public class DocStringAttribute : Attribute - { - public DocStringAttribute(string docStr) - { + public class DocStringAttribute : Attribute { + public DocStringAttribute(string docStr) { DocString = docStr; } - public string DocString - { + public string DocString { get { return docStr; } set { docStr = value; } } @@ -34,83 +29,39 @@ public string DocString [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] - internal class PythonMethodAttribute : Attribute - { - public PythonMethodAttribute() - { + internal class PythonMethodAttribute : Attribute { + public PythonMethodAttribute() { } } [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] - internal class ModuleFunctionAttribute : Attribute - { - public ModuleFunctionAttribute() - { + internal class ModuleFunctionAttribute : Attribute { + public ModuleFunctionAttribute() { } } [Serializable] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] - internal class ForbidPythonThreadsAttribute : Attribute - { - public ForbidPythonThreadsAttribute() - { + internal class ForbidPythonThreadsAttribute : Attribute { + public ForbidPythonThreadsAttribute() { } } [Serializable] [AttributeUsage(AttributeTargets.Property)] - internal class ModulePropertyAttribute : Attribute - { - public ModulePropertyAttribute() - { + internal class ModulePropertyAttribute : Attribute { + public ModulePropertyAttribute() { } } - internal static class ManagedDataOffsets - { - static ManagedDataOffsets() - { - FieldInfo[] fi = typeof(ManagedDataOffsets).GetFields(BindingFlags.Static | BindingFlags.Public); - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, -(i * IntPtr.Size) - IntPtr.Size); - } - size = fi.Length * IntPtr.Size; - } - - public static readonly int ob_data; - public static readonly int ob_dict; - - private static int BaseOffset(IntPtr type) - { - Debug.Assert(type != IntPtr.Zero); - int typeSize = Marshal.ReadInt32(type, TypeOffset.tp_basicsize); - Debug.Assert(typeSize > 0 && typeSize <= ExceptionOffset.Size()); - return typeSize; - } - public static int DataOffset(IntPtr type) - { - return BaseOffset(type) + ob_data; - } - - public static int DictOffset(IntPtr type) - { - return BaseOffset(type) + ob_dict; - } + // TODO: refactor + incorporate https://github.com/pythonnet/pythonnet/commit/4a92d80a4b8daa9d16f85ce9c5ccaaa6c812fab8 - public static int Size { get { return size; } } - - private static readonly int size; - } - - internal static class OriginalObjectOffsets - { - static OriginalObjectOffsets() - { + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal static class ObjectOffset { + static ObjectOffset() { int size = IntPtr.Size; var n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD #if PYTHON_WITH_PYDEBUG @@ -120,58 +71,82 @@ static OriginalObjectOffsets() #endif ob_refcnt = (n + 0) * size; ob_type = (n + 1) * size; + ob_dict = (n + 2) * size; + ob_data = (n + 3) * size; } - public static int Size { get { return size; } } - - private static readonly int size = -#if PYTHON_WITH_PYDEBUG - 4 * IntPtr.Size; -#else - 2 * IntPtr.Size; + public static int GetDefaultGCHandleOffset() => ob_data; + + /// + /// Gets GC handle offset in the instances of the specified type + /// + public static int InstanceGCHandle(BorrowedReference type) { +#if DEBUG + Debug.Assert(ManagedType.IsManagedType(type)); + var meta = Runtime.PyObject_TYPE(type); + if (Runtime.PyCLRMetaType != IntPtr.Zero && meta.DangerousGetAddress() != Runtime.PyCLRMetaType) + Debug.Assert(new PyObject(meta).ToString() == "", + $"Bad metatype: {new PyObject(meta)}"); #endif - -#if PYTHON_WITH_PYDEBUG - public static int _ob_next; - public static int _ob_prev; + int offset = (int)Marshal.ReadIntPtr(type.DangerousGetAddress(), TypeOffset.clr_gchandle_offset); +#if DEBUG + Debug.Assert(offset < checked((int)Marshal.ReadIntPtr(type.DangerousGetAddress(), TypeOffset.tp_basicsize))); #endif - public static int ob_refcnt; - public static int ob_type; - } + ClrGcHandleOffsetAssertSanity(offset); + return offset; + } + /// + /// Gets GC handle offset in the instance + /// + public static int ReflectedObjectGCHandle(BorrowedReference reflectedManagedObject) { + var type = Runtime.PyObject_TYPE(reflectedManagedObject); + return InstanceGCHandle(type); + } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class ObjectOffset - { - static ObjectOffset() - { -#if PYTHON_WITH_PYDEBUG - _ob_next = OriginalObjectOffsets._ob_next; - _ob_prev = OriginalObjectOffsets._ob_prev; + [Conditional("DEBUG")] + static void AssertIsClrType(IntPtr tp) => Debug.Assert(Runtime.PyObject_TYPE(tp) == Runtime.PyCLRMetaType); + [Conditional("DEBUG")] + internal static void ClrGcHandleOffsetAssertSanity(int offset) + => Debug.Assert(offset > 0 && offset < 1024 * 4, $"GC handle offset is insane: {offset}"); + + /// + /// Returns dict offset in instances of the specified + /// + public static unsafe int TypeDictOffset(BorrowedReference type) { +#if DEBUG + if (!Runtime.PyType_Check(type)) + throw new ArgumentException("Bad object type"); #endif - ob_refcnt = OriginalObjectOffsets.ob_refcnt; - ob_type = OriginalObjectOffsets.ob_type; - size = OriginalObjectOffsets.Size + ManagedDataOffsets.Size; + IntPtr dictoffset = type.DangerousGetAddress() + TypeOffset.tp_dictoffset; + int dict = *((int*)(dictoffset)); + Debug.Assert(dict > 0 && dict < 100_000); + return dict; } + public static int TypeDictOffset() => ob_dict; - public static int magic(IntPtr type) - { - return ManagedDataOffsets.DataOffset(type); - } + public static int Size(IntPtr ob) { + if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) || + (Runtime.PyType_Check(new BorrowedReference(ob)) && IsExceptionSubtype(new BorrowedReference(ob))))) { + return ExceptionOffset.Size(); + } - public static int TypeDictOffset(IntPtr type) - { - return ManagedDataOffsets.DictOffset(type); + return PyObject_HEAD_Size(); } - public static int Size(IntPtr pyType) + static bool IsExceptionSubtype(BorrowedReference type) { - if (IsException(pyType)) - { - return ExceptionOffset.Size(); - } + bool isException = Runtime.PyType_FastSubclass(type, TypeFlags.BaseExceptionSubclass); + Debug.Assert(Runtime.PyType_IsSubtype(type.DangerousGetAddress(), Exceptions.BaseException) == isException); + return isException; + } - return size; + public static int PyObject_HEAD_Size() { +#if PYTHON_WITH_PYDEBUG + return 6 * IntPtr.Size; +#else + return 4 * IntPtr.Size; +#endif } #if PYTHON_WITH_PYDEBUG @@ -180,62 +155,47 @@ public static int Size(IntPtr pyType) #endif public static int ob_refcnt; public static int ob_type; - private static readonly int size; - - private static bool IsException(IntPtr pyObject) - { - var type = Runtime.PyObject_TYPE(pyObject); - return Runtime.PyType_IsSameAsOrSubtype(type, ofType: Exceptions.BaseException) - || Runtime.PyType_IsSameAsOrSubtype(type, ofType: Runtime.PyTypeType) - && Runtime.PyType_IsSubtype(pyObject, Exceptions.BaseException); - } + private static int ob_dict; + private static int ob_data; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class ExceptionOffset - { - static ExceptionOffset() - { + internal class ExceptionOffset { + static ExceptionOffset() { Type type = typeof(ExceptionOffset); - FieldInfo[] fi = type.GetFields(BindingFlags.Static | BindingFlags.Public); - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, (i * IntPtr.Size) + OriginalObjectOffsets.Size); + FieldInfo[] fi = type.GetFields(); + int size = IntPtr.Size; + for (int i = 0; i < fi.Length; i++) { + fi[i].SetValue(null, (i * size) + ObjectOffset.ob_type + size); } - - size = fi.Length * IntPtr.Size + OriginalObjectOffsets.Size + ManagedDataOffsets.Size; } - public static int Size() { return size; } + public static int Size() { + return ob_data + IntPtr.Size; + } // PyException_HEAD // (start after PyObject_HEAD) public static int dict = 0; public static int args = 0; -#if PYTHON2 - public static int message = 0; -#elif PYTHON3 public static int traceback = 0; public static int context = 0; public static int cause = 0; public static int suppress_context = 0; -#endif - private static readonly int size; + // extra c# data + public static int ob_dict; + public static int ob_data; } -#if PYTHON3 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class BytesOffset - { - static BytesOffset() - { + internal class BytesOffset { + static BytesOffset() { Type type = typeof(BytesOffset); FieldInfo[] fi = type.GetFields(); int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { + for (int i = 0; i < fi.Length; i++) { fi[i].SetValue(null, i * size); } } @@ -266,21 +226,17 @@ static BytesOffset() } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class ModuleDefOffset - { - static ModuleDefOffset() - { + internal class ModuleDefOffset { + static ModuleDefOffset() { Type type = typeof(ModuleDefOffset); FieldInfo[] fi = type.GetFields(); int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { + for (int i = 0; i < fi.Length; i++) { fi[i].SetValue(null, (i * size) + TypeOffset.ob_size); } } - public static IntPtr AllocModuleDef(string modulename) - { + public static IntPtr AllocModuleDef(string modulename) { byte[] ascii = Encoding.ASCII.GetBytes(modulename); int size = name + ascii.Length + 1; IntPtr ptr = Marshal.AllocHGlobal(size); @@ -292,8 +248,7 @@ public static IntPtr AllocModuleDef(string modulename) return ptr; } - public static void FreeModuleDef(IntPtr ptr) - { + public static void FreeModuleDef(IntPtr ptr) { Marshal.FreeHGlobal(ptr); } @@ -316,7 +271,6 @@ public static void FreeModuleDef(IntPtr ptr) public static int name = 0; } -#endif // PYTHON3 /// /// TypeFlags(): The actual bit values for the Type Flags stored @@ -324,63 +278,42 @@ public static void FreeModuleDef(IntPtr ptr) /// Note that the two values reserved for stackless have been put /// to good use as PythonNet specific flags (Managed and Subclass) /// - internal class TypeFlags - { -#if PYTHON2 // these flags were removed in Python 3 - public static int HaveGetCharBuffer = (1 << 0); - public static int HaveSequenceIn = (1 << 1); - public static int GC = 0; - public static int HaveInPlaceOps = (1 << 3); - public static int CheckTypes = (1 << 4); - public static int HaveRichCompare = (1 << 5); - public static int HaveWeakRefs = (1 << 6); - public static int HaveIter = (1 << 7); - public static int HaveClass = (1 << 8); -#endif - public static int HeapType = (1 << 9); - public static int BaseType = (1 << 10); - public static int Ready = (1 << 12); - public static int Readying = (1 << 13); - public static int HaveGC = (1 << 14); + [Flags] + enum TypeFlags : int { + HeapType = (1 << 9), + /// + /// Unless this flag is set, the type can't be inherited from (equivalent to C# sealed) + /// + BaseType = (1 << 10), + Ready = (1 << 12), + Readying = (1 << 13), + HaveGC = (1 << 14), // 15 and 16 are reserved for stackless - public static int HaveStacklessExtension = 0; + HaveStacklessExtension = 0, /* XXX Reusing reserved constants */ - public static int Managed = (1 << 15); // PythonNet specific - public static int Subclass = (1 << 16); // PythonNet specific - public static int HaveIndex = (1 << 17); + Managed = (1 << 15), // PythonNet specific + Subclass = (1 << 16), // PythonNet specific + HaveIndex = (1 << 17), /* Objects support nb_index in PyNumberMethods */ - public static int HaveVersionTag = (1 << 18); - public static int ValidVersionTag = (1 << 19); - public static int IsAbstract = (1 << 20); - public static int HaveNewBuffer = (1 << 21); + HaveVersionTag = (1 << 18), + ValidVersionTag = (1 << 19), + IsAbstract = (1 << 20), + HaveNewBuffer = (1 << 21), // TODO: Implement FastSubclass functions - public static int IntSubclass = (1 << 23); - public static int LongSubclass = (1 << 24); - public static int ListSubclass = (1 << 25); - public static int TupleSubclass = (1 << 26); - public static int StringSubclass = (1 << 27); - public static int UnicodeSubclass = (1 << 28); - public static int DictSubclass = (1 << 29); - public static int BaseExceptionSubclass = (1 << 30); - public static int TypeSubclass = (1 << 31); - -#if PYTHON2 // Default flags for Python 2 - public static int Default = ( - HaveGetCharBuffer | - HaveSequenceIn | - HaveInPlaceOps | - HaveRichCompare | - HaveWeakRefs | - HaveIter | - HaveClass | + IntSubclass = (1 << 23), + LongSubclass = (1 << 24), + ListSubclass = (1 << 25), + TupleSubclass = (1 << 26), + StringSubclass = (1 << 27), + UnicodeSubclass = (1 << 28), + DictSubclass = (1 << 29), + BaseExceptionSubclass = (1 << 30), + TypeSubclass = (1 << 31), + + + Default = ( HaveStacklessExtension | - HaveIndex | - 0); -#elif PYTHON3 // Default flags for Python 3 - public static int Default = ( - HaveStacklessExtension | - HaveVersionTag); -#endif + HaveVersionTag), } @@ -389,21 +322,18 @@ internal class TypeFlags // based lookup of the correct prototype for a particular Python type // slot and utilities for generating method thunks for managed methods. - internal class Interop - { + internal class Interop { private static List keepAlive; private static Hashtable pmap; - static Interop() - { + static Interop() { // Here we build a mapping of PyTypeObject slot names to the // appropriate prototype (delegate) type to use for the slot. Type[] items = typeof(Interop).GetNestedTypes(); Hashtable p = new Hashtable(); - for (int i = 0; i < items.Length; i++) - { + for (int i = 0; i < items.Length; i++) { Type item = items[i]; p[item.Name] = item; } @@ -438,9 +368,6 @@ static Interop() pmap["nb_add"] = p["BinaryFunc"]; pmap["nb_subtract"] = p["BinaryFunc"]; pmap["nb_multiply"] = p["BinaryFunc"]; -#if PYTHON2 - pmap["nb_divide"] = p["BinaryFunc"]; -#endif pmap["nb_remainder"] = p["BinaryFunc"]; pmap["nb_divmod"] = p["BinaryFunc"]; pmap["nb_power"] = p["TernaryFunc"]; @@ -463,9 +390,6 @@ static Interop() pmap["nb_inplace_add"] = p["BinaryFunc"]; pmap["nb_inplace_subtract"] = p["BinaryFunc"]; pmap["nb_inplace_multiply"] = p["BinaryFunc"]; -#if PYTHON2 - pmap["nb_inplace_divide"] = p["BinaryFunc"]; -#endif pmap["nb_inplace_remainder"] = p["BinaryFunc"]; pmap["nb_inplace_power"] = p["TernaryFunc"]; pmap["nb_inplace_lshift"] = p["BinaryFunc"]; @@ -500,21 +424,18 @@ static Interop() pmap["bf_getcharbuffer"] = p["IntObjArgFunc"]; } - internal static Type GetPrototype(string name) - { + internal static Type GetPrototype(string name) { return pmap[name] as Type; } - internal static ThunkInfo GetThunk(MethodInfo method, string funcType = null) - { + internal static ThunkInfo GetThunk(MethodInfo method, string funcType = null) { Type dt; if (funcType != null) dt = typeof(Interop).GetNestedType(funcType) as Type; else dt = GetPrototype(method.Name); - if (dt == null) - { + if (dt == null) { return ThunkInfo.Empty; } Delegate d = Delegate.CreateDelegate(dt, method); @@ -566,27 +487,22 @@ internal static ThunkInfo GetThunk(MethodInfo method, string funcType = null) [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal struct Thunk - { + internal struct Thunk { public Delegate fn; - public Thunk(Delegate d) - { + public Thunk(Delegate d) { fn = d; } } - internal class ThunkInfo - { + internal class ThunkInfo { public readonly Delegate Target; public readonly IntPtr Address; public static readonly ThunkInfo Empty = new ThunkInfo(null); - public ThunkInfo(Delegate target) - { - if (target == null) - { + public ThunkInfo(Delegate target) { + if (target == null) { return; } Target = target; diff --git a/src/runtime/interop34.cs b/src/runtime/interop34.cs index 6857ff2d0..c4bff98a7 100644 --- a/src/runtime/interop34.cs +++ b/src/runtime/interop34.cs @@ -1,8 +1,6 @@ // Auto-generated by geninterop.py. // DO NOT MODIFIY BY HAND. - -#if PYTHON34 using System; using System.Collections; using System.Collections.Specialized; @@ -13,24 +11,8 @@ namespace Python.Runtime { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset + internal static class TypeOffset34 { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - // Auto-generated from PyHeapTypeObject in Python.h public static int ob_refcnt = 0; public static int ob_type = 0; @@ -140,5 +122,3 @@ public static int magic() public static int members = 0; } } - -#endif diff --git a/src/runtime/interop35.cs b/src/runtime/interop35.cs index a30bfa4fd..9411432f0 100644 --- a/src/runtime/interop35.cs +++ b/src/runtime/interop35.cs @@ -1,8 +1,6 @@ // Auto-generated by geninterop.py. // DO NOT MODIFIY BY HAND. - -#if PYTHON35 using System; using System.Collections; using System.Collections.Specialized; @@ -13,24 +11,8 @@ namespace Python.Runtime { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset + internal static class TypeOffset35 { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - // Auto-generated from PyHeapTypeObject in Python.h public static int ob_refcnt = 0; public static int ob_type = 0; @@ -145,5 +127,3 @@ public static int magic() public static int members = 0; } } - -#endif diff --git a/src/runtime/interop36.cs b/src/runtime/interop36.cs index c46bcc2f5..540f11ed0 100644 --- a/src/runtime/interop36.cs +++ b/src/runtime/interop36.cs @@ -1,8 +1,6 @@ // Auto-generated by geninterop.py. // DO NOT MODIFIY BY HAND. - -#if PYTHON36 using System; using System.Collections; using System.Collections.Specialized; @@ -13,24 +11,8 @@ namespace Python.Runtime { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset + internal static class TypeOffset36 { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - // Auto-generated from PyHeapTypeObject in Python.h public static int ob_refcnt = 0; public static int ob_type = 0; @@ -145,5 +127,3 @@ public static int magic() public static int members = 0; } } - -#endif diff --git a/src/runtime/interop37.cs b/src/runtime/interop37.cs index d5fc76ad3..b98a45b06 100644 --- a/src/runtime/interop37.cs +++ b/src/runtime/interop37.cs @@ -1,8 +1,6 @@ // Auto-generated by geninterop.py. // DO NOT MODIFIY BY HAND. - -#if PYTHON37 using System; using System.Collections; using System.Collections.Specialized; @@ -13,24 +11,8 @@ namespace Python.Runtime { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset + internal static class TypeOffset37 { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - // Auto-generated from PyHeapTypeObject in Python.h public static int ob_refcnt = 0; public static int ob_type = 0; @@ -145,5 +127,3 @@ public static int magic() public static int members = 0; } } - -#endif diff --git a/src/runtime/interop38.cs b/src/runtime/interop38.cs index 9126bca6a..aac8fedd4 100644 --- a/src/runtime/interop38.cs +++ b/src/runtime/interop38.cs @@ -3,7 +3,6 @@ // DO NOT MODIFY BY HAND. -#if PYTHON38 using System; using System.Collections; using System.Collections.Specialized; @@ -14,24 +13,8 @@ namespace Python.Runtime { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset + internal static class TypeOffset38 { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - // Auto-generated from PyHeapTypeObject in Python.h public static int ob_refcnt = 0; public static int ob_type = 0; @@ -148,5 +131,3 @@ public static int magic() public static int members = 0; } } - -#endif diff --git a/src/runtime/iterator.cs b/src/runtime/iterator.cs index f9cf10178..93246fdd4 100644 --- a/src/runtime/iterator.cs +++ b/src/runtime/iterator.cs @@ -22,7 +22,7 @@ public Iterator(IEnumerator e) /// public static IntPtr tp_iternext(IntPtr ob) { - var self = GetManagedObject(ob) as Iterator; + var self = GetManagedObject(new BorrowedReference(ob)); try { if (!self.iter.MoveNext()) @@ -33,15 +33,11 @@ public static IntPtr tp_iternext(IntPtr ob) } catch (Exception e) { - if (e.InnerException != null) - { - e = e.InnerException; - } Exceptions.SetError(e); return IntPtr.Zero; } object item = self.iter.Current; - return Converter.ToPythonImplicit(item); + return Converter.ToPython(item); } public static IntPtr tp_iter(IntPtr ob) diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs index 23f5898d1..870b8722b 100644 --- a/src/runtime/managedtype.cs +++ b/src/runtime/managedtype.cs @@ -13,27 +13,29 @@ internal abstract class ManagedType internal GCHandle gcHandle; // Native handle internal IntPtr pyHandle; // PyObject * internal IntPtr tpHandle; // PyType * + internal BorrowedReference Type => new BorrowedReference(this.tpHandle); + internal BorrowedReference Instance => new BorrowedReference(this.pyHandle); /// /// Given a Python object, return the associated managed object or null. /// - internal static ManagedType GetManagedObject(IntPtr ob) + internal static ManagedType GetManagedObject(BorrowedReference ob) { - if (ob != IntPtr.Zero) + if (!ob.IsNull) { - IntPtr tp = Runtime.PyObject_TYPE(ob); + var tp = Runtime.PyObject_TYPE(ob); if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) { tp = ob; } - var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); - if ((flags & TypeFlags.Managed) != 0) + if (IsManagedType(tp)) { - IntPtr op = tp == ob - ? Marshal.ReadIntPtr(tp, TypeOffset.magic()) - : Marshal.ReadIntPtr(ob, ObjectOffset.magic(tp)); + int gcHandleOffset = tp == ob + ? TypeOffset.magic() + : ObjectOffset.ReflectedObjectGCHandle(ob); + IntPtr op = Marshal.ReadIntPtr(ob.DangerousGetAddress(), gcHandleOffset); if (op == IntPtr.Zero) { return null; @@ -45,35 +47,31 @@ internal static ManagedType GetManagedObject(IntPtr ob) return null; } + [Obsolete("Use GetManagedObject(BorrowedReference)")] + internal static ManagedType GetManagedObject(IntPtr ob) + => GetManagedObject(new BorrowedReference(ob)); - internal static ManagedType GetManagedObjectErr(IntPtr ob) + internal static ManagedType GetManagedObject(BorrowedReference ob, int gcHandleOffset) { - ManagedType result = GetManagedObject(ob); - if (result == null) - { - Exceptions.SetError(Exceptions.TypeError, "invalid argument, expected CLR type"); - } - return result; - } + if (ob.IsNull) throw new ArgumentNullException(nameof(ob)); + ObjectOffset.ClrGcHandleOffsetAssertSanity(gcHandleOffset); + IntPtr gcHandleValue = Marshal.ReadIntPtr(ob.DangerousGetAddress(), gcHandleOffset); + var gcHandle = (GCHandle)gcHandleValue; + return (ManagedType)gcHandle.Target; + } - internal static bool IsManagedType(IntPtr ob) + /// + /// Checks if specified type is a CLR type + /// + internal static bool IsManagedType(IntPtr tp) { - if (ob != IntPtr.Zero) - { - IntPtr tp = Runtime.PyObject_TYPE(ob); - if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) - { - tp = ob; - } - - var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); - if ((flags & TypeFlags.Managed) != 0) - { - return true; - } - } - return false; + var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags); + return (flags & TypeFlags.Managed) != 0; } + + /// Checks if specified type is a CLR type + internal static bool IsManagedType(BorrowedReference type) + => IsManagedType(type.DangerousGetAddress()); } } diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs index 5af2e1a7e..0303dc1b0 100644 --- a/src/runtime/metatype.cs +++ b/src/runtime/metatype.cs @@ -22,6 +22,7 @@ public static IntPtr Initialize() return PyCLRMetaType; } + internal static int ExtraTypeDataSize => IntPtr.Size; /// /// Metatype __new__ implementation. This is called to create a new @@ -86,7 +87,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__")) { - return TypeManager.CreateSubType(name, base_type, dict); + return TypeManager.CreateSubType(name, base_type, dict).DangerousIncRefOrNull(); } } } @@ -99,15 +100,16 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) return IntPtr.Zero; } - int flags = TypeFlags.Default; + var flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.Subclass; flags |= TypeFlags.HaveGC; - Util.WriteCLong(type, TypeOffset.tp_flags, flags); + Util.WriteCLong(type, TypeOffset.tp_flags, (long)flags); TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc); + TypeManager.CopySlot(base_type, type, TypeOffset.clr_gchandle_offset); // Hmm - the standard subtype_traverse, clear look at ob_size to // do things, so to allow gc to work correctly we need to move @@ -195,7 +197,7 @@ public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) if (dt == Runtime.PyWrapperDescriptorType || dt == Runtime.PyMethodType - || typeof(ExtensionType).IsInstanceOfType(GetManagedObject(descr)) + || ExtensionType.IsExtensionType(new BorrowedReference(dt)) ) { IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set); @@ -237,7 +239,7 @@ public static void tp_dealloc(IntPtr tp) { // Fix this when we dont cheat on the handle for subclasses! - var flags = Util.ReadCLong(tp, TypeOffset.tp_flags); + var flags = (TypeFlags)Util.ReadCLong(tp, TypeOffset.tp_flags); if ((flags & TypeFlags.Subclass) == 0) { IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic()); diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index b74f21754..4dcc088d9 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -1,9 +1,11 @@ using System; using System.Collections; -using System.Reflection; -using System.Text; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Reflection; +using System.Text; namespace Python.Runtime { @@ -25,9 +27,9 @@ internal MethodBinder() list = new ArrayList(); } - internal MethodBinder(MethodInfo mi) + internal MethodBinder(MethodInfo mi): this() { - list = new ArrayList { mi }; + this.AddMethod(mi); } public int Count @@ -37,6 +39,7 @@ public int Count internal void AddMethod(MethodBase m) { + Debug.Assert(!init); list.Add(m); } @@ -372,7 +375,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out bool isNewReference) { isNewReference = false; - IntPtr op; + IntPtr op; // for a params method, we may have a sequence or single/multiple items // here we look to see if the item at the paramIndex is there or not // and then if it is a sequence itself. @@ -390,10 +393,6 @@ static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out { isNewReference = true; op = Runtime.PyTuple_GetSlice(args, arrayStart, pyArgCount); - if (item != IntPtr.Zero) - { - Runtime.XDecref(item); - } } } else @@ -427,7 +426,6 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray, outs = 0; var margs = new object[pi.Length]; int arrayStart = paramsArray ? pi.Length - 1 : -1; - for (int paramIndex = 0; paramIndex < pi.Length; paramIndex++) { var parameter = pi[paramIndex]; @@ -462,8 +460,7 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray, } bool isOut; - if (!TryConvertArgument(op, parameter.ParameterType, needsResolution, out margs[paramIndex], out isOut)) - { + if (!TryConvertArgument(new BorrowedReference(op), parameter.ParameterType, needsResolution, out margs[paramIndex], out isOut)) { return null; } @@ -484,7 +481,7 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray, return margs; } - static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResolution, + static bool TryConvertArgument(BorrowedReference op, Type parameterType, bool needsResolution, out object arg, out bool isOut) { arg = null; @@ -505,44 +502,36 @@ static bool TryConvertArgument(IntPtr op, Type parameterType, bool needsResoluti return true; } - static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool needsResolution) + static Type TryComputeClrArgumentType(Type parameterType, BorrowedReference argument, bool needsResolution) { // this logic below handles cases when multiple overloading methods // are ambiguous, hence comparison between Python and CLR types // is necessary Type clrtype = null; - IntPtr pyoptype; if (needsResolution) { // HACK: each overload should be weighted in some way instead - pyoptype = Runtime.PyObject_Type(argument); + BorrowedReference pyoptype = Runtime.PyObject_TYPE(argument); Exceptions.Clear(); - if (pyoptype != IntPtr.Zero) + if (!pyoptype.IsNull) { clrtype = Converter.GetTypeByAlias(pyoptype); } - Runtime.XDecref(pyoptype); } if (clrtype != null) { - var typematch = false; if ((parameterType != typeof(object)) && (parameterType != clrtype)) { - IntPtr pytype = Converter.GetPythonTypeByAlias(parameterType); - pyoptype = Runtime.PyObject_Type(argument); + BorrowedReference pytype = Converter.GetPythonTypeByAlias(parameterType); + BorrowedReference pyoptype = Runtime.PyObject_TYPE(argument); Exceptions.Clear(); - if (pyoptype != IntPtr.Zero) + + bool typematch = false; + if (pyoptype != IntPtr.Zero && pytype == pyoptype) { - if (pytype != pyoptype) - { - typematch = false; - } - else - { - typematch = true; - clrtype = parameterType; - } + typematch = true; + clrtype = parameterType; } if (!typematch) { @@ -555,7 +544,6 @@ static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool clrtype = parameterType; } } - Runtime.XDecref(pyoptype); if (!typematch) { return null; @@ -563,7 +551,6 @@ static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool } else { - typematch = true; clrtype = parameterType; } } @@ -584,6 +571,15 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa var match = false; paramsArray = parameters.Length > 0 ? Attribute.IsDefined(parameters[parameters.Length - 1], typeof(ParamArrayAttribute)) : false; + if (parameters.Length > 0 + && Attribute.IsDefined(parameters[parameters.Length - 1], typeof(ParamArrayAttribute))) + { + parameters = parameters.Take(parameters.Length - 1).ToArray(); + // since we have params array, any more parameters is fine + positionalArgumentCount = Math.Min(positionalArgumentCount, parameters.Length); + paramsArray = true; + } + if (positionalArgumentCount == parameters.Length) { match = true; @@ -617,13 +613,6 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa } } } - else if (positionalArgumentCount > parameters.Length && parameters.Length > 0 && - Attribute.IsDefined(parameters[parameters.Length - 1], typeof(ParamArrayAttribute))) - { - // This is a `foo(params object[] bar)` style method - match = true; - paramsArray = true; - } return match; } @@ -680,10 +669,18 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i if (binding == null) { + var methods = methodinfo ?? this.methods; var value = new StringBuilder("No method matches given arguments"); - if (methodinfo != null && methodinfo.Length > 0) - { - value.Append($" for {methodinfo[0].Name}"); + if (methods != null && methods.Length > 0) { + value.Append(" for "); + if (inst != IntPtr.Zero && inst != Runtime.PyNone) { + value.Append(Runtime.PyObject_GetTypeName(inst)); + value.Append(methods[0].IsStatic ? "::": "."); + } else { + value.Append(methods[0].DeclaringType.Name); + value.Append("::"); + } + value.Append(methods[0].Name); } value.Append(": "); @@ -739,7 +736,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i var n = 0; IntPtr t = Runtime.PyTuple_New(binding.outs + 1); - IntPtr v = Converter.ToPython(result, mi.ReturnType); + IntPtr v = Converter.ToPython(result); Runtime.PyTuple_SetItem(t, n, v); n++; @@ -748,7 +745,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i Type pt = pi[i].ParameterType; if (pi[i].IsOut || pt.IsByRef) { - v = Converter.ToPython(binding.args[i], pt); + v = Converter.ToPython(binding.args[i]); Runtime.PyTuple_SetItem(t, n, v); n++; } @@ -765,7 +762,7 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i return t; } - return Converter.ToPython(result, mi.ReturnType); + return Converter.ToPython(result); } } @@ -825,33 +822,4 @@ internal Binding(MethodBase info, object inst, object[] args, int outs) this.outs = outs; } } - - - static internal class ParameterInfoExtensions - { - public static object GetDefaultValue(this ParameterInfo parameterInfo) - { - // parameterInfo.HasDefaultValue is preferable but doesn't exist in .NET 4.0 - bool hasDefaultValue = (parameterInfo.Attributes & ParameterAttributes.HasDefault) == - ParameterAttributes.HasDefault; - - if (hasDefaultValue) - { - return parameterInfo.DefaultValue; - } - else - { - // [OptionalAttribute] was specified for the parameter. - // See https://stackoverflow.com/questions/3416216/optionalattribute-parameters-default-value - // for rules on determining the value to pass to the parameter - var type = parameterInfo.ParameterType; - if (type == typeof(object)) - return Type.Missing; - else if (type.IsValueType) - return Activator.CreateInstance(type); - else - return null; - } - } - } } diff --git a/src/runtime/methodbinding.cs b/src/runtime/methodbinding.cs index f402f91f8..c9851c947 100644 --- a/src/runtime/methodbinding.cs +++ b/src/runtime/methodbinding.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; namespace Python.Runtime @@ -15,10 +16,12 @@ internal class MethodBinding : ExtensionType internal MethodObject m; internal IntPtr target; internal IntPtr targetType; + internal BorrowedReference Target => new BorrowedReference(this.target); + internal BorrowedReference TargetType => new BorrowedReference(this.targetType); public MethodBinding(MethodObject m, IntPtr target, IntPtr targetType) { - Runtime.XIncref(target); + if (target != IntPtr.Zero) Runtime.XIncref(target); this.target = target; Runtime.XIncref(targetType); @@ -41,7 +44,7 @@ public MethodBinding(MethodObject m, IntPtr target) : this(m, target, IntPtr.Zer /// public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { - var self = (MethodBinding)GetManagedObject(tp); + var self = GetInstance(tp); Type[] types = Runtime.PythonArgsToTypeArray(idx); if (types == null) @@ -59,13 +62,71 @@ public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) return mb.pyHandle; } + PyObject Singature { + get { + var infos = this.info == null ? this.m.info : new[] {this.info}; + var type = infos.Select(i => i.DeclaringType) + .OrderByDescending(t => t, new TypeSpecificityComparer()) + .First(); + infos = infos.Where(info => info.DeclaringType == type).ToArray(); + // this is a primitive version + // the overload with the maximum number of parameters should be used + var primary = infos.OrderByDescending(i => i.GetParameters().Length).First(); + var primaryParameters = primary.GetParameters(); + PyObject signatureClass = Runtime.InspectModule.GetAttr("Signature"); + var primaryReturn = primary.ReturnParameter; + + var parameters = new PyList(); + var parameterClass = primaryParameters.Length > 0 ? Runtime.InspectModule.GetAttr("Parameter") : null; + var positionalOrKeyword = parameterClass?.GetAttr("POSITIONAL_OR_KEYWORD"); + for (int i = 0; i < primaryParameters.Length; i++) { + var parameter = primaryParameters[i]; + var alternatives = infos.Select(info => { + ParameterInfo[] altParamters = info.GetParameters(); + return i < altParamters.Length ? altParamters[i] : null; + }).Where(p => p != null); + var defaultValue = alternatives + .Select(alternative => alternative.DefaultValue != DBNull.Value ? alternative.DefaultValue.ToPython() : null) + .FirstOrDefault(v => v != null) ?? parameterClass.GetAttr("empty"); + + if (alternatives.Any(alternative => alternative.Name != parameter.Name)) { + return signatureClass.Invoke(); + } + + var args = new PyTuple(new []{ parameter.Name.ToPython(), positionalOrKeyword}); + var kw = new PyDict(); + if (defaultValue != null) { + kw["default"] = defaultValue; + } + var parameterInfo = parameterClass.Invoke(args: args, kw: kw); + parameters.Append(parameterInfo); + } + + // TODO: add return annotation + return signatureClass.Invoke(parameters); + } + } + + struct TypeSpecificityComparer : IComparer { + public int Compare(Type a, Type b) { + if (a == b) return 0; + if (a.IsSubclassOf(b)) return 1; + if (b.IsSubclassOf(a)) return -1; + throw new NotSupportedException(); + } + } + + static MethodBinding GetInstance(IntPtr ob) + => GetInstance(new BorrowedReference(ob)); + static MethodBinding GetInstance(BorrowedReference ob) + => GetManagedObject(ob); /// /// MethodBinding __getattribute__ implementation. /// public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - var self = (MethodBinding)GetManagedObject(ob); + var self = GetInstance(ob); if (!Runtime.PyString_Check(key)) { @@ -85,6 +146,18 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) case "Overloads": var om = new OverloadMapper(self.m, self.target); return om.pyHandle; + case "__signature__": + var sig = self.Singature; + if (sig is null) + { + return Runtime.PyObject_GenericGetAttr(ob, key); + } + return sig.Reference.DangerousIncRefOrNull(); + case "__name__": + var pyName = self.m.GetName(); + return pyName == IntPtr.Zero + ? IntPtr.Zero + : Runtime.SelfIncRef(pyName); default: return Runtime.PyObject_GenericGetAttr(ob, key); } @@ -96,7 +169,7 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) /// public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - var self = (MethodBinding)GetManagedObject(ob); + var self = GetInstance(ob); // This works around a situation where the wrong generic method is picked, // for example this method in the tests: string Overloaded(int arg1, int arg2, string arg3) @@ -125,7 +198,7 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) var disposeList = new List(); try { - IntPtr target = self.target; + var target = self.target; if (target == IntPtr.Zero && !self.m.IsStatic()) { @@ -149,22 +222,22 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) IntPtr superType = IntPtr.Zero; if (Runtime.PyObject_TYPE(target) != self.targetType) { - var inst = GetManagedObject(target) as CLRObject; + var inst = ManagedType.GetManagedObject(target) as CLRObject; if (inst?.inst is IPythonDerivedType) { - var baseType = GetManagedObject(self.targetType) as ClassBase; + var baseType = ManagedType.GetManagedObject(self.TargetType) as ClassBase; if (baseType != null) { string baseMethodName = "_" + baseType.type.Name + "__" + self.m.name; - IntPtr baseMethod = Runtime.PyObject_GetAttrString(target, baseMethodName); - if (baseMethod != IntPtr.Zero) + using var baseMethod = Runtime.PyObject_GetAttrString(self.Target, baseMethodName); + if (!baseMethod.IsNull()) { - var baseSelf = GetManagedObject(baseMethod) as MethodBinding; - if (baseSelf != null) + BorrowedReference baseMethodType = Runtime.PyObject_TYPE(baseMethod); + BorrowedReference methodBindingTypeHandle = TypeManager.GetTypeHandle(typeof(MethodBinding)); + if (baseMethodType == methodBindingTypeHandle) { - self = baseSelf; + self = GetInstance(baseMethod); } - Runtime.XDecref(baseMethod); } else { @@ -191,7 +264,7 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) /// public static IntPtr tp_hash(IntPtr ob) { - var self = (MethodBinding)GetManagedObject(ob); + var self = GetInstance(ob); long x = 0; long y = 0; @@ -225,7 +298,7 @@ public static IntPtr tp_hash(IntPtr ob) /// public static IntPtr tp_repr(IntPtr ob) { - var self = (MethodBinding)GetManagedObject(ob); + var self = GetInstance(ob); string type = self.target == IntPtr.Zero ? "unbound" : "bound"; string name = self.m.name; return Runtime.PyString_FromString($"<{type} method '{name}'>"); @@ -236,7 +309,7 @@ public static IntPtr tp_repr(IntPtr ob) /// public new static void tp_dealloc(IntPtr ob) { - var self = (MethodBinding)GetManagedObject(ob); + var self = GetInstance(ob); Runtime.XDecref(self.target); Runtime.XDecref(self.targetType); FinalizeObject(self); diff --git a/src/runtime/methodobject.cs b/src/runtime/methodobject.cs index 8df9c8029..47332b831 100644 --- a/src/runtime/methodobject.cs +++ b/src/runtime/methodobject.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Reflection; namespace Python.Runtime @@ -90,6 +92,16 @@ internal IntPtr GetDocString() return doc; } + internal IntPtr GetName() + { + var names = new HashSet(binder.GetMethods().Select(m => m.Name)); + if (names.Count != 1) { + Exceptions.SetError(Exceptions.AttributeError, "a method has no name"); + return IntPtr.Zero; + } + return Runtime.PyString_FromString(names.First()); + } + /// /// This is a little tricky: a class can actually have a static method @@ -138,7 +150,7 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) /// public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - var self = (MethodObject)GetManagedObject(ds); + var self = GetManagedObject(new BorrowedReference(ds)); MethodBinding binding; // If the method is accessed through its type (rather than via @@ -166,7 +178,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) // this descriptor was defined on then it will be because the base class method // is being called via super(Derived, self).method(...). // In which case create a MethodBinding bound to the base class. - var obj = GetManagedObject(ob) as CLRObject; + var obj = ManagedType.GetManagedObject(ob) as CLRObject; if (obj != null && obj.inst.GetType() != self.type && obj.inst is IPythonDerivedType diff --git a/src/runtime/modulefunctionobject.cs b/src/runtime/modulefunctionobject.cs index 8f8692af9..f6321eca9 100644 --- a/src/runtime/modulefunctionobject.cs +++ b/src/runtime/modulefunctionobject.cs @@ -23,7 +23,7 @@ public ModuleFunctionObject(Type type, string name, MethodInfo[] info, bool allo /// public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - var self = (ModuleFunctionObject)GetManagedObject(ob); + var self = GetManagedObject(new BorrowedReference(ob)); return self.Invoke(ob, args, kw); } @@ -32,7 +32,7 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) /// public new static IntPtr tp_repr(IntPtr ob) { - var self = (ModuleFunctionObject)GetManagedObject(ob); + var self = GetManagedObject(new BorrowedReference(ob)); return Runtime.PyString_FromString($""); } } diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs index 15e4feee8..abab4f8b2 100644 --- a/src/runtime/moduleobject.cs +++ b/src/runtime/moduleobject.cs @@ -45,16 +45,16 @@ public ModuleObject(string name) IntPtr pyname = Runtime.PyString_FromString(moduleName); IntPtr pyfilename = Runtime.PyString_FromString(filename); IntPtr pydocstring = Runtime.PyString_FromString(docstring); - IntPtr pycls = TypeManager.GetTypeHandle(GetType()); + BorrowedReference pycls = TypeManager.GetTypeHandle(GetType()); Runtime.PyDict_SetItemString(dict, "__name__", pyname); Runtime.PyDict_SetItemString(dict, "__file__", pyfilename); Runtime.PyDict_SetItemString(dict, "__doc__", pydocstring); - Runtime.PyDict_SetItemString(dict, "__class__", pycls); + Runtime.PyDict_SetItemString(dict, "__class__", pycls.DangerousGetAddress()); Runtime.XDecref(pyname); Runtime.XDecref(pyfilename); Runtime.XDecref(pydocstring); - Marshal.WriteIntPtr(pyHandle, ObjectOffset.TypeDictOffset(tpHandle), dict); + Marshal.WriteIntPtr(pyHandle, ObjectOffset.TypeDictOffset(Type), dict); InitializeModuleMembers(); } @@ -251,7 +251,7 @@ internal void InitializeModuleMembers() /// public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - var self = (ModuleObject)GetManagedObject(ob); + var self = GetManagedObject(new BorrowedReference(ob)); if (!Runtime.PyString_Check(key)) { @@ -301,7 +301,7 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key) /// public static IntPtr tp_repr(IntPtr ob) { - var self = (ModuleObject)GetManagedObject(ob); + var self = GetManagedObject(new BorrowedReference(ob)); return Runtime.PyString_FromString($""); } } diff --git a/src/runtime/nativecall.cs b/src/runtime/nativecall.cs index 4a7bf05c8..fc72209ee 100644 --- a/src/runtime/nativecall.cs +++ b/src/runtime/nativecall.cs @@ -21,7 +21,7 @@ namespace Python.Runtime /// build process to generate the thunks as a separate assembly /// that could then be referenced by the main Python runtime. /// - internal class NativeCall + internal static class NativeCall { #if NETSTANDARD [UnmanagedFunctionPointer(CallingConvention.Cdecl)] @@ -48,6 +48,12 @@ public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2, IntPtr a3) var d = Marshal.GetDelegateForFunctionPointer(fp); return d(a1, a2, a3); } + + public static IntPtr Call_2(IntPtr fp, IntPtr a1, IntPtr a2) + { + var d = (Interop.BinaryFunc)Marshal.GetDelegateForFunctionPointer(fp, typeof(Interop.BinaryFunc)); + return d(a1, a2); + } #else private static AssemblyBuilder aBuilder; private static ModuleBuilder mBuilder; @@ -149,6 +155,11 @@ public static void Void_Call_1(IntPtr fp, IntPtr a1) Impl.Void_Call_1(fp, a1); } + public static IntPtr Call_2(IntPtr fp, IntPtr a1, IntPtr a2) + { + return Impl.Call_2(fp, a1, a2); + } + public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2, IntPtr a3) { return Impl.Call_3(fp, a1, a2, a3); @@ -171,6 +182,8 @@ public interface INativeCall void Void_Call_1(IntPtr funcPtr, IntPtr arg1); + IntPtr Call_2(IntPtr funcPtr, IntPtr a1, IntPtr a2); + int Int_Call_3(IntPtr funcPtr, IntPtr t, IntPtr n, IntPtr v); IntPtr Call_3(IntPtr funcPtr, IntPtr a1, IntPtr a2, IntPtr a3); diff --git a/src/runtime/platform/LibraryLoader.cs b/src/runtime/platform/LibraryLoader.cs index a6d88cd19..4aa6d53a2 100644 --- a/src/runtime/platform/LibraryLoader.cs +++ b/src/runtime/platform/LibraryLoader.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using System.IO; using System.Runtime.InteropServices; namespace Python.Runtime.Platform @@ -40,7 +41,7 @@ class LinuxLoader : ILibraryLoader public IntPtr Load(string dllToLoad) { - var filename = $"lib{dllToLoad}.so"; + var filename = File.Exists(dllToLoad) ? dllToLoad : $"lib{dllToLoad}.so"; ClearError(); var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); if (res == IntPtr.Zero) @@ -111,7 +112,7 @@ class DarwinLoader : ILibraryLoader public IntPtr Load(string dllToLoad) { - var filename = $"lib{dllToLoad}.dylib"; + var filename = File.Exists(dllToLoad) ? dllToLoad : $"lib{dllToLoad}.dylib"; ClearError(); var res = dlopen(filename, RTLD_NOW | RTLD_GLOBAL); if (res == IntPtr.Zero) diff --git a/src/runtime/polyfill/ExceptionPolifills.cs b/src/runtime/polyfill/ExceptionPolifills.cs new file mode 100644 index 000000000..923ff41a3 --- /dev/null +++ b/src/runtime/polyfill/ExceptionPolifills.cs @@ -0,0 +1,19 @@ +namespace Python.Runtime +{ + using System; + using System.Runtime.ExceptionServices; + + static class ExceptionPolifills + { + public static Exception Rethrow(this Exception exception) + { + if (exception is null) + throw new ArgumentNullException(nameof(exception)); + +#if NETSTANDARD + ExceptionDispatchInfo.Capture(exception).Throw(); +#endif + throw exception; + } + } +} diff --git a/src/runtime/polyfill/ReflectionPolifills.cs b/src/runtime/polyfill/ReflectionPolifills.cs index b9ce78d63..b2c60a83e 100644 --- a/src/runtime/polyfill/ReflectionPolifills.cs +++ b/src/runtime/polyfill/ReflectionPolifills.cs @@ -16,9 +16,10 @@ public static AssemblyBuilder DefineDynamicAssembly(this AppDomain appDomain, As public static Type CreateType(this TypeBuilder typeBuilder) { - return typeBuilder.GetTypeInfo().GetType(); + return typeBuilder.CreateTypeInfo(); } #endif +#if NETFX public static T GetCustomAttribute(this Type type) where T: Attribute { return type.GetCustomAttributes(typeof(T), inherit: false) @@ -32,5 +33,31 @@ public static T GetCustomAttribute(this Assembly assembly) where T: Attribute .Cast() .SingleOrDefault(); } +#endif + + public static object GetDefaultValue(this ParameterInfo parameterInfo) + { + // parameterInfo.HasDefaultValue is preferable but doesn't exist in .NET 4.0 + bool hasDefaultValue = (parameterInfo.Attributes & ParameterAttributes.HasDefault) == + ParameterAttributes.HasDefault; + + if (hasDefaultValue) + { + return parameterInfo.DefaultValue; + } + else + { + // [OptionalAttribute] was specified for the parameter. + // See https://stackoverflow.com/questions/3416216/optionalattribute-parameters-default-value + // for rules on determining the value to pass to the parameter + var type = parameterInfo.ParameterType; + if (type == typeof(object)) + return Type.Missing; + else if (type.IsValueType) + return Activator.CreateInstance(type); + else + return null; + } + } } } diff --git a/src/runtime/propertyobject.cs b/src/runtime/propertyobject.cs index f2c97f163..728988bba 100644 --- a/src/runtime/propertyobject.cs +++ b/src/runtime/propertyobject.cs @@ -9,7 +9,7 @@ namespace Python.Runtime /// internal class PropertyObject : ExtensionType { - private PropertyInfo info; + internal PropertyInfo info; private MethodInfo getter; private MethodInfo setter; @@ -21,15 +21,17 @@ public PropertyObject(PropertyInfo md) info = md; } - + static PropertyObject GetInstance(IntPtr ob) + => GetManagedObject(new BorrowedReference(ob)); /// /// Descriptor __get__ implementation. This method returns the /// value of the property on the given object. The returned value /// is converted to an appropriately typed Python object. /// - public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) + public static IntPtr tp_descr_get(IntPtr ds, IntPtr obRaw, IntPtr tp) { - var self = (PropertyObject)GetManagedObject(ds); + var ob = new BorrowedReference(obRaw); + var self = GetInstance(ds); MethodInfo getter = self.getter; object result; @@ -43,23 +45,24 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { if (!getter.IsStatic) { - Exceptions.SetError(Exceptions.TypeError, - "instance property must be accessed through a class instance"); - return IntPtr.Zero; + Runtime.XIncref(ds); + // unbound property + return ds; } try { result = self.info.GetValue(null, null); - return Converter.ToPython(result, self.info.PropertyType); + return Converter.ToPython(result); } catch (Exception e) { - return Exceptions.RaiseTypeError(e.Message); + Exceptions.SetError(e); + return IntPtr.Zero; } } - var co = GetManagedObject(ob) as CLRObject; + var co = ManagedType.GetManagedObject(ob) as CLRObject; if (co == null) { return Exceptions.RaiseTypeError("invalid target"); @@ -68,7 +71,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) try { result = self.info.GetValue(co.inst, null); - return Converter.ToPython(result, self.info.PropertyType); + return Converter.ToPython(result); } catch (Exception e) { @@ -87,9 +90,10 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) /// a property based on the given Python value. The Python value must /// be convertible to the type of the property. /// - public new static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) + public new static int tp_descr_set(IntPtr ds, IntPtr obRaw, IntPtr val) { - var self = (PropertyObject)GetManagedObject(ds); + var ob = new BorrowedReference(obRaw); + var self = GetInstance(ds); MethodInfo setter = self.setter; object newval; @@ -126,7 +130,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { if (!is_static) { - var co = GetManagedObject(ob) as CLRObject; + var co = ManagedType.GetManagedObject(ob) as CLRObject; if (co == null) { Exceptions.RaiseTypeError("invalid target"); @@ -157,7 +161,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) /// public static IntPtr tp_repr(IntPtr ob) { - var self = (PropertyObject)GetManagedObject(ob); + var self = GetInstance(ob); return Runtime.PyString_FromString($""); } } diff --git a/src/runtime/pyansistring.cs b/src/runtime/pyansistring.cs index 3d1d6ab68..acedc59c6 100644 --- a/src/runtime/pyansistring.cs +++ b/src/runtime/pyansistring.cs @@ -25,14 +25,20 @@ public PyAnsiString(IntPtr ptr) : base(ptr) /// An ArgumentException will be thrown if the given object is not /// a Python string object. /// - public PyAnsiString(PyObject o) + public PyAnsiString(PyObject o): base(FromPyObject(o)) { + } + + static IntPtr FromPyObject(PyObject o) + { + if (o == null) throw new ArgumentNullException(nameof(o)); + if (!IsStringType(o)) { throw new ArgumentException("object is not a string"); } Runtime.XIncref(o.obj); - obj = o.obj; + return o.obj; } @@ -42,10 +48,8 @@ public PyAnsiString(PyObject o) /// /// Creates a Python string from a managed string. /// - public PyAnsiString(string s) + public PyAnsiString(string s):base(PythonException.ThrowIfIsNull(Runtime.PyString_FromString(s))) { - obj = Runtime.PyString_FromString(s); - Runtime.CheckExceptionOccurred(); } @@ -57,6 +61,8 @@ public PyAnsiString(string s) /// public static bool IsStringType(PyObject value) { + if (value == null) throw new ArgumentNullException(nameof(value)); + return Runtime.PyString_Check(value.obj); } } diff --git a/src/runtime/pybuffer.cs b/src/runtime/pybuffer.cs new file mode 100644 index 000000000..84ef2bde8 --- /dev/null +++ b/src/runtime/pybuffer.cs @@ -0,0 +1,241 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Python.Runtime +{ + public sealed class PyBuffer : IPyDisposable + { + private PyObject _exporter; + private Py_buffer _view; + + unsafe internal PyBuffer(PyObject exporter, PyBUF flags) + { + if (Runtime.PyObject_GetBuffer(exporter.Reference, out _view, flags) < 0) + { + throw PythonException.ThrowLastAsClrException(); + } + + _exporter = exporter; + + var intPtrBuf = new IntPtr[_view.ndim]; + if (_view.shape != IntPtr.Zero) + { + Marshal.Copy(_view.shape, intPtrBuf, 0, (int)_view.len * sizeof(IntPtr)); + Shape = intPtrBuf.Select(x => (long)x).ToArray(); + } + + if (_view.strides != IntPtr.Zero) { + Marshal.Copy(_view.strides, intPtrBuf, 0, (int)_view.len * sizeof(IntPtr)); + Strides = intPtrBuf.Select(x => (long)x).ToArray(); + } + + if (_view.suboffsets != IntPtr.Zero) { + Marshal.Copy(_view.suboffsets, intPtrBuf, 0, (int)_view.len * sizeof(IntPtr)); + SubOffsets = intPtrBuf.Select(x => (long)x).ToArray(); + } + } + + public PyObject Object => _exporter; + public long Length => (long)_view.len; + public long ItemSize => (long)_view.itemsize; + public int Dimensions => _view.ndim; + public bool ReadOnly => _view._readonly; + public IntPtr Buffer => _view.buf; + public string Format => _view.format; + + /// + /// An array of length indicating the shape of the memory as an n-dimensional array. + /// + public long[] Shape { get; private set; } + + /// + /// An array of length giving the number of bytes to skip to get to a new element in each dimension. + /// Will be null except when PyBUF_STRIDES or PyBUF_INDIRECT flags in GetBuffer/>. + /// + public long[] Strides { get; private set; } + + /// + /// An array of Py_ssize_t of length ndim. If suboffsets[n] >= 0, + /// the values stored along the nth dimension are pointers and the suboffset value dictates how many bytes to add to each pointer after de-referencing. + /// A suboffset value that is negative indicates that no de-referencing should occur (striding in a contiguous memory block). + /// + public long[] SubOffsets { get; private set; } + + /// + /// Return the implied itemsize from format. On error, raise an exception and return -1. + /// New in version 3.9. + /// + public static long SizeFromFormat(string format) + { + if (Runtime.PythonVersion < new Version(3, 9)) + throw new NotSupportedException("SizeFromFormat requires at least Python 3.9"); + return (long)Runtime.PyBuffer_SizeFromFormat(format); + } + + /// + /// Returns true if the memory defined by the view is C-style (order is 'C') or Fortran-style (order is 'F') contiguous or either one (order is 'A'). Returns false otherwise. + /// + /// C-style (order is 'C') or Fortran-style (order is 'F') contiguous or either one (order is 'A') + public bool IsContiguous(BufferOrderStyle order) + { + if (disposedValue) + throw new ObjectDisposedException(nameof(PyBuffer)); + return Convert.ToBoolean(Runtime.PyBuffer_IsContiguous(ref _view, order)); + } + + /// + /// Get the memory area pointed to by the indices inside the given view. indices must point to an array of view->ndim indices. + /// + public IntPtr GetPointer(long[] indices) + { + if (disposedValue) + throw new ObjectDisposedException(nameof(PyBuffer)); + if (Runtime.PythonVersion < new Version(3, 7)) + throw new NotSupportedException("GetPointer requires at least Python 3.7"); + return Runtime.PyBuffer_GetPointer(ref _view, indices.Select(x => (IntPtr)x).ToArray()); + } + + /// + /// Copy contiguous len bytes from buf to view. fort can be 'C' or 'F' (for C-style or Fortran-style ordering). + /// + public void FromContiguous(IntPtr buf, long len, BufferOrderStyle fort) + { + if (disposedValue) + throw new ObjectDisposedException(nameof(PyBuffer)); + if (Runtime.PythonVersion < new Version(3, 7)) + throw new NotSupportedException("FromContiguous requires at least Python 3.7"); + + if (Runtime.PyBuffer_FromContiguous(ref _view, buf, (IntPtr)len, fort) < 0) + throw PythonException.ThrowLastAsClrException(); + } + + /// + /// Copy len bytes from view to its contiguous representation in buf. order can be 'C' or 'F' or 'A' (for C-style or Fortran-style ordering or either one). 0 is returned on success, -1 on error. + /// + /// order can be 'C' or 'F' or 'A' (for C-style or Fortran-style ordering or either one). + /// Buffer to copy to + public void ToContiguous(IntPtr buf, BufferOrderStyle order) + { + if (disposedValue) + throw new ObjectDisposedException(nameof(PyBuffer)); + if (Runtime.PythonVersion < new Version(3, 6)) + throw new NotSupportedException("ToContiguous requires at least Python 3.6"); + + if (Runtime.PyBuffer_ToContiguous(buf, ref _view, _view.len, order) < 0) + throw new PythonException(); + } + + /// + /// Fill the strides array with byte-strides of a contiguous (C-style if order is 'C' or Fortran-style if order is 'F') array of the given shape with the given number of bytes per element. + /// + public static void FillContiguousStrides(int ndims, IntPtr[] shape, IntPtr[] strides, int itemsize, BufferOrderStyle order) + { + Runtime.PyBuffer_FillContiguousStrides(ndims, shape, strides, itemsize, order); + } + + /// + /// FillInfo Method + /// + /// + /// Handle buffer requests for an exporter that wants to expose buf of size len with writability set according to readonly. buf is interpreted as a sequence of unsigned bytes. + /// The flags argument indicates the request type. This function always fills in view as specified by flags, unless buf has been designated as read-only and PyBUF_WRITABLE is set in flags. + /// On success, set view->obj to a new reference to exporter and return 0. Otherwise, raise PyExc_BufferError, set view->obj to NULL and return -1; + /// If this function is used as part of a getbufferproc, exporter MUST be set to the exporting object and flags must be passed unmodified.Otherwise, exporter MUST be NULL. + /// + /// On success, set view->obj to a new reference to exporter and return 0. Otherwise, raise PyExc_BufferError, set view->obj to NULL and return -1; + public void FillInfo(IntPtr exporter, IntPtr buf, long len, bool @readonly, PyBUF flags) + { + if (disposedValue) + throw new ObjectDisposedException(nameof(PyBuffer)); + if (Runtime.PyBuffer_FillInfo(ref _view, new BorrowedReference(exporter), buf, (IntPtr)len, @readonly, flags) < 0) + throw new PythonException(); + } + + /// + /// Writes a managed byte array into the buffer of a python object. This can be used to pass data like images from managed to python. + /// + public void Write(byte[] buffer, int offset, int count) + { + if (disposedValue) + throw new ObjectDisposedException(nameof(PyBuffer)); + if (ReadOnly) + throw new InvalidOperationException("Buffer is read-only"); + if ((long)_view.len > int.MaxValue) + throw new NotSupportedException("Python buffers bigger than int.MaxValue are not supported."); + if (count > buffer.Length) + throw new ArgumentOutOfRangeException("count", "Count is bigger than the buffer."); + if (count > (int)_view.len) + throw new ArgumentOutOfRangeException("count", "Count is bigger than the python buffer."); + if (_view.ndim != 1) + throw new NotSupportedException("Multidimensional arrays, scalars and objects without a buffer are not supported."); + + Marshal.Copy(buffer, offset, _view.buf, count); + } + + /// + /// Reads the buffer of a python object into a managed byte array. This can be used to pass data like images from python to managed. + /// + public int Read(byte[] buffer, int offset, int count) { + if (disposedValue) + throw new ObjectDisposedException(nameof(PyBuffer)); + if (count > buffer.Length) + throw new ArgumentOutOfRangeException("count", "Count is bigger than the buffer."); + if (_view.ndim != 1) + throw new NotSupportedException("Multidimensional arrays, scalars and objects without a buffer are not supported."); + if (_view.len.ToInt64() > int.MaxValue) + throw new NotSupportedException("Python buffers bigger than int.MaxValue are not supported."); + + int copylen = count < (int)_view.len ? count : (int)_view.len; + Marshal.Copy(_view.buf, buffer, offset, copylen); + return copylen; + } + + private bool disposedValue = false; // To detect redundant calls + + private void Dispose(bool disposing) + { + if (!disposedValue) + { + if (Runtime.Py_IsInitialized() == 0) + throw new InvalidOperationException("Python runtime must be initialized"); + + // this also decrements ref count for _view->obj + Runtime.PyBuffer_Release(ref _view); + + _exporter = null; + Shape = null; + Strides = null; + SubOffsets = null; + + disposedValue = true; + } + } + + ~PyBuffer() + { + if (disposedValue) + { + return; + } + Finalizer.Instance.AddFinalizedObject(this); + } + + /// + /// Release the buffer view and decrement the reference count for view->obj. This function MUST be called when the buffer is no longer being used, otherwise reference leaks may occur. + /// It is an error to call this function on a buffer that was not obtained via . + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public IntPtr[] GetTrackedHandles() + { + return new IntPtr[] { _view.obj }; + } + } +} diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs index 7ff7a83c8..ea9633d61 100644 --- a/src/runtime/pydict.cs +++ b/src/runtime/pydict.cs @@ -29,13 +29,8 @@ public PyDict(IntPtr ptr) : base(ptr) /// /// Creates a new Python dictionary object. /// - public PyDict() + public PyDict():base(Exceptions.ErrorCheck(Runtime.PyDict_New())) { - obj = Runtime.PyDict_New(); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } } @@ -47,14 +42,20 @@ public PyDict() /// ArgumentException will be thrown if the given object is not a /// Python dictionary object. /// - public PyDict(PyObject o) + public PyDict(PyObject o):base(FromPyObject(o)) + { + } + + static IntPtr FromPyObject(PyObject o) { + if (o == null) throw new ArgumentNullException(nameof(o)); + if (!IsDictType(o)) { throw new ArgumentException("object is not a dict"); } Runtime.XIncref(o.obj); - obj = o.obj; + return o.obj; } @@ -106,10 +107,7 @@ public bool HasKey(string key) public PyObject Keys() { IntPtr items = Runtime.PyDict_Keys(obj); - if (items == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(items); return new PyObject(items); } @@ -123,10 +121,7 @@ public PyObject Keys() public PyObject Values() { IntPtr items = Runtime.PyDict_Values(obj); - if (items == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(items); return new PyObject(items); } @@ -144,7 +139,7 @@ public PyObject Items() { if (items.IsNull()) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } return items.MoveToPyObject(); @@ -165,10 +160,7 @@ public PyObject Items() public PyDict Copy() { IntPtr op = Runtime.PyDict_Copy(obj); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(op); return new PyDict(op); } @@ -184,7 +176,7 @@ public void Update(PyObject other) int result = Runtime.PyDict_Update(obj, other.obj); if (result < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } diff --git a/src/runtime/pyfloat.cs b/src/runtime/pyfloat.cs index edfaca542..3a5f92e3c 100644 --- a/src/runtime/pyfloat.cs +++ b/src/runtime/pyfloat.cs @@ -31,14 +31,19 @@ public PyFloat(IntPtr ptr) : base(ptr) /// ArgumentException will be thrown if the given object is not a /// Python float object. /// - public PyFloat(PyObject o) + public PyFloat(PyObject o):base(FromPyObject(o)) { + } + + static IntPtr FromPyObject(PyObject o) + { + if (o == null) throw new ArgumentNullException(nameof(o)); if (!IsFloatType(o)) { throw new ArgumentException("object is not a float"); } Runtime.XIncref(o.obj); - obj = o.obj; + return o.obj; } @@ -48,10 +53,8 @@ public PyFloat(PyObject o) /// /// Creates a new Python float from a double value. /// - public PyFloat(double value) + public PyFloat(double value):base(PythonException.ThrowIfIsNull(Runtime.PyFloat_FromDouble(value))) { - obj = Runtime.PyFloat_FromDouble(value); - Runtime.CheckExceptionOccurred(); } @@ -61,12 +64,19 @@ public PyFloat(double value) /// /// Creates a new Python float from a string value. /// - public PyFloat(string value) + public PyFloat(string value):base(FromString(value)) { + } + + static IntPtr FromString(string value) + { + if (value == null) throw new ArgumentNullException(nameof(value)); + using (var s = new PyString(value)) { - obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); + var obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); Runtime.CheckExceptionOccurred(); + return obj; } } @@ -79,6 +89,8 @@ public PyFloat(string value) /// public static bool IsFloatType(PyObject value) { + if (value == null) throw new ArgumentNullException(nameof(value)); + return Runtime.PyFloat_Check(value.obj); } diff --git a/src/runtime/pyint.cs b/src/runtime/pyint.cs index 217cf7e20..9ed41cdd7 100644 --- a/src/runtime/pyint.cs +++ b/src/runtime/pyint.cs @@ -31,14 +31,20 @@ public PyInt(IntPtr ptr) : base(ptr) /// ArgumentException will be thrown if the given object is not a /// Python int object. /// - public PyInt(PyObject o) + public PyInt(PyObject o):base(FromPyObject(o)) { + } + + static IntPtr FromPyObject(PyObject o) + { + if (o == null) throw new ArgumentNullException(nameof(o)); + if (!IsIntType(o)) { throw new ArgumentException("object is not an int"); } Runtime.XIncref(o.obj); - obj = o.obj; + return o.obj; } @@ -48,10 +54,8 @@ public PyInt(PyObject o) /// /// Creates a new Python int from an int32 value. /// - public PyInt(int value) + public PyInt(int value):base(PythonException.ThrowIfIsNull(Runtime.PyInt_FromInt32(value))) { - obj = Runtime.PyInt_FromInt32(value); - Runtime.CheckExceptionOccurred(); } @@ -62,10 +66,8 @@ public PyInt(int value) /// Creates a new Python int from a uint32 value. /// [CLSCompliant(false)] - public PyInt(uint value) + public PyInt(uint value) : base(PythonException.ThrowIfIsNull(Runtime.PyInt_FromInt64(value))) { - obj = Runtime.PyInt_FromInt64(value); - Runtime.CheckExceptionOccurred(); } @@ -75,10 +77,8 @@ public PyInt(uint value) /// /// Creates a new Python int from an int64 value. /// - public PyInt(long value) + public PyInt(long value) : base(PythonException.ThrowIfIsNull(Runtime.PyInt_FromInt64(value))) { - obj = Runtime.PyInt_FromInt64(value); - Runtime.CheckExceptionOccurred(); } @@ -89,10 +89,8 @@ public PyInt(long value) /// Creates a new Python int from a uint64 value. /// [CLSCompliant(false)] - public PyInt(ulong value) + public PyInt(ulong value) : base(PythonException.ThrowIfIsNull(Runtime.PyInt_FromInt64((long)value))) { - obj = Runtime.PyInt_FromInt64((long)value); - Runtime.CheckExceptionOccurred(); } @@ -148,10 +146,10 @@ public PyInt(sbyte value) : this((int)value) /// /// Creates a new Python int from a string value. /// - public PyInt(string value) + public PyInt(string value):base( + PythonException.ThrowIfIsNull( + Runtime.PyInt_FromString(value ?? throw new ArgumentNullException(nameof(value)), IntPtr.Zero, 0))) { - obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0); - Runtime.CheckExceptionOccurred(); } @@ -163,6 +161,8 @@ public PyInt(string value) /// public static bool IsIntType(PyObject value) { + if (value == null) throw new ArgumentNullException(nameof(value)); + return Runtime.PyInt_Check(value.obj); } @@ -177,6 +177,8 @@ public static bool IsIntType(PyObject value) /// public static PyInt AsInt(PyObject value) { + if (value == null) throw new ArgumentNullException(nameof(value)); + IntPtr op = Runtime.PyNumber_Int(value.obj); Runtime.CheckExceptionOccurred(); return new PyInt(op); diff --git a/src/runtime/pyiter.cs b/src/runtime/pyiter.cs index ee07bcecf..7be981678 100644 --- a/src/runtime/pyiter.cs +++ b/src/runtime/pyiter.cs @@ -9,7 +9,7 @@ namespace Python.Runtime /// PY3: https://docs.python.org/3/c-api/iterator.html /// for details. /// - public class PyIter : PyObject, IEnumerator + public class PyIter : PyObject, IEnumerator { private PyObject _current; @@ -24,59 +24,50 @@ public class PyIter : PyObject, IEnumerator public PyIter(IntPtr ptr) : base(ptr) { } - /// - /// PyIter Constructor + /// Creates new from an untyped reference to Python iterator object. /// - /// - /// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python. - /// - public PyIter(PyObject iterable) - { - obj = Runtime.PyObject_GetIter(iterable.obj); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } + public PyIter(PyObject pyObject) : base(FromPyObject(pyObject)) { } + static BorrowedReference FromPyObject(PyObject pyObject) { + if (pyObject is null) throw new ArgumentNullException(nameof(pyObject)); + + if (!Runtime.PyIter_Check(pyObject.Reference)) + throw new ArgumentException("Object does not support iterator protocol"); + + return pyObject.Reference; } + internal PyIter(BorrowedReference reference) : base(reference) { } + protected override void Dispose(bool disposing) { - if (null != _current) - { - _current.Dispose(); - _current = null; - } + _current = null; base.Dispose(disposing); } public bool MoveNext() { - // dispose of the previous object, if there was one - if (null != _current) + using var next = Runtime.PyIter_Next(Reference); + if (next.IsNull()) { - _current.Dispose(); - _current = null; - } + if (Exceptions.ErrorOccurred()) + throw PythonException.ThrowLastAsClrException(); - IntPtr next = Runtime.PyIter_Next(obj); - if (next == IntPtr.Zero) - { + // dispose of the previous object, if there was one + _current = null; return false; } - _current = new PyObject(next); + _current = next.MoveToPyObject(); return true; } public void Reset() { - //Not supported in python. + throw new NotSupportedException(); } - public object Current - { - get { return _current; } - } + public PyObject Current => _current; + object System.Collections.IEnumerator.Current => this.Current; } } diff --git a/src/runtime/pylist.cs b/src/runtime/pylist.cs index 347cc3000..2da90d027 100644 --- a/src/runtime/pylist.cs +++ b/src/runtime/pylist.cs @@ -10,6 +10,22 @@ namespace Python.Runtime /// public class PyList : PySequence { + /// + /// Gets an instance of representing the same object as the given object. + /// + public static PyList Wrap(PyObject o) + { + if (o is null) + { + throw new ArgumentNullException(nameof(o)); + } + if (!IsListType(o)) + { + throw new ArgumentException("object is not a list"); + } + return new PyList(o.Reference); + } + /// /// PyList Constructor /// @@ -22,39 +38,25 @@ public PyList(IntPtr ptr) : base(ptr) { } - /// /// PyList Constructor /// /// - /// Copy constructor - obtain a PyList from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python list object. + /// Creates a new PyList from an existing object reference. + /// The object reference is not checked for type-correctness. /// - public PyList(PyObject o) + internal PyList(BorrowedReference reference) : base(reference) { - if (!IsListType(o)) - { - throw new ArgumentException("object is not a list"); - } - Runtime.XIncref(o.obj); - obj = o.obj; } - /// /// PyList Constructor /// /// /// Creates a new empty Python list object. /// - public PyList() + public PyList(): base(Exceptions.ErrorCheck(Runtime.PyList_New(0))) { - obj = Runtime.PyList_New(0); - if (obj == IntPtr.Zero) - { - throw new PythonException(); - } } @@ -75,7 +77,7 @@ public PyList(PyObject[] items) int r = Runtime.PyList_SetItem(obj, i, ptr); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } } @@ -104,10 +106,7 @@ public static bool IsListType(PyObject value) public static PyList AsList(PyObject value) { IntPtr op = Runtime.PySequence_List(value.obj); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(op); return new PyList(op); } @@ -123,7 +122,7 @@ public void Append(PyObject item) int r = Runtime.PyList_Append(this.Reference, item.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -138,7 +137,7 @@ public void Insert(int index, PyObject item) int r = Runtime.PyList_Insert(this.Reference, index, item.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -154,7 +153,7 @@ public void Reverse() int r = Runtime.PyList_Reverse(this.Reference); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -170,7 +169,7 @@ public void Sort() int r = Runtime.PyList_Sort(this.Reference); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } } diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs index 699ebf873..500a9156a 100644 --- a/src/runtime/pyobject.cs +++ b/src/runtime/pyobject.cs @@ -20,6 +20,7 @@ public interface IPyDisposable : IDisposable /// PY3: https://docs.python.org/3/c-api/object.html /// for details. /// + [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] public class PyObject : DynamicObject, IEnumerable, IPyDisposable { #if TRACE_ALLOC @@ -27,8 +28,9 @@ public class PyObject : DynamicObject, IEnumerable, IPyDisposable /// Trace stack for PyObject's construction /// public StackTrace Traceback { get; private set; } -#endif +#endif + readonly long run = Runtime.GetRun(); protected internal IntPtr obj = IntPtr.Zero; internal BorrowedReference Reference => new BorrowedReference(obj); @@ -99,10 +101,7 @@ protected PyObject() /// Gets the native handle of the underlying Python object. This /// value is generally for internal use by the PythonNet runtime. /// - public IntPtr Handle - { - get { return obj; } - } + public IntPtr Handle => obj == IntPtr.Zero ? throw new ObjectDisposedException(this.GetType().Name) : obj; /// @@ -136,9 +135,10 @@ public static PyObject FromManagedObject(object ob) public object AsManagedObject(Type t) { object result; - if (!Converter.ToManaged(obj, t, out result, false)) + if (!Converter.ToManaged(obj, t, out result, setError: true)) { - throw new InvalidCastException("cannot convert object to target type"); + throw new InvalidCastException("cannot convert object to target type", + innerException: PythonException.FromPyErrOrNull()); } return result; } @@ -150,19 +150,7 @@ public object AsManagedObject(Type t) /// Return a managed object of the given type, based on the /// value of the Python object. /// - public T As() - { - if (typeof(T) == typeof(PyObject) || typeof(T) == typeof(object)) - { - return (T)(this as object); - } - object result; - if (!Converter.ToManaged(obj, typeof(T), out result, false)) - { - throw new InvalidCastException("cannot convert object to target type"); - } - return (T)result; - } + public T As() => (T)this.AsManagedObject(typeof(T)); /// @@ -178,6 +166,8 @@ public T As() /// protected virtual void Dispose(bool disposing) { + DebugUtil.EnsureGIL(); + if (this.obj == IntPtr.Zero) { return; @@ -204,7 +194,7 @@ protected virtual void Dispose(bool disposing) { // Python requires finalizers to preserve exception: // https://docs.python.org/3/extending/newtypes.html#finalization-and-de-allocation - Runtime.PyErr_Restore(errType, errVal, traceback); + Runtime.PyErr_Restore(errType.Steal(), errVal.Steal(), traceback.Steal()); } } else @@ -226,6 +216,8 @@ public IntPtr[] GetTrackedHandles() return new IntPtr[] { obj }; } + internal BorrowedReference GetPythonTypeHandle() => new BorrowedReference(Runtime.PyObject_TYPE(obj)); + /// /// GetPythonType Method /// @@ -295,11 +287,10 @@ public PyObject GetAttr(string name) { if (name == null) throw new ArgumentNullException(nameof(name)); + DebugUtil.EnsureGIL(); + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(op); return new PyObject(op); } @@ -311,10 +302,13 @@ public PyObject GetAttr(string name) /// Returns the named attribute of the Python object, or the given /// default object if the attribute access fails. /// + [Obsolete("This method ignores any Python exceptions, and should not be used. Use GetAttrOrElse.")] public PyObject GetAttr(string name, PyObject _default) { if (name == null) throw new ArgumentNullException(nameof(name)); + DebugUtil.EnsureGIL(); + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); if (op == IntPtr.Zero) { @@ -324,6 +318,29 @@ public PyObject GetAttr(string name, PyObject _default) return new PyObject(op); } + /// + /// Gets the specified attribute. If attribute is not found, returns the fallback value. + /// + public PyObject GetAttrOrElse(string name, PyObject _default) + { + if (name == null) throw new ArgumentNullException(nameof(name)); + + DebugUtil.EnsureGIL(); + + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); + if (op == IntPtr.Zero) + { + if (!Exceptions.ExceptionMatches(Exceptions.AttributeError)) + { + throw PythonException.ThrowLastAsClrException(); + } + + Runtime.PyErr_Clear(); + return _default; + } + return new PyObject(op); + } + /// /// GetAttr Method @@ -337,11 +354,10 @@ public PyObject GetAttr(PyObject name) { if (name == null) throw new ArgumentNullException(nameof(name)); + DebugUtil.EnsureGIL(); + IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); - if (op == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(op); return new PyObject(op); } @@ -358,6 +374,8 @@ public PyObject GetAttr(PyObject name, PyObject _default) { if (name == null) throw new ArgumentNullException(nameof(name)); + DebugUtil.EnsureGIL(); + IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); if (op == IntPtr.Zero) { @@ -380,10 +398,12 @@ public void SetAttr(string name, PyObject value) if (name == null) throw new ArgumentNullException(nameof(name)); if (value == null) throw new ArgumentNullException(nameof(value)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_SetAttrString(obj, name, value.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -401,10 +421,12 @@ public void SetAttr(PyObject name, PyObject value) if (name == null) throw new ArgumentNullException(nameof(name)); if (value == null) throw new ArgumentNullException(nameof(value)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_SetAttr(obj, name.obj, value.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -420,10 +442,12 @@ public void DelAttr(string name) { if (name == null) throw new ArgumentNullException(nameof(name)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_SetAttrString(obj, name, IntPtr.Zero); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -440,10 +464,12 @@ public void DelAttr(PyObject name) { if (name == null) throw new ArgumentNullException(nameof(name)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_SetAttr(obj, name.obj, IntPtr.Zero); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -460,12 +486,15 @@ public virtual PyObject GetItem(PyObject key) { if (key == null) throw new ArgumentNullException(nameof(key)); - IntPtr op = Runtime.PyObject_GetItem(obj, key.obj); - if (op == IntPtr.Zero) + DebugUtil.EnsureGIL(); + + using var op = Runtime.PyObject_GetItem(Reference, key.Reference); + if (op.IsNull()) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } - return new PyObject(op); + + return op.MoveToPyObject(); } @@ -518,10 +547,12 @@ public virtual void SetItem(PyObject key, PyObject value) if (key == null) throw new ArgumentNullException(nameof(key)); if (value == null) throw new ArgumentNullException(nameof(value)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_SetItem(obj, key.obj, value.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -577,10 +608,12 @@ public virtual void DelItem(PyObject key) { if (key == null) throw new ArgumentNullException(nameof(key)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_DelItem(obj, key.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -624,17 +657,14 @@ public virtual void DelItem(int index) /// /// Length Method /// - /// - /// Returns the length for objects that support the Python sequence - /// protocol, or 0 if the object does not support the protocol. - /// public virtual long Length() { + DebugUtil.EnsureGIL(); + var s = Runtime.PyObject_Size(obj); if (s < 0) { - Runtime.PyErr_Clear(); - return 0; + throw PythonException.ThrowLastAsClrException(); } return s; } @@ -690,14 +720,12 @@ public virtual PyObject this[int index] /// to the Python expression "iter(object)". A PythonException will be /// raised if the object cannot be iterated. /// - public PyObject GetIterator() + public PyIter GetIterator() { - IntPtr r = Runtime.PyObject_GetIter(obj); - if (r == IntPtr.Zero) - { - throw new PythonException(); - } - return new PyObject(r); + DebugUtil.EnsureGIL(); + using var r = Runtime.PyObject_GetIter(Reference); + Exceptions.ErrorCheck(r); + return new PyIter(r); } /// @@ -708,10 +736,7 @@ public PyObject GetIterator() /// python object to be iterated over in C#. A PythonException will be /// raised if the object is not iterable. /// - public IEnumerator GetEnumerator() - { - return new PyIter(this); - } + public IEnumerator GetEnumerator() => this.GetIterator(); /// @@ -726,13 +751,12 @@ public PyObject Invoke(params PyObject[] args) if (args == null) throw new ArgumentNullException(nameof(args)); if (args.Contains(null)) throw new ArgumentNullException(); + DebugUtil.EnsureGIL(); + var t = new PyTuple(args); IntPtr r = Runtime.PyObject_Call(obj, t.obj, IntPtr.Zero); t.Dispose(); - if (r == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(r); return new PyObject(r); } @@ -748,11 +772,10 @@ public PyObject Invoke(PyTuple args) { if (args == null) throw new ArgumentNullException(nameof(args)); + DebugUtil.EnsureGIL(); + IntPtr r = Runtime.PyObject_Call(obj, args.obj, IntPtr.Zero); - if (r == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(r); return new PyObject(r); } @@ -769,13 +792,12 @@ public PyObject Invoke(PyObject[] args, PyDict kw) if (args == null) throw new ArgumentNullException(nameof(args)); if (args.Contains(null)) throw new ArgumentNullException(); + DebugUtil.EnsureGIL(); + var t = new PyTuple(args); IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw?.obj ?? IntPtr.Zero); t.Dispose(); - if (r == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(r); return new PyObject(r); } @@ -791,11 +813,10 @@ public PyObject Invoke(PyTuple args, PyDict kw) { if (args == null) throw new ArgumentNullException(nameof(args)); + DebugUtil.EnsureGIL(); + IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw?.obj ?? IntPtr.Zero); - if (r == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(r); return new PyObject(r); } @@ -843,7 +864,7 @@ public PyObject InvokeMethod(string name, PyTuple args) /// /// /// Invoke the named method of the object with the given arguments. - /// A PythonException is raised if the invocation is unsuccessful. + /// A PythonException is raised if the invokation is unsuccessful. /// public PyObject InvokeMethod(PyObject name, params PyObject[] args) { @@ -863,7 +884,7 @@ public PyObject InvokeMethod(PyObject name, params PyObject[] args) /// /// /// Invoke the named method of the object with the given arguments. - /// A PythonException is raised if the invocation is unsuccessful. + /// A PythonException is raised if the invokation is unsuccessful. /// public PyObject InvokeMethod(PyObject name, PyTuple args) { @@ -929,6 +950,8 @@ public bool IsInstance(PyObject typeOrClass) { if (typeOrClass == null) throw new ArgumentNullException(nameof(typeOrClass)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_IsInstance(obj, typeOrClass.obj); if (r < 0) { @@ -950,6 +973,8 @@ public bool IsSubclass(PyObject typeOrClass) { if (typeOrClass == null) throw new ArgumentNullException(nameof(typeOrClass)); + DebugUtil.EnsureGIL(); + int r = Runtime.PyObject_IsSubclass(obj, typeOrClass.obj); if (r < 0) { @@ -969,6 +994,7 @@ public bool IsSubclass(PyObject typeOrClass) /// public bool IsCallable() { + DebugUtil.EnsureGIL(); return Runtime.PyCallable_Check(obj) != 0; } @@ -982,7 +1008,8 @@ public bool IsCallable() /// public bool IsIterable() { - return Runtime.PyObject_IsIterable(obj); + DebugUtil.EnsureGIL(); + return Runtime.PyObject_IsIterable(Reference); } @@ -995,6 +1022,7 @@ public bool IsIterable() /// public bool IsTrue() { + DebugUtil.EnsureGIL(); return Runtime.PyObject_IsTrue(obj) != 0; } @@ -1012,11 +1040,9 @@ public bool IsTrue() /// public PyList Dir() { + DebugUtil.EnsureGIL(); IntPtr r = Runtime.PyObject_Dir(obj); - if (r == IntPtr.Zero) - { - throw new PythonException(); - } + Exceptions.ErrorCheck(r); return new PyList(r); } @@ -1030,6 +1056,7 @@ public PyList Dir() /// public string Repr() { + DebugUtil.EnsureGIL(); IntPtr strval = Runtime.PyObject_Repr(obj); string result = Runtime.GetManagedString(strval); Runtime.XDecref(strval); @@ -1046,12 +1073,18 @@ public string Repr() /// public override string ToString() { + DebugUtil.EnsureGIL(); IntPtr strval = Runtime.PyObject_Unicode(obj); + PythonException.ThrowIfIsNull(strval); string result = Runtime.GetManagedString(strval); Runtime.XDecref(strval); return result; } + string DebuggerDisplay => DebugUtil.HaveInterpreterLock() != false + ? this.ToString() + : $"pyobj at 0x{this.obj:X} (get Py.GIL to see more info)"; + /// /// Equals Method @@ -1070,10 +1103,11 @@ public override bool Equals(object o) { return true; } + DebugUtil.EnsureGIL(); int r = Runtime.PyObject_Compare(obj, ((PyObject)o).obj); if (Exceptions.ErrorOccurred()) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } return r == 0; } @@ -1089,9 +1123,25 @@ public override bool Equals(object o) /// public override int GetHashCode() { + DebugUtil.EnsureGIL(); return ((ulong)Runtime.PyObject_Hash(obj)).GetHashCode(); } + /// + /// GetBuffer Method. This Method only works for objects that have a buffer (like "bytes", "bytearray" or "array.array") + /// + /// + /// Send a request to the PyObject to fill in view as specified by flags. If the PyObject cannot provide a buffer of the exact type, it MUST raise PyExc_BufferError, set view->obj to NULL and return -1. + /// On success, fill in view, set view->obj to a new reference to exporter and return 0. In the case of chained buffer providers that redirect requests to a single object, view->obj MAY refer to this object instead of exporter(See Buffer Object Structures). + /// Successful calls to must be paired with calls to , similar to malloc() and free(). Thus, after the consumer is done with the buffer, must be called exactly once. + /// + public PyBuffer GetBuffer(PyBUF flags = PyBUF.SIMPLE) + { + if (Runtime.PythonVersion < new Version(3, 5)) + throw new NotSupportedException("GetBuffer requires at least Python 3.5"); + return new PyBuffer(this, flags); + } + public long Refcount { @@ -1110,11 +1160,12 @@ public override bool TryGetMember(GetMemberBinder binder, out object result) public override bool TrySetMember(SetMemberBinder binder, object value) { - IntPtr ptr = Converter.ToPython(value, value?.GetType()); + DebugUtil.EnsureGIL(); + IntPtr ptr = Converter.ToPython(value); int r = Runtime.PyObject_SetAttrString(obj, binder.Name, ptr); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } Runtime.XDecref(ptr); return true; @@ -1132,6 +1183,7 @@ private void GetArgs(object[] inargs, CallInfo callInfo, out PyTuple args, out P var namedArgumentCount = callInfo.ArgumentNames.Count; var regularArgumentCount = callInfo.ArgumentCount - namedArgumentCount; + DebugUtil.EnsureGIL(); var argTuple = Runtime.PyTuple_New(regularArgumentCount); for (int i = 0; i < regularArgumentCount; ++i) { @@ -1155,6 +1207,7 @@ private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs) { ; } + DebugUtil.EnsureGIL(); IntPtr argtuple = Runtime.PyTuple_New(arg_count); for (var i = 0; i < arg_count; i++) { @@ -1182,11 +1235,12 @@ private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs) private static void AddArgument(IntPtr argtuple, int i, object target) { + DebugUtil.EnsureGIL(); IntPtr ptr = GetPythonObject(target); if (Runtime.PyTuple_SetItem(argtuple, i, ptr) < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -1200,7 +1254,7 @@ private static IntPtr GetPythonObject(object target) } else { - ptr = Converter.ToPython(target, target?.GetType()); + ptr = Converter.ToPython(target); } return ptr; @@ -1273,6 +1327,7 @@ public override bool TryConvert(ConvertBinder binder, out object result) public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result) { + DebugUtil.EnsureGIL(); IntPtr res; if (!(arg is PyObject)) { @@ -1363,6 +1418,7 @@ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg result = null; return false; } + Exceptions.ErrorCheck(res); result = CheckNone(new PyObject(res)); return true; } @@ -1384,6 +1440,7 @@ private static object CheckNone(PyObject pyObj) public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result) { + DebugUtil.EnsureGIL(); int r; IntPtr res; switch (binder.Operation) @@ -1415,6 +1472,7 @@ public override bool TryUnaryOperation(UnaryOperationBinder binder, out object r result = null; return false; } + Exceptions.ErrorCheck(res); result = CheckNone(new PyObject(res)); return true; } @@ -1433,5 +1491,7 @@ public override IEnumerable GetDynamicMemberNames() yield return pyObj.ToString(); } } + + public PyObject Clone() => new PyObject(Runtime.SelfIncRef(this.Handle)); } } diff --git a/src/runtime/pyscope.cs b/src/runtime/pyscope.cs index 8738824f5..f9c4b19f7 100644 --- a/src/runtime/pyscope.cs +++ b/src/runtime/pyscope.cs @@ -22,22 +22,15 @@ public class PyGILAttribute : Attribute } [PyGIL] - public class PyScope : DynamicObject, IPyDisposable + public class PyScope : PyObject, IPyDisposable { - public readonly string Name; - - /// - /// the python Module object the scope associated with. - /// - internal readonly IntPtr obj; + public string Name { get; } /// /// the variable dict of the scope. /// - internal readonly IntPtr variables; - - private bool _isDisposed; - private bool _finalized = false; + internal IntPtr variables; + internal BorrowedReference VarsReference => new BorrowedReference(variables); /// /// The Manager this scope associated with. @@ -56,20 +49,23 @@ public class PyScope : DynamicObject, IPyDisposable /// /// Create a scope based on a Python Module. /// - internal PyScope(IntPtr ptr, PyScopeManager manager) + internal PyScope(IntPtr ptr, PyScopeManager manager): base(ptr) { if (!Runtime.PyType_IsSubtype(Runtime.PyObject_TYPE(ptr), Runtime.PyModuleType)) { throw new PyScopeException("object is not a module"); } Manager = manager ?? PyScopeManager.Global; - obj = ptr; //Refcount of the variables not increase variables = Runtime.PyModule_GetDict(obj); + if (variables == IntPtr.Zero) + { + throw new ArgumentException(message: "Scope does not have '__dict__'"); + } Runtime.CheckExceptionOccurred(); Runtime.PyDict_SetItemString( - variables, "__builtins__", + VarsReference, "__builtins__", Runtime.PyEval_GetBuiltins() ); this.Name = this.Get("__name__"); @@ -81,6 +77,8 @@ internal PyScope(IntPtr ptr, PyScopeManager manager) /// public PyDict Variables() { + this.EnsureNotDisposed(); + Runtime.XIncref(variables); return new PyDict(variables); } @@ -91,6 +89,8 @@ public PyDict Variables() /// public PyScope NewScope() { + this.EnsureNotDisposed(); + var scope = Manager.Create(); scope.ImportAll(this); return scope; @@ -105,7 +105,9 @@ public PyScope NewScope() /// public dynamic Import(string name, string asname = null) { - Check(); + if (name is null) throw new ArgumentNullException(nameof(name)); + this.EnsureNotDisposed(); + if (String.IsNullOrEmpty(asname)) { asname = name; @@ -133,7 +135,9 @@ public dynamic Import(string name, string asname = null) /// public void Import(PyScope scope, string asname) { - this.Set(asname, scope.obj); + if (scope is null) throw new ArgumentNullException(nameof(scope)); + + this.SetInternal(asname, scope.Reference); } /// @@ -145,6 +149,8 @@ public void Import(PyScope scope, string asname) /// public void Import(PyObject module, string asname = null) { + if (module is null) throw new ArgumentNullException(nameof(module)); + if (String.IsNullOrEmpty(asname)) { asname = module.GetAttr("__name__").As(); @@ -161,6 +167,8 @@ public void Import(PyObject module, string asname = null) /// public void ImportAll(string name) { + if (name is null) throw new ArgumentNullException(nameof(name)); + PyScope scope; Manager.TryGet(name, out scope); if (scope != null) @@ -183,10 +191,13 @@ public void ImportAll(string name) /// public void ImportAll(PyScope scope) { + if (scope is null) throw new ArgumentNullException(nameof(scope)); + this.EnsureNotDisposed(); + int result = Runtime.PyDict_Update(variables, scope.variables); if (result < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -198,15 +209,18 @@ public void ImportAll(PyScope scope) /// public void ImportAll(PyObject module) { + if (module is null) throw new ArgumentNullException(nameof(module)); + this.EnsureNotDisposed(); if (Runtime.PyObject_Type(module.obj) != Runtime.PyModuleType) { throw new PyScopeException("object is not a module"); } + var module_dict = Runtime.PyModule_GetDict(module.obj); int result = Runtime.PyDict_Update(variables, module_dict); if (result < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -218,10 +232,13 @@ public void ImportAll(PyObject module) /// public void ImportAll(PyDict dict) { + if (dict is null) throw new ArgumentNullException(nameof(dict)); + this.EnsureNotDisposed(); + int result = Runtime.PyDict_Update(variables, dict.obj); if (result < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -234,7 +251,9 @@ public void ImportAll(PyDict dict) /// public PyObject Execute(PyObject script, PyDict locals = null) { - Check(); + if (script is null) throw new ArgumentNullException(nameof(script)); + this.EnsureNotDisposed(); + IntPtr _locals = locals == null ? variables : locals.obj; IntPtr ptr = Runtime.PyEval_EvalCode(script.Handle, variables, _locals); Runtime.CheckExceptionOccurred(); @@ -256,14 +275,12 @@ public PyObject Execute(PyObject script, PyDict locals = null) /// public T Execute(PyObject script, PyDict locals = null) { - Check(); PyObject pyObj = Execute(script, locals); if (pyObj == null) { return default(T); } - var obj = pyObj.As(); - return obj; + return pyObj.As(); } /// @@ -275,7 +292,8 @@ public T Execute(PyObject script, PyDict locals = null) /// public PyObject Eval(string code, PyDict locals = null) { - Check(); + this.EnsureNotDisposed(); + IntPtr _locals = locals == null ? variables : locals.obj; var flag = (IntPtr)Runtime.Py_eval_input; @@ -302,10 +320,8 @@ public PyObject Eval(string code, PyDict locals = null) /// public T Eval(string code, PyDict locals = null) { - Check(); PyObject pyObj = Eval(code, locals); - var obj = pyObj.As(); - return obj; + return pyObj.As(); } /// @@ -316,13 +332,14 @@ public T Eval(string code, PyDict locals = null) /// public void Exec(string code, PyDict locals = null) { - Check(); IntPtr _locals = locals == null ? variables : locals.obj; Exec(code, variables, _locals); } private void Exec(string code, IntPtr _globals, IntPtr _locals) { + this.EnsureNotDisposed(); + var flag = (IntPtr)Runtime.Py_file_input; NewReference reference = Runtime.PyRun_String( code, flag, _globals, _locals @@ -333,7 +350,7 @@ private void Exec(string code, IntPtr _globals, IntPtr _locals) Runtime.CheckExceptionOccurred(); if (!reference.IsNone()) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } finally @@ -351,20 +368,28 @@ private void Exec(string code, IntPtr _globals, IntPtr _locals) /// public void Set(string name, object value) { - IntPtr _value = Converter.ToPython(value, value?.GetType()); - Set(name, _value); - Runtime.XDecref(_value); + this.EnsureNotDisposed(); + + IntPtr _value = Converter.ToPython(value); + try + { + this.SetInternal(name, new BorrowedReference(_value)); + } + finally + { + Runtime.XDecref(_value); + } } - private void Set(string name, IntPtr value) + private void SetInternal(string name, BorrowedReference value) { - Check(); + this.EnsureNotDisposed(); using (var pyKey = new PyString(name)) { - int r = Runtime.PyObject_SetItem(variables, pyKey.obj, value); + int r = Runtime.PyObject_SetItem(variables, pyKey.obj, value.DangerousGetAddress()); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } } @@ -377,13 +402,14 @@ private void Set(string name, IntPtr value) /// public void Remove(string name) { - Check(); + this.EnsureNotDisposed(); + using (var pyKey = new PyString(name)) { int r = Runtime.PyObject_DelItem(variables, pyKey.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } } @@ -396,7 +422,8 @@ public void Remove(string name) /// public bool Contains(string name) { - Check(); + this.EnsureNotDisposed(); + using (var pyKey = new PyString(name)) { return Runtime.PyMapping_HasKey(variables, pyKey.obj) != 0; @@ -430,23 +457,23 @@ public PyObject Get(string name) /// public bool TryGet(string name, out PyObject value) { - Check(); + this.EnsureNotDisposed(); + using (var pyKey = new PyString(name)) { if (Runtime.PyMapping_HasKey(variables, pyKey.obj) != 0) { - IntPtr op = Runtime.PyObject_GetItem(variables, pyKey.obj); - if (op == IntPtr.Zero) + using var op = Runtime.PyObject_GetItem(VarsReference, pyKey.Reference); + if (op.IsNull()) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } - if (op == Runtime.PyNone) + if (op.IsNone()) { - Runtime.XDecref(op); value = null; return true; } - value = new PyObject(op); + value = op.MoveToPyObject(); return true; } else @@ -467,7 +494,8 @@ public bool TryGet(string name, out PyObject value) /// public T Get(string name) { - Check(); + this.EnsureNotDisposed(); + PyObject pyObj = Get(name); if (pyObj == null) { @@ -486,7 +514,8 @@ public T Get(string name) /// public bool TryGet(string name, out T value) { - Check(); + this.EnsureNotDisposed(); + PyObject pyObj; var result = TryGet(name, out pyObj); if (!result) @@ -522,38 +551,24 @@ public override bool TrySetMember(SetMemberBinder binder, object value) return true; } - private void Check() + private void EnsureNotDisposed() { - if (_isDisposed) + if (this.obj == IntPtr.Zero) { - throw new PyScopeException($"The scope of name '{Name}' object has been disposed"); + throw new ObjectDisposedException( + objectName: this.Name, + message: $"The scope object has been disposed"); } } - public void Dispose() + protected override void Dispose(bool disposing) { - if (_isDisposed) + this.variables = IntPtr.Zero; + if (disposing) { - return; - } - _isDisposed = true; - Runtime.XDecref(obj); - this.OnDispose?.Invoke(this); - } - - public IntPtr[] GetTrackedHandles() - { - return new IntPtr[] { obj }; - } - - ~PyScope() - { - if (_finalized || _isDisposed) - { - return; + this.OnDispose?.Invoke(this); } - _finalized = true; - Finalizer.Instance.AddFinalizedObject(this); + base.Dispose(disposing); } } @@ -577,7 +592,7 @@ internal PyScope NewScope(string name) var module = Runtime.PyModule_New(name); if (module == IntPtr.Zero) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } return new PyScope(module, this); } diff --git a/src/runtime/pysequence.cs b/src/runtime/pysequence.cs index bfaee79a6..5010531c4 100644 --- a/src/runtime/pysequence.cs +++ b/src/runtime/pysequence.cs @@ -12,10 +12,12 @@ namespace Python.Runtime /// public class PySequence : PyObject, IEnumerable { - protected PySequence(IntPtr ptr) : base(ptr) + public PySequence(IntPtr ptr) : base(ptr) { } + internal PySequence(BorrowedReference reference) : base(reference) { } + [Obsolete] protected PySequence() { } @@ -44,7 +46,7 @@ public PyObject GetSlice(int i1, int i2) IntPtr op = Runtime.PySequence_GetSlice(obj, i1, i2); if (op == IntPtr.Zero) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } return new PyObject(op); } @@ -61,7 +63,7 @@ public void SetSlice(int i1, int i2, PyObject v) int r = Runtime.PySequence_SetSlice(obj, i1, i2, v.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -77,7 +79,7 @@ public void DelSlice(int i1, int i2) int r = Runtime.PySequence_DelSlice(obj, i1, i2); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -113,7 +115,7 @@ public bool Contains(PyObject item) int r = Runtime.PySequence_Contains(obj, item.obj); if (r < 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } return r != 0; } @@ -131,7 +133,7 @@ public PyObject Concat(PyObject other) IntPtr op = Runtime.PySequence_Concat(obj, other.obj); if (op == IntPtr.Zero) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } return new PyObject(op); } @@ -149,7 +151,7 @@ public PyObject Repeat(int count) IntPtr op = Runtime.PySequence_Repeat(obj, count); if (op == IntPtr.Zero) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } return new PyObject(op); } diff --git a/src/runtime/pystring.cs b/src/runtime/pystring.cs index c9c4f9f5b..85b5af618 100644 --- a/src/runtime/pystring.cs +++ b/src/runtime/pystring.cs @@ -34,14 +34,19 @@ public PyString(IntPtr ptr) : base(ptr) /// An ArgumentException will be thrown if the given object is not /// a Python string object. /// - public PyString(PyObject o) + public PyString(PyObject o):base(FromString(o)) { + } + + static IntPtr FromString(PyObject o) + { + if (o == null) throw new ArgumentNullException(nameof(o)); if (!IsStringType(o)) { throw new ArgumentException("object is not a string"); } Runtime.XIncref(o.obj); - obj = o.obj; + return o.obj; } @@ -51,10 +56,10 @@ public PyString(PyObject o) /// /// Creates a Python string from a managed string. /// - public PyString(string s) + public PyString(string s):base( + Exceptions.ErrorOccurredCheck( + Runtime.PyUnicode_FromUnicode(s ?? throw new ArgumentNullException(nameof(s)), s.Length))) { - obj = Runtime.PyUnicode_FromUnicode(s, s.Length); - Runtime.CheckExceptionOccurred(); } @@ -64,8 +69,9 @@ public PyString(string s) /// /// Returns true if the given object is a Python string. /// - public static bool IsStringType(PyObject value) - { + public static bool IsStringType(PyObject value) { + if (value == null) throw new ArgumentNullException(nameof(value)); + return Runtime.PyString_Check(value.obj); } } diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 11fc88cd4..ddbb5e38c 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; @@ -17,6 +18,7 @@ public class PythonEngine : IDisposable private static IntPtr _pythonHome = IntPtr.Zero; private static IntPtr _programName = IntPtr.Zero; private static IntPtr _pythonPath = IntPtr.Zero; + private static InteropConfiguration interopConfiguration = InteropConfiguration.MakeDefault(); public PythonEngine() { @@ -56,6 +58,18 @@ internal static DelegateManager DelegateManager } } + public static InteropConfiguration InteropConfiguration + { + get => interopConfiguration; + set + { + if (IsInitialized) + throw new NotSupportedException("Changing interop configuration when engine is running is not supported"); + + interopConfiguration = value ?? throw new ArgumentNullException(nameof(InteropConfiguration)); + } + } + public static string ProgramName { get @@ -96,10 +110,6 @@ public static string PythonPath } set { - if (Runtime.IsPython2) - { - throw new NotSupportedException("Set PythonPath not supported on Python 2"); - } Marshal.FreeHGlobal(_pythonPath); _pythonPath = UcsMarshaler.Py3UnicodePy2StringtoPtr(value); Runtime.Py_SetPath(_pythonPath); @@ -205,15 +215,13 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, // Load the clr.py resource into the clr module IntPtr clr = Python.Runtime.ImportHook.GetCLRModule(); - IntPtr clr_dict = Runtime.PyModule_GetDict(clr); + var clr_dict = Runtime.PyModule_GetDict(new BorrowedReference(clr)); var locals = new PyDict(); try { - IntPtr module = Runtime.PyImport_AddModule("clr._extras"); - IntPtr module_globals = Runtime.PyModule_GetDict(module); - IntPtr builtins = Runtime.PyEval_GetBuiltins(); - Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins); + var module = DefineModule("clr._extras"); + var module_globals = Runtime.PyModule_GetDict(module); Assembly assembly = Assembly.GetExecutingAssembly(); using (Stream stream = assembly.GetManifestResourceStream("clr.py")) @@ -221,9 +229,13 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, { // add the contents of clr.py to the module string clr_py = reader.ReadToEnd(); - Exec(clr_py, module_globals, locals.Handle); + Exec(clr_py, module_globals.DangerousGetAddress(), locals.Handle); } + LoadMixins(module_globals); + + LoadSubmodule(module_globals, "clr.interop", "interop.py"); + // add the imported module to the clr module, and copy the API functions // and decorators into the main clr module. Runtime.PyDict_SetItemString(clr_dict, "_extras", module); @@ -232,7 +244,7 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, if (!key.ToString().StartsWith("_") || key.ToString().Equals("__version__")) { PyObject value = locals[key]; - Runtime.PyDict_SetItem(clr_dict, key.Handle, value.Handle); + Runtime.PyDict_SetItem(clr_dict, key.Reference, value.Reference); value.Dispose(); } key.Dispose(); @@ -245,6 +257,43 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true, } } + static BorrowedReference DefineModule(string name) + { + var module = Runtime.PyImport_AddModule(name); + var module_globals = Runtime.PyModule_GetDict(module); + var builtins = Runtime.PyEval_GetBuiltins(); + int r = Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins); + PythonException.ThrowIfIsNotZero(r); + return module; + } + + static void LoadMixins(BorrowedReference targetModuleDict) + { + foreach (string nested in new[] {"collections"}) + { + LoadSubmodule(targetModuleDict, + fullName: "clr._extras." + nested, + resourceName: typeof(PythonEngine).Namespace + ".Mixins." + nested + ".py"); + } + } + + static void LoadSubmodule(BorrowedReference targetModuleDict, string fullName, string resourceName) + { + string memberName = fullName.AfterLast('.'); + Debug.Assert(memberName != null); + Assembly assembly = Assembly.GetExecutingAssembly(); + var module = DefineModule(fullName); + var module_globals = Runtime.PyModule_GetDict(module); + using (var stream = assembly.GetManifestResourceStream(resourceName)) + using (var reader = new StreamReader(stream)) + { + string pyCode = reader.ReadToEnd(); + Exec(pyCode, module_globals.DangerousGetAddress(), module_globals.DangerousGetAddress()); + } + + Runtime.PyDict_SetItemString(targetModuleDict, memberName, module); + } + static void OnDomainUnload(object _, EventArgs __) { Shutdown(); @@ -255,11 +304,7 @@ static void OnDomainUnload(object _, EventArgs __) /// CPython interpreter process - this bootstraps the managed runtime /// when it is imported by the CLR extension module. /// -#if PYTHON3 public static IntPtr InitExt() -#elif PYTHON2 - public static void InitExt() -#endif { try { @@ -299,14 +344,10 @@ public static void InitExt() catch (PythonException e) { e.Restore(); -#if PYTHON3 return IntPtr.Zero; -#endif } -#if PYTHON3 return Python.Runtime.ImportHook.GetCLRModule(); -#endif } /// @@ -322,7 +363,7 @@ public static void Shutdown() if (initialized) { PyScopeManager.Global.Clear(); - + // If the shutdown handlers trigger a domain unload, // don't call shutdown again. AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload; @@ -332,6 +373,8 @@ public static void Shutdown() PyObjectConversions.Reset(); initialized = false; + + InteropConfiguration = InteropConfiguration.MakeDefault(); } } @@ -477,7 +520,7 @@ public static void EndAllowThreads(IntPtr ts) public static PyObject ImportModule(string name) { IntPtr op = Runtime.PyImport_ImportModule(name); - Runtime.CheckExceptionOccurred(); + Exceptions.ErrorCheck(op); return new PyObject(op); } @@ -492,7 +535,7 @@ public static PyObject ImportModule(string name) public static PyObject ReloadModule(PyObject module) { IntPtr op = Runtime.PyImport_ReloadModule(module.Handle); - Runtime.CheckExceptionOccurred(); + Exceptions.ErrorCheck(op); return new PyObject(op); } @@ -507,9 +550,9 @@ public static PyObject ReloadModule(PyObject module) public static PyObject ModuleFromString(string name, string code) { IntPtr c = Runtime.Py_CompileString(code, "none", (int)RunFlagType.File); - Runtime.CheckExceptionOccurred(); + Exceptions.ErrorCheck(c); IntPtr m = Runtime.PyImport_ExecCodeModule(name, c); - Runtime.CheckExceptionOccurred(); + Exceptions.ErrorCheck(c); return new PyObject(m); } @@ -517,7 +560,7 @@ public static PyObject Compile(string code, string filename = "", RunFlagType mo { var flag = (int)mode; IntPtr ptr = Runtime.Py_CompileString(code, filename, flag); - Runtime.CheckExceptionOccurred(); + Exceptions.ErrorCheck(ptr); return new PyObject(ptr); } @@ -548,7 +591,7 @@ public static void Exec(string code, IntPtr? globals = null, IntPtr? locals = nu { if (result.obj != Runtime.PyNone) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } } @@ -582,13 +625,13 @@ internal static PyObject RunString(string code, IntPtr? globals, IntPtr? locals, { globals = Runtime.PyDict_New(); Runtime.PyDict_SetItemString( - globals.Value, "__builtins__", + new BorrowedReference(globals.Value), "__builtins__", Runtime.PyEval_GetBuiltins() ); borrowedGlobals = false; } } - + if (locals == null) { locals = globals; @@ -651,7 +694,7 @@ public static PyScope CreateScope(string name) var scope = PyScopeManager.Global.Create(name); return scope; } - + public class GILState : IDisposable { private readonly IntPtr state; @@ -697,7 +740,7 @@ public static KeywordArguments kw(params object[] kv) } else { - value = Converter.ToPython(kv[i + 1], kv[i + 1]?.GetType()); + value = Converter.ToPython(kv[i + 1]); } if (Runtime.PyDict_SetItemString(dict.Handle, (string)kv[i], value) != 0) { @@ -752,7 +795,7 @@ public static void SetArgv(IEnumerable argv) public static void With(PyObject obj, Action Body) { - // Behavior described here: + // Behavior described here: // https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers IntPtr type = Runtime.PyNone; diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs index 8efdccc91..45cf43572 100644 --- a/src/runtime/pythonexception.cs +++ b/src/runtime/pythonexception.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; using System.Text; namespace Python.Runtime @@ -13,48 +14,208 @@ public class PythonException : System.Exception, IPyDisposable private IntPtr _pyType = IntPtr.Zero; private IntPtr _pyValue = IntPtr.Zero; private IntPtr _pyTB = IntPtr.Zero; - private string _tb = ""; + private string _traceback = ""; private string _message = ""; private string _pythonTypeName = ""; - private bool disposed = false; - private bool _finalized = false; + [Obsolete("Please, use FromPyErr instead")] public PythonException() { IntPtr gs = PythonEngine.AcquireLock(); - Runtime.PyErr_Fetch(out _pyType, out _pyValue, out _pyTB); + Runtime.PyErr_Fetch(out var type, out var value, out var traceback); + _pyType = type.IsNull() ? IntPtr.Zero : type.DangerousMoveToPointer(); + _pyValue = value.IsNull() ? IntPtr.Zero : value.DangerousMoveToPointer(); + _pyTB = traceback.IsNull() ? IntPtr.Zero : traceback.DangerousMoveToPointer(); if (_pyType != IntPtr.Zero && _pyValue != IntPtr.Zero) { - string type; string message; Runtime.XIncref(_pyType); using (var pyType = new PyObject(_pyType)) using (PyObject pyTypeName = pyType.GetAttr("__name__")) { - type = pyTypeName.ToString(); + _pythonTypeName = pyTypeName.ToString(); } - _pythonTypeName = type; - Runtime.XIncref(_pyValue); using (var pyValue = new PyObject(_pyValue)) { message = pyValue.ToString(); } - _message = type + " : " + message; + _message = _pythonTypeName + " : " + message; } if (_pyTB != IntPtr.Zero) { - using (PyObject tb_module = PythonEngine.ImportModule("traceback")) + this._traceback = TracebackHandleToString(new BorrowedReference(_pyTB)); + } + PythonEngine.ReleaseLock(gs); + } + + private PythonException(BorrowedReference pyTypeHandle, + BorrowedReference pyValueHandle, + BorrowedReference pyTracebackHandle, + string message, string pythonTypeName, string traceback, + Exception innerException) + : base(message, innerException) + { + _pyType = pyTypeHandle.DangerousIncRefOrNull(); + _pyValue = pyValueHandle.DangerousIncRefOrNull(); + _pyTB = pyTracebackHandle.DangerousIncRefOrNull(); + _message = message; + _pythonTypeName = pythonTypeName ?? _pythonTypeName; + _traceback = traceback ?? _traceback; + } + + internal static Exception FromPyErr() + { + Runtime.PyErr_Fetch(out var pyTypeHandle, out var pyValueHandle, out var pyTracebackHandle); + using (pyTypeHandle) + using (pyValueHandle) + using (pyTracebackHandle) { + return FromPyErr( + pyTypeHandle: pyTypeHandle, + pyValueHandle: pyValueHandle, + pyTracebackHandle: pyTracebackHandle); + } + } + + internal static Exception FromPyErrOrNull() + { + Runtime.PyErr_Fetch(out var pyTypeHandle, out var pyValueHandle, out var pyTracebackHandle); + using (pyTypeHandle) + using (pyValueHandle) + using (pyTracebackHandle) { + if (pyValueHandle.IsNull() && pyTypeHandle.IsNull() && pyTracebackHandle.IsNull()) { + return null; + } + + var result = FromPyErr(pyTypeHandle, pyValueHandle, pyTracebackHandle); + return result; + } + } + + /// + /// Rethrows the last Python exception as corresponding CLR exception. + /// It is recommended to call this as throw ThrowLastAsClrException() + /// to assist control flow checks. + /// + internal static Exception ThrowLastAsClrException() { + // prevent potential interop errors in this method + // from crashing process with undebuggable StackOverflowException + RuntimeHelpers.EnsureSufficientExecutionStack(); + + IntPtr gs = PythonEngine.AcquireLock(); + try { + Runtime.PyErr_Fetch(out var pyTypeHandle, out var pyValueHandle, out var pyTracebackHandle); + using (pyTypeHandle) + using (pyValueHandle) + using (pyTracebackHandle) { + var clrObject = ManagedType.GetManagedObject(pyValueHandle) as CLRObject; + if (clrObject?.inst is Exception e) { +#if NETSTANDARD + ExceptionDispatchInfo.Capture(e).Throw(); +#endif + throw e; + } + + var result = FromPyErr(pyTypeHandle, pyValueHandle, pyTracebackHandle); + throw result; + } + } finally { + PythonEngine.ReleaseLock(gs); + } + } + + /// + /// Requires lock to be acquired elsewhere + /// + static Exception FromPyErr(BorrowedReference pyTypeHandle, BorrowedReference pyValueHandle, BorrowedReference pyTracebackHandle) { + Exception inner = null; + string pythonTypeName = null, msg = "", traceback = null; + + var clrObject = ManagedType.GetManagedObject(pyValueHandle) as CLRObject; + if (clrObject?.inst is Exception e) { + return e; + } + + var errorDict = new PyDict(); + if (!pyTypeHandle.IsNull) errorDict["type"] = new PyObject(pyTypeHandle); + if (!pyValueHandle.IsNull) errorDict["value"] = new PyObject(pyValueHandle); + if (!pyTracebackHandle.IsNull) errorDict["traceback"] = new PyObject(pyTracebackHandle); + + object decoded; + + var pyErrType = Runtime.InteropModule.GetAttr("PyErr"); + using (PyObject pyErrInfo = pyErrType.Invoke(new PyTuple(), errorDict)) + { + if (PyObjectConversions.TryDecode(pyErrInfo.Reference, pyErrType.Reference, + typeof(Exception), out decoded) && decoded is Exception decodedPyErrInfo) { - Runtime.XIncref(_pyTB); - using (var pyTB = new PyObject(_pyTB)) + return decodedPyErrInfo; + } + } + + if (!pyTypeHandle.IsNull) + { + if (!pyValueHandle.IsNull) + { + if (Runtime.PyString_Check(pyValueHandle) && pyTypeHandle != Runtime.PyStringType) { + using var type = new PyObject(pyTypeHandle); + using var message = new PyObject(pyValueHandle); + var instance = type.Invoke(message); + if (PyObjectConversions.TryDecode(instance.Reference, pyTypeHandle, typeof(Exception), + out decoded) && decoded is Exception decodedExceptionInstance) { + return decodedExceptionInstance; + } + } else if (PyObjectConversions.TryDecode(pyValueHandle, pyTypeHandle, typeof(Exception), + out decoded) && decoded is Exception decodedException) { + return decodedException; + } + + using (var pyValue = new PyObject(pyValueHandle)) { - _tb = tb_module.InvokeMethod("format_tb", pyTB).ToString(); + msg = pyValue.ToString(); + var cause = pyValue.GetAttr("__cause__", null); + if (cause != null && cause.Handle != Runtime.PyNone) { + using var innerTraceback = cause.GetAttr("__traceback__", null); + inner = FromPyErr( + pyTypeHandle: cause.GetPythonTypeHandle(), + pyValueHandle: cause.Reference, + pyTracebackHandle: innerTraceback is null ? new BorrowedReference() : innerTraceback.Reference); + } } } + + using (var pyType = new PyObject(pyTypeHandle)) + using (PyObject pyTypeName = pyType.GetAttr("__name__")) + { + pythonTypeName = pyTypeName.ToString(); + } + + msg = string.IsNullOrEmpty(msg) ? pythonTypeName : pythonTypeName + " : " + msg; } - PythonEngine.ReleaseLock(gs); + if (!pyTracebackHandle.IsNull) + { + traceback = TracebackHandleToString(pyTracebackHandle); + } + + return new PythonException(pyTypeHandle, pyValueHandle, pyTracebackHandle, + msg, pythonTypeName, traceback, inner); + } + + static string TracebackHandleToString(BorrowedReference tracebackHandle) { + if (tracebackHandle.IsNull) { + throw new ArgumentNullException(nameof(tracebackHandle)); + } + + PyObject tracebackModule = PythonEngine.ImportModule("traceback"); + using var traceback = new PyObject(tracebackHandle); + PyList stackLines = PyList.Wrap(tracebackModule.InvokeMethod("format_tb", traceback)); + stackLines.Reverse(); + var result = new StringBuilder(); + foreach (object stackLine in stackLines) { + result.Append(stackLine); + } + return result.ToString(); } // Ensure that encapsulated Python objects are decref'ed appropriately @@ -62,11 +223,10 @@ public PythonException() ~PythonException() { - if (_finalized || disposed) + if (this.IsDisposed) { return; } - _finalized = true; Finalizer.Instance.AddFinalizedObject(this); } @@ -76,10 +236,10 @@ public PythonException() public void Restore() { IntPtr gs = PythonEngine.AcquireLock(); - Runtime.PyErr_Restore(_pyType, _pyValue, _pyTB); - _pyType = IntPtr.Zero; - _pyValue = IntPtr.Zero; - _pyTB = IntPtr.Zero; + Runtime.PyErr_Restore( + NewReference.DangerousMoveFromPointer(ref _pyType).Steal(), + NewReference.DangerousMoveFromPointer(ref _pyValue).Steal(), + NewReference.DangerousMoveFromPointer(ref _pyTB).Steal()); PythonEngine.ReleaseLock(gs); } @@ -94,6 +254,11 @@ public IntPtr PyType get { return _pyType; } } + /// + /// Type of the exception (nullable). + /// + internal BorrowedReference PythonType => new BorrowedReference(_pyType); + /// /// PyValue Property /// @@ -105,6 +270,11 @@ public IntPtr PyValue get { return _pyValue; } } + /// + /// Exception object value (nullable). + /// + internal BorrowedReference Value => new BorrowedReference(_pyValue); + /// /// PyTB Property /// @@ -116,6 +286,11 @@ public IntPtr PyTB get { return _pyTB; } } + /// + /// Traceback (nullable). + /// + internal BorrowedReference Traceback => new BorrowedReference(_pyTB); + /// /// Message Property /// @@ -135,7 +310,7 @@ public override string Message /// public override string StackTrace { - get { return _tb + base.StackTrace; } + get { return this._traceback + base.StackTrace; } } /// @@ -198,34 +373,35 @@ public string Format() /// public void Dispose() { - if (!disposed) + if (this.IsDisposed) + return; + + if (Runtime.Py_IsInitialized() == 0) + throw new InvalidOperationException("Python runtime must be initialized"); + + if (!Runtime.IsFinalizing) { - if (Runtime.Py_IsInitialized() > 0 && !Runtime.IsFinalizing) + if (_pyType != IntPtr.Zero) { - IntPtr gs = PythonEngine.AcquireLock(); - if (_pyType != IntPtr.Zero) - { - Runtime.XDecref(_pyType); - _pyType= IntPtr.Zero; - } + Runtime.XDecref(_pyType); + _pyType= IntPtr.Zero; + } - if (_pyValue != IntPtr.Zero) - { - Runtime.XDecref(_pyValue); - _pyValue = IntPtr.Zero; - } + if (_pyValue != IntPtr.Zero) + { + Runtime.XDecref(_pyValue); + _pyValue = IntPtr.Zero; + } - // XXX Do we ever get TraceBack? // - if (_pyTB != IntPtr.Zero) - { - Runtime.XDecref(_pyTB); - _pyTB = IntPtr.Zero; - } - PythonEngine.ReleaseLock(gs); + // XXX Do we ever get TraceBack? // + if (_pyTB != IntPtr.Zero) + { + Runtime.XDecref(_pyTB); + _pyTB = IntPtr.Zero; } - GC.SuppressFinalize(this); - disposed = true; } + + GC.SuppressFinalize(this); } public IntPtr[] GetTrackedHandles() @@ -233,6 +409,8 @@ public IntPtr[] GetTrackedHandles() return new IntPtr[] { _pyType, _pyValue, _pyTB }; } + bool IsDisposed => _pyType == IntPtr.Zero && _pyValue == IntPtr.Zero && _pyTB == IntPtr.Zero; + /// /// Matches Method /// @@ -245,19 +423,21 @@ public static bool Matches(IntPtr ob) return Runtime.PyErr_ExceptionMatches(ob) != 0; } - public static void ThrowIfIsNull(IntPtr ob) + public static IntPtr ThrowIfIsNull(IntPtr ob) { if (ob == IntPtr.Zero) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } + + return ob; } public static void ThrowIfIsNotZero(int value) { if (value != 0) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } } diff --git a/src/runtime/pytuple.cs b/src/runtime/pytuple.cs index 45f3d8350..e7c1d234a 100644 --- a/src/runtime/pytuple.cs +++ b/src/runtime/pytuple.cs @@ -31,14 +31,18 @@ public PyTuple(IntPtr ptr) : base(ptr) /// ArgumentException will be thrown if the given object is not a /// Python tuple object. /// - public PyTuple(PyObject o) + public PyTuple(PyObject o):base(FromPyObject(o)) { - if (!IsTupleType(o)) - { + } + + static BorrowedReference FromPyObject(PyObject o) + { + if (o == null) throw new ArgumentNullException(nameof(o)); + + if (!IsTupleType(o)) { throw new ArgumentException("object is not a tuple"); } - Runtime.XIncref(o.obj); - obj = o.obj; + return o.Reference; } @@ -48,10 +52,8 @@ public PyTuple(PyObject o) /// /// Creates a new empty PyTuple. /// - public PyTuple() + public PyTuple():base(PythonException.ThrowIfIsNull(Runtime.PyTuple_New(0))) { - obj = Runtime.PyTuple_New(0); - Runtime.CheckExceptionOccurred(); } @@ -64,17 +66,31 @@ public PyTuple() /// See caveats about PyTuple_SetItem: /// https://www.coursehero.com/file/p4j2ogg/important-exceptions-to-this-rule-PyTupleSetItem-and-PyListSetItem-These/ /// - public PyTuple(PyObject[] items) + public PyTuple(PyObject[] items):base(FromItems(items)) + { + } + + static IntPtr FromItems(PyObject[] items) { + if (items == null) throw new ArgumentNullException(nameof(items)); + int count = items.Length; - obj = Runtime.PyTuple_New(count); - for (var i = 0; i < count; i++) - { - IntPtr ptr = items[i].obj; - Runtime.XIncref(ptr); - Runtime.PyTuple_SetItem(obj, i, ptr); - Runtime.CheckExceptionOccurred(); + IntPtr obj = Runtime.PyTuple_New(count); + Exceptions.ErrorCheck(obj); + try { + for (var i = 0; i < count; i++) { + if (items[i] == null) throw new ArgumentNullException(); + + IntPtr ptr = items[i].obj; + Runtime.XIncref(ptr); + PythonException.ThrowIfIsNotZero(Runtime.PyTuple_SetItem(obj, i, ptr)); + } + } catch { + Runtime.XDecref(obj); + throw; } + + return obj; } @@ -104,5 +120,11 @@ public static PyTuple AsTuple(PyObject value) Runtime.CheckExceptionOccurred(); return new PyTuple(op); } + + /// + /// Create a with single element + /// + public static PyTuple FromSingleElement(PyObject value) + => new PyTuple(items: new []{value}); } } diff --git a/src/runtime/pytype.cs b/src/runtime/pytype.cs new file mode 100644 index 000000000..14d394360 --- /dev/null +++ b/src/runtime/pytype.cs @@ -0,0 +1,64 @@ +namespace Python.Runtime { + using System; + + public class PyType : PyObject + { + /// + /// Creates a new instance from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + public PyType(IntPtr ptr) : base(ptr) { } + + /// + /// Creates a new instance from an existing object reference. + /// Ensures the type of the object is Python type. + /// + public PyType(PyObject o) : base(FromPyObject(o)) { } + + static IntPtr FromPyObject(PyObject o) { + if (o == null) throw new ArgumentNullException(nameof(o)); + + if (!IsTypeType(o)) { + throw new ArgumentException("object is not a type"); + } + Runtime.XIncref(o.obj); + return o.obj; + } + + /// + /// Returns true if the given object is Python type. + /// + public static bool IsTypeType(PyObject obj) { + if (obj == null) { + throw new ArgumentNullException(nameof(obj)); + } + + return Runtime.PyType_Check(obj.Reference); + } + + /// + /// Returns true if the given object is Python type. + /// + public static bool IsTypeType(IntPtr typeHandle) { + if (typeHandle == IntPtr.Zero) { + throw new ArgumentNullException(nameof(typeHandle)); + } + + return Runtime.PyType_Check(new BorrowedReference(typeHandle)); + } + + /// + /// Gets , which represents the specified CLR type. + /// Must be called after the CLR type was mapped to its Python type. + /// + public static PyType Get(Type clrType) { + if (clrType == null) { + throw new ArgumentNullException(nameof(clrType)); + } + + ClassBase pyClass = ClassManager.GetClass(clrType); + return new PyType(Runtime.SelfIncRef(pyClass.pyHandle)); + } + } +} diff --git a/src/runtime/resources/interop.py b/src/runtime/resources/interop.py new file mode 100644 index 000000000..a47d16c68 --- /dev/null +++ b/src/runtime/resources/interop.py @@ -0,0 +1,10 @@ +_UNSET = object() + +class PyErr: + def __init__(self, type=_UNSET, value=_UNSET, traceback=_UNSET): + if not(type is _UNSET): + self.type = type + if not(value is _UNSET): + self.value = value + if not(traceback is _UNSET): + self.traceback = traceback diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 8cf24ba70..954c6286b 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -1,6 +1,7 @@ -using System.Reflection.Emit; using System; +using System.Globalization; using System.Diagnostics.Contracts; +using System.IO; using System.Runtime.InteropServices; using System.Security; using System.Text; @@ -8,100 +9,122 @@ using System.Collections.Generic; using Python.Runtime.Platform; +using Python.Runtime.Platforms; + namespace Python.Runtime { + [SuppressUnmanagedCodeSecurity] + internal static class NativeMethods + { + public static IntPtr LoadLibrary(string dllToLoad) => impl.LoadLibrary(dllToLoad); + public static IntPtr GetProcAddress(IntPtr hModule, string procedureName) + => impl.GetProcAddress(hModule, procedureName); + public static void FreeLibrary(IntPtr hModule) => impl.FreeLibrary(hModule); + + static readonly INativeLibraryLoader impl = + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? WindowsLibraryLoader.Instance + : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? LinuxLibraryLoader.Instance + : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? MacLibraryLoader.Instance + : Throw(new PlatformNotSupportedException()); + + internal static T Throw(Exception exception) + { + throw exception; + } + } + /// /// Encapsulates the low-level Python C API. Note that it is /// the responsibility of the caller to have acquired the GIL /// before calling any of these methods. /// - public class Runtime + public static class Runtime { + static Runtime() { + lock (VerLock) { + UpdateVersionFields(); + } + } + // C# compiler copies constants to the assemblies that references this library. // We needs to replace all public constants to static readonly fields to allow // binary substitution of different Python.Runtime.dll builds in a target application. - public static int UCS => _UCS; - -#if UCS4 - internal const int _UCS = 4; - - /// - /// EntryPoint to be used in DllImport to map to correct Unicode - /// methods prior to PEP393. Only used for PY27. - /// - private const string PyUnicodeEntryPoint = "PyUnicodeUCS4_"; -#elif UCS2 - internal const int _UCS = 2; - - /// - /// EntryPoint to be used in DllImport to map to correct Unicode - /// methods prior to PEP393. Only used for PY27. - /// - private const string PyUnicodeEntryPoint = "PyUnicodeUCS2_"; -#else -#error You must define either UCS2 or UCS4! -#endif + public static int UCS { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 2 : 4; // C# compiler copies constants to the assemblies that references this library. // We needs to replace all public constants to static readonly fields to allow // binary substitution of different Python.Runtime.dll builds in a target application. public static string pyversion => _pyversion; + /// + /// Two-character string, describing Python version (e.g. "36" for Python 3.6) + /// public static string pyver => _pyver; -#if PYTHON27 - internal const string _pyversion = "2.7"; - internal const string _pyver = "27"; -#elif PYTHON34 - internal const string _pyversion = "3.4"; - internal const string _pyver = "34"; -#elif PYTHON35 - internal const string _pyversion = "3.5"; - internal const string _pyver = "35"; -#elif PYTHON36 - internal const string _pyversion = "3.6"; - internal const string _pyver = "36"; -#elif PYTHON37 - internal const string _pyversion = "3.7"; - internal const string _pyver = "37"; -#elif PYTHON38 - internal const string _pyversion = "3.8"; - internal const string _pyver = "38"; -#else -#error You must define one of PYTHON34 to PYTHON38 or PYTHON27 -#endif + static readonly object VerLock = new object(); + static Version pythonVersion = new Version(3, 7); + public static Version PythonVersion { + get { + lock (VerLock) { + return pythonVersion; + } + } + set { + if (value == null) + throw new ArgumentNullException(nameof(Version)); -#if MONO_LINUX || MONO_OSX // Linux/macOS use dotted version string - internal const string dllBase = "python" + _pyversion; -#else // Windows - internal const string dllBase = "python" + _pyver; -#endif + lock (VerLock) { + pythonVersion = value; + UpdateVersionFields(); + } + } + } + + static void UpdateVersionFields() { + _pyversion = pythonVersion.ToString(2); + _pyver = string.Format(CultureInfo.InvariantCulture, + "{0}{1}", pythonVersion.Major, pythonVersion.Minor); + pyversionnumber = GetPyVersionNumber(); + } + + internal static string _pyversion { get; private set; } + internal static string _pyver { get; private set; } #if PYTHON_WITH_PYDEBUG - internal const string dllWithPyDebug = "d"; + const string dllWithPyDebug = "d"; #else - internal const string dllWithPyDebug = ""; + const string dllWithPyDebug = ""; #endif -#if PYTHON_WITH_PYMALLOC - internal const string dllWithPyMalloc = "m"; + + static readonly bool IsWindowsPlatform = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + static string GetDefaultDllName() { +#if PYTHON_WITHOUT_ENABLE_SHARED && !NETSTANDARD + return "__Internal"; #else - internal const string dllWithPyMalloc = ""; + string dllBase = "python" + (IsWindowsPlatform ? _pyver : _pyversion); + string dllWithPyMalloc = IsWindowsPlatform ? "" : "m"; + return dllBase + dllWithPyDebug + dllWithPyMalloc; #endif + } - // C# compiler copies constants to the assemblies that references this library. - // We needs to replace all public constants to static readonly fields to allow - // binary substitution of different Python.Runtime.dll builds in a target application. + static string pythonDllOverride; - public static readonly string PythonDLL = _PythonDll; + public static string PythonDLL { + get { return pythonDllOverride ?? GetDefaultDllName(); } + set { + if (value == null) + throw new ArgumentNullException(nameof(PythonDLL)); -#if PYTHON_WITHOUT_ENABLE_SHARED && !NETSTANDARD - internal const string _PythonDll = "__Internal"; -#else - internal const string _PythonDll = dllBase + dllWithPyDebug + dllWithPyMalloc; -#endif + pythonDllOverride = value; + } + } - public static readonly int pyversionnumber = Convert.ToInt32(_pyver); + static int GetPyVersionNumber() { + return PythonVersion.Major * 10 + PythonVersion.Minor;; + } + [Obsolete("Use PythonVersion instead")] + public static int pyversionnumber = GetPyVersionNumber(); // set to true when python is finalizing internal static object IsFinalizingLock = new object(); @@ -109,8 +132,8 @@ public class Runtime internal static bool Is32Bit => IntPtr.Size == 4; - // .NET core: System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - internal static bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; + [Obsolete("Use IsWindowsPlatform")] + internal static readonly bool IsWindows = Environment.OSVersion.Platform == PlatformID.Win32NT; static readonly Dictionary OperatingSystemTypeMapping = new Dictionary() { @@ -155,18 +178,23 @@ public class Runtime /// public static MachineType Machine { get; private set; }/* set in Initialize using python's platform.machine */ - internal static bool IsPython2 = pyversionnumber < 30; - internal static bool IsPython3 = pyversionnumber >= 30; - public static int MainManagedThreadId { get; private set; } /// /// Encoding to use to convert Unicode to/from Managed to Native /// - internal static readonly Encoding PyEncoding = _UCS == 2 ? Encoding.Unicode : Encoding.UTF32; + internal static readonly Encoding PyEncoding = UCS == 2 ? Encoding.Unicode : Encoding.UTF32; private static PyReferenceCollection _pyRefs = new PyReferenceCollection(); + static long run = 0; + + internal static long GetRun() { + long runNumber = Interlocked.Read(ref run); + System.Diagnostics.Debug.Assert(runNumber > 0); + return runNumber; + } + /// /// Initialize the runtime... /// @@ -244,12 +272,10 @@ internal static void Initialize(bool initSigs = false) () => PyUnicodeType = IntPtr.Zero); XDecref(op); -#if PYTHON3 op = PyBytes_FromString("bytes"); SetPyMember(ref PyBytesType, PyObject_Type(op), () => PyBytesType = IntPtr.Zero); XDecref(op); -#endif op = PyTuple_New(0); SetPyMember(ref PyTupleType, PyObject_Type(op), @@ -281,31 +307,13 @@ internal static void Initialize(bool initSigs = false) () => PyFloatType = IntPtr.Zero); XDecref(op); -#if !PYTHON2 PyClassType = IntPtr.Zero; PyInstanceType = IntPtr.Zero; -#else - { - IntPtr s = PyString_FromString("_temp"); - IntPtr d = PyDict_New(); - - IntPtr c = PyClass_New(IntPtr.Zero, d, s); - SetPyMember(ref PyClassType, PyObject_Type(c), - () => PyClassType = IntPtr.Zero); - - IntPtr i = PyInstance_New(c, IntPtr.Zero, IntPtr.Zero); - SetPyMember(ref PyInstanceType, PyObject_Type(i), - () => PyInstanceType = IntPtr.Zero); - - XDecref(s); - XDecref(i); - XDecref(c); - XDecref(d); - } -#endif Error = new IntPtr(-1); + Interlocked.Increment(ref run); + // Initialize data about the platform we're running on. We need // this for the type manager and potentially other details. Must // happen after caching the python types, above. @@ -314,9 +322,9 @@ internal static void Initialize(bool initSigs = false) IntPtr dllLocal = IntPtr.Zero; var loader = LibraryLoader.Get(OperatingSystem); - if (_PythonDll != "__Internal") + if (PythonDLL != "__Internal") { - dllLocal = loader.Load(_PythonDll); + dllLocal = loader.Load(PythonDLL); } _PyObject_NextNotImplemented = loader.GetFunction(dllLocal, "_PyObject_NextNotImplemented"); PyModuleType = loader.GetFunction(dllLocal, "PyModule_Type"); @@ -340,6 +348,9 @@ internal static void Initialize(bool initSigs = false) PyList_Append(new BorrowedReference(path), item); XDecref(item); AssemblyManager.UpdatePath(); + + inspect = GetModuleLazy("inspect"); + clrInterop = GetModuleLazy("clr.interop"); } /// @@ -431,6 +442,11 @@ internal static void Shutdown() Py_Finalize(); } + private static Lazy GetModuleLazy(string moduleName) + => moduleName is null + ? throw new ArgumentNullException(nameof(moduleName)) + : new Lazy(() => PythonEngine.ImportModule(moduleName), isThreadSafe: false); + // called *without* the GIL acquired by clr._AtExit internal static int AtExit() { @@ -481,9 +497,7 @@ private static void ResetPyMembers() internal static IntPtr Py_NoSiteFlag; -#if PYTHON3 internal static IntPtr PyBytesType; -#endif internal static IntPtr _PyObject_NextNotImplemented; internal static IntPtr PyNotImplemented; @@ -509,6 +523,11 @@ public static PyObject None } } + private static Lazy inspect; + internal static PyObject InspectModule => inspect.Value; + private static Lazy clrInterop; + internal static PyObject InteropModule => clrInterop.Value; + /// /// Check if any Python Exceptions occurred. /// If any exist throw new PythonException. @@ -520,7 +539,7 @@ internal static void CheckExceptionOccurred() { if (PyErr_Occurred() != IntPtr.Zero) { - throw new PythonException(); + throw PythonException.ThrowLastAsClrException(); } } @@ -575,7 +594,7 @@ internal static Type[] PythonArgsToTypeArray(IntPtr arg, bool mangleObjects) for (var i = 0; i < n; i++) { - IntPtr op = PyTuple_GetItem(args, i); + var op = new BorrowedReference(PyTuple_GetItem(args, i)); if (mangleObjects && (!PyType_Check(op))) { op = PyObject_TYPE(op); @@ -613,6 +632,12 @@ internal static Type[] PythonArgsToTypeArray(IntPtr arg, bool mangleObjects) return types; } + /// + /// Raise an exception when a refcount of Python object exceeds this limit. + /// Only affects debug builds. + /// + public static long RefCountSanityLimit { get; set; } = Int32.MaxValue; + /// /// Managed exports of the Python C API. Where appropriate, we do /// some optimization to avoid managed <--> unmanaged transitions @@ -620,6 +645,18 @@ internal static Type[] PythonArgsToTypeArray(IntPtr arg, bool mangleObjects) /// internal static unsafe void XIncref(IntPtr op) { + DebugUtil.EnsureGIL(); + if (op == IntPtr.Zero) + throw new ArgumentNullException(nameof(op)); +#if DEBUG + long refcount = Refcount(op); + if (refcount < 0 || refcount > RefCountSanityLimit) + throw new ArgumentOutOfRangeException( + message: "Reference count is insane", + paramName: nameof(op), + actualValue: refcount); +#endif + #if PYTHON_WITH_PYDEBUG || NETSTANDARD Py_IncRef(op); return; @@ -650,6 +687,18 @@ internal static IntPtr SelfIncRef(IntPtr op) internal static unsafe void XDecref(IntPtr op) { + DebugUtil.EnsureGIL(); +#if DEBUG + if (op == IntPtr.Zero) + throw new ArgumentNullException(nameof(op)); + long refcount = Refcount(op); + if (refcount <= 0 || refcount > RefCountSanityLimit) + throw new ArgumentOutOfRangeException( + paramName: nameof(refcount), + actualValue: refcount, + message: "Reference count is insane"); +#endif + #if PYTHON_WITH_PYDEBUG || NETSTANDARD Py_DecRef(op); return; @@ -685,6 +734,11 @@ internal static unsafe void XDecref(IntPtr op) #endif } + internal static void XDecrefIgnoreNull(IntPtr op) + { + if (op != IntPtr.Zero) { XDecref(op); } + } + [Pure] internal static unsafe long Refcount(IntPtr op) { @@ -701,157 +755,147 @@ internal static unsafe long Refcount(IntPtr op) /// Limit this function usage for Testing and Py_Debug builds /// /// PyObject Ptr - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_IncRef(IntPtr ob); + + internal static void Py_IncRef(IntPtr ob) => Delegates.Py_IncRef(ob); /// /// Export of Macro Py_XDecRef. Use XDecref instead. /// Limit this function usage for Testing and Py_Debug builds /// /// PyObject Ptr - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_DecRef(IntPtr ob); + + internal static void Py_DecRef(IntPtr ob) => Delegates.Py_DecRef(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_Initialize(); + + internal static void Py_Initialize() => Delegates.Py_Initialize(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_InitializeEx(int initsigs); + + internal static void Py_InitializeEx(int initsigs) => Delegates.Py_InitializeEx(initsigs); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int Py_IsInitialized(); + + internal static int Py_IsInitialized() => Delegates.Py_IsInitialized(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_Finalize(); + + internal static void Py_Finalize() => Delegates.Py_Finalize(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_NewInterpreter(); + + internal static IntPtr Py_NewInterpreter() => Delegates.Py_NewInterpreter(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_EndInterpreter(IntPtr threadState); + + internal static void Py_EndInterpreter(IntPtr threadState) => Delegates.Py_EndInterpreter(threadState); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyThreadState_New(IntPtr istate); + + internal static IntPtr PyThreadState_New(IntPtr istate) => Delegates.PyThreadState_New(istate); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyThreadState_Get(); + + internal static IntPtr PyThreadState_Get() => Delegates.PyThreadState_Get(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyThread_get_key_value(IntPtr key); + + internal static IntPtr PyThread_get_key_value(IntPtr key) => Delegates.PyThread_get_key_value(key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyThread_get_thread_ident(); + + internal static int PyThread_get_thread_ident() => Delegates.PyThread_get_thread_ident(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyThread_set_key_value(IntPtr key, IntPtr value); + + internal static int PyThread_set_key_value(IntPtr key, IntPtr value) => Delegates.PyThread_set_key_value(key, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyThreadState_Swap(IntPtr key); + + internal static IntPtr PyThreadState_Swap(IntPtr key) => Delegates.PyThreadState_Swap(key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyGILState_Ensure(); + + internal static IntPtr PyGILState_Ensure() => Delegates.PyGILState_Ensure(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyGILState_Release(IntPtr gs); + + internal static void PyGILState_Release(IntPtr gs) => Delegates.PyGILState_Release(gs); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyGILState_GetThisThreadState(); + + internal static IntPtr PyGILState_GetThisThreadState() => Delegates.PyGILState_GetThisThreadState(); -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - public static extern int Py_Main( + internal static int PyGILState_Check() => Delegates.PyGILState_Check(); + + public static int Py_Main( int argc, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv - ); -#elif PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - public static extern int Py_Main(int argc, string[] argv); -#endif + ) => Delegates.Py_Main(argc, argv +); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyEval_InitThreads(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyEval_ThreadsInitialized(); + + internal static void PyEval_InitThreads() => Delegates.PyEval_InitThreads(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyEval_AcquireLock(); + + internal static int PyEval_ThreadsInitialized() => Delegates.PyEval_ThreadsInitialized(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyEval_ReleaseLock(); + + internal static void PyEval_AcquireLock() => Delegates.PyEval_AcquireLock(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyEval_AcquireThread(IntPtr tstate); + + internal static void PyEval_ReleaseLock() => Delegates.PyEval_ReleaseLock(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyEval_ReleaseThread(IntPtr tstate); + + internal static void PyEval_AcquireThread(IntPtr tstate) => Delegates.PyEval_AcquireThread(tstate); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyEval_SaveThread(); + + internal static void PyEval_ReleaseThread(IntPtr tstate) => Delegates.PyEval_ReleaseThread(tstate); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyEval_RestoreThread(IntPtr tstate); + + internal static IntPtr PyEval_SaveThread() => Delegates.PyEval_SaveThread(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyEval_GetBuiltins(); + + internal static void PyEval_RestoreThread(IntPtr tstate) => Delegates.PyEval_RestoreThread(tstate); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyEval_GetGlobals(); + + internal static BorrowedReference PyEval_GetBuiltins() => Delegates.PyEval_GetBuiltins(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyEval_GetLocals(); + + internal static IntPtr PyEval_GetGlobals() => Delegates.PyEval_GetGlobals(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetProgramName(); + + internal static IntPtr PyEval_GetLocals() => Delegates.PyEval_GetLocals(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_SetProgramName(IntPtr name); + + internal static IntPtr Py_GetProgramName() => Delegates.Py_GetProgramName(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetPythonHome(); + + internal static void Py_SetProgramName(IntPtr name) => Delegates.Py_SetProgramName(name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_SetPythonHome(IntPtr home); + + internal static IntPtr Py_GetPythonHome() => Delegates.Py_GetPythonHome(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetPath(); + + internal static void Py_SetPythonHome(IntPtr home) => Delegates.Py_SetPythonHome(home); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void Py_SetPath(IntPtr home); + + internal static IntPtr Py_GetPath() => Delegates.Py_GetPath(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetVersion(); + + internal static void Py_SetPath(IntPtr home) => Delegates.Py_SetPath(home); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetPlatform(); + + internal static IntPtr Py_GetVersion() => Delegates.Py_GetVersion(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetCopyright(); + + internal static IntPtr Py_GetPlatform() => Delegates.Py_GetPlatform(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetCompiler(); + + internal static IntPtr Py_GetCopyright() => Delegates.Py_GetCopyright(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_GetBuildInfo(); + + internal static IntPtr Py_GetCompiler() => Delegates.Py_GetCompiler(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyRun_SimpleString(string code); + + internal static IntPtr Py_GetBuildInfo() => Delegates.Py_GetBuildInfo(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] -#if PYTHON2 - internal static extern NewReference PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals); -#else - internal static extern NewReference PyRun_String([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string code, IntPtr st, IntPtr globals, IntPtr locals); -#endif + + internal static int PyRun_SimpleString(string code) => Delegates.PyRun_SimpleString(code); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyEval_EvalCode(IntPtr co, IntPtr globals, IntPtr locals); + + internal static NewReference PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals) => Delegates.PyRun_String(code, st, globals, locals); + + + internal static IntPtr PyEval_EvalCode(IntPtr co, IntPtr globals, IntPtr locals) => Delegates.PyEval_EvalCode(co, globals, locals); -#if PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_CompileString(string code, string file, int start); -#else /// /// Return value: New reference. /// This is a simplified interface to Py_CompileStringFlags() below, leaving flags set to NULL. @@ -874,33 +918,16 @@ internal static IntPtr Py_CompileStringFlags(string str, string file, int start, /// Return value: New reference. /// Like Py_CompileStringObject(), but filename is a byte string decoded from the filesystem encoding(os.fsdecode()). /// - /// - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr Py_CompileStringExFlags(string str, string file, int start, IntPtr flags, int optimize); -#endif + internal static IntPtr Py_CompileStringExFlags(string str, string file, int start, IntPtr flags, int optimize) => Delegates.Py_CompileStringExFlags(str, file, start, flags, optimize); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyImport_ExecCodeModule(string name, IntPtr code); + + internal static IntPtr PyImport_ExecCodeModule(string name, IntPtr code) => Delegates.PyImport_ExecCodeModule(name, code); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyCFunction_NewEx(IntPtr ml, IntPtr self, IntPtr mod); + + internal static IntPtr PyCFunction_NewEx(IntPtr ml, IntPtr self, IntPtr mod) => Delegates.PyCFunction_NewEx(ml, self, mod); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyCFunction_Call(IntPtr func, IntPtr args, IntPtr kw); - -#if PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyClass_New(IntPtr bases, IntPtr dict, IntPtr name); -#endif - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyInstance_New(IntPtr cls, IntPtr args, IntPtr kw); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyInstance_NewRaw(IntPtr cls, IntPtr dict); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyMethod_New(IntPtr func, IntPtr self, IntPtr cls); + + internal static IntPtr PyCFunction_Call(IntPtr func, IntPtr args, IntPtr kw) => Delegates.PyCFunction_Call(func, args, kw); //==================================================================== @@ -929,6 +956,12 @@ internal static unsafe IntPtr PyObject_TYPE(IntPtr op) : new IntPtr((void*)(*((ulong*)p + n))); } + internal static BorrowedReference PyObject_TYPE(BorrowedReference reference) { + return reference.IsNull + ? throw new ArgumentNullException(nameof(reference)) + : new BorrowedReference(PyObject_TYPE(reference.DangerousGetAddress())); + } + /// /// Managed version of the standard Python C API PyObject_Type call. /// This version avoids a managed <-> unmanaged transition. @@ -951,57 +984,51 @@ internal static string PyObject_GetTypeName(IntPtr op) /// /// Test whether the Python object is an iterable. /// - internal static bool PyObject_IsIterable(IntPtr pointer) + internal static bool PyObject_IsIterable(BorrowedReference pointer) { - var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); -#if PYTHON2 - long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags); - if ((tp_flags & TypeFlags.HaveIter) == 0) - return false; -#endif + var ob_type = Marshal.ReadIntPtr(pointer.DangerousGetAddress(), ObjectOffset.ob_type); IntPtr tp_iter = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iter); return tp_iter != IntPtr.Zero; } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_HasAttrString(IntPtr pointer, string name); + + internal static int PyObject_HasAttrString(IntPtr pointer, string name) => Delegates.PyObject_HasAttrString(pointer, name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_GetAttrString(IntPtr pointer, string name); + internal static NewReference PyObject_GetAttrString(BorrowedReference pointer, string name) + => NewReference.DangerousFromPointer(PyObject_GetAttrString(pointer.DangerousGetAddress(), name)); + internal static IntPtr PyObject_GetAttrString(IntPtr pointer, string name) => Delegates.PyObject_GetAttrString(pointer, name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_SetAttrString(IntPtr pointer, string name, IntPtr value); + + internal static int PyObject_SetAttrString(IntPtr pointer, string name, IntPtr value) => Delegates.PyObject_SetAttrString(pointer, name, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_HasAttr(IntPtr pointer, IntPtr name); + + internal static int PyObject_HasAttr(IntPtr pointer, IntPtr name) => Delegates.PyObject_HasAttr(pointer, name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_GetAttr(IntPtr pointer, IntPtr name); + + internal static IntPtr PyObject_GetAttr(IntPtr pointer, IntPtr name) => Delegates.PyObject_GetAttr(pointer, name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_SetAttr(IntPtr pointer, IntPtr name, IntPtr value); + + internal static int PyObject_SetAttr(IntPtr pointer, IntPtr name, IntPtr value) => Delegates.PyObject_SetAttr(pointer, name, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_GetItem(IntPtr pointer, IntPtr key); + + internal static NewReference PyObject_GetItem(BorrowedReference pointer, BorrowedReference key) => Delegates.PyObject_GetItem(pointer, key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_SetItem(IntPtr pointer, IntPtr key, IntPtr value); + + internal static int PyObject_SetItem(IntPtr pointer, IntPtr key, IntPtr value) => Delegates.PyObject_SetItem(pointer, key, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_DelItem(IntPtr pointer, IntPtr key); + + internal static int PyObject_DelItem(IntPtr pointer, IntPtr key) => Delegates.PyObject_DelItem(pointer, key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_GetIter(IntPtr op); + + internal static NewReference PyObject_GetIter(BorrowedReference op) => Delegates.PyObject_GetIter(op); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw); + + internal static IntPtr PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw) => Delegates.PyObject_Call(pointer, args, kw); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_CallObject(IntPtr pointer, IntPtr args); + + internal static IntPtr PyObject_CallObject(IntPtr pointer, IntPtr args) => Delegates.PyObject_CallObject(pointer, args); -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_RichCompareBool(IntPtr value1, IntPtr value2, int opid); + internal static int PyObject_RichCompareBool(IntPtr value1, IntPtr value2, int opid) => Delegates.PyObject_RichCompareBool(value1, value2, opid); internal static int PyObject_Compare(IntPtr value1, IntPtr value2) { @@ -1027,77 +1054,101 @@ internal static int PyObject_Compare(IntPtr value1, IntPtr value2) Exceptions.SetError(Exceptions.SystemError, "Error comparing objects"); return -1; } -#elif PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_Compare(IntPtr value1, IntPtr value2); -#endif - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_IsInstance(IntPtr ob, IntPtr type); + + internal static int PyObject_IsInstance(IntPtr ob, IntPtr type) => Delegates.PyObject_IsInstance(ob, type); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_IsSubclass(IntPtr ob, IntPtr type); + + internal static int PyObject_IsSubclass(IntPtr ob, IntPtr type) => Delegates.PyObject_IsSubclass(ob, type); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyCallable_Check(IntPtr pointer); + + internal static int PyCallable_Check(IntPtr pointer) => Delegates.PyCallable_Check(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_IsTrue(IntPtr pointer); + + internal static int PyObject_IsTrue(IntPtr pointer) => Delegates.PyObject_IsTrue(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_Not(IntPtr pointer); + + internal static int PyObject_Not(IntPtr pointer) => Delegates.PyObject_Not(pointer); internal static long PyObject_Size(IntPtr pointer) { return (long)_PyObject_Size(pointer); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyObject_Size")] - private static extern IntPtr _PyObject_Size(IntPtr pointer); + + private static IntPtr _PyObject_Size(IntPtr pointer) => Delegates._PyObject_Size(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_Hash(IntPtr op); + + internal static IntPtr PyObject_Hash(IntPtr op) => Delegates.PyObject_Hash(op); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_Repr(IntPtr pointer); + + internal static IntPtr PyObject_Repr(IntPtr pointer) => Delegates.PyObject_Repr(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_Str(IntPtr pointer); + + internal static IntPtr PyObject_Str(IntPtr pointer) => Delegates.PyObject_Str(pointer); -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyObject_Str")] - internal static extern IntPtr PyObject_Unicode(IntPtr pointer); -#elif PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_Unicode(IntPtr pointer); -#endif + + internal static IntPtr PyObject_Unicode(IntPtr pointer) => Delegates.PyObject_Unicode(pointer); + + + internal static IntPtr PyObject_Dir(IntPtr pointer) => Delegates.PyObject_Dir(pointer); + + //==================================================================== + // Python buffer API + //==================================================================== + + + internal static bool PyObject_CheckBuffer(BorrowedReference obj) + { + var type = PyObject_TYPE(obj); + var bufferProcs = Marshal.ReadIntPtr(type.DangerousGetAddress(), TypeOffset.tp_as_buffer); + if (bufferProcs == IntPtr.Zero) return false; + var getBuffer = Marshal.ReadIntPtr(bufferProcs, 0); + return getBuffer != IntPtr.Zero; + } + + + internal static int PyObject_GetBuffer(BorrowedReference exporter, out Py_buffer view, PyBUF flags) => Delegates.PyObject_GetBuffer(exporter, out view, flags); + + + internal static void PyBuffer_Release(ref Py_buffer view) => Delegates.PyBuffer_Release(ref view); + + + internal static IntPtr PyBuffer_SizeFromFormat([MarshalAs(UnmanagedType.LPStr)] string format) => Delegates.PyBuffer_SizeFromFormat(format); + + + internal static int PyBuffer_IsContiguous(ref Py_buffer view, BufferOrderStyle order) => Delegates.PyBuffer_IsContiguous(ref view, order); + + + internal static IntPtr PyBuffer_GetPointer(ref Py_buffer view, IntPtr[] indices) => Delegates.PyBuffer_GetPointer(ref view, indices); + + + internal static int PyBuffer_FromContiguous(ref Py_buffer view, IntPtr buf, IntPtr len, BufferOrderStyle fort) => Delegates.PyBuffer_FromContiguous(ref view, buf, len, fort); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_Dir(IntPtr pointer); + + internal static int PyBuffer_ToContiguous(IntPtr buf, ref Py_buffer src, IntPtr len, BufferOrderStyle order) => Delegates.PyBuffer_ToContiguous(buf, ref src, len, order); + + internal static void PyBuffer_FillContiguousStrides(int ndims, IntPtr[] shape, IntPtr[] strides, int itemsize, BufferOrderStyle order) => Delegates.PyBuffer_FillContiguousStrides(ndims, shape, strides, itemsize, order); + + + internal static int PyBuffer_FillInfo(ref Py_buffer view, BorrowedReference exporter, IntPtr buf, IntPtr len, bool @readonly, PyBUF flags) => Delegates.PyBuffer_FillInfo(ref view, exporter, buf, len, @readonly, flags); //==================================================================== // Python number API //==================================================================== -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyNumber_Long")] - internal static extern IntPtr PyNumber_Int(IntPtr ob); -#elif PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Int(IntPtr ob); -#endif + + internal static IntPtr PyNumber_Int(IntPtr ob) => Delegates.PyNumber_Int(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Long(IntPtr ob); + + internal static IntPtr PyNumber_Long(IntPtr ob) => Delegates.PyNumber_Long(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Float(IntPtr ob); + + internal static IntPtr PyNumber_Float(IntPtr ob) => Delegates.PyNumber_Float(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PyNumber_Check(IntPtr ob); + + internal static bool PyNumber_Check(IntPtr ob) => Delegates.PyNumber_Check(ob); internal static bool PyInt_Check(IntPtr ob) { @@ -1121,47 +1172,24 @@ internal static IntPtr PyInt_FromInt64(long value) return PyInt_FromLong(v); } -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_FromLong")] - private static extern IntPtr PyInt_FromLong(IntPtr value); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_AsLong")] - internal static extern int PyInt_AsLong(IntPtr value); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_FromString")] - internal static extern IntPtr PyInt_FromString(string value, IntPtr end, int radix); -#elif PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyInt_FromLong(IntPtr value); + [Obsolete("Should not be used due to the size of long not being guaranteed")] + private static IntPtr PyInt_FromLong(IntPtr value) => Delegates.PyInt_FromLong(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyInt_AsLong(IntPtr value); + internal static int PyInt_AsLong(IntPtr value) => Delegates.PyInt_AsLong(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyInt_FromString(string value, IntPtr end, int radix); + internal static IntPtr PyInt_FromString(string value, IntPtr end, int radix) => Delegates.PyInt_FromString(value, end, radix); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyInt_GetMax(); -#endif internal static bool PyLong_Check(IntPtr ob) { return PyObject_TYPE(ob) == PyLongType; } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyLong_FromLong(long value); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_FromUnsignedLong")] - internal static extern IntPtr PyLong_FromUnsignedLong32(uint value); + [Obsolete("Should not be used due to the size of long not being guaranteed")] + internal static IntPtr PyLong_FromLong(long value) => Delegates.PyLong_FromLong(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_FromUnsignedLong")] - internal static extern IntPtr PyLong_FromUnsignedLong64(ulong value); + internal static IntPtr PyLong_FromUnsignedLong32(uint value) => Delegates.PyLong_FromUnsignedLong32(value); + internal static IntPtr PyLong_FromUnsignedLong64(ulong value) => Delegates.PyLong_FromUnsignedLong64(value); internal static IntPtr PyLong_FromUnsignedLong(object value) { @@ -1171,28 +1199,22 @@ internal static IntPtr PyLong_FromUnsignedLong(object value) return PyLong_FromUnsignedLong64(Convert.ToUInt64(value)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyLong_FromDouble(double value); + + internal static IntPtr PyLong_FromDouble(double value) => Delegates.PyLong_FromDouble(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyLong_FromLongLong(long value); + [Obsolete("Should not be used due to the size of long not being guaranteed")] + internal static IntPtr PyLong_FromLongLong(long value) => Delegates.PyLong_FromLongLong(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyLong_FromUnsignedLongLong(ulong value); + [Obsolete("Should not be used due to the size of long not being guaranteed")] + internal static IntPtr PyLong_FromUnsignedLongLong(ulong value) => Delegates.PyLong_FromUnsignedLongLong(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyLong_FromString(string value, IntPtr end, int radix); + + internal static IntPtr PyLong_FromString(string value, IntPtr end, int radix) => Delegates.PyLong_FromString(value, end, radix); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyLong_AsLong(IntPtr value); + internal static int PyLong_AsLong(IntPtr value) => Delegates.PyLong_AsLong(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_AsUnsignedLong")] - internal static extern uint PyLong_AsUnsignedLong32(IntPtr value); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyLong_AsUnsignedLong")] - internal static extern ulong PyLong_AsUnsignedLong64(IntPtr value); + internal static uint PyLong_AsUnsignedLong32(IntPtr value) => Delegates.PyLong_AsUnsignedLong32(value); + internal static ulong PyLong_AsUnsignedLong64(IntPtr value) => Delegates.PyLong_AsUnsignedLong64(value); internal static object PyLong_AsUnsignedLong(IntPtr value) { @@ -1202,195 +1224,195 @@ internal static object PyLong_AsUnsignedLong(IntPtr value) return PyLong_AsUnsignedLong64(value); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern long PyLong_AsLongLong(IntPtr value); + [Obsolete("Should not be used due to the size of long not being guaranteed")] + internal static long PyLong_AsLongLong(IntPtr value) => Delegates.PyLong_AsLongLong(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern ulong PyLong_AsUnsignedLongLong(IntPtr value); + [Obsolete("Should not be used due to the size of long not being guaranteed")] + internal static ulong PyLong_AsUnsignedLongLong(IntPtr value) => Delegates.PyLong_AsUnsignedLongLong(value); internal static bool PyFloat_Check(IntPtr ob) { return PyObject_TYPE(ob) == PyFloatType; } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyFloat_FromDouble(double value); + + internal static IntPtr PyFloat_FromDouble(double value) => Delegates.PyFloat_FromDouble(value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyFloat_FromString(IntPtr value, IntPtr junk); + + internal static IntPtr PyFloat_FromString(IntPtr value, IntPtr junk) => Delegates.PyFloat_FromString(value, junk); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern double PyFloat_AsDouble(IntPtr ob); + + internal static double PyFloat_AsDouble(IntPtr ob) => Delegates.PyFloat_AsDouble(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Add(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Add(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Add(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Subtract(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Subtract(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Subtract(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Multiply(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Multiply(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Multiply(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_TrueDivide(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_TrueDivide(IntPtr o1, IntPtr o2) => Delegates.PyNumber_TrueDivide(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_And(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_And(IntPtr o1, IntPtr o2) => Delegates.PyNumber_And(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Xor(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Xor(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Xor(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Or(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Or(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Or(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Lshift(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Lshift(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Lshift(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Rshift(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Rshift(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Rshift(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Power(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Power(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Power(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Remainder(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_Remainder(IntPtr o1, IntPtr o2) => Delegates.PyNumber_Remainder(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceAdd(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceAdd(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceAdd(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceSubtract(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceSubtract(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceSubtract(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceMultiply(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceMultiply(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceMultiply(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceTrueDivide(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceTrueDivide(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceTrueDivide(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceAnd(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceAnd(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceAnd(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceXor(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceXor(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceXor(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceOr(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceOr(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceOr(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceLshift(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceLshift(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceLshift(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceRshift(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceRshift(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceRshift(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlacePower(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlacePower(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlacePower(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_InPlaceRemainder(IntPtr o1, IntPtr o2); + + internal static IntPtr PyNumber_InPlaceRemainder(IntPtr o1, IntPtr o2) => Delegates.PyNumber_InPlaceRemainder(o1, o2); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Negative(IntPtr o1); + + internal static IntPtr PyNumber_Negative(IntPtr o1) => Delegates.PyNumber_Negative(o1); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Positive(IntPtr o1); + + internal static IntPtr PyNumber_Positive(IntPtr o1) => Delegates.PyNumber_Positive(o1); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyNumber_Invert(IntPtr o1); + + internal static IntPtr PyNumber_Invert(IntPtr o1) => Delegates.PyNumber_Invert(o1); //==================================================================== // Python sequence API //==================================================================== - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PySequence_Check(IntPtr pointer); + + internal static bool PySequence_Check(IntPtr pointer) => Delegates.PySequence_Check(pointer); internal static IntPtr PySequence_GetItem(IntPtr pointer, long index) { return PySequence_GetItem(pointer, new IntPtr(index)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PySequence_GetItem(IntPtr pointer, IntPtr index); + + private static IntPtr PySequence_GetItem(IntPtr pointer, IntPtr index) => Delegates.PySequence_GetItem(pointer, index); internal static int PySequence_SetItem(IntPtr pointer, long index, IntPtr value) { return PySequence_SetItem(pointer, new IntPtr(index), value); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PySequence_SetItem(IntPtr pointer, IntPtr index, IntPtr value); + + private static int PySequence_SetItem(IntPtr pointer, IntPtr index, IntPtr value) => Delegates.PySequence_SetItem(pointer, index, value); internal static int PySequence_DelItem(IntPtr pointer, long index) { return PySequence_DelItem(pointer, new IntPtr(index)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PySequence_DelItem(IntPtr pointer, IntPtr index); + + private static int PySequence_DelItem(IntPtr pointer, IntPtr index) => Delegates.PySequence_DelItem(pointer, index); internal static IntPtr PySequence_GetSlice(IntPtr pointer, long i1, long i2) { return PySequence_GetSlice(pointer, new IntPtr(i1), new IntPtr(i2)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PySequence_GetSlice(IntPtr pointer, IntPtr i1, IntPtr i2); + + private static IntPtr PySequence_GetSlice(IntPtr pointer, IntPtr i1, IntPtr i2) => Delegates.PySequence_GetSlice(pointer, i1, i2); internal static int PySequence_SetSlice(IntPtr pointer, long i1, long i2, IntPtr v) { return PySequence_SetSlice(pointer, new IntPtr(i1), new IntPtr(i2), v); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PySequence_SetSlice(IntPtr pointer, IntPtr i1, IntPtr i2, IntPtr v); + + private static int PySequence_SetSlice(IntPtr pointer, IntPtr i1, IntPtr i2, IntPtr v) => Delegates.PySequence_SetSlice(pointer, i1, i2, v); internal static int PySequence_DelSlice(IntPtr pointer, long i1, long i2) { return PySequence_DelSlice(pointer, new IntPtr(i1), new IntPtr(i2)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PySequence_DelSlice(IntPtr pointer, IntPtr i1, IntPtr i2); + + private static int PySequence_DelSlice(IntPtr pointer, IntPtr i1, IntPtr i2) => Delegates.PySequence_DelSlice(pointer, i1, i2); internal static long PySequence_Size(IntPtr pointer) { return (long)_PySequence_Size(pointer); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PySequence_Size")] - private static extern IntPtr _PySequence_Size(IntPtr pointer); + + private static IntPtr _PySequence_Size(IntPtr pointer) => Delegates._PySequence_Size(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PySequence_Contains(IntPtr pointer, IntPtr item); + + internal static int PySequence_Contains(IntPtr pointer, IntPtr item) => Delegates.PySequence_Contains(pointer, item); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PySequence_Concat(IntPtr pointer, IntPtr other); + + internal static IntPtr PySequence_Concat(IntPtr pointer, IntPtr other) => Delegates.PySequence_Concat(pointer, other); internal static IntPtr PySequence_Repeat(IntPtr pointer, long count) { return PySequence_Repeat(pointer, new IntPtr(count)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PySequence_Repeat(IntPtr pointer, IntPtr count); + + private static IntPtr PySequence_Repeat(IntPtr pointer, IntPtr count) => Delegates.PySequence_Repeat(pointer, count); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PySequence_Index(IntPtr pointer, IntPtr item); + + internal static int PySequence_Index(IntPtr pointer, IntPtr item) => Delegates.PySequence_Index(pointer, item); internal static long PySequence_Count(IntPtr pointer, IntPtr value) { return (long)_PySequence_Count(pointer, value); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PySequence_Count")] - private static extern IntPtr _PySequence_Count(IntPtr pointer, IntPtr value); + + private static IntPtr _PySequence_Count(IntPtr pointer, IntPtr value) => Delegates._PySequence_Count(pointer, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PySequence_Tuple(IntPtr pointer); + + internal static IntPtr PySequence_Tuple(IntPtr pointer) => Delegates.PySequence_Tuple(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PySequence_List(IntPtr pointer); + + internal static IntPtr PySequence_List(IntPtr pointer) => Delegates.PySequence_List(pointer); //==================================================================== @@ -1403,31 +1425,27 @@ internal static bool IsStringType(IntPtr op) return (t == PyStringType) || (t == PyUnicodeType); } + [Obsolete(Util.UseOverloadWithReferenceTypes)] internal static bool PyString_Check(IntPtr ob) { return PyObject_TYPE(ob) == PyStringType; } + internal static bool PyString_Check(BorrowedReference ob) + => PyObject_TYPE(ob) == PyStringType; internal static IntPtr PyString_FromString(string value) { -#if PYTHON3 - return PyUnicode_FromKindAndData(_UCS, value, value.Length); -#elif PYTHON2 - return PyString_FromStringAndSize(value, value.Length); -#endif + return PyUnicode_FromKindAndData(UCS, value, value.Length); } -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyBytes_FromString(string op); + internal static IntPtr PyBytes_FromString(string op) => Delegates.PyBytes_FromString(op); internal static long PyBytes_Size(IntPtr op) { return (long)_PyBytes_Size(op); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyBytes_Size")] - private static extern IntPtr _PyBytes_Size(IntPtr op); + private static IntPtr _PyBytes_Size(IntPtr op) => Delegates._PyBytes_Size(op); internal static IntPtr PyBytes_AS_STRING(IntPtr ob) { @@ -1439,67 +1457,44 @@ internal static IntPtr PyString_FromStringAndSize(string value, long size) return _PyString_FromStringAndSize(value, new IntPtr(size)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = "PyUnicode_FromStringAndSize")] - internal static extern IntPtr _PyString_FromStringAndSize( + internal static IntPtr _PyString_FromStringAndSize( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string value, IntPtr size - ); + ) => Delegates._PyString_FromStringAndSize(value, size); internal static IntPtr PyUnicode_FromStringAndSize(IntPtr value, long size) { return PyUnicode_FromStringAndSize(value, new IntPtr(size)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyUnicode_FromStringAndSize(IntPtr value, IntPtr size); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyUnicode_AsUTF8(IntPtr unicode); - -#elif PYTHON2 - internal static IntPtr PyString_FromStringAndSize(string value, long size) - { - return PyString_FromStringAndSize(value, new IntPtr(size)); - } - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyString_FromStringAndSize(string value, IntPtr size); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyString_AsString(IntPtr op); + private static IntPtr PyUnicode_FromStringAndSize(IntPtr value, IntPtr size) => Delegates.PyUnicode_FromStringAndSize(value, size); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyString_Size(IntPtr pointer); -#endif + internal static IntPtr PyUnicode_AsUTF8(IntPtr unicode) => Delegates.PyUnicode_AsUTF8(unicode); internal static bool PyUnicode_Check(IntPtr ob) { return PyObject_TYPE(ob) == PyUnicodeType; } -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyUnicode_FromObject(IntPtr ob); + internal static IntPtr PyUnicode_FromObject(IntPtr ob) => Delegates.PyUnicode_FromObject(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); + internal static IntPtr PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err) => Delegates.PyUnicode_FromEncodedObject(ob, enc, err); internal static IntPtr PyUnicode_FromKindAndData(int kind, string s, long size) { return PyUnicode_FromKindAndData(kind, s, new IntPtr(size)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyUnicode_FromKindAndData( + private static IntPtr PyUnicode_FromKindAndData( int kind, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s, IntPtr size - ); + ) => Delegates.PyUnicode_FromKindAndData(kind, s, size +); internal static IntPtr PyUnicode_FromUnicode(string s, long size) { - return PyUnicode_FromKindAndData(_UCS, s, size); + return PyUnicode_FromKindAndData(UCS, s, size); } internal static long PyUnicode_GetSize(IntPtr ob) @@ -1507,52 +1502,11 @@ internal static long PyUnicode_GetSize(IntPtr ob) return (long)_PyUnicode_GetSize(ob); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyUnicode_GetSize")] - private static extern IntPtr _PyUnicode_GetSize(IntPtr ob); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyUnicode_AsUnicode(IntPtr ob); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyUnicode_FromOrdinal(int c); -#elif PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = PyUnicodeEntryPoint + "FromObject")] - internal static extern IntPtr PyUnicode_FromObject(IntPtr ob); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = PyUnicodeEntryPoint + "FromEncodedObject")] - internal static extern IntPtr PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); - - internal static IntPtr PyUnicode_FromUnicode(string s, long size) - { - return PyUnicode_FromUnicode(s, new IntPtr(size)); - } - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = PyUnicodeEntryPoint + "FromUnicode")] - private static extern IntPtr PyUnicode_FromUnicode( - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s, - IntPtr size - ); - - internal static long PyUnicode_GetSize(IntPtr ob) - { - return (long) _PyUnicode_GetSize(ob); - } - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = PyUnicodeEntryPoint + "GetSize")] - internal static extern IntPtr _PyUnicode_GetSize(IntPtr ob); + private static IntPtr _PyUnicode_GetSize(IntPtr ob) => Delegates._PyUnicode_GetSize(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = PyUnicodeEntryPoint + "AsUnicode")] - internal static extern IntPtr PyUnicode_AsUnicode(IntPtr ob); + internal static IntPtr PyUnicode_AsUnicode(IntPtr ob) => Delegates.PyUnicode_AsUnicode(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, - EntryPoint = PyUnicodeEntryPoint + "FromOrdinal")] - internal static extern IntPtr PyUnicode_FromOrdinal(int c); -#endif + internal static IntPtr PyUnicode_FromOrdinal(int c) => Delegates.PyUnicode_FromOrdinal(c); internal static IntPtr PyUnicode_FromString(string s) { @@ -1578,19 +1532,13 @@ internal static string GetManagedString(IntPtr op) { IntPtr type = PyObject_TYPE(op); -#if PYTHON2 // Python 3 strings are all Unicode - if (type == PyStringType) - { - return Marshal.PtrToStringAnsi(PyString_AsString(op), PyString_Size(op)); - } -#endif - if (type == PyUnicodeType) { IntPtr p = PyUnicode_AsUnicode(op); - int length = (int)PyUnicode_GetSize(op); + Exceptions.ErrorCheck(p); + int length = checked((int)PyUnicode_GetSize(op)); - int size = length * _UCS; + int size = checked(length * UCS); var buffer = new byte[size]; Marshal.Copy(p, buffer, 0, size); return PyEncoding.GetString(buffer, 0, size); @@ -1609,58 +1557,60 @@ internal static bool PyDict_Check(IntPtr ob) return PyObject_TYPE(ob) == PyDictType; } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDict_New(); + + internal static IntPtr PyDict_New() => Delegates.PyDict_New(); + + + internal static IntPtr PyDictProxy_New(IntPtr dict) => Delegates.PyDictProxy_New(dict); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDictProxy_New(IntPtr dict); + + internal static IntPtr PyDict_GetItem(IntPtr pointer, IntPtr key) => Delegates.PyDict_GetItem(pointer, key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDict_GetItem(IntPtr pointer, IntPtr key); + + internal static IntPtr PyDict_GetItemString(IntPtr pointer, string key) => Delegates.PyDict_GetItemString(pointer, key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDict_GetItemString(IntPtr pointer, string key); + + internal static int PyDict_SetItem(BorrowedReference pointer, BorrowedReference key, BorrowedReference value) => Delegates.PyDict_SetItem(pointer, key, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyDict_SetItem(IntPtr pointer, IntPtr key, IntPtr value); + + internal static int PyDict_SetItemString(IntPtr pointer, string key, IntPtr value) => Delegates.PyDict_SetItemString(pointer, key, value); + internal static int PyDict_SetItemString(BorrowedReference pointer, string key, BorrowedReference value) + => PyDict_SetItemString(pointer.DangerousGetAddress(), key, value.DangerousGetAddress()); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyDict_SetItemString(IntPtr pointer, string key, IntPtr value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyDict_DelItem(IntPtr pointer, IntPtr key); + internal static int PyDict_DelItem(IntPtr pointer, IntPtr key) => Delegates.PyDict_DelItem(pointer, key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyDict_DelItemString(IntPtr pointer, string key); + + internal static int PyDict_DelItemString(IntPtr pointer, string key) => Delegates.PyDict_DelItemString(pointer, key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyMapping_HasKey(IntPtr pointer, IntPtr key); + + internal static int PyMapping_HasKey(IntPtr pointer, IntPtr key) => Delegates.PyMapping_HasKey(pointer, key); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDict_Keys(IntPtr pointer); + + internal static IntPtr PyDict_Keys(IntPtr pointer) => Delegates.PyDict_Keys(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDict_Values(IntPtr pointer); + + internal static IntPtr PyDict_Values(IntPtr pointer) => Delegates.PyDict_Values(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern NewReference PyDict_Items(IntPtr pointer); + + internal static NewReference PyDict_Items(IntPtr pointer) => Delegates.PyDict_Items(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyDict_Copy(IntPtr pointer); + + internal static IntPtr PyDict_Copy(IntPtr pointer) => Delegates.PyDict_Copy(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyDict_Update(IntPtr pointer, IntPtr other); + + internal static int PyDict_Update(IntPtr pointer, IntPtr other) => Delegates.PyDict_Update(pointer, other); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyDict_Clear(IntPtr pointer); + + internal static void PyDict_Clear(IntPtr pointer) => Delegates.PyDict_Clear(pointer); internal static long PyDict_Size(IntPtr pointer) { return (long)_PyDict_Size(pointer); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyDict_Size")] - internal static extern IntPtr _PyDict_Size(IntPtr pointer); + + internal static IntPtr _PyDict_Size(IntPtr pointer) => Delegates._PyDict_Size(pointer); //==================================================================== @@ -1677,68 +1627,68 @@ internal static IntPtr PyList_New(long size) return PyList_New(new IntPtr(size)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyList_New(IntPtr size); + + private static IntPtr PyList_New(IntPtr size) => Delegates.PyList_New(size); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyList_AsTuple(IntPtr pointer); + + internal static IntPtr PyList_AsTuple(IntPtr pointer) => Delegates.PyList_AsTuple(pointer); internal static BorrowedReference PyList_GetItem(IntPtr pointer, long index) { return PyList_GetItem(pointer, new IntPtr(index)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern BorrowedReference PyList_GetItem(IntPtr pointer, IntPtr index); + + private static BorrowedReference PyList_GetItem(IntPtr pointer, IntPtr index) => Delegates.PyList_GetItem(pointer, index); internal static int PyList_SetItem(IntPtr pointer, long index, IntPtr value) { return PyList_SetItem(pointer, new IntPtr(index), value); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PyList_SetItem(IntPtr pointer, IntPtr index, IntPtr value); + + private static int PyList_SetItem(IntPtr pointer, IntPtr index, IntPtr value) => Delegates.PyList_SetItem(pointer, index, value); internal static int PyList_Insert(BorrowedReference pointer, long index, IntPtr value) { return PyList_Insert(pointer, new IntPtr(index), value); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PyList_Insert(BorrowedReference pointer, IntPtr index, IntPtr value); + + private static int PyList_Insert(BorrowedReference pointer, IntPtr index, IntPtr value) => Delegates.PyList_Insert(pointer, index, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyList_Append(BorrowedReference pointer, IntPtr value); + + internal static int PyList_Append(BorrowedReference pointer, IntPtr value) => Delegates.PyList_Append(pointer, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyList_Reverse(BorrowedReference pointer); + + internal static int PyList_Reverse(BorrowedReference pointer) => Delegates.PyList_Reverse(pointer); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyList_Sort(BorrowedReference pointer); + + internal static int PyList_Sort(BorrowedReference pointer) => Delegates.PyList_Sort(pointer); internal static IntPtr PyList_GetSlice(IntPtr pointer, long start, long end) { return PyList_GetSlice(pointer, new IntPtr(start), new IntPtr(end)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyList_GetSlice(IntPtr pointer, IntPtr start, IntPtr end); + + private static IntPtr PyList_GetSlice(IntPtr pointer, IntPtr start, IntPtr end) => Delegates.PyList_GetSlice(pointer, start, end); internal static int PyList_SetSlice(IntPtr pointer, long start, long end, IntPtr value) { return PyList_SetSlice(pointer, new IntPtr(start), new IntPtr(end), value); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PyList_SetSlice(IntPtr pointer, IntPtr start, IntPtr end, IntPtr value); + + private static int PyList_SetSlice(IntPtr pointer, IntPtr start, IntPtr end, IntPtr value) => Delegates.PyList_SetSlice(pointer, start, end, value); internal static long PyList_Size(IntPtr pointer) { return (long)_PyList_Size(pointer); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyList_Size")] - private static extern IntPtr _PyList_Size(IntPtr pointer); + + private static IntPtr _PyList_Size(IntPtr pointer) => Delegates._PyList_Size(pointer); //==================================================================== // Python tuple API @@ -1754,138 +1704,120 @@ internal static IntPtr PyTuple_New(long size) return PyTuple_New(new IntPtr(size)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyTuple_New(IntPtr size); + + private static IntPtr PyTuple_New(IntPtr size) => Delegates.PyTuple_New(size); internal static IntPtr PyTuple_GetItem(IntPtr pointer, long index) { return PyTuple_GetItem(pointer, new IntPtr(index)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyTuple_GetItem(IntPtr pointer, IntPtr index); + + private static IntPtr PyTuple_GetItem(IntPtr pointer, IntPtr index) => Delegates.PyTuple_GetItem(pointer, index); internal static int PyTuple_SetItem(IntPtr pointer, long index, IntPtr value) { return PyTuple_SetItem(pointer, new IntPtr(index), value); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern int PyTuple_SetItem(IntPtr pointer, IntPtr index, IntPtr value); + + private static int PyTuple_SetItem(IntPtr pointer, IntPtr index, IntPtr value) => Delegates.PyTuple_SetItem(pointer, index, value); internal static IntPtr PyTuple_GetSlice(IntPtr pointer, long start, long end) { return PyTuple_GetSlice(pointer, new IntPtr(start), new IntPtr(end)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyTuple_GetSlice(IntPtr pointer, IntPtr start, IntPtr end); + + private static IntPtr PyTuple_GetSlice(IntPtr pointer, IntPtr start, IntPtr end) => Delegates.PyTuple_GetSlice(pointer, start, end); internal static long PyTuple_Size(IntPtr pointer) { return (long)_PyTuple_Size(pointer); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyTuple_Size")] - private static extern IntPtr _PyTuple_Size(IntPtr pointer); + + private static IntPtr _PyTuple_Size(IntPtr pointer) => Delegates._PyTuple_Size(pointer); //==================================================================== // Python iterator API //==================================================================== - internal static bool PyIter_Check(IntPtr pointer) + internal static bool PyIter_Check(BorrowedReference pointer) { - var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); -#if PYTHON2 - long tp_flags = Util.ReadCLong(ob_type, TypeOffset.tp_flags); - if ((tp_flags & TypeFlags.HaveIter) == 0) - return false; -#endif + var ob_type = Marshal.ReadIntPtr(pointer.DangerousGetAddress(), ObjectOffset.ob_type); IntPtr tp_iternext = Marshal.ReadIntPtr(ob_type, TypeOffset.tp_iternext); return tp_iternext != IntPtr.Zero && tp_iternext != _PyObject_NextNotImplemented; } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyIter_Next(IntPtr pointer); + + internal static NewReference PyIter_Next(BorrowedReference pointer) => Delegates.PyIter_Next(pointer); //==================================================================== // Python module API //==================================================================== - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyModule_New(string name); + + internal static IntPtr PyModule_New(string name) => Delegates.PyModule_New(name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern string PyModule_GetName(IntPtr module); + + internal static string PyModule_GetName(IntPtr module) => Delegates.PyModule_GetName(module); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyModule_GetDict(IntPtr module); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern string PyModule_GetFilename(IntPtr module); + [Obsolete(Util.UseOverloadWithReferenceTypes)] + internal static IntPtr PyModule_GetDict(IntPtr module) => Delegates.PyModule_GetDict(module); + internal static BorrowedReference PyModule_GetDict(BorrowedReference module) + => new BorrowedReference(PyModule_GetDict(module.DangerousGetAddress())); -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyModule_Create2(IntPtr module, int apiver); -#endif - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyImport_Import(IntPtr name); + internal static string PyModule_GetFilename(IntPtr module) => Delegates.PyModule_GetFilename(module); - /// - /// Return value: New reference. - /// - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyImport_ImportModule(string name); + internal static IntPtr PyModule_Create2(IntPtr module, int apiver) => Delegates.PyModule_Create2(module, apiver); + + internal static IntPtr PyImport_Import(IntPtr name) => Delegates.PyImport_Import(name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyImport_ReloadModule(IntPtr module); + internal static IntPtr PyImport_ImportModule(string name) => Delegates.PyImport_ImportModule(name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyImport_AddModule(string name); + internal static IntPtr PyImport_ReloadModule(IntPtr module) => Delegates.PyImport_ReloadModule(module); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyImport_GetModuleDict(); + internal static BorrowedReference PyImport_AddModule(string name) => Delegates.PyImport_AddModule(name); -#if PYTHON3 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PySys_SetArgvEx( + internal static IntPtr PyImport_GetModuleDict() => Delegates.PyImport_GetModuleDict(); + + internal static void PySys_SetArgvEx( int argc, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv, int updatepath - ); -#elif PYTHON2 - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PySys_SetArgvEx( - int argc, - string[] argv, - int updatepath - ); -#endif + ) => Delegates.PySys_SetArgvEx(argc, argv, updatepath +); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PySys_GetObject(string name); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PySys_SetObject(string name, IntPtr ob); + internal static IntPtr PySys_GetObject(string name) => Delegates.PySys_GetObject(name); + internal static int PySys_SetObject(string name, IntPtr ob) => Delegates.PySys_SetObject(name, ob); //==================================================================== // Python type object API //==================================================================== - internal static bool PyType_Check(IntPtr ob) + internal static bool PyType_Check(BorrowedReference ob) + { + // fast path using raw memory access + BorrowedReference type = PyObject_TYPE(ob); + if (type == PyTypeType) return true; + return PyType_FastSubclass(type, TypeFlags.TypeSubclass); + } + + internal static bool PyType_FastSubclass(BorrowedReference type, TypeFlags baseType) { - return PyObject_TypeCheck(ob, PyTypeType); + var flags = (TypeFlags)Util.ReadCLong(type.DangerousGetAddress(), TypeOffset.tp_flags); + return (flags & baseType) != 0; } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyType_Modified(IntPtr type); + internal static void PyType_Modified(IntPtr type) => Delegates.PyType_Modified(type); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern bool PyType_IsSubtype(IntPtr t1, IntPtr t2); + internal static bool PyType_IsSubtype(IntPtr t1, IntPtr t2) => Delegates.PyType_IsSubtype(t1, t2); internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) { @@ -1898,44 +1830,32 @@ internal static bool PyType_IsSameAsOrSubtype(IntPtr type, IntPtr ofType) return (type == ofType) || PyType_IsSubtype(type, ofType); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw); + internal static IntPtr PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw) => Delegates.PyType_GenericNew(type, args, kw); internal static IntPtr PyType_GenericAlloc(IntPtr type, long n) { return PyType_GenericAlloc(type, new IntPtr(n)); } + internal static NewReference PyType_GenericAlloc(BorrowedReference type, long n) + => NewReference.DangerousFromPointer(PyType_GenericAlloc(type.DangerousGetAddress(), n)); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyType_GenericAlloc(IntPtr type, IntPtr n); + private static IntPtr PyType_GenericAlloc(IntPtr type, IntPtr n) => Delegates.PyType_GenericAlloc(type, n); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyType_Ready(IntPtr type); + internal static int PyType_Ready(IntPtr type) => Delegates.PyType_Ready(type); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr _PyType_Lookup(IntPtr type, IntPtr name); + internal static IntPtr _PyType_Lookup(IntPtr type, IntPtr name) => Delegates._PyType_Lookup(type, name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_GenericGetAttr(IntPtr obj, IntPtr name); + internal static IntPtr PyObject_GenericGetAttr(IntPtr obj, IntPtr name) => Delegates.PyObject_GenericGetAttr(obj, name); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyObject_GenericSetAttr(IntPtr obj, IntPtr name, IntPtr value); + internal static int PyObject_GenericSetAttr(IntPtr obj, IntPtr name, IntPtr value) => Delegates.PyObject_GenericSetAttr(obj, name, value); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr _PyObject_GetDictPtr(IntPtr obj); + internal static IntPtr _PyObject_GetDictPtr(IntPtr obj) => Delegates._PyObject_GetDictPtr(obj); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyObject_GC_New(IntPtr tp); + internal static void PyObject_GC_Del(IntPtr tp) => Delegates.PyObject_GC_Del(tp); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyObject_GC_Del(IntPtr tp); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyObject_GC_Track(IntPtr tp); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyObject_GC_UnTrack(IntPtr tp); + internal static void PyObject_GC_Track(IntPtr tp) => Delegates.PyObject_GC_Track(tp); + internal static void PyObject_GC_UnTrack(IntPtr tp) => Delegates.PyObject_GC_UnTrack(tp); //==================================================================== // Python memory API @@ -1946,104 +1866,83 @@ internal static IntPtr PyMem_Malloc(long size) return PyMem_Malloc(new IntPtr(size)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyMem_Malloc(IntPtr size); + private static IntPtr PyMem_Malloc(IntPtr size) => Delegates.PyMem_Malloc(size); internal static IntPtr PyMem_Realloc(IntPtr ptr, long size) { return PyMem_Realloc(ptr, new IntPtr(size)); } - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - private static extern IntPtr PyMem_Realloc(IntPtr ptr, IntPtr size); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyMem_Free(IntPtr ptr); + private static IntPtr PyMem_Realloc(IntPtr ptr, IntPtr size) => Delegates.PyMem_Realloc(ptr, size); + internal static void PyMem_Free(IntPtr ptr) => Delegates.PyMem_Free(ptr); //==================================================================== // Python exception API //==================================================================== - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_SetString(IntPtr ob, string message); + internal static void PyErr_SetString(IntPtr ob, string message) => Delegates.PyErr_SetString(ob, message); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_SetObject(IntPtr ob, IntPtr message); + internal static void PyErr_SetObject(IntPtr ob, IntPtr message) => Delegates.PyErr_SetObject(ob, message); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyErr_SetFromErrno(IntPtr ob); + internal static IntPtr PyErr_SetFromErrno(IntPtr ob) => Delegates.PyErr_SetFromErrno(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_SetNone(IntPtr ob); + internal static void PyErr_SetNone(IntPtr ob) => Delegates.PyErr_SetNone(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyErr_ExceptionMatches(IntPtr exception); + internal static int PyErr_ExceptionMatches(IntPtr exception) => Delegates.PyErr_ExceptionMatches(exception); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val); + internal static int PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val) => Delegates.PyErr_GivenExceptionMatches(ob, val); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_NormalizeException(IntPtr ob, IntPtr val, IntPtr tb); + internal static void PyErr_NormalizeException(IntPtr ob, IntPtr val, IntPtr tb) => Delegates.PyErr_NormalizeException(ob, val, tb); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyErr_Occurred(); + internal static IntPtr PyErr_Occurred() => Delegates.PyErr_Occurred(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_Fetch(out IntPtr ob, out IntPtr val, out IntPtr tb); + internal static void PyErr_Fetch(out NewReference type, out NewReference value, out NewReference traceback) + => Delegates.PyErr_Fetch(out type, out value, out traceback); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_Restore(IntPtr ob, IntPtr val, IntPtr tb); + internal static void PyErr_Restore(StealingReference ob, StealingReference val, StealingReference tb) + => Delegates.PyErr_Restore( + ob.DangerousGetAddressOrNull(), + val.DangerousGetAddressOrNull(), + tb.DangerousGetAddressOrNull()); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_Clear(); + internal static void PyErr_Clear() => Delegates.PyErr_Clear(); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern void PyErr_Print(); + internal static void PyErr_Print() => Delegates.PyErr_Print(); //==================================================================== // Cell API //==================================================================== - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern NewReference PyCell_Get(BorrowedReference cell); - - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int PyCell_Set(BorrowedReference cell, IntPtr value); + internal static NewReference PyCell_Get(BorrowedReference cell) => Delegates.PyCell_Get(cell); + internal static int PyCell_Set(BorrowedReference cell, BorrowedReference value) => Delegates.PyCell_Set(cell, value); //==================================================================== // Miscellaneous //==================================================================== - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyMethod_Self(IntPtr ob); + internal static IntPtr PyMethod_Self(IntPtr ob) => Delegates.PyMethod_Self(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern IntPtr PyMethod_Function(IntPtr ob); + internal static IntPtr PyMethod_Function(IntPtr ob) => Delegates.PyMethod_Function(ob); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int Py_AddPendingCall(IntPtr func, IntPtr arg); + internal static IntPtr PyMethod_New(IntPtr func, IntPtr self) => Delegates.PyMethod_New(func, self); - [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] - internal static extern int Py_MakePendingCalls(); + internal static int Py_AddPendingCall(IntPtr func, IntPtr arg) => Delegates.Py_AddPendingCall(func, arg); - internal static void SetNoSiteFlag() - { + internal static int Py_MakePendingCalls() => Delegates.Py_MakePendingCalls(); + + internal static void SetNoSiteFlag() { var loader = LibraryLoader.Get(OperatingSystem); - IntPtr dllLocal = _PythonDll != "__Internal" - ? loader.Load(_PythonDll) + IntPtr dllLocal = PythonDLL != "__Internal" + ? loader.Load(PythonDLL) : IntPtr.Zero; - try - { + try { Py_NoSiteFlag = loader.GetFunction(dllLocal, "Py_NoSiteFlag"); Marshal.WriteInt32(Py_NoSiteFlag, 1); - } - finally - { - if (dllLocal != IntPtr.Zero) - { + } finally { + if (dllLocal != IntPtr.Zero) { loader.Free(dllLocal); } } @@ -2052,35 +1951,1518 @@ internal static void SetNoSiteFlag() /// /// Return value: New reference. /// - internal static IntPtr GetBuiltins() - { - return IsPython3 ? PyImport_ImportModule("builtins") - : PyImport_ImportModule("__builtin__"); - } - } + internal static IntPtr GetBuiltins() => PyImport_ImportModule("builtins"); + public static class Delegates + { + static Delegates() + { + Py_IncRef = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_IncRef), GetUnmanagedDll(PythonDLL))); + Py_DecRef = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_DecRef), GetUnmanagedDll(PythonDLL))); + Py_Initialize = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_Initialize), GetUnmanagedDll(PythonDLL))); + Py_InitializeEx = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_InitializeEx), GetUnmanagedDll(PythonDLL))); + Py_IsInitialized = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_IsInitialized), GetUnmanagedDll(PythonDLL))); + Py_Finalize = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_Finalize), GetUnmanagedDll(PythonDLL))); + Py_NewInterpreter = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_NewInterpreter), GetUnmanagedDll(PythonDLL))); + Py_EndInterpreter = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_EndInterpreter), GetUnmanagedDll(PythonDLL))); + PyThreadState_New = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyThreadState_New), GetUnmanagedDll(PythonDLL))); + PyThreadState_Get = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyThreadState_Get), GetUnmanagedDll(PythonDLL))); + PyThread_get_key_value = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyThread_get_key_value), GetUnmanagedDll(PythonDLL))); + PyThread_get_thread_ident = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyThread_get_thread_ident), GetUnmanagedDll(PythonDLL))); + PyThread_set_key_value = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyThread_set_key_value), GetUnmanagedDll(PythonDLL))); + PyThreadState_Swap = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyThreadState_Swap), GetUnmanagedDll(PythonDLL))); + PyGILState_Ensure = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyGILState_Ensure), GetUnmanagedDll(PythonDLL))); + PyGILState_Release = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyGILState_Release), GetUnmanagedDll(PythonDLL))); + PyGILState_GetThisThreadState = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyGILState_GetThisThreadState), GetUnmanagedDll(PythonDLL))); + if (PythonVersion >= new Version(3, 4)) { + PyGILState_Check = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyGILState_Check), GetUnmanagedDll(PythonDLL))); + } + Py_Main = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_Main), GetUnmanagedDll(PythonDLL))); + PyEval_InitThreads = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_InitThreads), GetUnmanagedDll(PythonDLL))); + PyEval_ThreadsInitialized = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_ThreadsInitialized), GetUnmanagedDll(PythonDLL))); + PyEval_AcquireLock = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_AcquireLock), GetUnmanagedDll(PythonDLL))); + PyEval_ReleaseLock = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_ReleaseLock), GetUnmanagedDll(PythonDLL))); + PyEval_AcquireThread = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_AcquireThread), GetUnmanagedDll(PythonDLL))); + PyEval_ReleaseThread = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_ReleaseThread), GetUnmanagedDll(PythonDLL))); + PyEval_SaveThread = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_SaveThread), GetUnmanagedDll(PythonDLL))); + PyEval_RestoreThread = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_RestoreThread), GetUnmanagedDll(PythonDLL))); + PyEval_GetBuiltins = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_GetBuiltins), GetUnmanagedDll(PythonDLL))); + PyEval_GetGlobals = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_GetGlobals), GetUnmanagedDll(PythonDLL))); + PyEval_GetLocals = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_GetLocals), GetUnmanagedDll(PythonDLL))); + Py_GetProgramName = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetProgramName), GetUnmanagedDll(PythonDLL))); + Py_SetProgramName = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_SetProgramName), GetUnmanagedDll(PythonDLL))); + Py_GetPythonHome = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetPythonHome), GetUnmanagedDll(PythonDLL))); + Py_SetPythonHome = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_SetPythonHome), GetUnmanagedDll(PythonDLL))); + Py_GetPath = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetPath), GetUnmanagedDll(PythonDLL))); + Py_SetPath = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_SetPath), GetUnmanagedDll(PythonDLL))); + Py_GetVersion = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetVersion), GetUnmanagedDll(PythonDLL))); + Py_GetPlatform = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetPlatform), GetUnmanagedDll(PythonDLL))); + Py_GetCopyright = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetCopyright), GetUnmanagedDll(PythonDLL))); + Py_GetCompiler = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetCompiler), GetUnmanagedDll(PythonDLL))); + Py_GetBuildInfo = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_GetBuildInfo), GetUnmanagedDll(PythonDLL))); + PyRun_SimpleString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyRun_SimpleString), GetUnmanagedDll(PythonDLL))); + PyRun_String = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyRun_String), GetUnmanagedDll(PythonDLL))); + PyEval_EvalCode = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyEval_EvalCode), GetUnmanagedDll(PythonDLL))); + Py_CompileString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_CompileString), GetUnmanagedDll(PythonDLL))); + Py_CompileStringExFlags = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_CompileStringExFlags), GetUnmanagedDll(PythonDLL))); + PyImport_ExecCodeModule = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyImport_ExecCodeModule), GetUnmanagedDll(PythonDLL))); + PyCFunction_NewEx = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyCFunction_NewEx), GetUnmanagedDll(PythonDLL))); + PyCFunction_Call = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyCFunction_Call), GetUnmanagedDll(PythonDLL))); + PyObject_HasAttrString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_HasAttrString), GetUnmanagedDll(PythonDLL))); + PyObject_GetAttrString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GetAttrString), GetUnmanagedDll(PythonDLL))); + PyObject_SetAttrString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_SetAttrString), GetUnmanagedDll(PythonDLL))); + PyObject_HasAttr = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_HasAttr), GetUnmanagedDll(PythonDLL))); + PyObject_GetAttr = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GetAttr), GetUnmanagedDll(PythonDLL))); + PyObject_SetAttr = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_SetAttr), GetUnmanagedDll(PythonDLL))); + PyObject_GetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GetItem), GetUnmanagedDll(PythonDLL))); + PyObject_SetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_SetItem), GetUnmanagedDll(PythonDLL))); + PyObject_DelItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_DelItem), GetUnmanagedDll(PythonDLL))); + PyObject_GetIter = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GetIter), GetUnmanagedDll(PythonDLL))); + PyObject_Call = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_Call), GetUnmanagedDll(PythonDLL))); + PyObject_CallObject = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_CallObject), GetUnmanagedDll(PythonDLL))); + PyObject_RichCompareBool = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_RichCompareBool), GetUnmanagedDll(PythonDLL))); + PyObject_IsInstance = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_IsInstance), GetUnmanagedDll(PythonDLL))); + PyObject_IsSubclass = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_IsSubclass), GetUnmanagedDll(PythonDLL))); + PyCallable_Check = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyCallable_Check), GetUnmanagedDll(PythonDLL))); + PyObject_IsTrue = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_IsTrue), GetUnmanagedDll(PythonDLL))); + PyObject_Not = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_Not), GetUnmanagedDll(PythonDLL))); + _PyObject_Size = GetDelegateForFunctionPointer<_PyObject_SizeDelegate>(GetFunctionByName("PyObject_Size", GetUnmanagedDll(PythonDLL))); + PyObject_Hash = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_Hash), GetUnmanagedDll(PythonDLL))); + PyObject_Repr = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_Repr), GetUnmanagedDll(PythonDLL))); + PyObject_Str = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_Str), GetUnmanagedDll(PythonDLL))); + PyObject_Unicode = GetDelegateForFunctionPointer(GetFunctionByName("PyObject_Str", GetUnmanagedDll(PythonDLL))); + PyObject_Dir = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_Dir), GetUnmanagedDll(PythonDLL))); + PyNumber_Int = GetDelegateForFunctionPointer(GetFunctionByName("PyNumber_Long", GetUnmanagedDll(PythonDLL))); + PyNumber_Long = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Long), GetUnmanagedDll(PythonDLL))); + PyNumber_Float = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Float), GetUnmanagedDll(PythonDLL))); + PyNumber_Check = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Check), GetUnmanagedDll(PythonDLL))); + PyInt_FromLong = GetDelegateForFunctionPointer(GetFunctionByName("PyLong_FromLong", GetUnmanagedDll(PythonDLL))); + PyInt_AsLong = GetDelegateForFunctionPointer(GetFunctionByName("PyLong_AsLong", GetUnmanagedDll(PythonDLL))); + PyInt_FromString = GetDelegateForFunctionPointer(GetFunctionByName("PyLong_FromString", GetUnmanagedDll(PythonDLL))); + PyLong_FromLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_FromLong), GetUnmanagedDll(PythonDLL))); + PyLong_FromUnsignedLong32 = GetDelegateForFunctionPointer(GetFunctionByName("PyLong_FromUnsignedLong", GetUnmanagedDll(PythonDLL))); + PyLong_FromUnsignedLong64 = GetDelegateForFunctionPointer(GetFunctionByName("PyLong_FromUnsignedLong", GetUnmanagedDll(PythonDLL))); + PyLong_FromUnsignedLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_FromUnsignedLong), GetUnmanagedDll(PythonDLL))); + PyLong_FromDouble = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_FromDouble), GetUnmanagedDll(PythonDLL))); + PyLong_FromLongLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_FromLongLong), GetUnmanagedDll(PythonDLL))); + PyLong_FromUnsignedLongLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_FromUnsignedLongLong), GetUnmanagedDll(PythonDLL))); + PyLong_FromString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_FromString), GetUnmanagedDll(PythonDLL))); + PyLong_AsLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_AsLong), GetUnmanagedDll(PythonDLL))); + PyLong_AsUnsignedLong32 = GetDelegateForFunctionPointer(GetFunctionByName("PyLong_AsUnsignedLong", GetUnmanagedDll(PythonDLL))); + PyLong_AsUnsignedLong64 = GetDelegateForFunctionPointer(GetFunctionByName("PyLong_AsUnsignedLong", GetUnmanagedDll(PythonDLL))); + PyLong_AsUnsignedLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_AsUnsignedLong), GetUnmanagedDll(PythonDLL))); + PyLong_AsLongLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_AsLongLong), GetUnmanagedDll(PythonDLL))); + PyLong_AsUnsignedLongLong = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyLong_AsUnsignedLongLong), GetUnmanagedDll(PythonDLL))); + PyFloat_FromDouble = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyFloat_FromDouble), GetUnmanagedDll(PythonDLL))); + PyFloat_FromString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyFloat_FromString), GetUnmanagedDll(PythonDLL))); + PyFloat_AsDouble = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyFloat_AsDouble), GetUnmanagedDll(PythonDLL))); + PyNumber_Add = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Add), GetUnmanagedDll(PythonDLL))); + PyNumber_Subtract = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Subtract), GetUnmanagedDll(PythonDLL))); + PyNumber_Multiply = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Multiply), GetUnmanagedDll(PythonDLL))); + PyNumber_TrueDivide = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_TrueDivide), GetUnmanagedDll(PythonDLL))); + PyNumber_And = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_And), GetUnmanagedDll(PythonDLL))); + PyNumber_Xor = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Xor), GetUnmanagedDll(PythonDLL))); + PyNumber_Or = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Or), GetUnmanagedDll(PythonDLL))); + PyNumber_Lshift = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Lshift), GetUnmanagedDll(PythonDLL))); + PyNumber_Rshift = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Rshift), GetUnmanagedDll(PythonDLL))); + PyNumber_Power = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Power), GetUnmanagedDll(PythonDLL))); + PyNumber_Remainder = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Remainder), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceAdd = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceAdd), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceSubtract = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceSubtract), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceMultiply = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceMultiply), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceTrueDivide = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceTrueDivide), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceAnd = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceAnd), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceXor = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceXor), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceOr = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceOr), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceLshift = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceLshift), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceRshift = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceRshift), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlacePower = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlacePower), GetUnmanagedDll(PythonDLL))); + PyNumber_InPlaceRemainder = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_InPlaceRemainder), GetUnmanagedDll(PythonDLL))); + PyNumber_Negative = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Negative), GetUnmanagedDll(PythonDLL))); + PyNumber_Positive = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Positive), GetUnmanagedDll(PythonDLL))); + PyNumber_Invert = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyNumber_Invert), GetUnmanagedDll(PythonDLL))); + PySequence_Check = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_Check), GetUnmanagedDll(PythonDLL))); + PySequence_GetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_GetItem), GetUnmanagedDll(PythonDLL))); + PySequence_SetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_SetItem), GetUnmanagedDll(PythonDLL))); + PySequence_DelItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_DelItem), GetUnmanagedDll(PythonDLL))); + PySequence_GetSlice = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_GetSlice), GetUnmanagedDll(PythonDLL))); + PySequence_SetSlice = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_SetSlice), GetUnmanagedDll(PythonDLL))); + PySequence_DelSlice = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_DelSlice), GetUnmanagedDll(PythonDLL))); + _PySequence_Size = GetDelegateForFunctionPointer<_PySequence_SizeDelegate>(GetFunctionByName("PySequence_Size", GetUnmanagedDll(PythonDLL))); + PySequence_Contains = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_Contains), GetUnmanagedDll(PythonDLL))); + PySequence_Concat = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_Concat), GetUnmanagedDll(PythonDLL))); + PySequence_Repeat = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_Repeat), GetUnmanagedDll(PythonDLL))); + PySequence_Index = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_Index), GetUnmanagedDll(PythonDLL))); + _PySequence_Count = GetDelegateForFunctionPointer<_PySequence_CountDelegate>(GetFunctionByName("PySequence_Count", GetUnmanagedDll(PythonDLL))); + PySequence_Tuple = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_Tuple), GetUnmanagedDll(PythonDLL))); + PySequence_List = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySequence_List), GetUnmanagedDll(PythonDLL))); + PyBytes_FromString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBytes_FromString), GetUnmanagedDll(PythonDLL))); + _PyBytes_Size = GetDelegateForFunctionPointer<_PyBytes_SizeDelegate>(GetFunctionByName("PyBytes_Size", GetUnmanagedDll(PythonDLL))); + _PyString_FromStringAndSize = GetDelegateForFunctionPointer<_PyString_FromStringAndSizeDelegate>(GetFunctionByName("PyUnicode_FromStringAndSize", GetUnmanagedDll(PythonDLL))); + PyUnicode_FromStringAndSize = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyUnicode_FromStringAndSize), GetUnmanagedDll(PythonDLL))); + PyUnicode_AsUTF8 = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyUnicode_AsUTF8), GetUnmanagedDll(PythonDLL))); + PyUnicode_FromObject = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyUnicode_FromObject), GetUnmanagedDll(PythonDLL))); + PyUnicode_FromEncodedObject = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyUnicode_FromEncodedObject), GetUnmanagedDll(PythonDLL))); + PyUnicode_FromKindAndData = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyUnicode_FromKindAndData), GetUnmanagedDll(PythonDLL))); + _PyUnicode_GetSize = GetDelegateForFunctionPointer<_PyUnicode_GetSizeDelegate>(GetFunctionByName("PyUnicode_GetSize", GetUnmanagedDll(PythonDLL))); + PyUnicode_AsUnicode = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyUnicode_AsUnicode), GetUnmanagedDll(PythonDLL))); + PyUnicode_FromOrdinal = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyUnicode_FromOrdinal), GetUnmanagedDll(PythonDLL))); + PyDict_New = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_New), GetUnmanagedDll(PythonDLL))); + PyDictProxy_New = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDictProxy_New), GetUnmanagedDll(PythonDLL))); + PyDict_GetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_GetItem), GetUnmanagedDll(PythonDLL))); + PyDict_GetItemString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_GetItemString), GetUnmanagedDll(PythonDLL))); + PyDict_SetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_SetItem), GetUnmanagedDll(PythonDLL))); + PyDict_SetItemString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_SetItemString), GetUnmanagedDll(PythonDLL))); + PyDict_DelItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_DelItem), GetUnmanagedDll(PythonDLL))); + PyDict_DelItemString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_DelItemString), GetUnmanagedDll(PythonDLL))); + PyMapping_HasKey = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyMapping_HasKey), GetUnmanagedDll(PythonDLL))); + PyDict_Keys = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_Keys), GetUnmanagedDll(PythonDLL))); + PyDict_Values = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_Values), GetUnmanagedDll(PythonDLL))); + PyDict_Items = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_Items), GetUnmanagedDll(PythonDLL))); + PyDict_Copy = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_Copy), GetUnmanagedDll(PythonDLL))); + PyDict_Update = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_Update), GetUnmanagedDll(PythonDLL))); + PyDict_Clear = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyDict_Clear), GetUnmanagedDll(PythonDLL))); + _PyDict_Size = GetDelegateForFunctionPointer<_PyDict_SizeDelegate>(GetFunctionByName("PyDict_Size", GetUnmanagedDll(PythonDLL))); + PyList_New = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_New), GetUnmanagedDll(PythonDLL))); + PyList_AsTuple = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_AsTuple), GetUnmanagedDll(PythonDLL))); + PyList_GetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_GetItem), GetUnmanagedDll(PythonDLL))); + PyList_SetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_SetItem), GetUnmanagedDll(PythonDLL))); + PyList_Insert = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_Insert), GetUnmanagedDll(PythonDLL))); + PyList_Append = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_Append), GetUnmanagedDll(PythonDLL))); + PyList_Reverse = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_Reverse), GetUnmanagedDll(PythonDLL))); + PyList_Sort = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_Sort), GetUnmanagedDll(PythonDLL))); + PyList_GetSlice = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_GetSlice), GetUnmanagedDll(PythonDLL))); + PyList_SetSlice = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyList_SetSlice), GetUnmanagedDll(PythonDLL))); + _PyList_Size = GetDelegateForFunctionPointer<_PyList_SizeDelegate>(GetFunctionByName("PyList_Size", GetUnmanagedDll(PythonDLL))); + PyTuple_New = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyTuple_New), GetUnmanagedDll(PythonDLL))); + PyTuple_GetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyTuple_GetItem), GetUnmanagedDll(PythonDLL))); + PyTuple_SetItem = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyTuple_SetItem), GetUnmanagedDll(PythonDLL))); + PyTuple_GetSlice = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyTuple_GetSlice), GetUnmanagedDll(PythonDLL))); + _PyTuple_Size = GetDelegateForFunctionPointer<_PyTuple_SizeDelegate>(GetFunctionByName("PyTuple_Size", GetUnmanagedDll(PythonDLL))); + PyIter_Next = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyIter_Next), GetUnmanagedDll(PythonDLL))); + PyModule_New = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyModule_New), GetUnmanagedDll(PythonDLL))); + PyModule_GetName = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyModule_GetName), GetUnmanagedDll(PythonDLL))); + PyModule_GetDict = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyModule_GetDict), GetUnmanagedDll(PythonDLL))); + PyModule_GetFilename = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyModule_GetFilename), GetUnmanagedDll(PythonDLL))); + PyModule_Create2 = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyModule_Create2), GetUnmanagedDll(PythonDLL))); + PyImport_Import = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyImport_Import), GetUnmanagedDll(PythonDLL))); + PyImport_ImportModule = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyImport_ImportModule), GetUnmanagedDll(PythonDLL))); + PyImport_ReloadModule = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyImport_ReloadModule), GetUnmanagedDll(PythonDLL))); + PyImport_AddModule = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyImport_AddModule), GetUnmanagedDll(PythonDLL))); + PyImport_GetModuleDict = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyImport_GetModuleDict), GetUnmanagedDll(PythonDLL))); + PySys_SetArgvEx = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySys_SetArgvEx), GetUnmanagedDll(PythonDLL))); + PySys_GetObject = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySys_GetObject), GetUnmanagedDll(PythonDLL))); + PySys_SetObject = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PySys_SetObject), GetUnmanagedDll(PythonDLL))); + PyType_Modified = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyType_Modified), GetUnmanagedDll(PythonDLL))); + PyType_IsSubtype = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyType_IsSubtype), GetUnmanagedDll(PythonDLL))); + PyType_GenericNew = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyType_GenericNew), GetUnmanagedDll(PythonDLL))); + PyType_GenericAlloc = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyType_GenericAlloc), GetUnmanagedDll(PythonDLL))); + PyType_Ready = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyType_Ready), GetUnmanagedDll(PythonDLL))); + _PyType_Lookup = GetDelegateForFunctionPointer<_PyType_LookupDelegate>(GetFunctionByName(nameof(_PyType_Lookup), GetUnmanagedDll(PythonDLL))); + PyObject_GenericGetAttr = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GenericGetAttr), GetUnmanagedDll(PythonDLL))); + PyObject_GenericSetAttr = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GenericSetAttr), GetUnmanagedDll(PythonDLL))); + _PyObject_GetDictPtr = GetDelegateForFunctionPointer<_PyObject_GetDictPtrDelegate>(GetFunctionByName(nameof(_PyObject_GetDictPtr), GetUnmanagedDll(PythonDLL))); + PyObject_GC_Del = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GC_Del), GetUnmanagedDll(PythonDLL))); + PyObject_GC_Track = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GC_Track), GetUnmanagedDll(PythonDLL))); + PyObject_GC_UnTrack = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GC_UnTrack), GetUnmanagedDll(PythonDLL))); + PyMem_Malloc = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyMem_Malloc), GetUnmanagedDll(PythonDLL))); + PyMem_Realloc = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyMem_Realloc), GetUnmanagedDll(PythonDLL))); + PyMem_Free = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyMem_Free), GetUnmanagedDll(PythonDLL))); + PyErr_SetString = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_SetString), GetUnmanagedDll(PythonDLL))); + PyErr_SetObject = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_SetObject), GetUnmanagedDll(PythonDLL))); + PyErr_SetFromErrno = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_SetFromErrno), GetUnmanagedDll(PythonDLL))); + PyErr_SetNone = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_SetNone), GetUnmanagedDll(PythonDLL))); + PyErr_ExceptionMatches = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_ExceptionMatches), GetUnmanagedDll(PythonDLL))); + PyErr_GivenExceptionMatches = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_GivenExceptionMatches), GetUnmanagedDll(PythonDLL))); + PyErr_NormalizeException = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_NormalizeException), GetUnmanagedDll(PythonDLL))); + PyErr_Occurred = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_Occurred), GetUnmanagedDll(PythonDLL))); + PyErr_Fetch = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_Fetch), GetUnmanagedDll(PythonDLL))); + PyErr_Restore = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_Restore), GetUnmanagedDll(PythonDLL))); + PyErr_Clear = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_Clear), GetUnmanagedDll(PythonDLL))); + PyErr_Print = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyErr_Print), GetUnmanagedDll(PythonDLL))); + PyCell_Get = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyCell_Get), GetUnmanagedDll(PythonDLL))); + PyCell_Set = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyCell_Set), GetUnmanagedDll(PythonDLL))); + PyMethod_Self = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyMethod_Self), GetUnmanagedDll(PythonDLL))); + PyMethod_Function = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyMethod_Function), GetUnmanagedDll(PythonDLL))); + PyMethod_New = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyMethod_New), GetUnmanagedDll(PythonDLL))); + Py_AddPendingCall = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_AddPendingCall), GetUnmanagedDll(PythonDLL))); + Py_MakePendingCalls = GetDelegateForFunctionPointer(GetFunctionByName(nameof(Py_MakePendingCalls), GetUnmanagedDll(PythonDLL))); + PyObject_GetBuffer = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyObject_GetBuffer), GetUnmanagedDll(PythonDLL))); + PyBuffer_Release = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_Release), GetUnmanagedDll(PythonDLL))); + if (Runtime.PythonVersion >= new Version(3,9)) + PyBuffer_SizeFromFormat = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_SizeFromFormat), GetUnmanagedDll(PythonDLL))); + PyBuffer_IsContiguous = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_IsContiguous), GetUnmanagedDll(PythonDLL))); + PyBuffer_GetPointer = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_GetPointer), GetUnmanagedDll(PythonDLL))); + PyBuffer_FromContiguous = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_FromContiguous), GetUnmanagedDll(PythonDLL))); + PyBuffer_ToContiguous = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_ToContiguous), GetUnmanagedDll(PythonDLL))); + PyBuffer_FillContiguousStrides = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_FillContiguousStrides), GetUnmanagedDll(PythonDLL))); + PyBuffer_FillInfo = GetDelegateForFunctionPointer(GetFunctionByName(nameof(PyBuffer_FillInfo), GetUnmanagedDll(PythonDLL))); + } - class PyReferenceCollection - { - private List> _actions = new List>(); + static T GetDelegateForFunctionPointer(IntPtr functionPointer) { +#if NETFX + return (T)(object)Marshal.GetDelegateForFunctionPointer(functionPointer, typeof(T)); +#else + return Marshal.GetDelegateForFunctionPointer(functionPointer); +#endif + } - /// - /// Record obj's address to release the obj in the future, - /// obj must alive before calling Release. - /// - public void Add(IntPtr ob, Action onRelease) - { - _actions.Add(new KeyValuePair(ob, onRelease)); - } + static global::System.IntPtr GetUnmanagedDll(string libraryName) { + if (string.IsNullOrEmpty(Path.GetExtension(libraryName))) { + libraryName = + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? libraryName + ".dll" + : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? $"lib{libraryName}.so" + : RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? $"lib{libraryName}.dylib" + : NativeMethods.Throw(new PlatformNotSupportedException()); + } + IntPtr handle = NativeMethods.LoadLibrary(libraryName); + if (handle == IntPtr.Zero) + throw new FileLoadException("Could not load " + libraryName); + return handle; + } - public void Release() - { - foreach (var item in _actions) - { - Runtime.XDecref(item.Key); - item.Value?.Invoke(); + static global::System.IntPtr GetFunctionByName(string functionName, global::System.IntPtr libraryHandle) { + IntPtr functionPointer = NativeMethods.GetProcAddress(libraryHandle, functionName); + if (functionPointer == IntPtr.Zero) + throw new EntryPointNotFoundException($"Function {functionName} was not found"); + return functionPointer; } - _actions.Clear(); - } - } + + internal static Py_IncRefDelegate Py_IncRef { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_IncRefDelegate(IntPtr ob); + + internal static Py_DecRefDelegate Py_DecRef { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_DecRefDelegate(IntPtr ob); + + internal static Py_InitializeDelegate Py_Initialize { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_InitializeDelegate(); + + internal static Py_InitializeExDelegate Py_InitializeEx { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_InitializeExDelegate(int initsigs); + + internal static Py_IsInitializedDelegate Py_IsInitialized { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int Py_IsInitializedDelegate(); + + internal static Py_FinalizeDelegate Py_Finalize { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_FinalizeDelegate(); + + internal static Py_NewInterpreterDelegate Py_NewInterpreter { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_NewInterpreterDelegate(); + + internal static Py_EndInterpreterDelegate Py_EndInterpreter { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_EndInterpreterDelegate(IntPtr threadState); + + internal static PyThreadState_NewDelegate PyThreadState_New { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyThreadState_NewDelegate(IntPtr istate); + + internal static PyThreadState_GetDelegate PyThreadState_Get { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyThreadState_GetDelegate(); + + internal static PyThread_get_key_valueDelegate PyThread_get_key_value { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyThread_get_key_valueDelegate(IntPtr key); + + internal static PyThread_get_thread_identDelegate PyThread_get_thread_ident { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyThread_get_thread_identDelegate(); + + internal static PyThread_set_key_valueDelegate PyThread_set_key_value { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyThread_set_key_valueDelegate(IntPtr key, IntPtr value); + + internal static PyThreadState_SwapDelegate PyThreadState_Swap { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyThreadState_SwapDelegate(IntPtr key); + + internal static PyGILState_EnsureDelegate PyGILState_Ensure { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyGILState_EnsureDelegate(); + + internal static PyGILState_ReleaseDelegate PyGILState_Release { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyGILState_ReleaseDelegate(IntPtr gs); + + internal static PyGILState_GetThisThreadStateDelegate PyGILState_GetThisThreadState { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyGILState_GetThisThreadStateDelegate(); + + internal static PyGILState_CheckDelegate PyGILState_Check { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyGILState_CheckDelegate(); + + internal static Py_MainDelegate Py_Main { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int Py_MainDelegate( + int argc, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv + ); + + internal static PyEval_InitThreadsDelegate PyEval_InitThreads { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyEval_InitThreadsDelegate(); + + internal static PyEval_ThreadsInitializedDelegate PyEval_ThreadsInitialized { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyEval_ThreadsInitializedDelegate(); + + internal static PyEval_AcquireLockDelegate PyEval_AcquireLock { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyEval_AcquireLockDelegate(); + + internal static PyEval_ReleaseLockDelegate PyEval_ReleaseLock { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyEval_ReleaseLockDelegate(); + + internal static PyEval_AcquireThreadDelegate PyEval_AcquireThread { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyEval_AcquireThreadDelegate(IntPtr tstate); + + internal static PyEval_ReleaseThreadDelegate PyEval_ReleaseThread { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyEval_ReleaseThreadDelegate(IntPtr tstate); + + internal static PyEval_SaveThreadDelegate PyEval_SaveThread { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyEval_SaveThreadDelegate(); + + internal static PyEval_RestoreThreadDelegate PyEval_RestoreThread { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyEval_RestoreThreadDelegate(IntPtr tstate); + + internal static PyEval_GetBuiltinsDelegate PyEval_GetBuiltins { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate BorrowedReference PyEval_GetBuiltinsDelegate(); + + internal static PyEval_GetGlobalsDelegate PyEval_GetGlobals { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyEval_GetGlobalsDelegate(); + + internal static PyEval_GetLocalsDelegate PyEval_GetLocals { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyEval_GetLocalsDelegate(); + + internal static Py_GetProgramNameDelegate Py_GetProgramName { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetProgramNameDelegate(); + + internal static Py_SetProgramNameDelegate Py_SetProgramName { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_SetProgramNameDelegate(IntPtr name); + + internal static Py_GetPythonHomeDelegate Py_GetPythonHome { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetPythonHomeDelegate(); + + internal static Py_SetPythonHomeDelegate Py_SetPythonHome { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_SetPythonHomeDelegate(IntPtr home); + + internal static Py_GetPathDelegate Py_GetPath { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetPathDelegate(); + + internal static Py_SetPathDelegate Py_SetPath { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void Py_SetPathDelegate(IntPtr home); + + internal static Py_GetVersionDelegate Py_GetVersion { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetVersionDelegate(); + + internal static Py_GetPlatformDelegate Py_GetPlatform { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetPlatformDelegate(); + + internal static Py_GetCopyrightDelegate Py_GetCopyright { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetCopyrightDelegate(); + + internal static Py_GetCompilerDelegate Py_GetCompiler { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetCompilerDelegate(); + + internal static Py_GetBuildInfoDelegate Py_GetBuildInfo { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_GetBuildInfoDelegate(); + + internal static PyRun_SimpleStringDelegate PyRun_SimpleString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyRun_SimpleStringDelegate(string code); + + internal static PyRun_StringDelegate PyRun_String { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate NewReference PyRun_StringDelegate([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string code, IntPtr st, IntPtr globals, IntPtr locals); + + internal static PyEval_EvalCodeDelegate PyEval_EvalCode { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyEval_EvalCodeDelegate(IntPtr co, IntPtr globals, IntPtr locals); + + internal static Py_CompileStringDelegate Py_CompileString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_CompileStringDelegate(string code, string file, IntPtr tok); + + internal static Py_CompileStringExFlagsDelegate Py_CompileStringExFlags { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr Py_CompileStringExFlagsDelegate(string str, string file, int start, IntPtr flags, int optimize); + + internal static PyImport_ExecCodeModuleDelegate PyImport_ExecCodeModule { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyImport_ExecCodeModuleDelegate(string name, IntPtr code); + + internal static PyCFunction_NewExDelegate PyCFunction_NewEx { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyCFunction_NewExDelegate(IntPtr ml, IntPtr self, IntPtr mod); + + internal static PyCFunction_CallDelegate PyCFunction_Call { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyCFunction_CallDelegate(IntPtr func, IntPtr args, IntPtr kw); + + internal static PyObject_HasAttrStringDelegate PyObject_HasAttrString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_HasAttrStringDelegate(IntPtr pointer, string name); + + internal static PyObject_GetAttrStringDelegate PyObject_GetAttrString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_GetAttrStringDelegate(IntPtr pointer, string name); + + internal static PyObject_SetAttrStringDelegate PyObject_SetAttrString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_SetAttrStringDelegate(IntPtr pointer, string name, IntPtr value); + + internal static PyObject_HasAttrDelegate PyObject_HasAttr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_HasAttrDelegate(IntPtr pointer, IntPtr name); + + internal static PyObject_GetAttrDelegate PyObject_GetAttr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_GetAttrDelegate(IntPtr pointer, IntPtr name); + + internal static PyObject_SetAttrDelegate PyObject_SetAttr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_SetAttrDelegate(IntPtr pointer, IntPtr name, IntPtr value); + + internal static PyObject_GetItemDelegate PyObject_GetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate NewReference PyObject_GetItemDelegate(BorrowedReference pointer, BorrowedReference key); + + internal static PyObject_SetItemDelegate PyObject_SetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_SetItemDelegate(IntPtr pointer, IntPtr key, IntPtr value); + + internal static PyObject_DelItemDelegate PyObject_DelItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_DelItemDelegate(IntPtr pointer, IntPtr key); + + internal static PyObject_GetIterDelegate PyObject_GetIter { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate NewReference PyObject_GetIterDelegate(BorrowedReference op); + + internal static PyObject_CallDelegate PyObject_Call { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_CallDelegate(IntPtr pointer, IntPtr args, IntPtr kw); + + internal static PyObject_CallObjectDelegate PyObject_CallObject { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_CallObjectDelegate(IntPtr pointer, IntPtr args); + + internal static PyObject_RichCompareBoolDelegate PyObject_RichCompareBool { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_RichCompareBoolDelegate(IntPtr value1, IntPtr value2, int opid); + + internal static PyObject_IsInstanceDelegate PyObject_IsInstance { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_IsInstanceDelegate(IntPtr ob, IntPtr type); + + internal static PyObject_IsSubclassDelegate PyObject_IsSubclass { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_IsSubclassDelegate(IntPtr ob, IntPtr type); + + internal static PyCallable_CheckDelegate PyCallable_Check { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyCallable_CheckDelegate(IntPtr pointer); + + internal static PyObject_IsTrueDelegate PyObject_IsTrue { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_IsTrueDelegate(IntPtr pointer); + + internal static PyObject_NotDelegate PyObject_Not { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_NotDelegate(IntPtr pointer); + + internal static _PyObject_SizeDelegate _PyObject_Size { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyObject_SizeDelegate(IntPtr pointer); + + internal static PyObject_HashDelegate PyObject_Hash { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_HashDelegate(IntPtr op); + + internal static PyObject_ReprDelegate PyObject_Repr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_ReprDelegate(IntPtr pointer); + + internal static PyObject_StrDelegate PyObject_Str { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_StrDelegate(IntPtr pointer); + + internal static PyObject_UnicodeDelegate PyObject_Unicode { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_UnicodeDelegate(IntPtr pointer); + + internal static PyObject_DirDelegate PyObject_Dir { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_DirDelegate(IntPtr pointer); + + internal static PyNumber_IntDelegate PyNumber_Int { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_IntDelegate(IntPtr ob); + + internal static PyNumber_LongDelegate PyNumber_Long { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_LongDelegate(IntPtr ob); + + internal static PyNumber_FloatDelegate PyNumber_Float { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_FloatDelegate(IntPtr ob); + + internal static PyNumber_CheckDelegate PyNumber_Check { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate bool PyNumber_CheckDelegate(IntPtr ob); + + internal static PyInt_FromLongDelegate PyInt_FromLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyInt_FromLongDelegate(IntPtr value); + + internal static PyInt_AsLongDelegate PyInt_AsLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyInt_AsLongDelegate(IntPtr value); + + internal static PyInt_FromStringDelegate PyInt_FromString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyInt_FromStringDelegate(string value, IntPtr end, int radix); + + internal static PyLong_FromLongDelegate PyLong_FromLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromLongDelegate(long value); + + internal static PyLong_FromUnsignedLong32Delegate PyLong_FromUnsignedLong32 { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromUnsignedLong32Delegate(uint value); + + internal static PyLong_FromUnsignedLong64Delegate PyLong_FromUnsignedLong64 { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromUnsignedLong64Delegate(ulong value); + + internal static PyLong_FromUnsignedLongDelegate PyLong_FromUnsignedLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromUnsignedLongDelegate(uint value); + + internal static PyLong_FromDoubleDelegate PyLong_FromDouble { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromDoubleDelegate(double value); + + internal static PyLong_FromLongLongDelegate PyLong_FromLongLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromLongLongDelegate(long value); + + internal static PyLong_FromUnsignedLongLongDelegate PyLong_FromUnsignedLongLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromUnsignedLongLongDelegate(ulong value); + + internal static PyLong_FromStringDelegate PyLong_FromString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyLong_FromStringDelegate(string value, IntPtr end, int radix); + + internal static PyLong_AsLongDelegate PyLong_AsLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyLong_AsLongDelegate(IntPtr value); + + internal static PyLong_AsUnsignedLong32Delegate PyLong_AsUnsignedLong32 { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate uint PyLong_AsUnsignedLong32Delegate(IntPtr value); + + internal static PyLong_AsUnsignedLong64Delegate PyLong_AsUnsignedLong64 { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate ulong PyLong_AsUnsignedLong64Delegate(IntPtr value); + + internal static PyLong_AsUnsignedLongDelegate PyLong_AsUnsignedLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate uint PyLong_AsUnsignedLongDelegate(IntPtr value); + + internal static PyLong_AsLongLongDelegate PyLong_AsLongLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate long PyLong_AsLongLongDelegate(IntPtr value); + + internal static PyLong_AsUnsignedLongLongDelegate PyLong_AsUnsignedLongLong { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate ulong PyLong_AsUnsignedLongLongDelegate(IntPtr value); + + internal static PyFloat_FromDoubleDelegate PyFloat_FromDouble { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyFloat_FromDoubleDelegate(double value); + + internal static PyFloat_FromStringDelegate PyFloat_FromString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyFloat_FromStringDelegate(IntPtr value, IntPtr junk); + + internal static PyFloat_AsDoubleDelegate PyFloat_AsDouble { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate double PyFloat_AsDoubleDelegate(IntPtr ob); + + internal static PyNumber_AddDelegate PyNumber_Add { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_AddDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_SubtractDelegate PyNumber_Subtract { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_SubtractDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_MultiplyDelegate PyNumber_Multiply { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_MultiplyDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_TrueDivideDelegate PyNumber_TrueDivide { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_TrueDivideDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_AndDelegate PyNumber_And { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_AndDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_XorDelegate PyNumber_Xor { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_XorDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_OrDelegate PyNumber_Or { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_OrDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_LshiftDelegate PyNumber_Lshift { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_LshiftDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_RshiftDelegate PyNumber_Rshift { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_RshiftDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_PowerDelegate PyNumber_Power { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_PowerDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_RemainderDelegate PyNumber_Remainder { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_RemainderDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceAddDelegate PyNumber_InPlaceAdd { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceAddDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceSubtractDelegate PyNumber_InPlaceSubtract { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceSubtractDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceMultiplyDelegate PyNumber_InPlaceMultiply { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceMultiplyDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceTrueDivideDelegate PyNumber_InPlaceTrueDivide { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceTrueDivideDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceAndDelegate PyNumber_InPlaceAnd { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceAndDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceXorDelegate PyNumber_InPlaceXor { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceXorDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceOrDelegate PyNumber_InPlaceOr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceOrDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceLshiftDelegate PyNumber_InPlaceLshift { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceLshiftDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceRshiftDelegate PyNumber_InPlaceRshift { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceRshiftDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlacePowerDelegate PyNumber_InPlacePower { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlacePowerDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_InPlaceRemainderDelegate PyNumber_InPlaceRemainder { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InPlaceRemainderDelegate(IntPtr o1, IntPtr o2); + + internal static PyNumber_NegativeDelegate PyNumber_Negative { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_NegativeDelegate(IntPtr o1); + + internal static PyNumber_PositiveDelegate PyNumber_Positive { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_PositiveDelegate(IntPtr o1); + + internal static PyNumber_InvertDelegate PyNumber_Invert { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyNumber_InvertDelegate(IntPtr o1); + + internal static PySequence_CheckDelegate PySequence_Check { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate bool PySequence_CheckDelegate(IntPtr pointer); + + internal static PySequence_GetItemDelegate PySequence_GetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PySequence_GetItemDelegate(IntPtr pointer, IntPtr index); + + internal static PySequence_SetItemDelegate PySequence_SetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PySequence_SetItemDelegate(IntPtr pointer, IntPtr index, IntPtr value); + + internal static PySequence_DelItemDelegate PySequence_DelItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PySequence_DelItemDelegate(IntPtr pointer, IntPtr index); + + internal static PySequence_GetSliceDelegate PySequence_GetSlice { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PySequence_GetSliceDelegate(IntPtr pointer, IntPtr i1, IntPtr i2); + + internal static PySequence_SetSliceDelegate PySequence_SetSlice { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PySequence_SetSliceDelegate(IntPtr pointer, IntPtr i1, IntPtr i2, IntPtr v); + + internal static PySequence_DelSliceDelegate PySequence_DelSlice { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PySequence_DelSliceDelegate(IntPtr pointer, IntPtr i1, IntPtr i2); + + internal static _PySequence_SizeDelegate _PySequence_Size { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PySequence_SizeDelegate(IntPtr pointer); + + internal static PySequence_ContainsDelegate PySequence_Contains { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PySequence_ContainsDelegate(IntPtr pointer, IntPtr item); + + internal static PySequence_ConcatDelegate PySequence_Concat { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PySequence_ConcatDelegate(IntPtr pointer, IntPtr other); + + internal static PySequence_RepeatDelegate PySequence_Repeat { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PySequence_RepeatDelegate(IntPtr pointer, IntPtr count); + + internal static PySequence_IndexDelegate PySequence_Index { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PySequence_IndexDelegate(IntPtr pointer, IntPtr item); + + internal static _PySequence_CountDelegate _PySequence_Count { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PySequence_CountDelegate(IntPtr pointer, IntPtr value); + + internal static PySequence_TupleDelegate PySequence_Tuple { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PySequence_TupleDelegate(IntPtr pointer); + + internal static PySequence_ListDelegate PySequence_List { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PySequence_ListDelegate(IntPtr pointer); + + internal static PyBytes_FromStringDelegate PyBytes_FromString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyBytes_FromStringDelegate(string op); + + internal static _PyBytes_SizeDelegate _PyBytes_Size { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyBytes_SizeDelegate(IntPtr op); + + internal static _PyString_FromStringAndSizeDelegate _PyString_FromStringAndSize { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyString_FromStringAndSizeDelegate( + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string value, + IntPtr size + ); + + internal static PyUnicode_FromStringAndSizeDelegate PyUnicode_FromStringAndSize { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyUnicode_FromStringAndSizeDelegate(IntPtr value, IntPtr size); + + internal static PyUnicode_AsUTF8Delegate PyUnicode_AsUTF8 { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyUnicode_AsUTF8Delegate(IntPtr unicode); + + internal static PyUnicode_FromObjectDelegate PyUnicode_FromObject { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyUnicode_FromObjectDelegate(IntPtr ob); + + internal static PyUnicode_FromEncodedObjectDelegate PyUnicode_FromEncodedObject { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyUnicode_FromEncodedObjectDelegate(IntPtr ob, IntPtr enc, IntPtr err); + + internal static PyUnicode_FromKindAndDataDelegate PyUnicode_FromKindAndData { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyUnicode_FromKindAndDataDelegate( + int kind, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s, + IntPtr size + ); + + internal static _PyUnicode_GetSizeDelegate _PyUnicode_GetSize { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyUnicode_GetSizeDelegate(IntPtr ob); + + internal static PyUnicode_AsUnicodeDelegate PyUnicode_AsUnicode { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyUnicode_AsUnicodeDelegate(IntPtr ob); + + internal static PyUnicode_FromOrdinalDelegate PyUnicode_FromOrdinal { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyUnicode_FromOrdinalDelegate(int c); + + internal static PyDict_NewDelegate PyDict_New { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyDict_NewDelegate(); + + internal static PyDictProxy_NewDelegate PyDictProxy_New { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyDictProxy_NewDelegate(IntPtr dict); + + internal static PyDict_GetItemDelegate PyDict_GetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyDict_GetItemDelegate(IntPtr pointer, IntPtr key); + + internal static PyDict_GetItemStringDelegate PyDict_GetItemString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyDict_GetItemStringDelegate(IntPtr pointer, string key); + + internal static PyDict_SetItemDelegate PyDict_SetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyDict_SetItemDelegate(BorrowedReference pointer, BorrowedReference key, BorrowedReference value); + + internal static PyDict_SetItemStringDelegate PyDict_SetItemString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyDict_SetItemStringDelegate(IntPtr pointer, string key, IntPtr value); + + internal static PyDict_DelItemDelegate PyDict_DelItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyDict_DelItemDelegate(IntPtr pointer, IntPtr key); + + internal static PyDict_DelItemStringDelegate PyDict_DelItemString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyDict_DelItemStringDelegate(IntPtr pointer, string key); + + internal static PyMapping_HasKeyDelegate PyMapping_HasKey { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyMapping_HasKeyDelegate(IntPtr pointer, IntPtr key); + + internal static PyDict_KeysDelegate PyDict_Keys { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyDict_KeysDelegate(IntPtr pointer); + + internal static PyDict_ValuesDelegate PyDict_Values { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyDict_ValuesDelegate(IntPtr pointer); + + internal static PyDict_ItemsDelegate PyDict_Items { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate NewReference PyDict_ItemsDelegate(IntPtr pointer); + + internal static PyDict_CopyDelegate PyDict_Copy { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyDict_CopyDelegate(IntPtr pointer); + + internal static PyDict_UpdateDelegate PyDict_Update { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyDict_UpdateDelegate(IntPtr pointer, IntPtr other); + + internal static PyDict_ClearDelegate PyDict_Clear { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyDict_ClearDelegate(IntPtr pointer); + + internal static _PyDict_SizeDelegate _PyDict_Size { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyDict_SizeDelegate(IntPtr pointer); + + internal static PyList_NewDelegate PyList_New { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyList_NewDelegate(IntPtr size); + + internal static PyList_AsTupleDelegate PyList_AsTuple { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyList_AsTupleDelegate(IntPtr pointer); + + internal static PyList_GetItemDelegate PyList_GetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate BorrowedReference PyList_GetItemDelegate(IntPtr pointer, IntPtr index); + + internal static PyList_SetItemDelegate PyList_SetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyList_SetItemDelegate(IntPtr pointer, IntPtr index, IntPtr value); + + internal static PyList_InsertDelegate PyList_Insert { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyList_InsertDelegate(BorrowedReference pointer, IntPtr index, IntPtr value); + + internal static PyList_AppendDelegate PyList_Append { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyList_AppendDelegate(BorrowedReference pointer, IntPtr value); + + internal static PyList_ReverseDelegate PyList_Reverse { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyList_ReverseDelegate(BorrowedReference pointer); + + internal static PyList_SortDelegate PyList_Sort { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyList_SortDelegate(BorrowedReference pointer); + + internal static PyList_GetSliceDelegate PyList_GetSlice { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyList_GetSliceDelegate(IntPtr pointer, IntPtr start, IntPtr end); + + internal static PyList_SetSliceDelegate PyList_SetSlice { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyList_SetSliceDelegate(IntPtr pointer, IntPtr start, IntPtr end, IntPtr value); + + internal static _PyList_SizeDelegate _PyList_Size { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyList_SizeDelegate(IntPtr pointer); + + internal static PyTuple_NewDelegate PyTuple_New { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyTuple_NewDelegate(IntPtr size); + + internal static PyTuple_GetItemDelegate PyTuple_GetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyTuple_GetItemDelegate(IntPtr pointer, IntPtr index); + + internal static PyTuple_SetItemDelegate PyTuple_SetItem { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyTuple_SetItemDelegate(IntPtr pointer, IntPtr index, IntPtr value); + + internal static PyTuple_GetSliceDelegate PyTuple_GetSlice { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyTuple_GetSliceDelegate(IntPtr pointer, IntPtr start, IntPtr end); + + internal static _PyTuple_SizeDelegate _PyTuple_Size { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyTuple_SizeDelegate(IntPtr pointer); + + internal static PyIter_NextDelegate PyIter_Next { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate NewReference PyIter_NextDelegate(BorrowedReference pointer); + + internal static PyModule_NewDelegate PyModule_New { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyModule_NewDelegate(string name); + + internal static PyModule_GetNameDelegate PyModule_GetName { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate string PyModule_GetNameDelegate(IntPtr module); + + internal static PyModule_GetDictDelegate PyModule_GetDict { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyModule_GetDictDelegate(IntPtr module); + + internal static PyModule_GetFilenameDelegate PyModule_GetFilename { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate string PyModule_GetFilenameDelegate(IntPtr module); + + internal static PyModule_Create2Delegate PyModule_Create2 { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyModule_Create2Delegate(IntPtr module, int apiver); + + internal static PyImport_ImportDelegate PyImport_Import { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyImport_ImportDelegate(IntPtr name); + + internal static PyImport_ImportModuleDelegate PyImport_ImportModule { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyImport_ImportModuleDelegate(string name); + + internal static PyImport_ReloadModuleDelegate PyImport_ReloadModule { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyImport_ReloadModuleDelegate(IntPtr module); + + internal static PyImport_AddModuleDelegate PyImport_AddModule { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate BorrowedReference PyImport_AddModuleDelegate(string name); + + internal static PyImport_GetModuleDictDelegate PyImport_GetModuleDict { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyImport_GetModuleDictDelegate(); + + internal static PySys_SetArgvExDelegate PySys_SetArgvEx { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PySys_SetArgvExDelegate( + int argc, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv, + int updatepath + ); + + internal static PySys_GetObjectDelegate PySys_GetObject { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PySys_GetObjectDelegate(string name); + + internal static PySys_SetObjectDelegate PySys_SetObject { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PySys_SetObjectDelegate(string name, IntPtr ob); + + internal static PyType_ModifiedDelegate PyType_Modified { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyType_ModifiedDelegate(IntPtr type); + + internal static PyType_IsSubtypeDelegate PyType_IsSubtype { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate bool PyType_IsSubtypeDelegate(IntPtr t1, IntPtr t2); + + internal static PyType_GenericNewDelegate PyType_GenericNew { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyType_GenericNewDelegate(IntPtr type, IntPtr args, IntPtr kw); + + internal static PyType_GenericAllocDelegate PyType_GenericAlloc { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyType_GenericAllocDelegate(IntPtr type, IntPtr n); + + internal static PyType_ReadyDelegate PyType_Ready { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyType_ReadyDelegate(IntPtr type); + + internal static _PyType_LookupDelegate _PyType_Lookup { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyType_LookupDelegate(IntPtr type, IntPtr name); + + internal static PyObject_GenericGetAttrDelegate PyObject_GenericGetAttr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyObject_GenericGetAttrDelegate(IntPtr obj, IntPtr name); + + internal static PyObject_GenericSetAttrDelegate PyObject_GenericSetAttr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_GenericSetAttrDelegate(IntPtr obj, IntPtr name, IntPtr value); + + internal static _PyObject_GetDictPtrDelegate _PyObject_GetDictPtr { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr _PyObject_GetDictPtrDelegate(IntPtr obj); + + internal static PyObject_GC_DelDelegate PyObject_GC_Del { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyObject_GC_DelDelegate(IntPtr tp); + + internal static PyObject_GC_TrackDelegate PyObject_GC_Track { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyObject_GC_TrackDelegate(IntPtr tp); + + internal static PyObject_GC_UnTrackDelegate PyObject_GC_UnTrack { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyObject_GC_UnTrackDelegate(IntPtr tp); + + internal static PyMem_MallocDelegate PyMem_Malloc { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyMem_MallocDelegate(IntPtr size); + + internal static PyMem_ReallocDelegate PyMem_Realloc { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyMem_ReallocDelegate(IntPtr ptr, IntPtr size); + + internal static PyMem_FreeDelegate PyMem_Free { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyMem_FreeDelegate(IntPtr ptr); + + internal static PyErr_SetStringDelegate PyErr_SetString { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_SetStringDelegate(IntPtr ob, string message); + + internal static PyErr_SetObjectDelegate PyErr_SetObject { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_SetObjectDelegate(IntPtr ob, IntPtr message); + + internal static PyErr_SetFromErrnoDelegate PyErr_SetFromErrno { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyErr_SetFromErrnoDelegate(IntPtr ob); + + internal static PyErr_SetNoneDelegate PyErr_SetNone { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_SetNoneDelegate(IntPtr ob); + + internal static PyErr_ExceptionMatchesDelegate PyErr_ExceptionMatches { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyErr_ExceptionMatchesDelegate(IntPtr exception); + + internal static PyErr_GivenExceptionMatchesDelegate PyErr_GivenExceptionMatches { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyErr_GivenExceptionMatchesDelegate(IntPtr ob, IntPtr val); + + internal static PyErr_NormalizeExceptionDelegate PyErr_NormalizeException { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_NormalizeExceptionDelegate(IntPtr ob, IntPtr val, IntPtr tb); + + internal static PyErr_OccurredDelegate PyErr_Occurred { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyErr_OccurredDelegate(); + + internal static PyErr_FetchDelegate PyErr_Fetch { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_FetchDelegate(out NewReference ob, out NewReference val, out NewReference tb); + + internal static PyErr_RestoreDelegate PyErr_Restore { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_RestoreDelegate(IntPtr ob, IntPtr val, IntPtr tb); + + internal static PyErr_ClearDelegate PyErr_Clear { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_ClearDelegate(); + + internal static PyErr_PrintDelegate PyErr_Print { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyErr_PrintDelegate(); + + //==================================================================== + // Cell API + //==================================================================== + internal static PyCell_GetDelegate PyCell_Get { get; } + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate NewReference PyCell_GetDelegate(BorrowedReference cell); + + internal static PyCell_SetDelegate PyCell_Set { get; } + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyCell_SetDelegate(BorrowedReference cell, BorrowedReference value); + + internal static PyMethod_SelfDelegate PyMethod_Self { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyMethod_SelfDelegate(IntPtr ob); + + internal static PyMethod_FunctionDelegate PyMethod_Function { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyMethod_FunctionDelegate(IntPtr ob); + + internal static PyMethod_NewDelegate PyMethod_New { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyMethod_NewDelegate(IntPtr func, IntPtr self); + + internal static Py_AddPendingCallDelegate Py_AddPendingCall { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int Py_AddPendingCallDelegate(IntPtr func, IntPtr arg); + + internal static Py_MakePendingCallsDelegate Py_MakePendingCalls { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int Py_MakePendingCallsDelegate(); + // end of PY3 + + enum Py2 { } + + internal static PyObject_GetBufferDelegate PyObject_GetBuffer { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyObject_GetBufferDelegate(BorrowedReference exporter, out Py_buffer view, PyBUF flags); + + internal static PyBuffer_ReleaseDelegate PyBuffer_Release { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate void PyBuffer_ReleaseDelegate(ref Py_buffer view); + + internal static PyBuffer_SizeFromFormatDelegate PyBuffer_SizeFromFormat { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + internal delegate IntPtr PyBuffer_SizeFromFormatDelegate([MarshalAs(UnmanagedType.LPStr)] string format); + + internal static PyBuffer_IsContiguousDelegate PyBuffer_IsContiguous { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyBuffer_IsContiguousDelegate(ref Py_buffer view, BufferOrderStyle order); + + internal static PyBuffer_GetPointerDelegate PyBuffer_GetPointer { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate IntPtr PyBuffer_GetPointerDelegate(ref Py_buffer view, IntPtr[] indices); + + internal static PyBuffer_FromContiguousDelegate PyBuffer_FromContiguous { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyBuffer_FromContiguousDelegate(ref Py_buffer view, IntPtr buf, IntPtr len, BufferOrderStyle fort); + + internal static PyBuffer_ToContiguousDelegate PyBuffer_ToContiguous { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyBuffer_ToContiguousDelegate(IntPtr buf, ref Py_buffer src, IntPtr len, BufferOrderStyle order); + + internal static PyBuffer_FillContiguousStridesDelegate PyBuffer_FillContiguousStrides { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + public delegate void PyBuffer_FillContiguousStridesDelegate(int ndims, IntPtr[] shape, IntPtr[] strides, int itemsize, BufferOrderStyle order); + + internal static PyBuffer_FillInfoDelegate PyBuffer_FillInfo { get; } + + [global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)] + internal delegate int PyBuffer_FillInfoDelegate(ref Py_buffer view, BorrowedReference exporter, IntPtr buf, IntPtr len, bool @readonly, PyBUF flags); + } + } + + + class PyReferenceCollection + { + private List> _actions = new List>(); + + /// + /// Record obj's address to release the obj in the future, + /// obj must alive before calling Release. + /// + public void Add(IntPtr ob, Action onRelease) + { + _actions.Add(new KeyValuePair(ob, onRelease)); + } + + public void Release() + { + foreach (var item in _actions) + { + Runtime.XDecref(item.Key); + item.Value?.Invoke(); + } + _actions.Clear(); + } + } +#if NETFX + public static class RuntimeInformation { + public static OSPlatform OSPlatform { get; set; } = Environment.OSVersion.Platform == PlatformID.Unix ? OSPlatform.Linux : OSPlatform.Windows; + public static bool IsOSPlatform(OSPlatform platform){return platform == OSPlatform;} + } + + public enum OSPlatform{ Windows, Linux, OSX } +#endif } diff --git a/src/runtime/slots.cs b/src/runtime/slots.cs new file mode 100644 index 000000000..792b3726c --- /dev/null +++ b/src/runtime/slots.cs @@ -0,0 +1,98 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Python.Runtime.Slots +{ + /// + /// Implement this interface to override Python's __getattr__ for your class + /// + public interface IGetAttr { + bool TryGetAttr(string name, out PyObject value); + } + + static class SlotOverrides { + public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { + if (!Runtime.PyString_Check(key)) { + return Runtime.PyObject_GenericGetAttr(ob, key); + } + + Exceptions.Clear(); + + var self = (IGetAttr)((CLRObject)ManagedType.GetManagedObject(ob)).inst; + string attr = Runtime.GetManagedString(key); + RuntimeHelpers.EnsureSufficientExecutionStack(); + bool gotAttr; + PyObject value; + try { + gotAttr = self.TryGetAttr(attr, out value); + } catch (Exception error) { + Exceptions.SetError(error); + return IntPtr.Zero; + } + if (gotAttr) { + if (value == null || value.Handle == IntPtr.Zero) { + Exceptions.SetError(Exceptions.ValueError, + nameof(IGetAttr) + " implementation returned null value"); + return IntPtr.Zero; + } + + return Runtime.SelfIncRef(value.Handle); + } else { + IntPtr result = Runtime.PyObject_GenericGetAttr(ob, key); + System.Diagnostics.Debug.Assert(result != IntPtr.Zero + || Exceptions.ErrorOccurred()); + return result; + } + } + } + + public static class GetAttr { + static readonly PyObject getAttr = "__getattr__".ToPython(); + + /// + /// Tries to call base type's __getattr__ on the specified instance. + /// Only use when base.TryGetAttr is not available. + /// + /// Python object to call __getattr__ on + /// Name of the attribute to retrieve + /// Reference to a variable, that will receive the attribute value + public static bool TryGetBaseAttr(PyObject self, string name, out PyObject result) { + if (self == null) throw new ArgumentNullException(nameof(self)); + if (name == null) throw new ArgumentNullException(nameof(name)); + + using (var super = new PyObject(Runtime.SelfIncRef(Runtime.PySuper_Type))) + using (var @class = self.GetPythonType()) + using (var @base = super.Invoke(@class, self)) { + if (!@base.HasAttr(getAttr)) { + result = null; + return false; + } + + using (var pythonName = name.ToPython()) { + result = @base.InvokeMethod(getAttr, pythonName); + return true; + } + } + } + + public static bool GenericGetAttr(PyObject self, string name, out PyObject result) { + if (self == null) throw new ArgumentNullException(nameof(self)); + if (name == null) throw new ArgumentNullException(nameof(name)); + + using (var pyName = name.ToPython()) { + IntPtr pyResult = Runtime.PyObject_GenericGetAttr(self.Handle, pyName.Handle); + if (pyResult == IntPtr.Zero) { + result = null; + if (!PythonException.Matches(Exceptions.AttributeError)) { + throw PythonException.ThrowLastAsClrException(); + } + + Exceptions.Clear(); + return false; + } + result = new PyObject(Runtime.SelfIncRef(pyResult)); + return true; + } + } + } +} diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 3df873eb5..3ec7fd00e 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -1,6 +1,6 @@ using System; -using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; @@ -9,15 +9,15 @@ namespace Python.Runtime { - /// /// The TypeManager class is responsible for building binary-compatible /// Python type objects that are implemented in managed code. /// - internal class TypeManager + internal static class TypeManager { private static BindingFlags tbFlags; private static Dictionary cache; + private static IPythonBaseTypeProvider pythonBaseTypeProvider; static TypeManager() { @@ -28,6 +28,7 @@ static TypeManager() public static void Reset() { cache = new Dictionary(128); + pythonBaseTypeProvider = PythonEngine.InteropConfiguration.pythonBaseTypeProviders; } /// @@ -36,7 +37,7 @@ public static void Reset() /// object. These Python type instances are used to implement internal /// descriptor and utility types like ModuleObject, PropertyObject, etc. /// - internal static IntPtr GetTypeHandle(Type type) + internal static BorrowedReference GetTypeHandle(Type type) { // Note that these types are cached with a refcount of 1, so they // effectively exist until the CPython runtime is finalized. @@ -44,11 +45,11 @@ internal static IntPtr GetTypeHandle(Type type) cache.TryGetValue(type, out handle); if (handle != IntPtr.Zero) { - return handle; + return new BorrowedReference(handle); } handle = CreateType(type); cache[type] = handle; - return handle; + return new BorrowedReference(handle); } @@ -57,17 +58,17 @@ internal static IntPtr GetTypeHandle(Type type) /// The given ManagedType instance is a managed object that implements /// the appropriate semantics in Python for the reflected managed type. /// - internal static IntPtr GetTypeHandle(ManagedType obj, Type type) + internal static BorrowedReference GetTypeHandle(ManagedType obj, Type type) { IntPtr handle; cache.TryGetValue(type, out handle); if (handle != IntPtr.Zero) { - return handle; + return new BorrowedReference(handle); } handle = CreateType(obj, type); cache[type] = handle; - return handle; + return new BorrowedReference(handle); } @@ -87,16 +88,17 @@ internal static IntPtr CreateType(Type impl) // Set tp_basicsize to the size of our managed instance objects. Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); - var offset = (IntPtr)ObjectOffset.TypeDictOffset(type); + var offset = (IntPtr)ObjectOffset.TypeDictOffset(); Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); InitializeSlots(type, impl); - int flags = TypeFlags.Default | TypeFlags.Managed | + var flags = TypeFlags.Default | TypeFlags.Managed | TypeFlags.HeapType | TypeFlags.HaveGC; - Util.WriteCLong(type, TypeOffset.tp_flags, flags); + Util.WriteCLong(type, TypeOffset.tp_flags, (long)flags); - Runtime.PyType_Ready(type); + if (Runtime.PyType_Ready(type) != 0) + throw new PythonEngineException("Can not create type", PythonException.FromPyErr()); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); IntPtr mod = Runtime.PyString_FromString("CLR"); @@ -107,56 +109,23 @@ internal static IntPtr CreateType(Type impl) return type; } - internal static IntPtr CreateType(ManagedType impl, Type clrType) { - // Cleanup the type name to get rid of funny nested type names. - string name = "CLR." + clrType.FullName; - int i = name.LastIndexOf('+'); - if (i > -1) - { - name = name.Substring(i + 1); - } - i = name.LastIndexOf('.'); - if (i > -1) - { - name = name.Substring(i + 1); - } + string name = GetPythonTypeName(clrType); - IntPtr base_ = IntPtr.Zero; - int ob_size = ObjectOffset.Size(Runtime.PyTypeType); + int ob_size; - // XXX Hack, use a different base class for System.Exception - // Python 2.5+ allows new style class exceptions but they *must* - // subclass BaseException (or better Exception). - if (typeof(Exception).IsAssignableFrom(clrType)) - { - ob_size = ObjectOffset.Size(Exceptions.Exception); - } - - int tp_dictoffset = ob_size + ManagedDataOffsets.ob_dict; - - if (clrType == typeof(Exception)) - { - base_ = Exceptions.Exception; - } - else if (clrType.BaseType != null) - { - ClassBase bc = ClassManager.GetClass(clrType.BaseType); - base_ = bc.pyHandle; - } - - IntPtr type = AllocateTypeObject(name); + IntPtr type = AllocateTypeObject(name, typeType: Runtime.PyCLRMetaType); Marshal.WriteIntPtr(type, TypeOffset.ob_type, Runtime.PyCLRMetaType); Runtime.XIncref(Runtime.PyCLRMetaType); - Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); - Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); - Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset); + // Hide the gchandle of the implementation in a magic type slot. + GCHandle gc = GCHandle.Alloc(impl); + Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc); // add a __len__ slot for inheritors of ICollection and ICollection<> - if (typeof(ICollection).IsAssignableFrom(clrType) || clrType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>))) + if (typeof(System.Collections.ICollection).IsAssignableFrom(clrType) || clrType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ICollection<>))) { InitializeSlot(type, TypeOffset.mp_length, typeof(mp_length_slot).GetMethod(nameof(mp_length_slot.mp_length))); } @@ -164,34 +133,82 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) // we want to do this after the slot stuff above in case the class itself implements a slot method InitializeSlots(type, impl.GetType()); - if (base_ != IntPtr.Zero) + if (typeof(IGetAttr).IsAssignableFrom(clrType)) { + InitializeSlot(type, TypeOffset.tp_getattro, typeof(SlotOverrides).GetMethod(nameof(SlotOverrides.tp_getattro))); + } + + int extraTypeDataOffset; + try { - Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); - Runtime.XIncref(base_); + using PyTuple baseTuple = GetBaseTypeTuple(clrType); + Debug.Assert(baseTuple.Length() > 0); + IntPtr primaryBase = baseTuple[0].Reference.DangerousIncRefOrNull(); + Marshal.WriteIntPtr(type, TypeOffset.tp_base, primaryBase); + + if (baseTuple.Length() > 1) { + Marshal.WriteIntPtr(type, TypeOffset.tp_bases, baseTuple.Reference.DangerousIncRefOrNull()); + } + + ob_size = checked((int)Marshal.ReadIntPtr(primaryBase, TypeOffset.tp_basicsize)); + void InheritOrAllocate(int typeField) { + int value = Marshal.ReadInt32(primaryBase, typeField); + if (value == 0) { + Marshal.WriteIntPtr(type, typeField, new IntPtr(ob_size)); + ob_size += IntPtr.Size; + } else { + Marshal.WriteIntPtr(type, typeField, new IntPtr(value)); + } + } + + InheritOrAllocate(TypeOffset.tp_dictoffset); + InheritOrAllocate(TypeOffset.tp_weaklistoffset); + + if (!ManagedType.IsManagedType(primaryBase)) { + // base type is a Python type, so we must allocate additional space for GC handle + extraTypeDataOffset = ob_size; + ObjectOffset.ClrGcHandleOffsetAssertSanity(extraTypeDataOffset); + ob_size += MetaType.ExtraTypeDataSize; + } else { + extraTypeDataOffset = checked((int)Marshal.ReadIntPtr(primaryBase, TypeOffset.clr_gchandle_offset)); + ObjectOffset.ClrGcHandleOffsetAssertSanity(extraTypeDataOffset); + } } + catch (Exception error) + { + Exceptions.SetError(error); + return IntPtr.Zero; + } + + ObjectOffset.ClrGcHandleOffsetAssertSanity(extraTypeDataOffset); + + Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size); + Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); + Marshal.WriteIntPtr(type, TypeOffset.clr_gchandle_offset, (IntPtr)extraTypeDataOffset); - int flags = TypeFlags.Default; + var flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.BaseType; flags |= TypeFlags.HaveGC; - Util.WriteCLong(type, TypeOffset.tp_flags, flags); + Util.WriteCLong(type, TypeOffset.tp_flags, (long)flags); // Leverage followup initialization from the Python runtime. Note // that the type of the new type must PyType_Type at the time we // call this, else PyType_Ready will skip some slot initialization. - Runtime.PyType_Ready(type); + if (Runtime.PyType_Ready(type) != 0) + { + gc.Free(); + return IntPtr.Zero; + } + + Debug.Assert(extraTypeDataOffset > Marshal.ReadInt32(type, TypeOffset.tp_dictoffset)); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); string mn = clrType.Namespace ?? ""; IntPtr mod = Runtime.PyString_FromString(mn); Runtime.PyDict_SetItemString(dict, "__module__", mod); - // Hide the gchandle of the implementation in a magic type slot. - GCHandle gc = GCHandle.Alloc(impl); - Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc); - // Set the handle attributes on the implementing instance. impl.tpHandle = Runtime.PyCLRMetaType; impl.gcHandle = gc; @@ -202,13 +219,84 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) return type; } - static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method) + static string GetPythonTypeName(Type clrType) { - var thunk = Interop.GetThunk(method); - Marshal.WriteIntPtr(type, slotOffset, thunk.Address); + var result = new System.Text.StringBuilder(); + GetPythonTypeName(clrType, target: result); + return result.ToString(); } - internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict) + static void GetPythonTypeName(Type clrType, System.Text.StringBuilder target) + { + if (clrType.IsGenericType) + { + string fullName = clrType.GetGenericTypeDefinition().FullName; + int argCountIndex = fullName.LastIndexOf('`'); + if (argCountIndex >= 0) + { + string nonGenericFullName = fullName.Substring(0, argCountIndex); + string nonGenericName = CleanupFullName(nonGenericFullName); + target.Append(nonGenericName); + + var arguments = clrType.GetGenericArguments(); + target.Append('<'); + for (int argIndex = 0; argIndex < arguments.Length; argIndex++) + { + if (argIndex != 0) + { + target.Append(','); + } + + GetPythonTypeName(arguments[argIndex], target); + } + + target.Append('>'); + return; + } + } + + string name = CleanupFullName(clrType.FullName); + target.Append(name); + } + + static string CleanupFullName(string fullTypeName) + { + // Cleanup the type name to get rid of funny nested type names. + string name = "CLR." + fullTypeName; + int i = name.LastIndexOf('+'); + if (i > -1) + { + name = name.Substring(i + 1); + } + + i = name.LastIndexOf('.'); + if (i > -1) + { + name = name.Substring(i + 1); + } + + return name; + } + + static PyTuple GetBaseTypeTuple(Type clrType) + { + var bases = pythonBaseTypeProvider + .GetBaseTypes(clrType, new PyObject[0]) + ?.ToArray(); + if (bases is null || bases.Length == 0) + { + throw new InvalidOperationException("At least one base type must be specified"); + } + + if (bases.Any(@base => !PyType.IsTypeType(@base))) + { + throw new InvalidOperationException("Entries in base types must be Python types"); + } + + return new PyTuple(bases); + } + + internal static BorrowedReference CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict) { // Utility to create a subtype of a managed type with the ability for the // a python subtype able to override the managed implementation @@ -222,7 +310,7 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr var disposeList = new List(); try { - var assemblyKey = new PyObject(Converter.ToPython("__assembly__", typeof(string))); + var assemblyKey = new PyObject(Converter.ToPython("__assembly__")); disposeList.Add(assemblyKey); if (0 != Runtime.PyMapping_HasKey(py_dict, assemblyKey.Handle)) { @@ -235,7 +323,7 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr } } - var namespaceKey = new PyObject(Converter.ToPythonImplicit("__namespace__")); + var namespaceKey = new PyObject(Converter.ToPython("__namespace__")); disposeList.Add(namespaceKey); if (0 != Runtime.PyMapping_HasKey(py_dict, namespaceKey.Handle)) { @@ -260,7 +348,7 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr var baseClass = ManagedType.GetManagedObject(py_base_type) as ClassBase; if (null == baseClass) { - return Exceptions.RaiseTypeError("invalid base class, expected CLR class type"); + return new BorrowedReference(Exceptions.RaiseTypeError("invalid base class, expected CLR class type")); } try @@ -273,26 +361,32 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr // create the new ManagedType and python type ClassBase subClass = ClassManager.GetClass(subType); - IntPtr py_type = GetTypeHandle(subClass, subType); + BorrowedReference py_type = GetTypeHandle(subClass, subType); + if (py_type.IsNull) + { + return new BorrowedReference(); + } // by default the class dict will have all the C# methods in it, but as this is a // derived class we want the python overrides in there instead if they exist. - IntPtr cls_dict = Marshal.ReadIntPtr(py_type, TypeOffset.tp_dict); + IntPtr cls_dict = Marshal.ReadIntPtr(py_type.DangerousGetAddress(), TypeOffset.tp_dict); Runtime.PyDict_Update(cls_dict, py_dict); // Update the __classcell__ if it exists var cell = new BorrowedReference(Runtime.PyDict_GetItemString(cls_dict, "__classcell__")); if (!cell.IsNull) { - Runtime.PyCell_Set(cell, py_type); - Runtime.PyDict_DelItemString(cls_dict, "__classcell__"); + int r = Runtime.PyCell_Set(cell, py_type); + if (r == 0) return new BorrowedReference(); + r = Runtime.PyDict_DelItemString(cls_dict, "__classcell__"); + if (r == 0) return new BorrowedReference(); } return py_type; } catch (Exception e) { - return Exceptions.RaiseTypeError(e.Message); + return new BorrowedReference(Exceptions.RaiseTypeError(e.Message)); } } @@ -332,6 +426,13 @@ internal static IntPtr CreateMetaType(Type impl) Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type); Runtime.XIncref(py_type); + TypeOffset.clr_gchandle_offset = checked((int)Marshal.ReadIntPtr(py_type, TypeOffset.tp_basicsize)); + if (TypeOffset.clr_gchandle_offset <= 0) + throw new PythonEngineException("CLR Metatype initialization failed: unable to read tp_basicsize correctly"); + ObjectOffset.ClrGcHandleOffsetAssertSanity(TypeOffset.clr_gchandle_offset); + int structSize = TypeOffset.clr_gchandle_offset + MetaType.ExtraTypeDataSize; + Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, new IntPtr(structSize)); + // Slots will inherit from TypeType, it's not neccesary for setting them. // Inheried slots: // tp_basicsize, tp_itemsize, @@ -342,11 +443,11 @@ internal static IntPtr CreateMetaType(Type impl) InitializeSlots(type, impl); - int flags = TypeFlags.Default; + var flags = TypeFlags.Default; flags |= TypeFlags.Managed; flags |= TypeFlags.HeapType; flags |= TypeFlags.HaveGC; - Util.WriteCLong(type, TypeOffset.tp_flags, flags); + Util.WriteCLong(type, TypeOffset.tp_flags, (long)flags); // We need space for 3 PyMethodDef structs, each of them // 4 int-ptrs in size. @@ -371,7 +472,8 @@ internal static IntPtr CreateMetaType(Type impl) Marshal.WriteIntPtr(type, TypeOffset.tp_methods, mdefStart); - Runtime.PyType_Ready(type); + if (Runtime.PyType_Ready(type) != 0) + throw new PythonEngineException("Failed to create CLR Metatype", PythonException.FromPyErr()); IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); IntPtr mod = Runtime.PyString_FromString("CLR"); @@ -382,70 +484,30 @@ internal static IntPtr CreateMetaType(Type impl) return type; } - - internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl) - { - // Utility to create a subtype of a std Python type, but with - // a managed type able to override implementation - - IntPtr type = AllocateTypeObject(name); - //Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); - //Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); - - //IntPtr offset = (IntPtr)ObjectOffset.ob_dict; - //Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); - - //IntPtr dc = Runtime.PyDict_Copy(dict); - //Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc); - - Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); - Runtime.XIncref(base_); - - int flags = TypeFlags.Default; - flags |= TypeFlags.Managed; - flags |= TypeFlags.HeapType; - flags |= TypeFlags.HaveGC; - Util.WriteCLong(type, TypeOffset.tp_flags, flags); - - CopySlot(base_, type, TypeOffset.tp_traverse); - CopySlot(base_, type, TypeOffset.tp_clear); - CopySlot(base_, type, TypeOffset.tp_is_gc); - - InitializeSlots(type, impl); - - Runtime.PyType_Ready(type); - - IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - IntPtr mod = Runtime.PyString_FromString("CLR"); - Runtime.PyDict_SetItemString(tp_dict, "__module__", mod); - - return type; - } - - /// /// Utility method to allocate a type object & do basic initialization. /// internal static IntPtr AllocateTypeObject(string name) + => AllocateTypeObject(name, Runtime.PyTypeType); + /// + /// Utility method to allocate a type object & do basic initialization. + /// + internal static IntPtr AllocateTypeObject(string name, IntPtr typeType) { - IntPtr type = Runtime.PyType_GenericAlloc(Runtime.PyTypeType, 0); + if (name == null) throw new ArgumentNullException(nameof(name)); + if (typeType == IntPtr.Zero) throw new ArgumentNullException(nameof(typeType)); + + IntPtr type = Runtime.PyType_GenericAlloc(typeType, 0); // Cheat a little: we'll set tp_name to the internal char * of // the Python version of the type name - otherwise we'd have to // allocate the tp_name and would have no way to free it. -#if PYTHON3 IntPtr temp = Runtime.PyUnicode_FromString(name); IntPtr raw = Runtime.PyUnicode_AsUTF8(temp); -#elif PYTHON2 - IntPtr temp = Runtime.PyString_FromString(name); - IntPtr raw = Runtime.PyString_AsString(temp); -#endif Marshal.WriteIntPtr(type, TypeOffset.tp_name, raw); Marshal.WriteIntPtr(type, TypeOffset.name, temp); - -#if PYTHON3 + Runtime.XIncref(temp); Marshal.WriteIntPtr(type, TypeOffset.qualname, temp); -#endif long ptr = type.ToInt64(); // 64-bit safe @@ -458,11 +520,7 @@ internal static IntPtr AllocateTypeObject(string name) temp = new IntPtr(ptr + TypeOffset.mp_length); Marshal.WriteIntPtr(type, TypeOffset.tp_as_mapping, temp); -#if PYTHON3 temp = new IntPtr(ptr + TypeOffset.bf_getbuffer); -#elif PYTHON2 - temp = new IntPtr(ptr + TypeOffset.bf_getreadbuffer); -#endif Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp); return type; } @@ -730,6 +788,9 @@ internal static void InitializeSlots(IntPtr type, Type impl) seen.Add(name); } + var initSlot = impl.GetMethod("InitializeSlots", BindingFlags.Static | BindingFlags.Public); + initSlot?.Invoke(null, parameters: new object[] {type, seen}); + impl = impl.BaseType; } @@ -777,7 +838,7 @@ internal static void InitializeSlots(IntPtr type, Type impl) /// Type being initialized. /// Function pointer. /// Name of the method. - static void InitializeSlot(IntPtr type, IntPtr slot, string name) + internal static void InitializeSlot(IntPtr type, IntPtr slot, string name) { Type typeOffset = typeof(TypeOffset); FieldInfo fi = typeOffset.GetField(name); @@ -786,6 +847,12 @@ static void InitializeSlot(IntPtr type, IntPtr slot, string name) Marshal.WriteIntPtr(type, offset, slot); } + static void InitializeSlot(IntPtr type, int slotOffset, MethodInfo method) + { + var thunk = Interop.GetThunk(method); + Marshal.WriteIntPtr(type, slotOffset, thunk.Address); + } + /// /// Given a newly allocated Python type object and a managed Type that /// implements it, initialize any methods defined by the Type that need diff --git a/src/runtime/interop27.cs b/src/runtime/typeoffset.cs similarity index 78% rename from src/runtime/interop27.cs rename to src/runtime/typeoffset.cs index 4782e9d3b..1da7ec281 100644 --- a/src/runtime/interop27.cs +++ b/src/runtime/typeoffset.cs @@ -1,14 +1,9 @@ -// Auto-generated by geninterop.py. -// DO NOT MODIFIY BY HAND. - - -#if PYTHON27 using System; using System.Collections; using System.Collections.Specialized; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Reflection; -using System.Text; namespace Python.Runtime { @@ -17,12 +12,22 @@ internal class TypeOffset { static TypeOffset() { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); + string versionedOffsetTypeName = typeof(TypeOffset).FullName + Runtime.pyver; + var versionedOffsetType = typeof(TypeOffset).Assembly.GetType(versionedOffsetTypeName); + if (versionedOffsetType == null) + throw new NotSupportedException("Python version is not supported"); + + FieldInfo[] fi = versionedOffsetType.GetFields(); + Type typeOffset = typeof(TypeOffset); int size = IntPtr.Size; for (int i = 0; i < fi.Length; i++) { fi[i].SetValue(null, i * size); + var field = typeOffset.GetField(fi[i].Name); + if (field is null) + Debug.WriteLine("ignoring field " + fi[i].Name); + else + field.SetValue(null, i * size); } } @@ -31,7 +36,8 @@ public static int magic() return ob_size; } - // Auto-generated from PyHeapTypeObject in Python.h + public static int clr_gchandle_offset = 0; + public static int ob_refcnt = 0; public static int ob_type = 0; public static int ob_size = 0; @@ -42,7 +48,7 @@ public static int magic() public static int tp_print = 0; public static int tp_getattr = 0; public static int tp_setattr = 0; - public static int tp_compare = 0; + public static int tp_as_async = 0; public static int tp_repr = 0; public static int tp_as_number = 0; public static int tp_as_sequence = 0; @@ -81,33 +87,32 @@ public static int magic() public static int tp_weaklist = 0; public static int tp_del = 0; public static int tp_version_tag = 0; + public static int tp_finalize = 0; + public static int am_await = 0; + public static int am_aiter = 0; + public static int am_anext = 0; public static int nb_add = 0; public static int nb_subtract = 0; public static int nb_multiply = 0; - public static int nb_divide = 0; public static int nb_remainder = 0; public static int nb_divmod = 0; public static int nb_power = 0; public static int nb_negative = 0; public static int nb_positive = 0; public static int nb_absolute = 0; - public static int nb_nonzero = 0; + public static int nb_bool = 0; public static int nb_invert = 0; public static int nb_lshift = 0; public static int nb_rshift = 0; public static int nb_and = 0; public static int nb_xor = 0; public static int nb_or = 0; - public static int nb_coerce = 0; public static int nb_int = 0; - public static int nb_long = 0; + public static int nb_reserved = 0; public static int nb_float = 0; - public static int nb_oct = 0; - public static int nb_hex = 0; public static int nb_inplace_add = 0; public static int nb_inplace_subtract = 0; public static int nb_inplace_multiply = 0; - public static int nb_inplace_divide = 0; public static int nb_inplace_remainder = 0; public static int nb_inplace_power = 0; public static int nb_inplace_lshift = 0; @@ -120,6 +125,8 @@ public static int magic() public static int nb_inplace_floor_divide = 0; public static int nb_inplace_true_divide = 0; public static int nb_index = 0; + public static int nb_matrix_multiply = 0; + public static int nb_inplace_matrix_multiply = 0; public static int mp_length = 0; public static int mp_subscript = 0; public static int mp_ass_subscript = 0; @@ -127,24 +134,20 @@ public static int magic() public static int sq_concat = 0; public static int sq_repeat = 0; public static int sq_item = 0; - public static int sq_slice = 0; + public static int was_sq_slice = 0; public static int sq_ass_item = 0; - public static int sq_ass_slice = 0; + public static int was_sq_ass_slice = 0; public static int sq_contains = 0; public static int sq_inplace_concat = 0; public static int sq_inplace_repeat = 0; - public static int bf_getreadbuffer = 0; - public static int bf_getwritebuffer = 0; - public static int bf_getsegcount = 0; - public static int bf_getcharbuffer = 0; public static int bf_getbuffer = 0; public static int bf_releasebuffer = 0; public static int name = 0; public static int ht_slots = 0; + public static int qualname = 0; + public static int ht_cached_keys = 0; /* here are optional user slots, followed by the members. */ public static int members = 0; } } - -#endif diff --git a/src/testing/Python.Test.15.csproj b/src/testing/Python.Test.15.csproj index 0e19adf91..c4e165a16 100644 --- a/src/testing/Python.Test.15.csproj +++ b/src/testing/Python.Test.15.csproj @@ -1,9 +1,8 @@ - net40;netstandard2.0 + netstandard2.0 x64;x86 - DebugMono;DebugMonoPY3;ReleaseMono;ReleaseMonoPY3;DebugWin;DebugWinPY3;ReleaseWin;ReleaseWinPY3 Python.Test Python.Test Python.Test diff --git a/src/testing/Python.Test.csproj b/src/testing/Python.Test.csproj deleted file mode 100644 index 63526c060..000000000 --- a/src/testing/Python.Test.csproj +++ /dev/null @@ -1,117 +0,0 @@ - - - - Debug - AnyCPU - {6F401A34-273B-450F-9A4C-13550BE0767B} - Library - Python.Test - Python.Test - bin\Python.Test.xml - bin\ - v4.0 - - 1591,0067 - ..\..\ - $(SolutionDir)\bin\ - 6 - false - ..\pythonnet.snk - prompt - - - x86 - - - x64 - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - true - DEBUG;TRACE - full - - - - - true - pdbonly - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {097B4AC0-74E9-4C58-BCF8-C69746EC8271} - Python.Runtime - - - - - $(TargetPath) - $(TargetDir)$(TargetName).pdb - - - - - - diff --git a/src/testing/arraytest.cs b/src/testing/arraytest.cs index 946684962..7e79701e6 100644 --- a/src/testing/arraytest.cs +++ b/src/testing/arraytest.cs @@ -297,7 +297,7 @@ public MultiDimensionalArrayTest() } - public class ArrayConversionTest + public static class ArrayConversionTest { public static Spam[] EchoRange(Spam[] items) { diff --git a/src/testing/classtest.cs b/src/testing/classtest.cs index 68c0d8c55..797959bc6 100644 --- a/src/testing/classtest.cs +++ b/src/testing/classtest.cs @@ -5,7 +5,7 @@ namespace Python.Test /// /// Supports CLR class unit tests. /// - public class ClassTest + public static class ClassTest { public static ArrayList GetArrayList() { diff --git a/src/testing/generictest.cs b/src/testing/generictest.cs index 1e9c71ac6..51639cf39 100644 --- a/src/testing/generictest.cs +++ b/src/testing/generictest.cs @@ -36,27 +36,27 @@ public DerivedFromOpenGeneric(int arg1, V arg2, W arg3) : base(arg1, arg2) } - public class GenericNameTest1 + public static class GenericNameTest1 { public static int value = 0; } - public class GenericNameTest1 + public static class GenericNameTest1 { public static int value = 1; } - public class GenericNameTest1 + public static class GenericNameTest1 { public static int value = 2; } - public class GenericNameTest2 + public static class GenericNameTest2 { public static int value = 1; } - public class GenericNameTest2 + public static class GenericNameTest2 { public static int value = 2; } diff --git a/src/testing/moduletest.cs b/src/testing/moduletest.cs index 2df5269f3..820928279 100644 --- a/src/testing/moduletest.cs +++ b/src/testing/moduletest.cs @@ -4,7 +4,7 @@ namespace Python.Test { - public class ModuleTest + public static class ModuleTest { private static Thread _thread; diff --git a/src/testing/subclasstest.cs b/src/testing/subclasstest.cs index 9817d865e..772023591 100644 --- a/src/testing/subclasstest.cs +++ b/src/testing/subclasstest.cs @@ -74,7 +74,7 @@ public void SomeMethod() } } - public class FunctionsTest + public static class FunctionsTest { public static string test_foo(IInterfaceTest x) { diff --git a/src/testing/threadtest.cs b/src/testing/threadtest.cs index 2825c3fef..83f1c392b 100644 --- a/src/testing/threadtest.cs +++ b/src/testing/threadtest.cs @@ -6,7 +6,7 @@ namespace Python.Test /// /// Supports CLR threading / reentrant unit tests. /// - public class ThreadTest + public static class ThreadTest { private static PyObject module; diff --git a/tools/geninterop/geninterop.py b/tools/geninterop/geninterop.py index 902296229..61df16c65 100644 --- a/tools/geninterop/geninterop.py +++ b/tools/geninterop/geninterop.py @@ -214,9 +214,7 @@ def preprocess_python_headers(): def gen_interop_code(members): """Generate the TypeOffset C# class""" - defines = [ - "PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR) - ] + PY_VER = "{0}{1}".format(PY_MAJOR, PY_MINOR) if hasattr(sys, "abiflags"): if "d" in sys.abiflags: @@ -227,13 +225,10 @@ def gen_interop_code(members): defines.append("PYTHON_WITH_WIDE_UNICODE") filename = os.path.basename(__file__) - defines_str = " && ".join(defines) class_definition = """ // Auto-generated by %s. // DO NOT MODIFY BY HAND. - -#if %s using System; using System.Collections; using System.Collections.Specialized; @@ -242,28 +237,12 @@ def gen_interop_code(members): using System.Text; namespace Python.Runtime -{ +{{ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] - internal class TypeOffset - { - static TypeOffset() - { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) - { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() - { - return ob_size; - } - + internal static class TypeOffset{1} + {{ // Auto-generated from PyHeapTypeObject in Python.h -""" % (filename, defines_str) +""".format(filename, PY_VER) # All the members are sizeof(void*) so we don't need to do any # extra work to determine the size based on the type. @@ -276,8 +255,6 @@ def gen_interop_code(members): public static int members = 0; } } - -#endif """ return class_definition