mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-01-18 14:41:21 +08:00
Merge branch 'PythonPlugin'
This commit is contained in:
commit
53120faeba
2
.gitignore
vendored
2
.gitignore
vendored
@ -62,6 +62,8 @@ _ReSharper*
|
||||
# Installshield output folder
|
||||
[Ee]xpress
|
||||
|
||||
.idea
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
|
BIN
Plugins/WinAlfred.Plugin.DouBan/Images/movies.png
Normal file
BIN
Plugins/WinAlfred.Plugin.DouBan/Images/movies.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
@ -2,21 +2,31 @@
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import json
|
||||
import webbrowser
|
||||
|
||||
class PyWinAlfred():
|
||||
def query(key):
|
||||
k = key.split(" ")[1]
|
||||
if not k:
|
||||
return ""
|
||||
r = requests.get('http://movie.douban.com/subject_search?search_text=' + k)
|
||||
bs = BeautifulSoup(r.text)
|
||||
results = []
|
||||
for i in bs.select(".article table .pl2"):
|
||||
res = {}
|
||||
title = i.select("a")[0].text.replace("\n","").replace(" ","")
|
||||
score = i.select("span.rating_nums")[0].text if i.select("span.rating_nums") else "0"
|
||||
res["Title"] = title.split("/")[0]
|
||||
year = i.select("p.pl")[0].text.split("-")[0] if i.select("p.pl")[0] else "Null"
|
||||
alias = title.split("/")[1] if len(title.split("/")) >= 2 else "Null"
|
||||
res["SubTitle"] = "Year: " + year + " Score: " + score + " Alias: " + alias
|
||||
res["ActionName"] = "openUrl"
|
||||
res["IcoPath"] = "Images\\movies.png"
|
||||
res["ActionPara"] = i.select("a[href]")[0]["href"]
|
||||
results.append(res)
|
||||
return json.dumps(results)
|
||||
|
||||
def query(self,key):
|
||||
k = key.split(" ")[1]
|
||||
r = requests.get('http://movie.douban.com/subject_search?search_text=' + k)
|
||||
bs = BeautifulSoup(r.text)
|
||||
results = []
|
||||
for i in bs.select(".article table .pl2 a"):
|
||||
res = {}
|
||||
t = i.text.strip().replace(" ","")
|
||||
res["Title"] = t.replace("\\n","")
|
||||
results.append(res)
|
||||
return json.dumps(results)
|
||||
def openUrl(url):
|
||||
webbrowser.open(url)
|
||||
|
||||
if __name__ == "__main__":
|
||||
p = PyWinAlfred()
|
||||
print p.query("movie geo")
|
||||
print query("movie geo")
|
||||
|
@ -1,116 +0,0 @@
|
||||
#include <tchar.h>
|
||||
#include "Python.h"
|
||||
#include <thread>
|
||||
#include <future>
|
||||
|
||||
extern "C" __declspec(dllexport) void InitPythonEnv()
|
||||
{
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
}
|
||||
|
||||
char* GetErrorMessage()
|
||||
{
|
||||
char *pStrErrorMessage = NULL;
|
||||
|
||||
if(PyErr_Occurred()){
|
||||
PyObject *ptype, *pvalue, *ptraceback;
|
||||
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
|
||||
pStrErrorMessage = PyString_AsString(pvalue);
|
||||
}
|
||||
|
||||
return pStrErrorMessage;
|
||||
}
|
||||
|
||||
|
||||
char* Exec(char* directory, char* file, char* method, char* para)
|
||||
{
|
||||
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pClass, *pInstance;
|
||||
char *error;
|
||||
|
||||
PyThreadState* global_state = PyThreadState_Get();
|
||||
PyThreadState* ts = Py_NewInterpreter();
|
||||
PyThreadState_Swap(ts);
|
||||
// Initialise the Python interpreter
|
||||
|
||||
// Create GIL/enable threads
|
||||
|
||||
//PyGILState_STATE gstate = PyGILState_Ensure();
|
||||
// // Get the default thread state
|
||||
// PyThreadState* state = PyThreadState_Get();
|
||||
// // Once in each thread
|
||||
//PyThreadState* stateForNewThread = PyThreadState_New(state->interp);
|
||||
//PyEval_RestoreThread(stateForNewThread);
|
||||
|
||||
// Build the name object
|
||||
PyObject *sys = PyImport_ImportModule("sys");
|
||||
PyObject *path = PyObject_GetAttrString(sys, "path");
|
||||
PyList_Append(path, PyString_FromString(directory));
|
||||
|
||||
pName = PyString_FromString(file);
|
||||
error = GetErrorMessage();
|
||||
if(error != NULL){
|
||||
char* err =new char[5000]();
|
||||
sprintf(error, "%s:%s","PYTHONERROR",error);
|
||||
return err;
|
||||
}
|
||||
|
||||
pModule = PyImport_Import(pName);
|
||||
error = GetErrorMessage();
|
||||
if(error != NULL){
|
||||
char* err =new char[5000]();
|
||||
sprintf(err, "%s:%s","PYTHONERROR",error);
|
||||
return err;
|
||||
}
|
||||
|
||||
pDict = PyModule_GetDict(pModule);
|
||||
error = GetErrorMessage();
|
||||
if(error != NULL){
|
||||
char* err =new char[5000]();
|
||||
sprintf(err, "%s:%s","PYTHONERROR",error);
|
||||
return err;
|
||||
}
|
||||
|
||||
pClass = PyDict_GetItemString(pDict,"PyWinAlfred");
|
||||
error = GetErrorMessage();
|
||||
if(error != NULL){
|
||||
char* err =new char[5000]();
|
||||
sprintf(err, "%s:%s","PYTHONERROR",error);
|
||||
return err;
|
||||
}
|
||||
|
||||
pInstance = PyObject_CallObject(pClass, NULL);
|
||||
error = GetErrorMessage();
|
||||
if(error != NULL){
|
||||
char* err =new char[5000]();
|
||||
sprintf(err, "%s:%s","PYTHONERROR",error);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Call a method of the class with two parameters
|
||||
pValue = PyObject_CallMethod(pInstance,method, "(s)",para);
|
||||
error = GetErrorMessage();
|
||||
if(error != NULL){
|
||||
char* err =new char[5000]();
|
||||
sprintf(err, "%s:%s","PYTHONERROR",error);
|
||||
return err;
|
||||
}
|
||||
|
||||
char * str_ret = PyString_AsString(pValue);
|
||||
|
||||
//PyEval_SaveThread();
|
||||
|
||||
// Finish the Python Interpreter
|
||||
|
||||
PyErr_Clear();
|
||||
Py_EndInterpreter(ts);
|
||||
PyThreadState_Swap(global_state);
|
||||
|
||||
return str_ret;
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) char* ExecPython(char* directory, char* file, char* method, char* para)
|
||||
{
|
||||
auto future = std::async(Exec,directory,file,method,para);
|
||||
return future.get();
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D03FD663-38A8-4C1A-8431-EB44F93E7EBA}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>PyWinAlfred</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>C:\Python27\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Python27\libs;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>C:\Python27\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>C:\Python27\libs;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>$(SolutionDir)WinAlfred\bin\Debug\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PYWINALFRED_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PYWINALFRED_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PYWINALFRED_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PYWINALFRED_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
BIN
Python.Runtime.dll
Normal file
BIN
Python.Runtime.dll
Normal file
Binary file not shown.
170
Pythonnet.Runtime/Python.Runtime.csproj
Normal file
170
Pythonnet.Runtime/Python.Runtime.csproj
Normal file
@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{097B4AC0-74E9-4C58-BCF8-C69746EC8271}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<NoStandardLibraries>false</NoStandardLibraries>
|
||||
<AssemblyName>Python.Runtime</AssemblyName>
|
||||
<RootNamespace>Python.Runtime</RootNamespace>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>.\bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;PYTHON27,UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>.\bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;PYTHON27, UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'EmbeddingTest|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\EmbeddingTest\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;PYTHON27,UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'UnitTests|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\UnitTests\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;PYTHON27,UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;PYTHON26,UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<NoWarn>1607</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;PYTHON26,UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<NoWarn>1607</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'EmbeddingTest|x64' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\EmbeddingTest\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;PYTHON26,UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<NoWarn>1607</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'UnitTests|x64' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\UnitTests\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;PYTHON26,UCS2</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<NoWarn>1607</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="arrayobject.cs" />
|
||||
<Compile Include="assemblyinfo.cs" />
|
||||
<Compile Include="assemblymanager.cs" />
|
||||
<Compile Include="classbase.cs" />
|
||||
<Compile Include="classmanager.cs" />
|
||||
<Compile Include="classobject.cs" />
|
||||
<Compile Include="clrobject.cs" />
|
||||
<Compile Include="codegenerator.cs" />
|
||||
<Compile Include="constructorbinder.cs" />
|
||||
<Compile Include="constructorbinding.cs" />
|
||||
<Compile Include="converter.cs" />
|
||||
<Compile Include="debughelper.cs" />
|
||||
<Compile Include="delegatemanager.cs" />
|
||||
<Compile Include="delegateobject.cs" />
|
||||
<Compile Include="eventbinding.cs" />
|
||||
<Compile Include="eventobject.cs" />
|
||||
<Compile Include="exceptions.cs" />
|
||||
<Compile Include="extensiontype.cs" />
|
||||
<Compile Include="fieldobject.cs" />
|
||||
<Compile Include="generictype.cs" />
|
||||
<Compile Include="genericutil.cs" />
|
||||
<Compile Include="importhook.cs" />
|
||||
<Compile Include="indexer.cs" />
|
||||
<Compile Include="interfaceobject.cs" />
|
||||
<Compile Include="interfaces.cs" />
|
||||
<Compile Include="interop.cs" />
|
||||
<Compile Include="iterator.cs" />
|
||||
<Compile Include="managedtype.cs" />
|
||||
<Compile Include="metatype.cs" />
|
||||
<Compile Include="methodbinder.cs" />
|
||||
<Compile Include="methodbinding.cs" />
|
||||
<Compile Include="methodobject.cs" />
|
||||
<Compile Include="methodwrapper.cs" />
|
||||
<Compile Include="modulefunctionobject.cs" />
|
||||
<Compile Include="moduleobject.cs" />
|
||||
<Compile Include="modulepropertyobject.cs" />
|
||||
<Compile Include="monosupport.cs" />
|
||||
<Compile Include="nativecall.cs" />
|
||||
<Compile Include="overload.cs" />
|
||||
<Compile Include="propertyobject.cs" />
|
||||
<Compile Include="pyansistring.cs" />
|
||||
<Compile Include="pydict.cs" />
|
||||
<Compile Include="pyfloat.cs" />
|
||||
<Compile Include="pyint.cs" />
|
||||
<Compile Include="pyiter.cs" />
|
||||
<Compile Include="pylist.cs" />
|
||||
<Compile Include="pylong.cs" />
|
||||
<Compile Include="pynumber.cs" />
|
||||
<Compile Include="pyobject.cs" />
|
||||
<Compile Include="pysequence.cs" />
|
||||
<Compile Include="pystring.cs" />
|
||||
<Compile Include="pythonengine.cs" />
|
||||
<Compile Include="pythonexception.cs" />
|
||||
<Compile Include="pytuple.cs" />
|
||||
<Compile Include="runtime.cs" />
|
||||
<Compile Include="typemanager.cs" />
|
||||
<Compile Include="typemethod.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="buildclrmodule.bat" />
|
||||
<None Include="clrmodule.il" />
|
||||
<None Include="x64\clrmodule-platform.il" />
|
||||
<None Include="x86\clrmodule-platform.il" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="python-clear.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio AllowExistingFolder="true" />
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>call "$(ProjectDir)buildclrmodule.bat" $(Platform) "$(ProjectDir)" "$(TargetDir)clr.pyd"
|
||||
copy "$(TargetPath)" "$(SolutionDir)"
|
||||
copy "$(TargetDir)*.pdb" "$(SolutionDir)"
|
||||
copy "$(TargetDir)clr.pyd" "$(SolutionDir)"
|
||||
</PostBuildEvent>
|
||||
<PreBuildEvent>del "$(TargetDir)clr.pyd"</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
78
Pythonnet.Runtime/Python.Runtime.mdp
Normal file
78
Pythonnet.Runtime/Python.Runtime.mdp
Normal file
@ -0,0 +1,78 @@
|
||||
<Project name="Python.Runtime" fileversion="2.0" language="C#" clr-version="Net_2_0" ctype="DotNetProject">
|
||||
<Configurations active="Debug">
|
||||
<Configuration name="Debug" ctype="DotNetProjectConfiguration">
|
||||
<Output directory="./bin/Debug" assembly="Python.Runtime" />
|
||||
<Build debugmode="True" target="Library" />
|
||||
<Execution runwithwarnings="True" consolepause="False" runtime="MsNet" clr-version="Net_2_0" />
|
||||
<CodeGeneration compiler="Csc" warninglevel="4" optimize="True" unsafecodeallowed="True" generateoverflowchecks="True" mainclass="" definesymbols="PYTHON26,UCS4" generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
|
||||
</Configuration>
|
||||
<Configuration name="Release" ctype="DotNetProjectConfiguration">
|
||||
<Output directory="./bin/Release" assembly="Python.Runtime" />
|
||||
<Build debugmode="False" target="Library" />
|
||||
<Execution runwithwarnings="True" consolepause="False" runtime="MsNet" clr-version="Net_2_0" />
|
||||
<CodeGeneration compiler="Csc" warninglevel="4" optimize="True" unsafecodeallowed="True" generateoverflowchecks="True" mainclass="" definesymbols="PYTHON26,UCS4" generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<DeployTargets />
|
||||
<Contents>
|
||||
<File name="./arrayobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./assemblyinfo.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./assemblymanager.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./classbase.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./classmanager.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./classobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./clrobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./codegenerator.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./constructorbinder.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./converter.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./debughelper.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./delegatemanager.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./delegateobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./eventbinding.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./eventobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./exceptions.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./extensiontype.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./fieldobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./generictype.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./genericutil.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./importhook.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./indexer.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./interfaceobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./interfaces.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./interop.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./iterator.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./managedtype.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./metatype.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./methodbinder.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./methodbinding.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./methodobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./methodwrapper.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./modulefunctionobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./moduleobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./modulepropertyobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./monosupport.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./nativecall.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./overload.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./propertyobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pydict.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pyfloat.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pyint.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pyiter.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pylist.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pylong.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pynumber.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pyobject.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pysequence.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pystring.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pythonengine.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pythonexception.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./pytuple.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./runtime.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./typemanager.cs" subtype="Code" buildaction="Compile" />
|
||||
<File name="./typemethod.cs" subtype="Code" buildaction="Compile" />
|
||||
</Contents>
|
||||
<References>
|
||||
<ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.2, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<ProjectReference type="Gac" localcopy="True" refto="Mono.Posix, Version=2.0.0.2, Culture=neutral, PublicKeyToken=0738eb9f132ed756" />
|
||||
</References>
|
||||
</Project>
|
252
Pythonnet.Runtime/arrayobject.cs
Normal file
252
Pythonnet.Runtime/arrayobject.cs
Normal file
@ -0,0 +1,252 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Implements a Python type for managed arrays. This type is essentially
|
||||
/// the same as a ClassObject, except that it provides sequence semantics
|
||||
/// to support natural array usage (indexing) from Python.
|
||||
/// </summary>
|
||||
|
||||
internal class ArrayObject : ClassBase {
|
||||
|
||||
internal ArrayObject(Type tp) : base(tp) {}
|
||||
|
||||
internal override bool CanSubclass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
ArrayObject self = GetManagedObject(tp) as ArrayObject;
|
||||
if (Runtime.PyTuple_Size(args) != 1) {
|
||||
return Exceptions.RaiseTypeError("array expects 1 argument");
|
||||
}
|
||||
IntPtr op = Runtime.PyTuple_GetItem(args, 0);
|
||||
Object result;
|
||||
|
||||
if (!Converter.ToManaged(op, self.type, out result, true)) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
return CLRObject.GetInstHandle(result, tp);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __getitem__ for array types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) {
|
||||
CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob);
|
||||
Array items = obj.inst as Array;
|
||||
Type itemType = obj.inst.GetType().GetElementType();
|
||||
int rank = items.Rank;
|
||||
int index = 0;
|
||||
object value;
|
||||
|
||||
// Note that CLR 1.0 only supports int indexes - methods to
|
||||
// support long indices were introduced in 1.1. We could
|
||||
// support long indices automatically, but given that long
|
||||
// indices are not backward compatible and a relative edge
|
||||
// case, we won't bother for now.
|
||||
|
||||
// Single-dimensional arrays are the most common case and are
|
||||
// cheaper to deal with than multi-dimensional, so check first.
|
||||
|
||||
if (rank == 1) {
|
||||
index = (int)Runtime.PyInt_AsLong(idx);
|
||||
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
return Exceptions.RaiseTypeError("invalid index value");
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = items.Length + index;
|
||||
}
|
||||
|
||||
try {
|
||||
value = items.GetValue(index);
|
||||
}
|
||||
catch (IndexOutOfRangeException) {
|
||||
Exceptions.SetError(Exceptions.IndexError,
|
||||
"array index out of range"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return Converter.ToPython(items.GetValue(index), itemType);
|
||||
}
|
||||
|
||||
// Multi-dimensional arrays can be indexed a la: list[1, 2, 3].
|
||||
|
||||
if (!Runtime.PyTuple_Check(idx)) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"invalid index value"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
int count = Runtime.PyTuple_Size(idx);
|
||||
|
||||
Array args = Array.CreateInstance(typeof(Int32), count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntPtr op = Runtime.PyTuple_GetItem(idx, i);
|
||||
index = (int)Runtime.PyInt_AsLong(op);
|
||||
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
return Exceptions.RaiseTypeError("invalid index value");
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = items.GetLength(i) + index;
|
||||
}
|
||||
|
||||
args.SetValue(index, i);
|
||||
}
|
||||
|
||||
try {
|
||||
value = items.GetValue((int[]) args);
|
||||
}
|
||||
catch (IndexOutOfRangeException) {
|
||||
Exceptions.SetError(Exceptions.IndexError,
|
||||
"array index out of range"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return Converter.ToPython(value, itemType);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __setitem__ for array types.
|
||||
//====================================================================
|
||||
|
||||
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
|
||||
CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob);
|
||||
Array items = obj.inst as Array;
|
||||
Type itemType = obj.inst.GetType().GetElementType();
|
||||
int rank = items.Rank;
|
||||
int index = 0;
|
||||
object value;
|
||||
|
||||
if (items.IsReadOnly) {
|
||||
Exceptions.RaiseTypeError("array is read-only");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!Converter.ToManaged(v, itemType, out value, true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rank == 1) {
|
||||
index = (int)Runtime.PyInt_AsLong(idx);
|
||||
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
Exceptions.RaiseTypeError("invalid index value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = items.Length + index;
|
||||
}
|
||||
|
||||
try {
|
||||
items.SetValue(value, index);
|
||||
}
|
||||
catch (IndexOutOfRangeException) {
|
||||
Exceptions.SetError(Exceptions.IndexError,
|
||||
"array index out of range"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!Runtime.PyTuple_Check(idx)) {
|
||||
Exceptions.RaiseTypeError("invalid index value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int count = Runtime.PyTuple_Size(idx);
|
||||
|
||||
Array args = Array.CreateInstance(typeof(Int32), count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntPtr op = Runtime.PyTuple_GetItem(idx, i);
|
||||
index = (int)Runtime.PyInt_AsLong(op);
|
||||
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
Exceptions.RaiseTypeError("invalid index value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
index = items.GetLength(i) + index;
|
||||
}
|
||||
|
||||
args.SetValue(index, i);
|
||||
}
|
||||
|
||||
try {
|
||||
items.SetValue(value, (int[])args);
|
||||
}
|
||||
catch (IndexOutOfRangeException) {
|
||||
Exceptions.SetError(Exceptions.IndexError,
|
||||
"array index out of range"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __contains__ for array types.
|
||||
//====================================================================
|
||||
|
||||
public static int sq_contains(IntPtr ob, IntPtr v) {
|
||||
CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob);
|
||||
Type itemType = obj.inst.GetType().GetElementType();
|
||||
IList items = obj.inst as IList;
|
||||
object value;
|
||||
|
||||
if (!Converter.ToManaged(v, itemType, out value, false)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (items.Contains(value)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __len__ for array types.
|
||||
//====================================================================
|
||||
|
||||
public static int mp_length(IntPtr ob) {
|
||||
CLRObject self = (CLRObject)ManagedType.GetManagedObject(ob);
|
||||
Array items = self.inst as Array;
|
||||
return items.Length;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
48
Pythonnet.Runtime/assemblyinfo.cs
Normal file
48
Pythonnet.Runtime/assemblyinfo.cs
Normal file
@ -0,0 +1,48 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Security.Permissions;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Resources;
|
||||
|
||||
[assembly: System.Reflection.AssemblyProduct("Python for .NET")]
|
||||
[assembly: System.Reflection.AssemblyVersion("2.0.0.2")]
|
||||
[assembly: AssemblyDefaultAliasAttribute("Python.Runtime.dll")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
|
||||
[assembly:PermissionSetAttribute(SecurityAction.RequestMinimum,
|
||||
Name = "FullTrust")]
|
||||
[assembly: AssemblyCopyrightAttribute("Zope Public License, Version 2.0 (ZPL)")]
|
||||
[assembly: AssemblyFileVersionAttribute("2.0.0.2")]
|
||||
[assembly: NeutralResourcesLanguageAttribute("en")]
|
||||
|
||||
#if (PYTHON23)
|
||||
[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.3")]
|
||||
[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.3")]
|
||||
#endif
|
||||
#if (PYTHON24)
|
||||
[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.4")]
|
||||
[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.4")]
|
||||
#endif
|
||||
#if (PYTHON25)
|
||||
[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.5")]
|
||||
[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.5")]
|
||||
#endif
|
||||
#if (PYTHON26)
|
||||
[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.6")]
|
||||
[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.6")]
|
||||
#endif
|
||||
#if (PYTHON27)
|
||||
[assembly: AssemblyTitle("Python.Runtime for Python 2.7")]
|
||||
[assembly: AssemblyDescription("Python Runtime for Python 2.7")]
|
||||
#endif
|
376
Pythonnet.Runtime/assemblymanager.cs
Normal file
376
Pythonnet.Runtime/assemblymanager.cs
Normal file
@ -0,0 +1,376 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// The AssemblyManager maintains information about loaded assemblies
|
||||
/// namespaces and provides an interface for name-based type lookup.
|
||||
/// </summary>
|
||||
|
||||
internal class AssemblyManager {
|
||||
|
||||
static Dictionary<string, Dictionary<Assembly, string>> namespaces;
|
||||
//static Dictionary<string, Dictionary<string, string>> generics;
|
||||
static AssemblyLoadEventHandler lhandler;
|
||||
static ResolveEventHandler rhandler;
|
||||
static Dictionary<string, int> probed;
|
||||
static List<Assembly> assemblies;
|
||||
internal static List<string> pypath;
|
||||
|
||||
private AssemblyManager() {}
|
||||
|
||||
//===================================================================
|
||||
// Initialization performed on startup of the Python runtime. Here we
|
||||
// scan all of the currently loaded assemblies to determine exported
|
||||
// names, and register to be notified of new assembly loads.
|
||||
//===================================================================
|
||||
|
||||
internal static void Initialize() {
|
||||
namespaces = new
|
||||
Dictionary<string, Dictionary<Assembly, string>>(32);
|
||||
probed = new Dictionary<string, int>(32);
|
||||
//generics = new Dictionary<string, Dictionary<string, string>>();
|
||||
assemblies = new List<Assembly>(16);
|
||||
pypath = new List<string>(16);
|
||||
|
||||
AppDomain domain = AppDomain.CurrentDomain;
|
||||
|
||||
lhandler = new AssemblyLoadEventHandler(AssemblyLoadHandler);
|
||||
domain.AssemblyLoad += lhandler;
|
||||
|
||||
rhandler = new ResolveEventHandler(ResolveHandler);
|
||||
domain.AssemblyResolve += rhandler;
|
||||
|
||||
Assembly[] items = domain.GetAssemblies();
|
||||
for (int i = 0; i < items.Length; i++) {
|
||||
Assembly a = items[i];
|
||||
assemblies.Add(a);
|
||||
ScanAssembly(a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Cleanup resources upon shutdown of the Python runtime.
|
||||
//===================================================================
|
||||
|
||||
internal static void Shutdown() {
|
||||
AppDomain domain = AppDomain.CurrentDomain;
|
||||
domain.AssemblyLoad -= lhandler;
|
||||
domain.AssemblyResolve -= rhandler;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Event handler for assembly load events. At the time the Python
|
||||
// runtime loads, we scan the app domain to map the assemblies that
|
||||
// are loaded at the time. We also have to register this event handler
|
||||
// so that we can know about assemblies that get loaded after the
|
||||
// Python runtime is initialized.
|
||||
//===================================================================
|
||||
|
||||
static void AssemblyLoadHandler(Object ob, AssemblyLoadEventArgs args){
|
||||
Assembly assembly = args.LoadedAssembly;
|
||||
assemblies.Add(assembly);
|
||||
ScanAssembly(assembly);
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Event handler for assembly resolve events. This is needed because
|
||||
// we augment the assembly search path with the PYTHONPATH when we
|
||||
// load an assembly from Python. Because of that, we need to listen
|
||||
// for failed loads, because they might be dependencies of something
|
||||
// we loaded from Python which also needs to be found on PYTHONPATH.
|
||||
//===================================================================
|
||||
|
||||
static Assembly ResolveHandler(Object ob, ResolveEventArgs args){
|
||||
string name = args.Name.ToLower();
|
||||
for (int i = 0; i < assemblies.Count; i++) {
|
||||
Assembly a = (Assembly)assemblies[i];
|
||||
string full = a.FullName.ToLower();
|
||||
if (full.StartsWith(name)) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return LoadAssemblyPath(args.Name);
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// We __really__ want to avoid using Python objects or APIs when
|
||||
// probing for assemblies to load, since our ResolveHandler may be
|
||||
// called in contexts where we don't have the Python GIL and can't
|
||||
// even safely try to get it without risking a deadlock ;(
|
||||
//
|
||||
// To work around that, we update a managed copy of sys.path (which
|
||||
// is the main thing we care about) when UpdatePath is called. The
|
||||
// import hook calls this whenever it knows its about to use the
|
||||
// assembly manager, which lets us keep up with changes to sys.path
|
||||
// in a relatively lightweight and low-overhead way.
|
||||
//===================================================================
|
||||
|
||||
internal static void UpdatePath() {
|
||||
IntPtr list = Runtime.PySys_GetObject("path");
|
||||
int count = Runtime.PyList_Size(list);
|
||||
if (count != pypath.Count) {
|
||||
pypath.Clear();
|
||||
probed.Clear();
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntPtr item = Runtime.PyList_GetItem(list, i);
|
||||
string path = Runtime.GetManagedString(item);
|
||||
if (path != null) {
|
||||
pypath.Add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Given an assembly name, try to find this assembly file using the
|
||||
// PYTHONPATH. If not found, return null to indicate implicit load
|
||||
// using standard load semantics (app base directory then GAC, etc.)
|
||||
//===================================================================
|
||||
|
||||
public static string FindAssembly(string name) {
|
||||
char sep = Path.DirectorySeparatorChar;
|
||||
string path;
|
||||
string temp;
|
||||
|
||||
for (int i = 0; i < pypath.Count; i++) {
|
||||
string head = pypath[i];
|
||||
if (head == null || head.Length == 0) {
|
||||
path = name;
|
||||
}
|
||||
else {
|
||||
path = head + sep + name;
|
||||
}
|
||||
|
||||
temp = path + ".dll";
|
||||
if (File.Exists(temp)) {
|
||||
return temp;
|
||||
}
|
||||
temp = path + ".exe";
|
||||
if (File.Exists(temp)) {
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Loads an assembly from the application directory or the GAC
|
||||
// given a simple assembly name. Returns the assembly if loaded.
|
||||
//===================================================================
|
||||
|
||||
public static Assembly LoadAssembly(string name) {
|
||||
Assembly assembly = null;
|
||||
try {
|
||||
assembly = Assembly.Load(name);
|
||||
}
|
||||
catch { }
|
||||
return assembly;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Loads an assembly using an augmented search path (the python path).
|
||||
//===================================================================
|
||||
|
||||
public static Assembly LoadAssemblyPath(string name) {
|
||||
string path = FindAssembly(name);
|
||||
Assembly assembly = null;
|
||||
if (path != null) {
|
||||
try { assembly = Assembly.LoadFrom(path); }
|
||||
catch {}
|
||||
}
|
||||
return assembly;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Given a qualified name of the form A.B.C.D, attempt to load
|
||||
// an assembly named after each of A.B.C.D, A.B.C, A.B, A. This
|
||||
// will only actually probe for the assembly once for each unique
|
||||
// namespace. Returns true if any assemblies were loaded.
|
||||
// TODO item 3 "* Deprecate implicit loading of assemblies":
|
||||
// Set the fromFile flag if the name of the loaded assembly matches
|
||||
// the fully qualified name that was requested if the framework
|
||||
// actually loads an assembly.
|
||||
// Call ONLY for namespaces that HAVE NOT been cached yet.
|
||||
//===================================================================
|
||||
|
||||
public static bool LoadImplicit(string name, out bool fromFile) {
|
||||
// 2010-08-16: Deprecation support
|
||||
// Added out param to detect fully qualified name load
|
||||
fromFile = false;
|
||||
string[] names = name.Split('.');
|
||||
bool loaded = false;
|
||||
string s = "";
|
||||
for (int i = 0; i < names.Length; i++) {
|
||||
s = (i == 0) ? names[0] : s + "." + names[i];
|
||||
if (!probed.ContainsKey(s)) {
|
||||
if (LoadAssemblyPath(s) != null) {
|
||||
loaded = true;
|
||||
/* 2010-08-16: Deprecation support */
|
||||
if (s == name) {
|
||||
fromFile = true;
|
||||
}
|
||||
}
|
||||
else if (LoadAssembly(s) != null) {
|
||||
loaded = true;
|
||||
/* 2010-08-16: Deprecation support */
|
||||
if (s == name) {
|
||||
fromFile = true;
|
||||
}
|
||||
}
|
||||
probed[s] = 1;
|
||||
// 2010-12-24: Deprecation logic
|
||||
/* if (loaded && (s == name)) {
|
||||
fromFile = true;
|
||||
break;
|
||||
} */
|
||||
}
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Scans an assembly for exported namespaces, adding them to the
|
||||
// mapping of valid namespaces. Note that for a given namespace
|
||||
// a.b.c.d, each of a, a.b, a.b.c and a.b.c.d are considered to
|
||||
// be valid namespaces (to better match Python import semantics).
|
||||
//===================================================================
|
||||
|
||||
static void ScanAssembly(Assembly assembly) {
|
||||
|
||||
// A couple of things we want to do here: first, we want to
|
||||
// gather a list of all of the namespaces contributed to by
|
||||
// the assembly.
|
||||
|
||||
Type[] types = assembly.GetTypes();
|
||||
for (int i = 0; i < types.Length; i++) {
|
||||
Type t = types[i];
|
||||
string ns = t.Namespace;
|
||||
if ((ns != null) && (!namespaces.ContainsKey(ns))) {
|
||||
string[] names = ns.Split('.');
|
||||
string s = "";
|
||||
for (int n = 0; n < names.Length; n++) {
|
||||
s = (n == 0) ? names[0] : s + "." + names[n];
|
||||
if (!namespaces.ContainsKey(s)) {
|
||||
namespaces.Add(s,
|
||||
new Dictionary<Assembly, string>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ns != null && !namespaces[ns].ContainsKey(assembly)) {
|
||||
namespaces[ns].Add(assembly, String.Empty);
|
||||
}
|
||||
|
||||
if (t.IsGenericTypeDefinition) {
|
||||
GenericUtil.Register(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static AssemblyName[] ListAssemblies()
|
||||
{
|
||||
AssemblyName[] names = new AssemblyName[assemblies.Count];
|
||||
Assembly assembly;
|
||||
for (int i=0; i < assemblies.Count; i++)
|
||||
{
|
||||
assembly = assemblies[i];
|
||||
names.SetValue(assembly.GetName(), i);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Returns true if the given qualified name matches a namespace
|
||||
// exported by an assembly loaded in the current app domain.
|
||||
//===================================================================
|
||||
|
||||
public static bool IsValidNamespace(string name) {
|
||||
return namespaces.ContainsKey(name);
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Returns the current list of valid names for the input namespace.
|
||||
//===================================================================
|
||||
|
||||
public static List<string> GetNames(string nsname) {
|
||||
//Dictionary<string, int> seen = new Dictionary<string, int>();
|
||||
List<string> names = new List<string>(8);
|
||||
|
||||
List<string> g = GenericUtil.GetGenericBaseNames(nsname);
|
||||
if (g != null) {
|
||||
foreach (string n in g) {
|
||||
names.Add(n);
|
||||
}
|
||||
}
|
||||
|
||||
if (namespaces.ContainsKey(nsname)) {
|
||||
foreach (Assembly a in namespaces[nsname].Keys) {
|
||||
Type[] types = a.GetTypes();
|
||||
for (int i = 0; i < types.Length; i++) {
|
||||
Type t = types[i];
|
||||
if (t.Namespace == nsname) {
|
||||
names.Add(t.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
int nslen = nsname.Length;
|
||||
foreach (string key in namespaces.Keys) {
|
||||
if (key.Length > nslen && key.StartsWith(nsname)) {
|
||||
//string tail = key.Substring(nslen);
|
||||
if (key.IndexOf('.') == -1) {
|
||||
names.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Returns the System.Type object for a given qualified name,
|
||||
// looking in the currently loaded assemblies for the named
|
||||
// type. Returns null if the named type cannot be found.
|
||||
//===================================================================
|
||||
|
||||
public static Type LookupType(string qname) {
|
||||
for (int i = 0; i < assemblies.Count; i++) {
|
||||
Assembly assembly = (Assembly)assemblies[i];
|
||||
Type type = assembly.GetType(qname);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
36
Pythonnet.Runtime/buildclrmodule.bat
Normal file
36
Pythonnet.Runtime/buildclrmodule.bat
Normal file
@ -0,0 +1,36 @@
|
||||
:: Call with buildclrmodule.bat <AnyCPU|x64> <INPUT_DIRECTORY> <OUTPUT_PATH>
|
||||
|
||||
@echo off
|
||||
|
||||
set TARGET_PLATFORM=%1
|
||||
set INPUT_DIRECTORY=%~2
|
||||
set INPUT_PATH="%INPUT_DIRECTORY%\clrmodule.il"
|
||||
set OUTPUT_PATH=%3
|
||||
|
||||
if %TARGET_PLATFORM%==AnyCPU goto SETUP32
|
||||
if %TARGET_PLATFORM%==x64 goto SETUP64
|
||||
goto ERROR_BAD_PLATFORM
|
||||
|
||||
:SETUP32
|
||||
set INCLUDE_PATH="%INPUT_DIRECTORY%\x86"
|
||||
goto BUILD_CLR_MODULE
|
||||
|
||||
:SETUP64
|
||||
set INCLUDE_PATH="%INPUT_DIRECTORY%\x64"
|
||||
set ILASM_EXTRA_ARGS=/pe64 /x64
|
||||
goto BUILD_CLR_MODULE
|
||||
|
||||
:ERROR_BAD_PLATFORM
|
||||
echo Unknown target platform: %TARGET_PLATFORM%
|
||||
exit /b 1
|
||||
|
||||
:ERROR_MISSING_INPUT
|
||||
echo Can't find input file: %INPUT_PATH%
|
||||
exit /b 1
|
||||
|
||||
:BUILD_CLR_MODULE
|
||||
if not exist %INPUT_PATH% goto ERROR_MISSING_INPUT
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\ilasm /nologo /quiet /dll %ILASM_EXTRA_ARGS% /include=%INCLUDE_PATH% /output=%OUTPUT_PATH% %INPUT_PATH%
|
||||
|
||||
::: 2.0
|
||||
:::%windir%\Microsoft.NET\Framework\v2.0.50727\ilasm /nologo /quiet /dll %ILASM_EXTRA_ARGS% /include=%INCLUDE_PATH% /output=%OUTPUT_PATH% %INPUT_PATH%
|
170
Pythonnet.Runtime/classbase.cs
Normal file
170
Pythonnet.Runtime/classbase.cs
Normal file
@ -0,0 +1,170 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Base class for Python types that reflect managed types / classes.
|
||||
/// Concrete subclasses include ClassObject and DelegateObject. This
|
||||
/// class provides common attributes and common machinery for doing
|
||||
/// class initialization (initialization of the class __dict__). The
|
||||
/// concrete subclasses provide slot implementations appropriate for
|
||||
/// each variety of reflected type.
|
||||
/// </summary>
|
||||
|
||||
internal class ClassBase : ManagedType {
|
||||
|
||||
internal Indexer indexer;
|
||||
internal Type type;
|
||||
|
||||
internal ClassBase(Type tp) : base() {
|
||||
indexer = null;
|
||||
type = tp;
|
||||
}
|
||||
|
||||
internal virtual bool CanSubclass() {
|
||||
return (!this.type.IsEnum);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Implements __init__ for reflected classes and value types.
|
||||
//====================================================================
|
||||
|
||||
public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Default implementation of [] semantics for reflected types.
|
||||
//====================================================================
|
||||
|
||||
public virtual IntPtr type_subscript(IntPtr idx) {
|
||||
return Exceptions.RaiseTypeError("unsubscriptable object");
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Standard comparison implementation for instances of reflected types.
|
||||
//====================================================================
|
||||
|
||||
public static int tp_compare(IntPtr ob, IntPtr other) {
|
||||
if (ob == other) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CLRObject co1 = GetManagedObject(ob) as CLRObject;
|
||||
CLRObject co2 = GetManagedObject(other) as CLRObject;
|
||||
Object o1 = co1.inst;
|
||||
Object o2 = co2.inst;
|
||||
|
||||
if (Object.Equals(o1, o2)) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Standard iteration support for instances of reflected types. This
|
||||
// allows natural iteration over objects that either are IEnumerable
|
||||
// or themselves support IEnumerator directly.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_iter(IntPtr ob) {
|
||||
CLRObject co = GetManagedObject(ob) as CLRObject;
|
||||
if (co == null) {
|
||||
return Exceptions.RaiseTypeError("invalid object");
|
||||
}
|
||||
|
||||
IEnumerable e = co.inst as IEnumerable;
|
||||
IEnumerator o;
|
||||
|
||||
if (e != null) {
|
||||
o = e.GetEnumerator();
|
||||
}
|
||||
else {
|
||||
o = co.inst as IEnumerator;
|
||||
|
||||
if (o == null) {
|
||||
string message = "iteration over non-sequence";
|
||||
return Exceptions.RaiseTypeError(message);
|
||||
}
|
||||
}
|
||||
|
||||
return new Iterator(o).pyHandle;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Standard __hash__ implementation for instances of reflected types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_hash(IntPtr ob) {
|
||||
CLRObject co = GetManagedObject(ob) as CLRObject;
|
||||
if (co == null) {
|
||||
return Exceptions.RaiseTypeError("unhashable type");
|
||||
}
|
||||
return new IntPtr(co.inst.GetHashCode());
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Standard __str__ implementation for instances of reflected types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_str(IntPtr ob) {
|
||||
CLRObject co = GetManagedObject(ob) as CLRObject;
|
||||
if (co == null) {
|
||||
return Exceptions.RaiseTypeError("invalid object");
|
||||
}
|
||||
return Runtime.PyString_FromString(co.inst.ToString());
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Default implementations for required Python GC support.
|
||||
//====================================================================
|
||||
|
||||
public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int tp_clear(IntPtr ob) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int tp_is_gc(IntPtr type) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Standard dealloc implementation for instances of reflected types.
|
||||
//====================================================================
|
||||
|
||||
public static void tp_dealloc(IntPtr ob) {
|
||||
ManagedType self = GetManagedObject(ob);
|
||||
IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.ob_dict);
|
||||
if (dict != IntPtr.Zero) {
|
||||
Runtime.Decref(dict);
|
||||
}
|
||||
Runtime.PyObject_GC_UnTrack(self.pyHandle);
|
||||
Runtime.PyObject_GC_Del(self.pyHandle);
|
||||
Runtime.Decref(self.tpHandle);
|
||||
self.gcHandle.Free();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
368
Pythonnet.Runtime/classmanager.cs
Normal file
368
Pythonnet.Runtime/classmanager.cs
Normal file
@ -0,0 +1,368 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// The ClassManager is responsible for creating and managing instances
|
||||
/// that implement the Python type objects that reflect managed classes.
|
||||
///
|
||||
/// Each managed type reflected to Python is represented by an instance
|
||||
/// of a concrete subclass of ClassBase. Each instance is associated with
|
||||
/// a generated Python type object, whose slots point to static methods
|
||||
/// of the managed instance's class.
|
||||
/// </summary>
|
||||
|
||||
internal class ClassManager {
|
||||
|
||||
static Dictionary<Type, ClassBase> cache;
|
||||
static Type dtype;
|
||||
|
||||
private ClassManager() {}
|
||||
|
||||
static ClassManager() {
|
||||
cache = new Dictionary<Type, ClassBase>(128);
|
||||
// SEE: http://msdn.microsoft.com/en-us/library/96b1ayy4%28VS.90%29.aspx
|
||||
// ""All delegates inherit from MulticastDelegate, which inherits from Delegate.""
|
||||
// Was Delegate, which caused a null MethodInfo returned from GetMethode("Invoke")
|
||||
// and crashed on Linux under Mono.
|
||||
dtype = typeof(System.MulticastDelegate);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Return the ClassBase-derived instance that implements a particular
|
||||
// reflected managed type, creating it if it doesn't yet exist.
|
||||
//====================================================================
|
||||
|
||||
internal static ClassBase GetClass(Type type) {
|
||||
ClassBase cb = null;
|
||||
cache.TryGetValue(type, out cb);
|
||||
if (cb != null) {
|
||||
return cb;
|
||||
}
|
||||
cb = CreateClass(type);
|
||||
cache.Add(type, cb);
|
||||
return cb;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Create a new ClassBase-derived instance that implements a reflected
|
||||
// managed type. The new object will be associated with a generated
|
||||
// Python type object.
|
||||
//====================================================================
|
||||
|
||||
private static ClassBase CreateClass(Type type) {
|
||||
|
||||
// First, we introspect the managed type and build some class
|
||||
// information, including generating the member descriptors
|
||||
// that we'll be putting in the Python class __dict__.
|
||||
|
||||
ClassInfo info = GetClassInfo(type);
|
||||
|
||||
// Next, select the appropriate managed implementation class.
|
||||
// Different kinds of types, such as array types or interface
|
||||
// types, want to vary certain implementation details to make
|
||||
// sure that the type semantics are consistent in Python.
|
||||
|
||||
ClassBase impl;
|
||||
|
||||
// Check to see if the given type extends System.Exception. This
|
||||
// lets us check once (vs. on every lookup) in case we need to
|
||||
// wrap Exception-derived types in old-style classes
|
||||
|
||||
if (type.ContainsGenericParameters) {
|
||||
impl = new GenericType(type);
|
||||
}
|
||||
|
||||
else if (type.IsSubclassOf(dtype)) {
|
||||
impl = new DelegateObject(type);
|
||||
}
|
||||
|
||||
else if (type.IsArray) {
|
||||
impl = new ArrayObject(type);
|
||||
}
|
||||
|
||||
else if (type.IsInterface) {
|
||||
impl = new InterfaceObject(type);
|
||||
}
|
||||
|
||||
else if (type == typeof(Exception) ||
|
||||
type.IsSubclassOf(typeof(Exception))) {
|
||||
impl = new ExceptionClassObject(type);
|
||||
}
|
||||
|
||||
else {
|
||||
impl = new ClassObject(type);
|
||||
}
|
||||
|
||||
impl.indexer = info.indexer;
|
||||
|
||||
// Now we allocate the Python type object to reflect the given
|
||||
// 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;
|
||||
|
||||
// Finally, initialize the class __dict__ and return the object.
|
||||
IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict);
|
||||
|
||||
|
||||
IDictionaryEnumerator iter = info.members.GetEnumerator();
|
||||
while(iter.MoveNext()) {
|
||||
ManagedType item = (ManagedType)iter.Value;
|
||||
string name = (string)iter.Key;
|
||||
Runtime.PyDict_SetItemString(dict, name, item.pyHandle);
|
||||
}
|
||||
|
||||
// If class has constructors, generate an __doc__ attribute.
|
||||
|
||||
IntPtr doc;
|
||||
Type marker = typeof(DocStringAttribute);
|
||||
Attribute[] attrs = (Attribute[])type.GetCustomAttributes(marker, false);
|
||||
if (attrs.Length == 0) {
|
||||
doc = IntPtr.Zero;
|
||||
}
|
||||
else {
|
||||
DocStringAttribute attr = (DocStringAttribute)attrs[0];
|
||||
string docStr = attr.DocString;
|
||||
doc = Runtime.PyString_FromString(docStr);
|
||||
Runtime.PyDict_SetItemString(dict, "__doc__", doc);
|
||||
Runtime.Decref(doc);
|
||||
}
|
||||
|
||||
ClassObject co = impl as ClassObject;
|
||||
// If this is a ClassObject AND it has constructors, generate a __doc__ attribute.
|
||||
// required that the ClassObject.ctors be changed to internal
|
||||
if (co != null) {
|
||||
if (co.ctors.Length > 0) {
|
||||
// Implement Overloads on the class object
|
||||
ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder);
|
||||
// ExtensionType types are untracked, so don't Incref() them.
|
||||
// XXX deprecate __overloads__ soon...
|
||||
Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle);
|
||||
Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle);
|
||||
|
||||
if (doc == IntPtr.Zero) {
|
||||
doc = co.GetDocString();
|
||||
Runtime.PyDict_SetItemString(dict, "__doc__", doc);
|
||||
Runtime.Decref(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static ClassInfo GetClassInfo(Type type) {
|
||||
ClassInfo ci = new ClassInfo(type);
|
||||
Hashtable methods = new Hashtable();
|
||||
ArrayList list;
|
||||
MethodInfo meth;
|
||||
ManagedType ob;
|
||||
String name;
|
||||
Object item;
|
||||
Type tp;
|
||||
int i, n;
|
||||
|
||||
// This is complicated because inheritance in Python is name
|
||||
// based. We can't just find DeclaredOnly members, because we
|
||||
// could have a base class A that defines two overloads of a
|
||||
// method and a class B that defines two more. The name-based
|
||||
// descriptor Python will find needs to know about inherited
|
||||
// overloads as well as those declared on the sub class.
|
||||
|
||||
BindingFlags flags = BindingFlags.Static |
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Public |
|
||||
BindingFlags.NonPublic;
|
||||
|
||||
MemberInfo[] info = type.GetMembers(flags);
|
||||
Hashtable local = new Hashtable();
|
||||
ArrayList items = new ArrayList();
|
||||
MemberInfo m;
|
||||
|
||||
// Loop through once to find out which names are declared
|
||||
for (i = 0; i < info.Length; i++) {
|
||||
m = info[i];
|
||||
if (m.DeclaringType == type) {
|
||||
local[m.Name] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Now again to filter w/o losing overloaded member info
|
||||
for (i = 0; i < info.Length; i++) {
|
||||
m = info[i];
|
||||
if (local[m.Name] != null) {
|
||||
items.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.IsInterface) {
|
||||
// Interface inheritance seems to be a different animal:
|
||||
// more contractual, less structural. Thus, a Type that
|
||||
// represents an interface that inherits from another
|
||||
// interface does not return the inherited interface's
|
||||
// methods in GetMembers. For example ICollection inherits
|
||||
// from IEnumerable, but ICollection's GetMemebers does not
|
||||
// return GetEnumerator.
|
||||
//
|
||||
// Not sure if this is the correct way to fix this, but it
|
||||
// seems to work. Thanks to Bruce Dodson for the fix.
|
||||
|
||||
Type[] inheritedInterfaces = type.GetInterfaces();
|
||||
|
||||
for (i = 0; i < inheritedInterfaces.Length; ++i) {
|
||||
Type inheritedType = inheritedInterfaces[i];
|
||||
MemberInfo[] imembers = inheritedType.GetMembers(flags);
|
||||
for (n = 0; n < imembers.Length; n++) {
|
||||
m = imembers[n];
|
||||
if (local[m.Name] == null) {
|
||||
items.Add(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < items.Count; i++) {
|
||||
|
||||
MemberInfo mi = (MemberInfo)items[i];
|
||||
|
||||
switch(mi.MemberType) {
|
||||
|
||||
case MemberTypes.Method:
|
||||
meth = (MethodInfo) mi;
|
||||
if (!(meth.IsPublic || meth.IsFamily ||
|
||||
meth.IsFamilyOrAssembly))
|
||||
continue;
|
||||
name = meth.Name;
|
||||
item = methods[name];
|
||||
if (item == null) {
|
||||
item = methods[name] = new ArrayList();
|
||||
}
|
||||
list = (ArrayList) item;
|
||||
list.Add(meth);
|
||||
continue;
|
||||
|
||||
case MemberTypes.Property:
|
||||
PropertyInfo pi = (PropertyInfo) mi;
|
||||
|
||||
MethodInfo mm = null;
|
||||
try {
|
||||
mm = pi.GetGetMethod(true);
|
||||
if (mm == null) {
|
||||
mm = pi.GetSetMethod(true);
|
||||
}
|
||||
}
|
||||
catch (SecurityException) {
|
||||
// GetGetMethod may try to get a method protected by
|
||||
// StrongNameIdentityPermission - effectively private.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mm == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(mm.IsPublic || mm.IsFamily || mm.IsFamilyOrAssembly))
|
||||
continue;
|
||||
|
||||
// Check for indexer
|
||||
ParameterInfo[] args = pi.GetIndexParameters();
|
||||
if (args.GetLength(0) > 0) {
|
||||
Indexer idx = ci.indexer;
|
||||
if (idx == null) {
|
||||
ci.indexer = new Indexer();
|
||||
idx = ci.indexer;
|
||||
}
|
||||
idx.AddProperty(pi);
|
||||
continue;
|
||||
}
|
||||
|
||||
ob = new PropertyObject(pi);
|
||||
ci.members[pi.Name] = ob;
|
||||
continue;
|
||||
|
||||
case MemberTypes.Field:
|
||||
FieldInfo fi = (FieldInfo) mi;
|
||||
if (!(fi.IsPublic || fi.IsFamily || fi.IsFamilyOrAssembly))
|
||||
continue;
|
||||
ob = new FieldObject(fi);
|
||||
ci.members[mi.Name] = ob;
|
||||
continue;
|
||||
|
||||
case MemberTypes.Event:
|
||||
EventInfo ei = (EventInfo)mi;
|
||||
MethodInfo me = ei.GetAddMethod(true);
|
||||
if (!(me.IsPublic || me.IsFamily || me.IsFamilyOrAssembly))
|
||||
continue;
|
||||
ob = new EventObject(ei);
|
||||
ci.members[ei.Name] = ob;
|
||||
continue;
|
||||
|
||||
case MemberTypes.NestedType:
|
||||
tp = (Type) mi;
|
||||
if (!(tp.IsNestedPublic || tp.IsNestedFamily ||
|
||||
tp.IsNestedFamORAssem))
|
||||
continue;
|
||||
ob = ClassManager.GetClass(tp);
|
||||
ci.members[mi.Name] = ob;
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
IDictionaryEnumerator iter = methods.GetEnumerator();
|
||||
|
||||
while(iter.MoveNext()) {
|
||||
name = (string) iter.Key;
|
||||
list = (ArrayList) iter.Value;
|
||||
|
||||
MethodInfo[] mlist = (MethodInfo[])list.ToArray(
|
||||
typeof(MethodInfo)
|
||||
);
|
||||
|
||||
ob = new MethodObject(name, mlist);
|
||||
ci.members[name] = ob;
|
||||
}
|
||||
|
||||
return ci;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
internal class ClassInfo {
|
||||
|
||||
internal ClassInfo(Type t) {
|
||||
members = new Hashtable();
|
||||
indexer = null;
|
||||
}
|
||||
|
||||
public Hashtable members;
|
||||
public Indexer indexer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
299
Pythonnet.Runtime/classobject.cs
Normal file
299
Pythonnet.Runtime/classobject.cs
Normal file
@ -0,0 +1,299 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Managed class that provides the implementation for reflected types.
|
||||
/// Managed classes and value types are represented in Python by actual
|
||||
/// Python type objects. Each of those type objects is associated with
|
||||
/// an instance of ClassObject, which provides its implementation.
|
||||
/// </summary>
|
||||
|
||||
internal class ClassObject : ClassBase {
|
||||
|
||||
internal ConstructorBinder binder;
|
||||
internal ConstructorInfo[] ctors;
|
||||
|
||||
internal ClassObject(Type tp) : base(tp) {
|
||||
ctors = type.GetConstructors();
|
||||
binder = new ConstructorBinder();
|
||||
|
||||
for (int i = 0; i < ctors.Length; i++) {
|
||||
binder.AddMethod(ctors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Helper to get docstring from reflected constructor info.
|
||||
//====================================================================
|
||||
|
||||
internal IntPtr GetDocString() {
|
||||
MethodBase[] methods = binder.GetMethods();
|
||||
string str = "";
|
||||
for (int i = 0; i < methods.Length; i++) {
|
||||
if (str.Length > 0)
|
||||
str += Environment.NewLine;
|
||||
str += methods[i].ToString();
|
||||
}
|
||||
return Runtime.PyString_FromString(str);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __new__ for reflected classes and value types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
|
||||
ClassObject self = GetManagedObject(tp) as ClassObject;
|
||||
|
||||
// Sanity check: this ensures a graceful error if someone does
|
||||
// something intentially wrong like use the managed metatype for
|
||||
// a class that is not really derived from a managed class.
|
||||
|
||||
if (self == null) {
|
||||
return Exceptions.RaiseTypeError("invalid object");
|
||||
}
|
||||
|
||||
Type type = self.type;
|
||||
|
||||
// Primitive types do not have constructors, but they look like
|
||||
// they do from Python. If the ClassObject represents one of the
|
||||
// convertible primitive types, just convert the arg directly.
|
||||
|
||||
if (type.IsPrimitive || type == typeof(String)) {
|
||||
if (Runtime.PyTuple_Size(args) != 1) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"no constructors match given arguments"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
IntPtr op = Runtime.PyTuple_GetItem(args, 0);
|
||||
Object result;
|
||||
|
||||
if (!Converter.ToManaged(op, type, out result, true)) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return CLRObject.GetInstHandle(result, tp);
|
||||
}
|
||||
|
||||
if (type.IsAbstract) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"cannot instantiate abstract class"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (type.IsEnum) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"cannot instantiate enumeration"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw);
|
||||
if (obj == null) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return CLRObject.GetInstHandle(obj, tp);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implementation of [] semantics for reflected types. This exists
|
||||
// both to implement the Array[int] syntax for creating arrays and
|
||||
// to support generic name overload resolution using [].
|
||||
//====================================================================
|
||||
|
||||
public override IntPtr type_subscript(IntPtr idx) {
|
||||
|
||||
// If this type is the Array type, the [<type>] means we need to
|
||||
// construct and return an array type of the given element type.
|
||||
|
||||
if ((this.type) == typeof(Array)) {
|
||||
if (Runtime.PyTuple_Check(idx)) {
|
||||
return Exceptions.RaiseTypeError("type expected");
|
||||
}
|
||||
ClassBase c = GetManagedObject(idx) as ClassBase;
|
||||
Type t = (c != null) ? c.type : Converter.GetTypeByAlias(idx);
|
||||
if (t == null) {
|
||||
return Exceptions.RaiseTypeError("type expected");
|
||||
}
|
||||
Type a = t.MakeArrayType();
|
||||
ClassBase o = ClassManager.GetClass(a);
|
||||
Runtime.Incref(o.pyHandle);
|
||||
return o.pyHandle;
|
||||
}
|
||||
|
||||
// If there are generics in our namespace with the same base name
|
||||
// as the current type, then [<type>] means the caller wants to
|
||||
// bind the generic type matching the given type parameters.
|
||||
|
||||
Type[] types = Runtime.PythonArgsToTypeArray(idx);
|
||||
if (types == null) {
|
||||
return Exceptions.RaiseTypeError("type(s) expected");
|
||||
}
|
||||
|
||||
string gname = this.type.FullName + "`" + types.Length.ToString();
|
||||
Type gtype = AssemblyManager.LookupType(gname);
|
||||
if (gtype != null) {
|
||||
GenericType g = ClassManager.GetClass(gtype) as GenericType;
|
||||
return g.type_subscript(idx);
|
||||
/*Runtime.Incref(g.pyHandle);
|
||||
return g.pyHandle;*/
|
||||
}
|
||||
return Exceptions.RaiseTypeError("unsubscriptable object");
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __getitem__ for reflected classes and value types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) {
|
||||
//ManagedType self = GetManagedObject(ob);
|
||||
IntPtr tp = Runtime.PyObject_TYPE(ob);
|
||||
ClassBase cls = (ClassBase)GetManagedObject(tp);
|
||||
|
||||
if (cls.indexer == null || !cls.indexer.CanGet) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"unindexable object"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// Arg may be a tuple in the case of an indexer with multiple
|
||||
// parameters. If so, use it directly, else make a new tuple
|
||||
// with the index arg (method binders expect arg tuples).
|
||||
|
||||
IntPtr args = idx;
|
||||
bool free = false;
|
||||
|
||||
if (!Runtime.PyTuple_Check(idx)) {
|
||||
args = Runtime.PyTuple_New(1);
|
||||
Runtime.Incref(idx);
|
||||
Runtime.PyTuple_SetItem(args, 0, idx);
|
||||
free = true;
|
||||
}
|
||||
|
||||
IntPtr value = IntPtr.Zero;
|
||||
|
||||
try {
|
||||
value = cls.indexer.GetItem(ob, args);
|
||||
}
|
||||
finally {
|
||||
if (free) {
|
||||
Runtime.Decref(args);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __setitem__ for reflected classes and value types.
|
||||
//====================================================================
|
||||
|
||||
public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
|
||||
//ManagedType self = GetManagedObject(ob);
|
||||
IntPtr tp = Runtime.PyObject_TYPE(ob);
|
||||
ClassBase cls = (ClassBase)GetManagedObject(tp);
|
||||
|
||||
if (cls.indexer == null || !cls.indexer.CanSet) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"object doesn't support item assignment"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Arg may be a tuple in the case of an indexer with multiple
|
||||
// parameters. If so, use it directly, else make a new tuple
|
||||
// with the index arg (method binders expect arg tuples).
|
||||
|
||||
IntPtr args = idx;
|
||||
bool free = false;
|
||||
|
||||
if (!Runtime.PyTuple_Check(idx)) {
|
||||
args = Runtime.PyTuple_New(1);
|
||||
Runtime.Incref(idx);
|
||||
Runtime.PyTuple_SetItem(args, 0, idx);
|
||||
free = true;
|
||||
}
|
||||
|
||||
int i = Runtime.PyTuple_Size(args);
|
||||
IntPtr real = Runtime.PyTuple_New(i + 1);
|
||||
for (int n = 0; n < i; n++) {
|
||||
IntPtr item = Runtime.PyTuple_GetItem(args, n);
|
||||
Runtime.Incref(item);
|
||||
Runtime.PyTuple_SetItem(real, n, item);
|
||||
}
|
||||
Runtime.Incref(v);
|
||||
Runtime.PyTuple_SetItem(real, i, v);
|
||||
|
||||
try {
|
||||
cls.indexer.SetItem(ob, real);
|
||||
}
|
||||
finally {
|
||||
Runtime.Decref(real);
|
||||
|
||||
if (free) {
|
||||
Runtime.Decref(args);
|
||||
}
|
||||
}
|
||||
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// This is a hack. Generally, no managed class is considered callable
|
||||
// from Python - with the exception of System.Delegate. It is useful
|
||||
// to be able to call a System.Delegate instance directly, especially
|
||||
// when working with multicast delegates.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
|
||||
//ManagedType self = GetManagedObject(ob);
|
||||
IntPtr tp = Runtime.PyObject_TYPE(ob);
|
||||
ClassBase cb = (ClassBase)GetManagedObject(tp);
|
||||
|
||||
if (cb.type != typeof(System.Delegate)) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"object is not callable");
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
CLRObject co = (CLRObject)ManagedType.GetManagedObject(ob);
|
||||
Delegate d = co.inst as Delegate;
|
||||
BindingFlags flags = BindingFlags.Public |
|
||||
BindingFlags.NonPublic |
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Static;
|
||||
|
||||
MethodInfo method = d.GetType().GetMethod("Invoke", flags);
|
||||
MethodBinder binder = new MethodBinder(method);
|
||||
return binder.Invoke(ob, args, kw);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
278
Pythonnet.Runtime/clrmodule.il
Normal file
278
Pythonnet.Runtime/clrmodule.il
Normal file
@ -0,0 +1,278 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
//============================================================================
|
||||
// This file is a hand-maintained stub - it implements clr.dll, which can be
|
||||
// loaded by a standard CPython interpreter as an extension module. When it
|
||||
// is loaded, it bootstraps the managed runtime integration layer and defers
|
||||
// to it to do initialization and put the clr module into sys.modules, etc.
|
||||
|
||||
// The "USE_PYTHON_RUNTIME_*" defines control what extra evidence is used
|
||||
// to help the CLR find the appropriate Python.Runtime assembly.
|
||||
|
||||
// If defined, the "pythonRuntimeVersionString" variable must be set to
|
||||
// Python.Runtime's current version.
|
||||
#define USE_PYTHON_RUNTIME_VERSION
|
||||
|
||||
// If defined, the "PythonRuntimePublicKeyTokenData" data array must be
|
||||
// set to Python.Runtime's public key token.
|
||||
//#define USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
|
||||
// If DEBUG_PRINT is defined, a few System.Console.WriteLine calls are made
|
||||
// to indicate what's going on during the load...
|
||||
//#define DEBUG_PRINT
|
||||
//============================================================================
|
||||
|
||||
.assembly extern mscorlib
|
||||
{
|
||||
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
|
||||
.ver 4:0:0:0
|
||||
}
|
||||
|
||||
.assembly clr
|
||||
{
|
||||
.hash algorithm 0x00008004
|
||||
.ver 2:4:2:7
|
||||
}
|
||||
|
||||
.module clr.dll
|
||||
.imagebase 0x00400000
|
||||
.subsystem 0x00000003
|
||||
.file alignment 512
|
||||
|
||||
// This includes the platform-specific IL. The include search path
|
||||
// is set depending on whether we're compiling 32 or 64 bit.
|
||||
// This MUST come before any other .data directives!
|
||||
// Why, oh why, can't ilasm support command line #defines? :(
|
||||
#include "clrmodule-platform.il"
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
.data PythonRuntimePublicKeyTokenData = bytearray (64 e1 4e 84 5a bf 2e 60)
|
||||
#endif
|
||||
|
||||
.class public auto ansi beforefieldinit clrModule extends [mscorlib]System.Object
|
||||
{
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
.field static assembly int64 PythonRuntimePublicKeyToken at PythonRuntimePublicKeyTokenData
|
||||
#endif
|
||||
|
||||
.method public hidebysig specialname rtspecialname instance void
|
||||
.ctor() cil managed
|
||||
{
|
||||
.maxstack 1
|
||||
ldarg.0
|
||||
call instance void [mscorlib]System.Object::.ctor()
|
||||
ret
|
||||
}
|
||||
|
||||
.method public hidebysig static void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
|
||||
initclr() cil managed
|
||||
{
|
||||
.vtentry 1:1
|
||||
.export [1] as initclr
|
||||
|
||||
.maxstack 6
|
||||
.locals init (
|
||||
class [mscorlib]System.Reflection.Assembly pythonRuntime,
|
||||
class [mscorlib]System.Reflection.Assembly executingAssembly,
|
||||
class [mscorlib]System.Reflection.AssemblyName pythonRuntimeName,
|
||||
class [mscorlib]System.Type pythonEngineType,
|
||||
int8[] publicKeyToken,
|
||||
string assemblyDirectory,
|
||||
string pythonRuntimeVersionString,
|
||||
string pythonRuntimeDllPath)
|
||||
|
||||
// pythonRuntime = null;
|
||||
ldnull
|
||||
stloc pythonRuntime
|
||||
|
||||
.try
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Attempting to load Python.Runtime using standard binding rules... "
|
||||
call void [mscorlib]System.Console::Write(string)
|
||||
#endif
|
||||
|
||||
// Attempt to find and load Python.Runtime using standard assembly binding rules.
|
||||
// This roughly translates into looking in order:
|
||||
// - GAC
|
||||
// - ApplicationBase
|
||||
// - A PrivateBinPath under ApplicationBase
|
||||
// With an unsigned assembly, the GAC is skipped.
|
||||
|
||||
// System.Reflection.AssemblyName pythonRuntimeName = new System.Reflection.AssemblyName();
|
||||
newobj instance void [mscorlib]System.Reflection.AssemblyName::.ctor()
|
||||
stloc pythonRuntimeName
|
||||
|
||||
// pythonRuntimeName.Name = "Python.Runtime";
|
||||
ldloc pythonRuntimeName
|
||||
ldstr "Python.Runtime"
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Name(string)
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_VERSION
|
||||
// pythonRuntimeVersionString = "...";
|
||||
ldstr "2.0.0.2"
|
||||
stloc pythonRuntimeVersionString
|
||||
|
||||
// pythonRuntimeName.Version = new Version(pythonRuntimeVersionString);
|
||||
ldloc pythonRuntimeName
|
||||
ldloc pythonRuntimeVersionString
|
||||
newobj instance void [mscorlib]System.Version::.ctor(string)
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Version(class [mscorlib]System.Version)
|
||||
#endif
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
// publicKeyToken = new byte[] { ... };
|
||||
ldc.i4.8
|
||||
newarr [mscorlib]System.Byte
|
||||
dup
|
||||
ldtoken field int64 clrModule::PythonRuntimePublicKeyToken
|
||||
call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
|
||||
stloc publicKeyToken
|
||||
|
||||
// pythonRuntimeName.SetPublicKeyToken(publicKeyToken);
|
||||
ldloc pythonRuntimeName
|
||||
ldloc publicKeyToken
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::SetPublicKeyToken(uint8[])
|
||||
#endif
|
||||
|
||||
// pythonRuntimeName.CultureInfo = System.Globalization.CultureInfo.InvariantCulture;
|
||||
ldloc pythonRuntimeName
|
||||
call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_CultureInfo(class [mscorlib]System.Globalization.CultureInfo)
|
||||
|
||||
// return System.Reflection.Assembly.Load(pythonRuntimeName);
|
||||
ldloc pythonRuntimeName
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::Load(class [mscorlib]System.Reflection.AssemblyName)
|
||||
stloc pythonRuntime
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Success!"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s LOADED_PYTHON_RUNTIME
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Failed."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_CLR_LOAD
|
||||
}
|
||||
EXIT_CLR_LOAD: nop
|
||||
|
||||
.try
|
||||
{
|
||||
// If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll"
|
||||
// from the directory this assembly is running in. "This assembly" is probably "clr.pyd",
|
||||
// sitting somewhere in PYTHONPATH. This is using Assembly.LoadFrom, and inherits all the
|
||||
// caveats of that call. See MSDN docs for details.
|
||||
// Suzanne Cook's blog is also an excellent source of info on this:
|
||||
// http://blogs.msdn.com/suzcook/
|
||||
// http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx
|
||||
// http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx
|
||||
// executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly()
|
||||
stloc executingAssembly
|
||||
|
||||
// assemblyDirectory = System.IO.Path.GetDirectoryName(executingAssembly.Location);
|
||||
ldloc executingAssembly
|
||||
callvirt instance string [mscorlib]System.Reflection.Assembly::get_Location()
|
||||
call string [mscorlib]System.IO.Path::GetDirectoryName(string)
|
||||
stloc assemblyDirectory
|
||||
|
||||
// pythonRuntimeDllPath = System.IO.Path.Combine(assemblyDirectory, "Python.Runtime.dll");
|
||||
ldloc assemblyDirectory
|
||||
ldstr "Python.Runtime.dll"
|
||||
call string [mscorlib]System.IO.Path::Combine(string, string)
|
||||
stloc pythonRuntimeDllPath
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Attempting to load Python.Runtime from: '{0}'... "
|
||||
ldloc pythonRuntimeDllPath
|
||||
call void [mscorlib]System.Console::Write(string, object)
|
||||
#endif
|
||||
|
||||
// pythonRuntime = System.Reflection.Assembly.LoadFrom(pythonRuntimeDllPath);
|
||||
ldloc pythonRuntimeDllPath
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::LoadFrom(string)
|
||||
stloc pythonRuntime
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Success!"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
|
||||
ldloc pythonRuntime
|
||||
callvirt instance string [mscorlib]System.Reflection.Assembly::get_CodeBase()
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s LOADED_PYTHON_RUNTIME
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Failed."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_PYTHONPATH_LOAD
|
||||
}
|
||||
EXIT_PYTHONPATH_LOAD: nop
|
||||
|
||||
// If we get here, we haven't loaded Python.Runtime, so bail.
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Could not load Python.Runtime, so sad."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
ret;
|
||||
|
||||
// Once here, we've successfully loaded SOME version of Python.Runtime
|
||||
// So now we get the PythonEngine and execute the InitExt method on it.
|
||||
LOADED_PYTHON_RUNTIME: nop
|
||||
.try
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Running Python.Runtime.PythonEngine.InitExt()"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
// pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine");
|
||||
ldloc pythonRuntime
|
||||
ldstr "Python.Runtime.PythonEngine"
|
||||
callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string)
|
||||
stloc pythonEngineType
|
||||
|
||||
// pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null);
|
||||
ldloc pythonEngineType
|
||||
ldstr "InitExt"
|
||||
ldc.i4 0x100
|
||||
ldnull
|
||||
ldnull
|
||||
ldnull
|
||||
callvirt instance object [mscorlib]System.Type::InvokeMember( string,
|
||||
valuetype [mscorlib]System.Reflection.BindingFlags,
|
||||
class [mscorlib]System.Reflection.Binder,
|
||||
object,
|
||||
object[])
|
||||
pop
|
||||
leave.s EXIT_TRY_INVOKE
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Error calling Python.Runtime.PythonEngine.InitExt()."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_TRY_INVOKE
|
||||
}
|
||||
EXIT_TRY_INVOKE: nop
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
279
Pythonnet.Runtime/clrmodule.pp.il
Normal file
279
Pythonnet.Runtime/clrmodule.pp.il
Normal file
@ -0,0 +1,279 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
//============================================================================
|
||||
// This file is a hand-maintained stub - it implements clr.dll, which can be
|
||||
// loaded by a standard CPython interpreter as an extension module. When it
|
||||
// is loaded, it bootstraps the managed runtime integration layer and defers
|
||||
// to it to do initialization and put the clr module into sys.modules, etc.
|
||||
|
||||
// The "USE_PYTHON_RUNTIME_*" defines control what extra evidence is used
|
||||
// to help the CLR find the appropriate Python.Runtime assembly.
|
||||
|
||||
// If defined, the "pythonRuntimeVersionString" variable must be set to
|
||||
// Python.Runtime's current version.
|
||||
#define USE_PYTHON_RUNTIME_VERSION
|
||||
|
||||
// If defined, the "PythonRuntimePublicKeyTokenData" data array must be
|
||||
// set to Python.Runtime's public key token.
|
||||
//#define USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
|
||||
// If DEBUG_PRINT is defined, a few System.Console.WriteLine calls are made
|
||||
// to indicate what's going on during the load...
|
||||
//#define DEBUG_PRINT
|
||||
//============================================================================
|
||||
|
||||
.assembly extern mscorlib
|
||||
{
|
||||
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
|
||||
.ver 2:0:0:0
|
||||
}
|
||||
|
||||
.assembly clr
|
||||
{
|
||||
.hash algorithm 0x00008004
|
||||
.ver 2:0:0:2
|
||||
}
|
||||
|
||||
.module clr.dll
|
||||
.imagebase 0x00400000
|
||||
.subsystem 0x00000003
|
||||
.file alignment 512
|
||||
|
||||
// This includes the platform-specific IL. The include search path
|
||||
// is set depending on whether we're compiling 32 or 64 bit.
|
||||
// This MUST come before any other .data directives!
|
||||
// Why, oh why, can't ilasm support command line #defines? :(
|
||||
|
||||
// Contributed by VIKAS DHIMAN - Handled by /home/barton/Projects/PyDotNet/pythonnet/makefile
|
||||
// gcc -C -P -x c++ -I $(ARCH) clrmodule.pp.il -o clrmodule.il
|
||||
// to copy the correct architecture to the clrModule.
|
||||
// Nice formating, as well - Thanks, Vikas!
|
||||
#include "clrmodule-platform.il"
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
.data PythonRuntimePublicKeyTokenData = bytearray (64 e1 4e 84 5a bf 2e 60)
|
||||
#endif
|
||||
|
||||
.class public auto ansi beforefieldinit clrModule extends [mscorlib]System.Object
|
||||
{
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
.field static assembly int64 PythonRuntimePublicKeyToken at PythonRuntimePublicKeyTokenData
|
||||
#endif
|
||||
|
||||
.method public hidebysig specialname rtspecialname instance void
|
||||
.ctor() cil managed
|
||||
{
|
||||
.maxstack 1
|
||||
ldarg.0
|
||||
call instance void [mscorlib]System.Object::.ctor()
|
||||
ret
|
||||
}
|
||||
|
||||
.method public hidebysig static void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
|
||||
initclr() cil managed
|
||||
{
|
||||
.vtentry 1:1
|
||||
.export [1] as initclr
|
||||
|
||||
.maxstack 6
|
||||
.locals init (
|
||||
class [mscorlib]System.Reflection.Assembly pythonRuntime,
|
||||
class [mscorlib]System.Reflection.Assembly executingAssembly,
|
||||
class [mscorlib]System.Reflection.AssemblyName pythonRuntimeName,
|
||||
class [mscorlib]System.Type pythonEngineType,
|
||||
int8[] publicKeyToken,
|
||||
string assemblyDirectory,
|
||||
string pythonRuntimeVersionString,
|
||||
string pythonRuntimeDllPath)
|
||||
|
||||
// pythonRuntime = null;
|
||||
ldnull
|
||||
stloc pythonRuntime
|
||||
|
||||
.try
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Attempting to load Python.Runtime using standard binding rules... "
|
||||
call void [mscorlib]System.Console::Write(string)
|
||||
#endif
|
||||
|
||||
// Attempt to find and load Python.Runtime using standard assembly binding rules.
|
||||
// This roughly translates into looking in order:
|
||||
// - GAC
|
||||
// - ApplicationBase
|
||||
// - A PrivateBinPath under ApplicationBase
|
||||
// With an unsigned assembly, the GAC is skipped.
|
||||
|
||||
// System.Reflection.AssemblyName pythonRuntimeName = new System.Reflection.AssemblyName();
|
||||
newobj instance void [mscorlib]System.Reflection.AssemblyName::.ctor()
|
||||
stloc pythonRuntimeName
|
||||
|
||||
// pythonRuntimeName.Name = "Python.Runtime";
|
||||
ldloc pythonRuntimeName
|
||||
ldstr "Python.Runtime"
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Name(string)
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_VERSION
|
||||
// pythonRuntimeVersionString = "...";
|
||||
ldstr "2.0.0.2"
|
||||
stloc pythonRuntimeVersionString
|
||||
|
||||
// pythonRuntimeName.Version = new Version(pythonRuntimeVersionString);
|
||||
ldloc pythonRuntimeName
|
||||
ldloc pythonRuntimeVersionString
|
||||
newobj instance void [mscorlib]System.Version::.ctor(string)
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Version(class [mscorlib]System.Version)
|
||||
#endif
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
// publicKeyToken = new byte[] { ... };
|
||||
ldc.i4.8
|
||||
newarr [mscorlib]System.Byte
|
||||
dup
|
||||
ldtoken field int64 clrModule::PythonRuntimePublicKeyToken
|
||||
call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
|
||||
stloc publicKeyToken
|
||||
|
||||
// pythonRuntimeName.SetPublicKeyToken(publicKeyToken);
|
||||
ldloc pythonRuntimeName
|
||||
ldloc publicKeyToken
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::SetPublicKeyToken(uint8[])
|
||||
#endif
|
||||
|
||||
// pythonRuntimeName.CultureInfo = System.Globalization.CultureInfo.InvariantCulture;
|
||||
ldloc pythonRuntimeName
|
||||
call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_CultureInfo(class [mscorlib]System.Globalization.CultureInfo)
|
||||
|
||||
// return System.Reflection.Assembly.Load(pythonRuntimeName);
|
||||
ldloc pythonRuntimeName
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::Load(class [mscorlib]System.Reflection.AssemblyName)
|
||||
stloc pythonRuntime
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Success!"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s LOADED_PYTHON_RUNTIME
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Failed."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_CLR_LOAD
|
||||
}
|
||||
EXIT_CLR_LOAD: nop
|
||||
|
||||
.try
|
||||
{
|
||||
// If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll"
|
||||
// from the directory this assembly is running in. "This assembly" is probably "clr.pyd",
|
||||
// sitting somewhere in PYTHONPATH. This is using Assembly.LoadFrom, and inherits all the
|
||||
// caveats of that call. See MSDN docs for details.
|
||||
// Suzanne Cook's blog is also an excellent source of info on this:
|
||||
// http://blogs.msdn.com/suzcook/
|
||||
// http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx
|
||||
// http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx
|
||||
// executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly()
|
||||
stloc executingAssembly
|
||||
|
||||
// assemblyDirectory = System.IO.Path.GetDirectoryName(executingAssembly.Location);
|
||||
ldloc executingAssembly
|
||||
callvirt instance string [mscorlib]System.Reflection.Assembly::get_Location()
|
||||
call string [mscorlib]System.IO.Path::GetDirectoryName(string)
|
||||
stloc assemblyDirectory
|
||||
|
||||
// pythonRuntimeDllPath = System.IO.Path.Combine(assemblyDirectory, "Python.Runtime.dll");
|
||||
ldloc assemblyDirectory
|
||||
ldstr "Python.Runtime.dll"
|
||||
call string [mscorlib]System.IO.Path::Combine(string, string)
|
||||
stloc pythonRuntimeDllPath
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Attempting to load Python.Runtime from: '{0}'... "
|
||||
ldloc pythonRuntimeDllPath
|
||||
call void [mscorlib]System.Console::Write(string, object)
|
||||
#endif
|
||||
|
||||
// pythonRuntime = System.Reflection.Assembly.LoadFrom(pythonRuntimeDllPath);
|
||||
ldloc pythonRuntimeDllPath
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::LoadFrom(string)
|
||||
stloc pythonRuntime
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Success!"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s LOADED_PYTHON_RUNTIME
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Failed."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_PYTHONPATH_LOAD
|
||||
}
|
||||
EXIT_PYTHONPATH_LOAD: nop
|
||||
|
||||
// If we get here, we haven't loaded Python.Runtime, so bail.
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Could not load Python.Runtime, so sad."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
ret
|
||||
|
||||
// Once here, we've successfully loaded SOME version of Python.Runtime
|
||||
// So now we get the PythonEngine and execute the InitExt method on it.
|
||||
LOADED_PYTHON_RUNTIME: nop
|
||||
.try
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Running Python.Runtime.PythonEngine.InitExt()"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
// pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine");
|
||||
ldloc pythonRuntime
|
||||
ldstr "Python.Runtime.PythonEngine"
|
||||
callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string)
|
||||
stloc pythonEngineType
|
||||
|
||||
// pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null);
|
||||
ldloc pythonEngineType
|
||||
ldstr "InitExt"
|
||||
ldc.i4 0x100
|
||||
ldnull
|
||||
ldnull
|
||||
ldnull
|
||||
callvirt instance object [mscorlib]System.Type::InvokeMember( string,
|
||||
valuetype [mscorlib]System.Reflection.BindingFlags,
|
||||
class [mscorlib]System.Reflection.Binder,
|
||||
object,
|
||||
object[])
|
||||
pop
|
||||
leave.s EXIT_TRY_INVOKE
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Error calling Python.Runtime.PythonEngine.InitExt()."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_TRY_INVOKE
|
||||
}
|
||||
EXIT_TRY_INVOKE: nop
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
78
Pythonnet.Runtime/clrobject.cs
Normal file
78
Pythonnet.Runtime/clrobject.cs
Normal file
@ -0,0 +1,78 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
|
||||
internal class CLRObject : ManagedType {
|
||||
|
||||
internal Object inst;
|
||||
|
||||
internal CLRObject(Object ob, IntPtr tp) : base() {
|
||||
|
||||
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
|
||||
|
||||
int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
|
||||
if ((flags & TypeFlags.Subclass) != 0) {
|
||||
IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.ob_dict);
|
||||
if (dict == IntPtr.Zero) {
|
||||
dict = Runtime.PyDict_New();
|
||||
Marshal.WriteIntPtr(py, ObjectOffset.ob_dict, dict);
|
||||
}
|
||||
}
|
||||
|
||||
GCHandle gc = GCHandle.Alloc(this);
|
||||
Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc);
|
||||
this.tpHandle = tp;
|
||||
this.pyHandle = py;
|
||||
this.gcHandle = gc;
|
||||
inst = ob;
|
||||
}
|
||||
|
||||
|
||||
internal static CLRObject GetInstance(Object ob, IntPtr pyType) {
|
||||
return new CLRObject(ob, pyType);
|
||||
}
|
||||
|
||||
|
||||
internal static CLRObject GetInstance(Object ob) {
|
||||
ClassBase cc = ClassManager.GetClass(ob.GetType());
|
||||
return GetInstance(ob, cc.tpHandle);
|
||||
}
|
||||
|
||||
|
||||
internal static IntPtr GetInstHandle(Object ob, IntPtr pyType) {
|
||||
CLRObject co = GetInstance(ob, pyType);
|
||||
return co.pyHandle;
|
||||
}
|
||||
|
||||
|
||||
internal static IntPtr GetInstHandle(Object ob, Type type) {
|
||||
ClassBase cc = ClassManager.GetClass(type);
|
||||
CLRObject co = GetInstance(ob, cc.tpHandle);
|
||||
return co.pyHandle;
|
||||
}
|
||||
|
||||
|
||||
internal static IntPtr GetInstHandle(Object ob) {
|
||||
CLRObject co = GetInstance(ob);
|
||||
return co.pyHandle;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
62
Pythonnet.Runtime/codegenerator.cs
Normal file
62
Pythonnet.Runtime/codegenerator.cs
Normal file
@ -0,0 +1,62 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Several places in the runtime generate code on the fly to support
|
||||
/// dynamic functionality. The CodeGenerator class manages the dynamic
|
||||
/// assembly used for code generation and provides utility methods for
|
||||
/// certain repetitive tasks.
|
||||
/// </summary>
|
||||
|
||||
internal class CodeGenerator {
|
||||
|
||||
AssemblyBuilder aBuilder;
|
||||
ModuleBuilder mBuilder;
|
||||
|
||||
internal CodeGenerator() {
|
||||
AssemblyName aname = new AssemblyName();
|
||||
aname.Name = "__CodeGenerator_Assembly";
|
||||
AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run;
|
||||
|
||||
aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa);
|
||||
mBuilder = aBuilder.DefineDynamicModule("__CodeGenerator_Module");
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// DefineType is a shortcut utility to get a new TypeBuilder.
|
||||
//====================================================================
|
||||
|
||||
internal TypeBuilder DefineType(string name) {
|
||||
TypeAttributes attrs = TypeAttributes.Public;
|
||||
return mBuilder.DefineType(name, attrs);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// DefineType is a shortcut utility to get a new TypeBuilder.
|
||||
//====================================================================
|
||||
|
||||
internal TypeBuilder DefineType(string name, Type basetype) {
|
||||
TypeAttributes attrs = TypeAttributes.Public;
|
||||
return mBuilder.DefineType(name, attrs, basetype);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
96
Pythonnet.Runtime/constructorbinder.cs
Normal file
96
Pythonnet.Runtime/constructorbinder.cs
Normal file
@ -0,0 +1,96 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// A ConstructorBinder encapsulates information about one or more managed
|
||||
// constructors, and is responsible for selecting the right constructor
|
||||
// given a set of Python arguments. This is slightly different than the
|
||||
// standard MethodBinder because of a difference in invoking constructors
|
||||
// using reflection (which is seems to be a CLR bug).
|
||||
//========================================================================
|
||||
|
||||
internal class ConstructorBinder : MethodBinder {
|
||||
|
||||
internal ConstructorBinder () : base() {}
|
||||
|
||||
//====================================================================
|
||||
// Constructors get invoked when an instance of a wrapped managed
|
||||
// class or a subclass of a managed class is created. This differs
|
||||
// from the MethodBinder implementation in that we return the raw
|
||||
// result of the constructor rather than wrapping it as a Python
|
||||
// object - the reason is that only the caller knows the correct
|
||||
// Python type to use when wrapping the result (may be a subclass).
|
||||
//====================================================================
|
||||
|
||||
internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) {
|
||||
return this.InvokeRaw(inst, args, kw, null);
|
||||
}
|
||||
/// <summary>
|
||||
/// Allows ctor selection to be limited to a single attempt at a
|
||||
/// match by providing the MethodBase to use instead of searching
|
||||
/// the entire MethodBinder.list (generic ArrayList)
|
||||
/// </summary>
|
||||
/// <param name="inst"> (possibly null) instance </param>
|
||||
/// <param name="args"> PyObject* to the arg tuple </param>
|
||||
/// <param name="kw"> PyObject* to the keyword args dict </param>
|
||||
/// <param name="info"> The sole ContructorInfo to use or null </param>
|
||||
/// <returns> The result of the constructor call with converted params </returns>
|
||||
/// <remarks>
|
||||
/// 2010-07-24 BC: I added the info parameter to the call to Bind()
|
||||
/// Binding binding = this.Bind(inst, args, kw, info);
|
||||
/// to take advantage of Bind()'s ability to use a single MethodBase (CI or MI).
|
||||
/// </remarks>
|
||||
internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw,
|
||||
MethodBase info) {
|
||||
Binding binding = this.Bind(inst, args, kw, info);
|
||||
Object result;
|
||||
|
||||
if (binding == null) {
|
||||
// It is possible for __new__ to be invoked on construction
|
||||
// of a Python subclass of a managed class, so args may
|
||||
// reflect more args than are required to instantiate the
|
||||
// class. So if we cant find a ctor that matches, we'll see
|
||||
// if there is a default constructor and, if so, assume that
|
||||
// any extra args are intended for the subclass' __init__.
|
||||
|
||||
IntPtr eargs = Runtime.PyTuple_New(0);
|
||||
binding = this.Bind(inst, eargs, kw);
|
||||
Runtime.Decref(eargs);
|
||||
|
||||
if (binding == null) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"no constructor matches given arguments"
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Fire the selected ctor and catch errors...
|
||||
ConstructorInfo ci = (ConstructorInfo)binding.info;
|
||||
// Object construction is presumed to be non-blocking and fast
|
||||
// enough that we shouldn't really need to release the GIL.
|
||||
try {
|
||||
result = ci.Invoke(binding.args);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (e.InnerException != null) {
|
||||
e = e.InnerException;
|
||||
}
|
||||
Exceptions.SetError(e);
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
237
Pythonnet.Runtime/constructorbinding.cs
Normal file
237
Pythonnet.Runtime/constructorbinding.cs
Normal file
@ -0,0 +1,237 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Implements a Python type that wraps a CLR ctor call. Constructor objects
|
||||
/// support a .Overloads[] syntax to allow explicit ctor overload selection.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ClassManager stores a ConstructorBinding instance in the class's __dict__['Overloads']
|
||||
///
|
||||
/// SomeType.Overloads[Type, ...] works like this:
|
||||
/// 1) Python retreives the Overloads attribute from this ClassObject's dictionary normally
|
||||
/// and finds a non-null tp_descr_get slot which is called by the interpreter
|
||||
/// and returns an IncRef()ed pyHandle to itself.
|
||||
/// 2) The ConstructorBinding object handles the [] syntax in its mp_subscript by matching
|
||||
/// the Type object parameters to a contructor overload using Type.GetConstructor()
|
||||
/// [NOTE: I don't know why method overloads are not searched the same way.]
|
||||
/// and creating the BoundContructor oject which contains ContructorInfo object.
|
||||
/// 3) In tp_call, if ctorInfo is not null, ctorBinder.InvokeRaw() is called.
|
||||
/// </remarks>
|
||||
internal class ConstructorBinding : ExtensionType
|
||||
{
|
||||
Type type; // The managed Type being wrapped in a ClassObject
|
||||
IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create.
|
||||
ConstructorBinder ctorBinder;
|
||||
IntPtr repr;
|
||||
|
||||
public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) : base() {
|
||||
this.type = type;
|
||||
Runtime.Incref(pyTypeHndl);
|
||||
this.pyTypeHndl = pyTypeHndl;
|
||||
this.ctorBinder = ctorBinder;
|
||||
repr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Descriptor __get__ implementation.
|
||||
/// Implements a Python type that wraps a CLR ctor call that requires the use
|
||||
/// of a .Overloads[pyTypeOrType...] syntax to allow explicit ctor overload
|
||||
/// selection.
|
||||
/// </summary>
|
||||
/// <param name="op"> PyObject* to a Constructors wrapper </param>
|
||||
/// <param name="instance"> the instance that the attribute was accessed through,
|
||||
/// or None when the attribute is accessed through the owner </param>
|
||||
/// <param name="owner"> always the owner class </param>
|
||||
/// <returns> a CtorMapper (that borrows a reference to this python type and the
|
||||
/// ClassObject's ConstructorBinder) wrapper. </returns>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Python 2.6.5 docs:
|
||||
/// object.__get__(self, instance, owner)
|
||||
/// Called to get the attribute of the owner class (class attribute access)
|
||||
/// or of an instance of that class (instance attribute access).
|
||||
/// owner is always the owner class, while instance is the instance that
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner)
|
||||
{
|
||||
ConstructorBinding self = (ConstructorBinding)GetManagedObject(op);
|
||||
if (self == null) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// It doesn't seem to matter if it's accessed through an instance (rather than via the type).
|
||||
/*if (instance != IntPtr.Zero) {
|
||||
// This is ugly! PyObject_IsInstance() returns 1 for true, 0 for false, -1 for error...
|
||||
if (Runtime.PyObject_IsInstance(instance, owner) < 1) {
|
||||
return Exceptions.RaiseTypeError("How in the world could that happen!");
|
||||
}
|
||||
}*/
|
||||
Runtime.Incref(self.pyHandle); // Decref'd by the interpreter.
|
||||
return self.pyHandle;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Implement explicit overload selection using subscript syntax ([]).
|
||||
//====================================================================
|
||||
/// <summary>
|
||||
/// ConstructorBinding.GetItem(PyObject *o, PyObject *key)
|
||||
/// Return element of o corresponding to the object key or NULL on failure.
|
||||
/// This is the equivalent of the Python expression o[key].
|
||||
/// </summary>
|
||||
/// <param name="tp"></param>
|
||||
/// <param name="idx"></param>
|
||||
/// <returns></returns>
|
||||
public static IntPtr mp_subscript(IntPtr op, IntPtr key) {
|
||||
ConstructorBinding self = (ConstructorBinding)GetManagedObject(op);
|
||||
|
||||
Type[] types = Runtime.PythonArgsToTypeArray(key);
|
||||
if (types == null) {
|
||||
return Exceptions.RaiseTypeError("type(s) expected");
|
||||
}
|
||||
//MethodBase[] methBaseArray = self.ctorBinder.GetMethods();
|
||||
//MethodBase ci = MatchSignature(methBaseArray, types);
|
||||
ConstructorInfo ci = self.type.GetConstructor(types);
|
||||
if (ci == null) {
|
||||
string msg = "No match found for constructor signature";
|
||||
return Exceptions.RaiseTypeError(msg);
|
||||
}
|
||||
BoundContructor boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci);
|
||||
|
||||
/* Since nothing's chached, do we need the increment???
|
||||
Runtime.Incref(boundCtor.pyHandle); // Decref'd by the interpreter??? */
|
||||
return boundCtor.pyHandle;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// ConstructorBinding __repr__ implementation [borrowed from MethodObject].
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob);
|
||||
if (self.repr != IntPtr.Zero) {
|
||||
Runtime.Incref(self.repr);
|
||||
return self.repr;
|
||||
}
|
||||
MethodBase[] methods = self.ctorBinder.GetMethods();
|
||||
string name = self.type.FullName;
|
||||
string doc = "";
|
||||
for (int i = 0; i < methods.Length; i++) {
|
||||
if (doc.Length > 0)
|
||||
doc += "\n";
|
||||
string str = methods[i].ToString();
|
||||
int idx = str.IndexOf("(");
|
||||
doc += String.Format("{0}{1}", name, str.Substring(idx));
|
||||
}
|
||||
self.repr = Runtime.PyString_FromString(doc);
|
||||
Runtime.Incref(self.repr);
|
||||
return self.repr;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// ConstructorBinding dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new void tp_dealloc(IntPtr ob) {
|
||||
ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob);
|
||||
Runtime.Decref(self.repr);
|
||||
Runtime.Decref(self.pyTypeHndl);
|
||||
ExtensionType.FinalizeObject(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implements a Python type that constucts the given Type given a particular ContructorInfo.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Here mostly because I wanted a new __repr__ function for the selected constructor.
|
||||
/// An earlier implementation hung the __call__ on the ContructorBinding class and
|
||||
/// returned an Incref()ed self.pyHandle from the __get__ function.
|
||||
/// </remarks>
|
||||
internal class BoundContructor : ExtensionType {
|
||||
Type type; // The managed Type being wrapped in a ClassObject
|
||||
IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create.
|
||||
ConstructorBinder ctorBinder;
|
||||
ConstructorInfo ctorInfo;
|
||||
IntPtr repr;
|
||||
|
||||
public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci)
|
||||
: base() {
|
||||
this.type = type;
|
||||
Runtime.Incref(pyTypeHndl);
|
||||
this.pyTypeHndl = pyTypeHndl;
|
||||
this.ctorBinder = ctorBinder;
|
||||
ctorInfo = ci;
|
||||
repr = IntPtr.Zero;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// BoundContructor.__call__(PyObject *callable_object, PyObject *args, PyObject *kw)
|
||||
/// </summary>
|
||||
/// <param name="ob"> PyObject *callable_object </param>
|
||||
/// <param name="args"> PyObject *args </param>
|
||||
/// <param name="kw"> PyObject *kw </param>
|
||||
/// <returns> A reference to a new instance of the class by invoking the selected ctor(). </returns>
|
||||
public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) {
|
||||
BoundContructor self = (BoundContructor)GetManagedObject(op);
|
||||
// Even though a call with null ctorInfo just produces the old behavior
|
||||
/*if (self.ctorInfo == null) {
|
||||
string msg = "Usage: Class.Overloads[CLR_or_python_Type, ...]";
|
||||
return Exceptions.RaiseTypeError(msg);
|
||||
}*/
|
||||
// Bind using ConstructorBinder.Bind and invoke the ctor providing a null instancePtr
|
||||
// which will fire self.ctorInfo using ConstructorInfo.Invoke().
|
||||
Object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo);
|
||||
if (obj == null) {
|
||||
// XXX set an error
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
// Instantiate the python object that wraps the result of the method call
|
||||
// and return the PyObject* to it.
|
||||
return CLRObject.GetInstHandle(obj, self.pyTypeHndl);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// BoundContructor __repr__ implementation [borrowed from MethodObject].
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
BoundContructor self = (BoundContructor)GetManagedObject(ob);
|
||||
if (self.repr != IntPtr.Zero) {
|
||||
Runtime.Incref(self.repr);
|
||||
return self.repr;
|
||||
}
|
||||
string name = self.type.FullName;
|
||||
string str = self.ctorInfo.ToString();
|
||||
int idx = str.IndexOf("(");
|
||||
str = String.Format("returns a new {0}{1}", name, str.Substring(idx));
|
||||
self.repr = Runtime.PyString_FromString(str);
|
||||
Runtime.Incref(self.repr);
|
||||
return self.repr;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// ConstructorBinding dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new void tp_dealloc(IntPtr ob) {
|
||||
BoundContructor self = (BoundContructor)GetManagedObject(ob);
|
||||
Runtime.Decref(self.repr);
|
||||
Runtime.Decref(self.pyTypeHndl);
|
||||
ExtensionType.FinalizeObject(self);
|
||||
}
|
||||
}
|
||||
}
|
714
Pythonnet.Runtime/converter.cs
Normal file
714
Pythonnet.Runtime/converter.cs
Normal file
@ -0,0 +1,714 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Globalization;
|
||||
using System.Security;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Performs data conversions between managed types and Python types.
|
||||
//========================================================================
|
||||
|
||||
[SuppressUnmanagedCodeSecurityAttribute()]
|
||||
|
||||
internal class Converter {
|
||||
|
||||
private Converter() {}
|
||||
|
||||
static NumberFormatInfo nfi;
|
||||
static Type objectType;
|
||||
static Type stringType;
|
||||
static Type doubleType;
|
||||
static Type int32Type;
|
||||
static Type int64Type;
|
||||
static Type flagsType;
|
||||
static Type boolType;
|
||||
//static Type typeType;
|
||||
|
||||
static Converter () {
|
||||
nfi = NumberFormatInfo.InvariantInfo;
|
||||
objectType = typeof(Object);
|
||||
stringType = typeof(String);
|
||||
int32Type = typeof(Int32);
|
||||
int64Type = typeof(Int64);
|
||||
doubleType = typeof(Double);
|
||||
flagsType = typeof(FlagsAttribute);
|
||||
boolType = typeof(Boolean);
|
||||
//typeType = typeof(Type);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a builtin Python type, return the corresponding CLR type.
|
||||
//====================================================================
|
||||
|
||||
internal static Type GetTypeByAlias(IntPtr op) {
|
||||
if ((op == Runtime.PyStringType) ||
|
||||
(op == Runtime.PyUnicodeType)) {
|
||||
return stringType;
|
||||
}
|
||||
else if (op == Runtime.PyIntType) {
|
||||
return int32Type;
|
||||
}
|
||||
else if (op == Runtime.PyLongType) {
|
||||
return int64Type;
|
||||
}
|
||||
else if (op == Runtime.PyFloatType) {
|
||||
return doubleType;
|
||||
}
|
||||
else if (op == Runtime.PyBoolType) {
|
||||
return boolType;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// 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(Object value, Type type) {
|
||||
IntPtr result = IntPtr.Zero;
|
||||
|
||||
// Null always converts to None in Python.
|
||||
|
||||
if (value == null) {
|
||||
result = Runtime.PyNone;
|
||||
Runtime.Incref(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
case TypeCode.Object:
|
||||
result = CLRObject.GetInstHandle(value, type);
|
||||
|
||||
// XXX - hack to make sure we convert new-style class based
|
||||
// managed exception instances to wrappers ;(
|
||||
if (Runtime.wrap_exceptions) {
|
||||
Exception e = value as Exception;
|
||||
if (e != null) {
|
||||
return Exceptions.GetExceptionInstanceWrapper(result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
case TypeCode.String:
|
||||
return Runtime.PyUnicode_FromString((string)value);
|
||||
|
||||
case TypeCode.Int32:
|
||||
return Runtime.PyInt_FromInt32((int)value);
|
||||
|
||||
case TypeCode.Boolean:
|
||||
if ((bool)value) {
|
||||
Runtime.Incref(Runtime.PyTrue);
|
||||
return Runtime.PyTrue;
|
||||
}
|
||||
Runtime.Incref(Runtime.PyFalse);
|
||||
return Runtime.PyFalse;
|
||||
|
||||
case TypeCode.Byte:
|
||||
return Runtime.PyInt_FromInt32((int)((byte)value));
|
||||
|
||||
case TypeCode.Char:
|
||||
return Runtime.PyUnicode_FromOrdinal((int)((char)value));
|
||||
|
||||
case TypeCode.Int16:
|
||||
return Runtime.PyInt_FromInt32((int)((short)value));
|
||||
|
||||
case TypeCode.Int64:
|
||||
return Runtime.PyLong_FromLongLong((long)value);
|
||||
|
||||
case TypeCode.Single:
|
||||
// return Runtime.PyFloat_FromDouble((double)((float)value));
|
||||
string ss = ((float)value).ToString(nfi);
|
||||
IntPtr ps = Runtime.PyString_FromString(ss);
|
||||
IntPtr op = Runtime.PyFloat_FromString(ps, IntPtr.Zero);
|
||||
Runtime.Decref(ps);
|
||||
return op;
|
||||
|
||||
case TypeCode.Double:
|
||||
return Runtime.PyFloat_FromDouble((double)value);
|
||||
|
||||
case TypeCode.SByte:
|
||||
return Runtime.PyInt_FromInt32((int)((sbyte)value));
|
||||
|
||||
case TypeCode.UInt16:
|
||||
return Runtime.PyInt_FromInt32((int)((ushort)value));
|
||||
|
||||
case TypeCode.UInt32:
|
||||
return Runtime.PyLong_FromUnsignedLong((uint)value);
|
||||
|
||||
case TypeCode.UInt64:
|
||||
return Runtime.PyLong_FromUnsignedLongLong((ulong)value);
|
||||
|
||||
default:
|
||||
result = CLRObject.GetInstHandle(value, type);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// In a few situations, we don't have any advisory type information
|
||||
// when we want to convert an object to Python.
|
||||
//====================================================================
|
||||
|
||||
internal static IntPtr ToPythonImplicit(Object value) {
|
||||
if (value == null) {
|
||||
IntPtr result = Runtime.PyNone;
|
||||
Runtime.Incref(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return ToPython(value, objectType);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Return a managed object for the given Python object, taking funny
|
||||
// byref types into account.
|
||||
//====================================================================
|
||||
|
||||
internal static bool ToManaged(IntPtr value, Type type,
|
||||
out object result, bool setError) {
|
||||
if (type.IsByRef) {
|
||||
type = type.GetElementType();
|
||||
}
|
||||
return Converter.ToManagedValue(value, type, out result, setError);
|
||||
}
|
||||
|
||||
|
||||
internal static bool ToManagedValue(IntPtr value, Type obType,
|
||||
out Object result, bool setError) {
|
||||
// Common case: if the Python value is a wrapped managed object
|
||||
// instance, just return the wrapped object.
|
||||
ManagedType mt = ManagedType.GetManagedObject(value);
|
||||
result = null;
|
||||
|
||||
// XXX - hack to support objects wrapped in old-style classes
|
||||
// (such as exception objects).
|
||||
if (Runtime.wrap_exceptions) {
|
||||
if (mt == null) {
|
||||
if (Runtime.PyObject_IsInstance(
|
||||
value, Exceptions.Exception
|
||||
) > 0) {
|
||||
IntPtr p = Runtime.PyObject_GetAttrString(value, "_inner");
|
||||
if (p != IntPtr.Zero) {
|
||||
// This is safe because we know that the __dict__ of
|
||||
// value holds a reference to _inner.
|
||||
value = p;
|
||||
Runtime.Decref(p);
|
||||
mt = ManagedType.GetManagedObject(value);
|
||||
}
|
||||
}
|
||||
IntPtr c = Exceptions.UnwrapExceptionClass(value);
|
||||
if ((c != IntPtr.Zero) && (c != value)) {
|
||||
value = c;
|
||||
Runtime.Decref(c);
|
||||
mt = ManagedType.GetManagedObject(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mt != null) {
|
||||
if (mt is CLRObject) {
|
||||
object tmp = ((CLRObject)mt).inst;
|
||||
if (obType.IsInstanceOfType(tmp)) {
|
||||
result = tmp;
|
||||
return true;
|
||||
}
|
||||
string err = "value cannot be converted to {0}";
|
||||
err = String.Format(err, obType);
|
||||
Exceptions.SetError(Exceptions.TypeError, err);
|
||||
return false;
|
||||
}
|
||||
if (mt is ClassBase) {
|
||||
result = ((ClassBase)mt).type;
|
||||
return true;
|
||||
}
|
||||
// shouldnt happen
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value == Runtime.PyNone && !obType.IsValueType) {
|
||||
result = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obType.IsArray) {
|
||||
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) {
|
||||
if (Runtime.IsStringType(value)) {
|
||||
return ToPrimitive(value, stringType, out result,
|
||||
setError);
|
||||
}
|
||||
|
||||
else if (Runtime.PyBool_Check(value)) {
|
||||
return ToPrimitive(value, boolType, out result, setError);
|
||||
}
|
||||
|
||||
else if (Runtime.PyInt_Check(value)) {
|
||||
return ToPrimitive(value, int32Type, out result, setError);
|
||||
}
|
||||
|
||||
else if (Runtime.PyLong_Check(value)) {
|
||||
return ToPrimitive(value, int64Type, out result, setError);
|
||||
}
|
||||
|
||||
else if (Runtime.PyFloat_Check(value)) {
|
||||
return ToPrimitive(value, doubleType, out result, setError);
|
||||
}
|
||||
|
||||
else if (Runtime.PySequence_Check(value)) {
|
||||
return ToArray(value, typeof(object[]), out result,
|
||||
setError);
|
||||
}
|
||||
|
||||
if (setError) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"value cannot be converted to Object"
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return ToPrimitive(value, obType, out result, setError);
|
||||
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Convert a Python value to an instance of a primitive managed type.
|
||||
//====================================================================
|
||||
|
||||
static bool ToPrimitive(IntPtr value, Type obType, out Object result,
|
||||
bool setError) {
|
||||
|
||||
IntPtr overflow = Exceptions.OverflowError;
|
||||
TypeCode tc = Type.GetTypeCode(obType);
|
||||
result = null;
|
||||
IntPtr op;
|
||||
int ival;
|
||||
|
||||
switch(tc) {
|
||||
|
||||
case TypeCode.String:
|
||||
string st = Runtime.GetManagedString(value);
|
||||
if (st == null) {
|
||||
goto type_error;
|
||||
}
|
||||
result = st;
|
||||
return true;
|
||||
|
||||
case TypeCode.Int32:
|
||||
// Trickery to support 64-bit platforms.
|
||||
if (IntPtr.Size == 4) {
|
||||
op = Runtime.PyNumber_Int(value);
|
||||
|
||||
// As of Python 2.3, large ints magically convert :(
|
||||
if (Runtime.PyLong_Check(op) ) {
|
||||
Runtime.Decref(op);
|
||||
goto overflow;
|
||||
}
|
||||
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
ival = (int)Runtime.PyInt_AsLong(op);
|
||||
Runtime.Decref(op);
|
||||
result = ival;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
op = Runtime.PyNumber_Long(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
long ll = (long)Runtime.PyLong_AsLongLong(op);
|
||||
Runtime.Decref(op);
|
||||
if ((ll == -1) && Exceptions.ErrorOccurred()) {
|
||||
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 (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) {
|
||||
if (Runtime.PyString_Size(value) == 1) {
|
||||
op = Runtime.PyString_AS_STRING(value);
|
||||
result = (byte)Marshal.ReadByte(op);
|
||||
return true;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
|
||||
op = Runtime.PyNumber_Int(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
ival = (int) Runtime.PyInt_AsLong(op);
|
||||
Runtime.Decref(op);
|
||||
|
||||
if (ival > Byte.MaxValue || ival < Byte.MinValue) {
|
||||
goto overflow;
|
||||
}
|
||||
byte b = (byte) ival;
|
||||
result = b;
|
||||
return true;
|
||||
|
||||
case TypeCode.SByte:
|
||||
if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) {
|
||||
if (Runtime.PyString_Size(value) == 1) {
|
||||
op = Runtime.PyString_AS_STRING(value);
|
||||
result = (sbyte)Marshal.ReadByte(op);
|
||||
return true;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
|
||||
op = Runtime.PyNumber_Int(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
ival = (int) Runtime.PyInt_AsLong(op);
|
||||
Runtime.Decref(op);
|
||||
|
||||
if (ival > SByte.MaxValue || ival < SByte.MinValue) {
|
||||
goto overflow;
|
||||
}
|
||||
sbyte sb = (sbyte) ival;
|
||||
result = sb;
|
||||
return true;
|
||||
|
||||
case TypeCode.Char:
|
||||
|
||||
if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) {
|
||||
if (Runtime.PyString_Size(value) == 1) {
|
||||
op = Runtime.PyString_AS_STRING(value);
|
||||
result = (char)Marshal.ReadByte(op);
|
||||
return true;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
|
||||
else if (Runtime.PyObject_TypeCheck(value,
|
||||
Runtime.PyUnicodeType)) {
|
||||
if (Runtime.PyUnicode_GetSize(value) == 1) {
|
||||
op = Runtime.PyUnicode_AS_UNICODE(value);
|
||||
#if (!UCS4)
|
||||
// 2011-01-02: Marshal as character array because the cast
|
||||
// result = (char)Marshal.ReadInt16(op); throws an OverflowException
|
||||
// on negative numbers with Check Overflow option set on the project
|
||||
Char[] buff = new Char[1];
|
||||
Marshal.Copy(op, buff, 0, 1);
|
||||
result = buff[0];
|
||||
#else
|
||||
// XXX this is probably NOT correct?
|
||||
result = (char)Marshal.ReadInt32(op);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
|
||||
op = Runtime.PyNumber_Int(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
goto type_error;
|
||||
}
|
||||
ival = Runtime.PyInt_AsLong(op);
|
||||
if (ival > Char.MaxValue || ival < Char.MinValue) {
|
||||
goto overflow;
|
||||
}
|
||||
Runtime.Decref(op);
|
||||
result = (char)ival;
|
||||
return true;
|
||||
|
||||
case TypeCode.Int16:
|
||||
op = Runtime.PyNumber_Int(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
ival = (int) Runtime.PyInt_AsLong(op);
|
||||
Runtime.Decref(op);
|
||||
if (ival > Int16.MaxValue || ival < Int16.MinValue) {
|
||||
goto overflow;
|
||||
}
|
||||
short s = (short) ival;
|
||||
result = s;
|
||||
return true;
|
||||
|
||||
case TypeCode.Int64:
|
||||
op = Runtime.PyNumber_Long(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
long l = (long)Runtime.PyLong_AsLongLong(op);
|
||||
Runtime.Decref(op);
|
||||
if ((l == -1) && Exceptions.ErrorOccurred()) {
|
||||
goto overflow;
|
||||
}
|
||||
result = l;
|
||||
return true;
|
||||
|
||||
case TypeCode.UInt16:
|
||||
op = Runtime.PyNumber_Int(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
ival = (int) Runtime.PyInt_AsLong(op);
|
||||
Runtime.Decref(op);
|
||||
if (ival > UInt16.MaxValue || ival < UInt16.MinValue) {
|
||||
goto overflow;
|
||||
}
|
||||
ushort us = (ushort) ival;
|
||||
result = us;
|
||||
return true;
|
||||
|
||||
case TypeCode.UInt32:
|
||||
op = Runtime.PyNumber_Long(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op);
|
||||
Runtime.Decref(op);
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
goto overflow;
|
||||
}
|
||||
result = ui;
|
||||
return true;
|
||||
|
||||
case TypeCode.UInt64:
|
||||
op = Runtime.PyNumber_Long(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
ulong ul = (ulong)Runtime.PyLong_AsUnsignedLongLong(op);
|
||||
Runtime.Decref(op);
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
goto overflow;
|
||||
}
|
||||
result = ul;
|
||||
return true;
|
||||
|
||||
|
||||
case TypeCode.Single:
|
||||
op = Runtime.PyNumber_Float(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
if (Exceptions.ExceptionMatches(overflow)) {
|
||||
goto overflow;
|
||||
}
|
||||
goto type_error;
|
||||
}
|
||||
double dd = Runtime.PyFloat_AsDouble(value);
|
||||
if (dd > Single.MaxValue || dd < Single.MinValue) {
|
||||
goto overflow;
|
||||
}
|
||||
result = (float)dd;
|
||||
return true;
|
||||
|
||||
case TypeCode.Double:
|
||||
op = Runtime.PyNumber_Float(value);
|
||||
if (op == IntPtr.Zero) {
|
||||
goto type_error;
|
||||
}
|
||||
double d = Runtime.PyFloat_AsDouble(op);
|
||||
Runtime.Decref(op);
|
||||
if (d > Double.MaxValue || d < Double.MinValue) {
|
||||
goto overflow;
|
||||
}
|
||||
result = d;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
type_error:
|
||||
|
||||
if (setError) {
|
||||
string format = "'{0}' value cannot be converted to {1}";
|
||||
string tpName = Runtime.PyObject_GetTypeName(value);
|
||||
string error = String.Format(format, tpName, obType);
|
||||
Exceptions.SetError(Exceptions.TypeError, error);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
overflow:
|
||||
|
||||
if (setError) {
|
||||
string error = "value too large to convert";
|
||||
Exceptions.SetError(Exceptions.OverflowError, error);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void SetConversionError(IntPtr value, Type target) {
|
||||
IntPtr ob = Runtime.PyObject_Repr(value);
|
||||
string src = Runtime.GetManagedString(ob);
|
||||
Runtime.Decref(ob);
|
||||
string error = String.Format(
|
||||
"Cannot convert {0} to {1}", src, target
|
||||
);
|
||||
Exceptions.SetError(Exceptions.TypeError, error);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Convert a Python value to a correctly typed managed array instance.
|
||||
// The Python value must support the Python sequence protocol and the
|
||||
// items in the sequence must be convertible to the target array type.
|
||||
//====================================================================
|
||||
|
||||
static bool ToArray(IntPtr value, Type obType, out Object result,
|
||||
bool setError) {
|
||||
|
||||
Type elementType = obType.GetElementType();
|
||||
int size = Runtime.PySequence_Size(value);
|
||||
result = null;
|
||||
|
||||
if (size < 0) {
|
||||
if (setError) {
|
||||
SetConversionError(value, obType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Array items = Array.CreateInstance(elementType, size);
|
||||
|
||||
// XXX - is there a better way to unwrap this if it is a real
|
||||
// array?
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object obj = null;
|
||||
IntPtr item = Runtime.PySequence_GetItem(value, i);
|
||||
if (item == IntPtr.Zero) {
|
||||
if (setError) {
|
||||
SetConversionError(value, obType);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Converter.ToManaged(item, elementType, out obj, true)) {
|
||||
Runtime.Decref(item);
|
||||
return false;
|
||||
}
|
||||
|
||||
items.SetValue(obj, i);
|
||||
Runtime.Decref(item);
|
||||
}
|
||||
|
||||
result = items;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Convert a Python value to a correctly typed managed enum instance.
|
||||
//====================================================================
|
||||
|
||||
static bool ToEnum(IntPtr value, Type obType, out Object result,
|
||||
bool setError) {
|
||||
|
||||
Type etype = Enum.GetUnderlyingType(obType);
|
||||
result = null;
|
||||
|
||||
if (!ToPrimitive(value, etype, out result, setError)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Enum.IsDefined(obType, result)) {
|
||||
result = Enum.ToObject(obType, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obType.GetCustomAttributes(flagsType, true).Length > 0) {
|
||||
result = Enum.ToObject(obType, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (setError) {
|
||||
string error = "invalid enumeration value";
|
||||
Exceptions.SetError(Exceptions.ValueError, error);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
128
Pythonnet.Runtime/debughelper.cs
Normal file
128
Pythonnet.Runtime/debughelper.cs
Normal file
@ -0,0 +1,128 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Debugging helper utilities.
|
||||
/// The methods are only executed when the DEBUG flag is set. Otherwise
|
||||
/// they are automagically hidden by the compiler and silently surpressed.
|
||||
/// </summary>
|
||||
|
||||
internal class DebugUtil {
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void Print(string msg, params IntPtr[] args) {
|
||||
string result = msg;
|
||||
result += " ";
|
||||
|
||||
for (int i = 0; i < args.Length; i++) {
|
||||
if (args[i] == IntPtr.Zero) {
|
||||
Console.WriteLine("null arg to print");
|
||||
}
|
||||
IntPtr ob = Runtime.PyObject_Repr(args[i]);
|
||||
result += Runtime.GetManagedString(ob);
|
||||
Runtime.Decref(ob);
|
||||
result += " ";
|
||||
}
|
||||
Console.WriteLine(result);
|
||||
return;
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public static void Print(string msg) {
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
internal static void DumpType(IntPtr type) {
|
||||
IntPtr op = Marshal.ReadIntPtr(type, TypeOffset.tp_name);
|
||||
string name = Marshal.PtrToStringAnsi(op);
|
||||
|
||||
Console.WriteLine("Dump type: {0}", name);
|
||||
|
||||
op = Marshal.ReadIntPtr(type, TypeOffset.ob_type);
|
||||
DebugUtil.Print(" type: ", op);
|
||||
|
||||
op = Marshal.ReadIntPtr(type, TypeOffset.tp_base);
|
||||
DebugUtil.Print(" base: ", op);
|
||||
|
||||
op = Marshal.ReadIntPtr(type, TypeOffset.tp_bases);
|
||||
DebugUtil.Print(" bases: ", op);
|
||||
|
||||
//op = Marshal.ReadIntPtr(type, TypeOffset.tp_mro);
|
||||
//DebugUtil.Print(" mro: ", op);
|
||||
|
||||
|
||||
FieldInfo[] slots = typeof(TypeOffset).GetFields();
|
||||
int size = IntPtr.Size;
|
||||
|
||||
for (int i = 0; i < slots.Length; i++) {
|
||||
int offset = i * size;
|
||||
name = slots[i].Name;
|
||||
op = Marshal.ReadIntPtr(type, offset);
|
||||
Console.WriteLine(" {0}: {1}", name, op);
|
||||
}
|
||||
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("");
|
||||
|
||||
op = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
|
||||
if (op == IntPtr.Zero) {
|
||||
Console.WriteLine(" dict: null");
|
||||
}
|
||||
else {
|
||||
DebugUtil.Print(" dict: ", op);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
internal static void DumpInst(IntPtr ob) {
|
||||
IntPtr tp = Runtime.PyObject_TYPE(ob);
|
||||
int sz = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_basicsize);
|
||||
|
||||
for (int i = 0; i < sz; i += IntPtr.Size) {
|
||||
IntPtr pp = new IntPtr(ob.ToInt64() + i);
|
||||
IntPtr v = Marshal.ReadIntPtr(pp);
|
||||
Console.WriteLine("offset {0}: {1}", i, v);
|
||||
}
|
||||
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("");
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
internal static void debug(string msg) {
|
||||
StackTrace st = new StackTrace(1, true);
|
||||
StackFrame sf = st.GetFrame(0);
|
||||
MethodBase mb = sf.GetMethod();
|
||||
Type mt = mb.DeclaringType;
|
||||
string caller = mt.Name + "." + sf.GetMethod().Name;
|
||||
Thread t = Thread.CurrentThread;
|
||||
string tid = t.GetHashCode().ToString();
|
||||
Console.WriteLine("thread {0} : {1}", tid, caller);
|
||||
Console.WriteLine(" {0}", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
289
Pythonnet.Runtime/delegatemanager.cs
Normal file
289
Pythonnet.Runtime/delegatemanager.cs
Normal file
@ -0,0 +1,289 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// The DelegateManager class manages the creation of true managed
|
||||
/// delegate instances that dispatch calls to Python methods.
|
||||
/// </summary>
|
||||
|
||||
internal class DelegateManager {
|
||||
|
||||
Hashtable cache;
|
||||
Type basetype;
|
||||
Type listtype;
|
||||
Type voidtype;
|
||||
Type typetype;
|
||||
Type ptrtype;
|
||||
CodeGenerator codeGenerator;
|
||||
|
||||
public DelegateManager() {
|
||||
basetype = typeof(Dispatcher);
|
||||
listtype = typeof(ArrayList);
|
||||
voidtype = typeof(void);
|
||||
typetype = typeof(Type);
|
||||
ptrtype = typeof(IntPtr);
|
||||
cache = new Hashtable();
|
||||
codeGenerator = new CodeGenerator();
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Given a true delegate instance, return the PyObject handle of the
|
||||
// Python object implementing the delegate (or IntPtr.Zero if the
|
||||
// delegate is not implemented in Python code.
|
||||
//====================================================================
|
||||
|
||||
public IntPtr GetPythonHandle(Delegate d) {
|
||||
if ((d != null) && (d.Target is Dispatcher)) {
|
||||
Dispatcher disp = d.Target as Dispatcher;
|
||||
return disp.target;
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// GetDispatcher is responsible for creating a class that provides
|
||||
// an appropriate managed callback method for a given delegate type.
|
||||
//====================================================================
|
||||
|
||||
private Type GetDispatcher(Type dtype) {
|
||||
|
||||
// If a dispatcher type for the given delegate type has already
|
||||
// been generated, get it from the cache. The cache maps delegate
|
||||
// types to generated dispatcher types. A possible optimization
|
||||
// for the future would be to generate dispatcher types based on
|
||||
// unique signatures rather than delegate types, since multiple
|
||||
// delegate types with the same sig could use the same dispatcher.
|
||||
|
||||
Object item = cache[dtype];
|
||||
if (item != null) {
|
||||
return (Type)item;
|
||||
}
|
||||
|
||||
string name = "__" + dtype.FullName + "Dispatcher";
|
||||
name = name.Replace('.', '_');
|
||||
name = name.Replace('+', '_');
|
||||
TypeBuilder tb = codeGenerator.DefineType(name, basetype);
|
||||
|
||||
// Generate a constructor for the generated type that calls the
|
||||
// appropriate constructor of the Dispatcher base type.
|
||||
|
||||
MethodAttributes ma = MethodAttributes.Public |
|
||||
MethodAttributes.HideBySig |
|
||||
MethodAttributes.SpecialName |
|
||||
MethodAttributes.RTSpecialName;
|
||||
CallingConventions cc = CallingConventions.Standard;
|
||||
Type[] args = {ptrtype, typetype};
|
||||
ConstructorBuilder cb = tb.DefineConstructor(ma, cc, args);
|
||||
ConstructorInfo ci = basetype.GetConstructor(args);
|
||||
ILGenerator il = cb.GetILGenerator();
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
il.Emit(OpCodes.Ldarg_2);
|
||||
il.Emit(OpCodes.Call, ci);
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
// Method generation: we generate a method named "Invoke" on the
|
||||
// dispatcher type, whose signature matches the delegate type for
|
||||
// which it is generated. The method body simply packages the
|
||||
// arguments and hands them to the Dispatch() method, which deals
|
||||
// with converting the arguments, calling the Python method and
|
||||
// converting the result of the call.
|
||||
|
||||
MethodInfo method = dtype.GetMethod("Invoke");
|
||||
ParameterInfo[] pi = method.GetParameters();
|
||||
|
||||
Type[] signature = new Type[pi.Length];
|
||||
for (int i = 0; i < pi.Length; i++) {
|
||||
signature[i] = pi[i].ParameterType;
|
||||
}
|
||||
|
||||
MethodBuilder mb = tb.DefineMethod(
|
||||
"Invoke",
|
||||
MethodAttributes.Public,
|
||||
method.ReturnType,
|
||||
signature
|
||||
);
|
||||
|
||||
ConstructorInfo ctor = listtype.GetConstructor(Type.EmptyTypes);
|
||||
MethodInfo dispatch = basetype.GetMethod("Dispatch");
|
||||
MethodInfo add = listtype.GetMethod("Add");
|
||||
|
||||
il = mb.GetILGenerator();
|
||||
il.DeclareLocal(listtype);
|
||||
il.Emit(OpCodes.Newobj, ctor);
|
||||
il.Emit(OpCodes.Stloc_0);
|
||||
|
||||
for (int c = 0; c < signature.Length; c++) {
|
||||
Type t = signature[c];
|
||||
il.Emit(OpCodes.Ldloc_0);
|
||||
il.Emit(OpCodes.Ldarg_S, (byte)(c + 1));
|
||||
|
||||
if (t.IsValueType) {
|
||||
il.Emit(OpCodes.Box, t);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Callvirt, add);
|
||||
il.Emit(OpCodes.Pop);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Ldloc_0);
|
||||
il.Emit(OpCodes.Call, dispatch);
|
||||
|
||||
if (method.ReturnType == voidtype) {
|
||||
il.Emit(OpCodes.Pop);
|
||||
}
|
||||
else if (method.ReturnType.IsValueType) {
|
||||
il.Emit(OpCodes.Unbox_Any, method.ReturnType);
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
Type disp = tb.CreateType();
|
||||
cache[dtype] = disp;
|
||||
return disp;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Given a delegate type and a callable Python object, GetDelegate
|
||||
// returns an instance of the delegate type. The delegate instance
|
||||
// returned will dispatch calls to the given Python object.
|
||||
//====================================================================
|
||||
|
||||
internal Delegate GetDelegate(Type dtype, IntPtr callable) {
|
||||
Type dispatcher = GetDispatcher(dtype);
|
||||
object[] args = {callable, dtype};
|
||||
object o = Activator.CreateInstance(dispatcher, args);
|
||||
return Delegate.CreateDelegate(dtype, o, "Invoke");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* When a delegate instance is created that has a Python implementation,
|
||||
the delegate manager generates a custom subclass of Dispatcher and
|
||||
instantiates it, passing the IntPtr of the Python callable.
|
||||
|
||||
The "real" delegate is created using CreateDelegate, passing the
|
||||
instance of the generated type and the name of the (generated)
|
||||
implementing method (Invoke).
|
||||
|
||||
The true delegate instance holds the only reference to the dispatcher
|
||||
instance, which ensures that when the delegate dies, the finalizer
|
||||
of the referenced instance will be able to decref the Python
|
||||
callable.
|
||||
|
||||
A possible alternate strategy would be to create custom subclasses
|
||||
of the required delegate type, storing the IntPtr in it directly.
|
||||
This would be slightly cleaner, but I'm not sure if delegates are
|
||||
too "special" for this to work. It would be more work, so for now
|
||||
the 80/20 rule applies :)
|
||||
|
||||
*/
|
||||
|
||||
public class Dispatcher {
|
||||
|
||||
public IntPtr target;
|
||||
public Type dtype;
|
||||
|
||||
public Dispatcher(IntPtr target, Type dtype) {
|
||||
Runtime.Incref(target);
|
||||
this.target = target;
|
||||
this.dtype = dtype;
|
||||
}
|
||||
|
||||
~Dispatcher() {
|
||||
// Note: the managed GC thread can run and try to free one of
|
||||
// these *after* the Python runtime has been finalized!
|
||||
if (Runtime.Py_IsInitialized() > 0) {
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
Runtime.Decref(target);
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
}
|
||||
}
|
||||
|
||||
public object Dispatch(ArrayList args) {
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
object ob = null;
|
||||
|
||||
try {
|
||||
ob = TrueDispatch(args);
|
||||
}
|
||||
catch (Exception e) {
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
throw e;
|
||||
}
|
||||
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
return ob;
|
||||
}
|
||||
|
||||
public object TrueDispatch(ArrayList args) {
|
||||
MethodInfo method = dtype.GetMethod("Invoke");
|
||||
ParameterInfo[] pi = method.GetParameters();
|
||||
IntPtr pyargs = Runtime.PyTuple_New(pi.Length);
|
||||
Type rtype = method.ReturnType;
|
||||
|
||||
for (int i = 0; i < pi.Length; i++) {
|
||||
// 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);
|
||||
Runtime.PyTuple_SetItem(pyargs, i, arg);
|
||||
}
|
||||
|
||||
IntPtr op = Runtime.PyObject_Call(target, pyargs, IntPtr.Zero);
|
||||
Runtime.Decref(pyargs);
|
||||
|
||||
if (op == IntPtr.Zero) {
|
||||
PythonException e = new PythonException();
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (rtype == typeof(void)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object result = null;
|
||||
if (!Converter.ToManaged(op, rtype, out result, false)) {
|
||||
string s = "could not convert Python result to " +
|
||||
rtype.ToString();
|
||||
Runtime.Decref(op);
|
||||
throw new ConversionException(s);
|
||||
}
|
||||
|
||||
Runtime.Decref(op);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class ConversionException : System.Exception {
|
||||
|
||||
public ConversionException() : base() {}
|
||||
|
||||
public ConversionException(string msg) : base(msg) {}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
120
Pythonnet.Runtime/delegateobject.cs
Normal file
120
Pythonnet.Runtime/delegateobject.cs
Normal file
@ -0,0 +1,120 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Managed class that provides the implementation for reflected delegate
|
||||
/// types. Delegates are represented in Python by generated type objects.
|
||||
/// Each of those type objects is associated an instance of this class,
|
||||
/// which provides its implementation.
|
||||
/// </summary>
|
||||
|
||||
internal class DelegateObject : ClassBase {
|
||||
|
||||
MethodBinder binder;
|
||||
|
||||
internal DelegateObject(Type tp) : base(tp) {
|
||||
binder = new MethodBinder(tp.GetMethod("Invoke"));
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a PyObject pointer to an instance of a delegate type, return
|
||||
// the true managed delegate the Python object represents (or null).
|
||||
//====================================================================
|
||||
|
||||
private static Delegate GetTrueDelegate(IntPtr op) {
|
||||
CLRObject o = GetManagedObject(op) as CLRObject;
|
||||
if (o != null) {
|
||||
Delegate d = o.inst as Delegate;
|
||||
return d;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
internal override bool CanSubclass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// DelegateObject __new__ implementation. The result of this is a new
|
||||
// PyObject whose type is DelegateObject and whose ob_data is a handle
|
||||
// to an actual delegate instance. The method wrapped by the actual
|
||||
// delegate instance belongs to an object generated to relay the call
|
||||
// to the Python callable passed in.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
DelegateObject self = (DelegateObject)GetManagedObject(tp);
|
||||
|
||||
if (Runtime.PyTuple_Size(args) != 1) {
|
||||
string message = "class takes exactly one argument";
|
||||
return Exceptions.RaiseTypeError(message);
|
||||
}
|
||||
|
||||
IntPtr method = Runtime.PyTuple_GetItem(args, 0);
|
||||
|
||||
if (Runtime.PyCallable_Check(method) != 1) {
|
||||
return Exceptions.RaiseTypeError("argument must be callable");
|
||||
}
|
||||
|
||||
Delegate d = PythonEngine.DelegateManager.GetDelegate(self.type, method);
|
||||
return CLRObject.GetInstHandle(d, self.pyHandle);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __call__ for reflected delegate types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
|
||||
// todo: add fast type check!
|
||||
IntPtr pytype = Runtime.PyObject_TYPE(ob);
|
||||
DelegateObject self = (DelegateObject)GetManagedObject(pytype);
|
||||
CLRObject o = GetManagedObject(ob) as CLRObject;
|
||||
|
||||
if (o == null) {
|
||||
return Exceptions.RaiseTypeError("invalid argument");
|
||||
}
|
||||
|
||||
Delegate d = o.inst as Delegate;
|
||||
|
||||
if (d == null) {
|
||||
return Exceptions.RaiseTypeError("invalid argument");
|
||||
}
|
||||
return self.binder.Invoke(ob, args, kw);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __cmp__ for reflected delegate types.
|
||||
//====================================================================
|
||||
|
||||
public static new int tp_compare(IntPtr ob, IntPtr other) {
|
||||
Delegate d1 = GetTrueDelegate(ob);
|
||||
Delegate d2 = GetTrueDelegate(other);
|
||||
if (d1 == d2) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
132
Pythonnet.Runtime/eventbinding.cs
Normal file
132
Pythonnet.Runtime/eventbinding.cs
Normal file
@ -0,0 +1,132 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python event binding type, similar to a method binding.
|
||||
//========================================================================
|
||||
|
||||
internal class EventBinding : ExtensionType {
|
||||
|
||||
EventObject e;
|
||||
IntPtr target;
|
||||
|
||||
public EventBinding(EventObject e, IntPtr target) : base() {
|
||||
Runtime.Incref(target);
|
||||
this.target = target;
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// EventBinding += operator implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr nb_inplace_add(IntPtr ob, IntPtr arg) {
|
||||
EventBinding self = (EventBinding)GetManagedObject(ob);
|
||||
|
||||
if (Runtime.PyCallable_Check(arg) < 1) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"event handlers must be callable"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
if(!self.e.AddEventHandler(self.target, arg)) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
Runtime.Incref(self.pyHandle);
|
||||
return self.pyHandle;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// EventBinding -= operator implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr nb_inplace_subtract(IntPtr ob, IntPtr arg) {
|
||||
EventBinding self = (EventBinding)GetManagedObject(ob);
|
||||
|
||||
if (Runtime.PyCallable_Check(arg) < 1) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"invalid event handler"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (!self.e.RemoveEventHandler(self.target, arg)) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
Runtime.Incref(self.pyHandle);
|
||||
return self.pyHandle;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// EventBinding __hash__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_hash(IntPtr ob) {
|
||||
EventBinding self = (EventBinding)GetManagedObject(ob);
|
||||
long x = 0;
|
||||
long y = 0;
|
||||
|
||||
if (self.target != IntPtr.Zero) {
|
||||
x = Runtime.PyObject_Hash(self.target).ToInt64();
|
||||
if (x == -1) {
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
}
|
||||
|
||||
y = Runtime.PyObject_Hash(self.e.pyHandle).ToInt64();
|
||||
if (y == -1) {
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
|
||||
x ^= y;
|
||||
|
||||
if (x == -1) {
|
||||
x = -1;
|
||||
}
|
||||
|
||||
return new IntPtr(x);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// EventBinding __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
EventBinding self = (EventBinding)GetManagedObject(ob);
|
||||
string type = (self.target == IntPtr.Zero) ? "unbound" : "bound";
|
||||
string s = String.Format("<{0} event '{1}'>", type, self.e.name);
|
||||
return Runtime.PyString_FromString(s);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// EventBinding dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new void tp_dealloc(IntPtr ob) {
|
||||
EventBinding self = (EventBinding)GetManagedObject(ob);
|
||||
Runtime.Decref(self.target);
|
||||
ExtensionType.FinalizeObject(self);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
230
Pythonnet.Runtime/eventobject.cs
Normal file
230
Pythonnet.Runtime/eventobject.cs
Normal file
@ -0,0 +1,230 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python descriptor type that provides access to CLR events.
|
||||
//========================================================================
|
||||
|
||||
internal class EventObject : ExtensionType {
|
||||
|
||||
internal string name;
|
||||
internal EventBinding unbound;
|
||||
internal EventInfo info;
|
||||
internal Hashtable reg;
|
||||
|
||||
public EventObject(EventInfo info) : base() {
|
||||
this.name = info.Name;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Register a new Python object event handler with the event.
|
||||
//====================================================================
|
||||
|
||||
internal bool AddEventHandler(IntPtr target, IntPtr handler) {
|
||||
Object obj = null;
|
||||
if (target != IntPtr.Zero) {
|
||||
CLRObject co = (CLRObject)ManagedType.GetManagedObject(target);
|
||||
obj = co.inst;
|
||||
}
|
||||
|
||||
// Create a true delegate instance of the appropriate type to
|
||||
// wrap the Python handler. Note that wrapper delegate creation
|
||||
// always succeeds, though calling the wrapper may fail.
|
||||
|
||||
Type type = this.info.EventHandlerType;
|
||||
Delegate d = PythonEngine.DelegateManager.GetDelegate(type, handler);
|
||||
|
||||
// Now register the handler in a mapping from instance to pairs
|
||||
// of (handler hash, delegate) so we can lookup to remove later.
|
||||
// All this is done lazily to avoid overhead until an event is
|
||||
// actually subscribed to by a Python event handler.
|
||||
|
||||
if (reg == null) {
|
||||
reg = new Hashtable();
|
||||
}
|
||||
object key = (obj != null) ? obj : this.info.ReflectedType;
|
||||
ArrayList list = reg[key] as ArrayList;
|
||||
if (list == null) {
|
||||
list = new ArrayList();
|
||||
reg[key] = list;
|
||||
}
|
||||
list.Add(new Handler(Runtime.PyObject_Hash(handler), d));
|
||||
|
||||
// Note that AddEventHandler helper only works for public events,
|
||||
// so we have to get the underlying add method explicitly.
|
||||
|
||||
object[] args = { d };
|
||||
MethodInfo mi = this.info.GetAddMethod(true);
|
||||
mi.Invoke(obj, BindingFlags.Default, null, args, null);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Remove the given Python object event handler.
|
||||
//====================================================================
|
||||
|
||||
internal bool RemoveEventHandler(IntPtr target, IntPtr handler) {
|
||||
Object obj = null;
|
||||
if (target != IntPtr.Zero) {
|
||||
CLRObject co = (CLRObject)ManagedType.GetManagedObject(target);
|
||||
obj = co.inst;
|
||||
}
|
||||
|
||||
IntPtr hash = Runtime.PyObject_Hash(handler);
|
||||
if (Exceptions.ErrorOccurred() || (reg == null)) {
|
||||
Exceptions.SetError(Exceptions.ValueError,
|
||||
"unknown event handler"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
object key = (obj != null) ? obj : this.info.ReflectedType;
|
||||
ArrayList list = reg[key] as ArrayList;
|
||||
|
||||
if (list == null) {
|
||||
Exceptions.SetError(Exceptions.ValueError,
|
||||
"unknown event handler"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
object[] args = { null };
|
||||
MethodInfo mi = this.info.GetRemoveMethod(true);
|
||||
|
||||
for (int i = 0; i < list.Count; i++) {
|
||||
Handler item = (Handler)list[i];
|
||||
if (item.hash != hash) {
|
||||
continue;
|
||||
}
|
||||
args[0] = item.del;
|
||||
try {
|
||||
mi.Invoke(obj, BindingFlags.Default, null, args, null);
|
||||
}
|
||||
catch {
|
||||
continue;
|
||||
}
|
||||
list.RemoveAt(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
Exceptions.SetError(Exceptions.ValueError,
|
||||
"unknown event handler"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __get__ implementation. A getattr on an event returns
|
||||
// a "bound" event that keeps a reference to the object instance.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) {
|
||||
EventObject self = GetManagedObject(ds) as EventObject;
|
||||
EventBinding binding;
|
||||
|
||||
if (self == null) {
|
||||
return Exceptions.RaiseTypeError("invalid argument");
|
||||
}
|
||||
|
||||
// If the event is accessed through its type (rather than via
|
||||
// an instance) we return an 'unbound' EventBinding that will
|
||||
// be cached for future accesses through the type.
|
||||
|
||||
if (ob == IntPtr.Zero) {
|
||||
if (self.unbound == null) {
|
||||
self.unbound = new EventBinding(self, IntPtr.Zero);
|
||||
}
|
||||
binding = self.unbound;
|
||||
Runtime.Incref(binding.pyHandle);
|
||||
return binding.pyHandle;
|
||||
}
|
||||
|
||||
if (Runtime.PyObject_IsInstance(ob, tp) < 1) {
|
||||
return Exceptions.RaiseTypeError("invalid argument");
|
||||
}
|
||||
|
||||
binding = new EventBinding(self, ob);
|
||||
return binding.pyHandle;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __set__ implementation. This actually never allows you
|
||||
// to set anything; it exists solely to support the '+=' spelling of
|
||||
// event handler registration. The reason is that given code like:
|
||||
// 'ob.SomeEvent += method', Python will attempt to set the attribute
|
||||
// SomeEvent on ob to the result of the '+=' operation.
|
||||
//====================================================================
|
||||
|
||||
public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
|
||||
EventBinding e = GetManagedObject(val) as EventBinding;
|
||||
|
||||
if (e != null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
string message = "cannot set event attributes";
|
||||
Exceptions.RaiseTypeError(message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
EventObject self = (EventObject)GetManagedObject(ob);
|
||||
string s = String.Format("<event '{0}'>", self.name);
|
||||
return Runtime.PyString_FromString(s);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Descriptor dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new void tp_dealloc(IntPtr ob) {
|
||||
EventObject self = (EventObject)GetManagedObject(ob);
|
||||
if (self.unbound != null) {
|
||||
Runtime.Decref(self.unbound.pyHandle);
|
||||
}
|
||||
ExtensionType.FinalizeObject(self);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal class Handler {
|
||||
|
||||
public IntPtr hash;
|
||||
public Delegate del;
|
||||
|
||||
public Handler(IntPtr hash, Delegate d) {
|
||||
this.hash = hash;
|
||||
this.del = d;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
639
Pythonnet.Runtime/exceptions.cs
Normal file
639
Pythonnet.Runtime/exceptions.cs
Normal file
@ -0,0 +1,639 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Base class for Python types that reflect managed exceptions based on
|
||||
/// System.Exception
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Python wrapper for managed exceptions LIES about its inheritance
|
||||
/// tree. Although the real System.Exception is a subclass of
|
||||
/// System.Object the Python type for System.Exception does NOT claim that
|
||||
/// it subclasses System.Object. Instead TypeManager.CreateType() uses
|
||||
/// Python's exception.Exception class as base class for System.Exception.
|
||||
/// </remarks>
|
||||
internal class ExceptionClassObject : ClassObject {
|
||||
|
||||
internal ExceptionClassObject(Type tp) : base(tp) {
|
||||
}
|
||||
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
internal static Exception ToException(IntPtr ob) {
|
||||
CLRObject co = GetManagedObject(ob) as CLRObject;
|
||||
if (co == null) {
|
||||
return null;
|
||||
}
|
||||
Exception e = co.inst as Exception;
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Exception __str__ implementation
|
||||
//====================================================================
|
||||
|
||||
public new static IntPtr tp_str(IntPtr ob) {
|
||||
Exception e = ToException(ob);
|
||||
if (e == null) {
|
||||
return Exceptions.RaiseTypeError("invalid object");
|
||||
}
|
||||
|
||||
string message = String.Empty;
|
||||
if (e.Message != String.Empty) {
|
||||
message = e.Message;
|
||||
}
|
||||
if ((e.StackTrace != null) && (e.StackTrace != String.Empty)) {
|
||||
message = message + "\n" + e.StackTrace;
|
||||
}
|
||||
return Runtime.PyUnicode_FromString(message);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Exception __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
Exception e = ToException(ob);
|
||||
if (e == null) {
|
||||
return Exceptions.RaiseTypeError("invalid object");
|
||||
}
|
||||
string name = e.GetType().Name;
|
||||
string message;
|
||||
if (e.Message != String.Empty) {
|
||||
message = String.Format("{0}('{1}',)", name, e.Message);
|
||||
} else {
|
||||
message = String.Format("{0}()", name);
|
||||
}
|
||||
return Runtime.PyUnicode_FromString(message);
|
||||
}
|
||||
//====================================================================
|
||||
// Exceptions __getattribute__ implementation.
|
||||
// handles Python's args and message attributes
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_getattro(IntPtr ob, IntPtr key)
|
||||
{
|
||||
if (!Runtime.PyString_Check(key)) {
|
||||
Exceptions.SetError(Exceptions.TypeError, "string expected");
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
string name = Runtime.GetManagedString(key);
|
||||
if (name == "args") {
|
||||
Exception e = ToException(ob);
|
||||
IntPtr args;
|
||||
if (e.Message != String.Empty) {
|
||||
args = Runtime.PyTuple_New(1);
|
||||
IntPtr msg = Runtime.PyUnicode_FromString(e.Message);
|
||||
Runtime.PyTuple_SetItem(args, 0, msg);
|
||||
} else {
|
||||
args = Runtime.PyTuple_New(0);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
if (name == "message") {
|
||||
return ExceptionClassObject.tp_str(ob);
|
||||
}
|
||||
|
||||
return Runtime.PyObject_GenericGetAttr(ob, key);
|
||||
}
|
||||
#endif // (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates the Python exception APIs.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Readability of the Exceptions class improvements as we look toward version 2.7 ...
|
||||
/// </remarks>
|
||||
|
||||
public class Exceptions {
|
||||
|
||||
internal static IntPtr warnings_module;
|
||||
internal static IntPtr exceptions_module;
|
||||
|
||||
private Exceptions() {}
|
||||
|
||||
//===================================================================
|
||||
// Initialization performed on startup of the Python runtime.
|
||||
//===================================================================
|
||||
|
||||
internal static void Initialize() {
|
||||
exceptions_module = Runtime.PyImport_ImportModule("exceptions");
|
||||
Exceptions.ErrorCheck(exceptions_module);
|
||||
warnings_module = Runtime.PyImport_ImportModule("warnings");
|
||||
Exceptions.ErrorCheck(warnings_module);
|
||||
Type type = typeof(Exceptions);
|
||||
foreach (FieldInfo fi in type.GetFields(BindingFlags.Public |
|
||||
BindingFlags.Static)) {
|
||||
IntPtr op = Runtime.PyObject_GetAttrString(exceptions_module, fi.Name);
|
||||
if (op != IntPtr.Zero) {
|
||||
fi.SetValue(type, op);
|
||||
}
|
||||
else {
|
||||
fi.SetValue(type, IntPtr.Zero);
|
||||
DebugUtil.Print("Unknown exception: " + fi.Name);
|
||||
}
|
||||
}
|
||||
Runtime.PyErr_Clear();
|
||||
if (Runtime.wrap_exceptions) {
|
||||
SetupExceptionHack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Cleanup resources upon shutdown of the Python runtime.
|
||||
//===================================================================
|
||||
|
||||
internal static void Shutdown() {
|
||||
Type type = typeof(Exceptions);
|
||||
foreach (FieldInfo fi in type.GetFields(BindingFlags.Public |
|
||||
BindingFlags.Static)) {
|
||||
IntPtr op = (IntPtr)fi.GetValue(type);
|
||||
if (op != IntPtr.Zero) {
|
||||
Runtime.Decref(op);
|
||||
}
|
||||
}
|
||||
Runtime.Decref(exceptions_module);
|
||||
Runtime.Decref(warnings_module);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shortcut for (pointer == NULL) -> throw PythonException
|
||||
/// </summary>
|
||||
/// <param name="pointer">Pointer to a Python object</param>
|
||||
internal unsafe static void ErrorCheck(IntPtr pointer) {
|
||||
if (pointer == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shortcut for (pointer == NULL or ErrorOccurred()) -> throw PythonException
|
||||
/// </summary>
|
||||
/// Shortcut for (pointer == NULL) -> throw PythonException
|
||||
internal unsafe static void ErrorOccurredCheck(IntPtr pointer) {
|
||||
if ((pointer == IntPtr.Zero) || Exceptions.ErrorOccurred()) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
// Versions of CPython up to 2.4 do not allow exceptions to be
|
||||
// new-style classes. To get around that restriction and provide
|
||||
// a consistent user experience for programmers, we wrap managed
|
||||
// exceptions in an old-style class that (through some dont-try-
|
||||
// this-at-home hackery) delegates to the managed exception and
|
||||
// obeys the conventions of both Python and managed exceptions.
|
||||
|
||||
/// <remarks>
|
||||
/// Conditionally initialized variables!
|
||||
/// </remarks>
|
||||
static IntPtr ns_exc; // new-style class for System.Exception
|
||||
static IntPtr os_exc; // old-style class for System.Exception
|
||||
static Hashtable cache;
|
||||
|
||||
/// <remarks>
|
||||
/// the lines
|
||||
/// // XXX - hack to raise a compatible old-style exception ;(
|
||||
/// if (Runtime.wrap_exceptions) {
|
||||
/// CallOneOfTheseMethods();
|
||||
///
|
||||
/// </remarks>
|
||||
internal static void SetupExceptionHack() {
|
||||
ns_exc = ClassManager.GetClass(typeof(Exception)).pyHandle;
|
||||
cache = new Hashtable();
|
||||
|
||||
string code =
|
||||
"import exceptions\n" +
|
||||
"class Exception(exceptions.Exception):\n" +
|
||||
" _class = None\n" +
|
||||
" _inner = None\n" +
|
||||
" \n" +
|
||||
" #@property\n" +
|
||||
" def message(self):\n" +
|
||||
" return self.Message\n" +
|
||||
" message = property(message)\n" +
|
||||
" \n" +
|
||||
" def __init__(self, *args, **kw):\n" +
|
||||
" inst = self.__class__._class(*args, **kw)\n" +
|
||||
" self.__dict__['_inner'] = inst\n" +
|
||||
" exceptions.Exception.__init__(self, *args, **kw)\n" +
|
||||
"\n" +
|
||||
" def __getattr__(self, name, _marker=[]):\n" +
|
||||
" inner = self.__dict__['_inner']\n" +
|
||||
" v = getattr(inner, name, _marker)\n" +
|
||||
" if v is not _marker:\n" +
|
||||
" return v\n" +
|
||||
" v = self.__dict__.get(name, _marker)\n" +
|
||||
" if v is not _marker:\n" +
|
||||
" return v\n" +
|
||||
" raise AttributeError(name)\n" +
|
||||
"\n" +
|
||||
" def __setattr__(self, name, value):\n" +
|
||||
" inner = self.__dict__['_inner']\n" +
|
||||
" setattr(inner, name, value)\n" +
|
||||
"\n" +
|
||||
" def __str__(self):\n" +
|
||||
" inner = self.__dict__.get('_inner')\n" +
|
||||
" msg = getattr(inner, 'Message', '')\n" +
|
||||
" st = getattr(inner, 'StackTrace', '')\n" +
|
||||
" st = st and '\\n' + st or ''\n" +
|
||||
" return msg + st\n" +
|
||||
" \n" +
|
||||
" def __repr__(self):\n" +
|
||||
" inner = self.__dict__.get('_inner')\n" +
|
||||
" msg = getattr(inner, 'Message', '')\n" +
|
||||
" name = self.__class__.__name__\n" +
|
||||
" return '%s(\\'%s\\',)' % (name, msg) \n" +
|
||||
"\n";
|
||||
|
||||
IntPtr dict = Runtime.PyDict_New();
|
||||
|
||||
IntPtr builtins = Runtime.PyEval_GetBuiltins();
|
||||
Runtime.PyDict_SetItemString(dict, "__builtins__", builtins);
|
||||
|
||||
IntPtr namestr = Runtime.PyString_FromString("System");
|
||||
Runtime.PyDict_SetItemString(dict, "__name__", namestr);
|
||||
Runtime.Decref(namestr);
|
||||
|
||||
Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone);
|
||||
Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone);
|
||||
|
||||
IntPtr flag = Runtime.Py_file_input;
|
||||
IntPtr result = Runtime.PyRun_String(code, flag, dict, dict);
|
||||
Exceptions.ErrorCheck(result);
|
||||
Runtime.Decref(result);
|
||||
|
||||
os_exc = Runtime.PyDict_GetItemString(dict, "Exception");
|
||||
Runtime.PyObject_SetAttrString(os_exc, "_class", ns_exc);
|
||||
Runtime.PyErr_Clear();
|
||||
}
|
||||
|
||||
|
||||
internal static IntPtr GenerateExceptionClass(IntPtr real) {
|
||||
if (real == ns_exc) {
|
||||
return os_exc;
|
||||
}
|
||||
|
||||
IntPtr nbases = Runtime.PyObject_GetAttrString(real, "__bases__");
|
||||
if (Runtime.PyTuple_Size(nbases) != 1) {
|
||||
throw new SystemException("Invalid __bases__");
|
||||
}
|
||||
IntPtr nsbase = Runtime.PyTuple_GetItem(nbases, 0);
|
||||
Runtime.Decref(nbases);
|
||||
|
||||
IntPtr osbase = GetExceptionClassWrapper(nsbase);
|
||||
IntPtr baselist = Runtime.PyTuple_New(1);
|
||||
Runtime.Incref(osbase);
|
||||
Runtime.PyTuple_SetItem(baselist, 0, osbase);
|
||||
IntPtr name = Runtime.PyObject_GetAttrString(real, "__name__");
|
||||
|
||||
IntPtr dict = Runtime.PyDict_New();
|
||||
IntPtr mod = Runtime.PyObject_GetAttrString(real, "__module__");
|
||||
Runtime.PyDict_SetItemString(dict, "__module__", mod);
|
||||
Runtime.Decref(mod);
|
||||
|
||||
IntPtr subc = Runtime.PyClass_New(baselist, dict, name);
|
||||
Runtime.Decref(baselist);
|
||||
Runtime.Decref(dict);
|
||||
Runtime.Decref(name);
|
||||
|
||||
Runtime.PyObject_SetAttrString(subc, "_class", real);
|
||||
return subc;
|
||||
}
|
||||
|
||||
internal static IntPtr GetExceptionClassWrapper(IntPtr real) {
|
||||
// Given the pointer to a new-style class representing a managed
|
||||
// exception, return an appropriate old-style class wrapper that
|
||||
// maintains all of the expectations and delegates to the wrapped
|
||||
// class.
|
||||
object ob = cache[real];
|
||||
if (ob == null) {
|
||||
IntPtr op = GenerateExceptionClass(real);
|
||||
cache[real] = op;
|
||||
return op;
|
||||
}
|
||||
return (IntPtr)ob;
|
||||
}
|
||||
|
||||
internal static IntPtr GetExceptionInstanceWrapper(IntPtr real) {
|
||||
// Given the pointer to a new-style class instance representing a
|
||||
// managed exception, return an appropriate old-style class
|
||||
// wrapper instance that delegates to the wrapped instance.
|
||||
IntPtr tp = Runtime.PyObject_TYPE(real);
|
||||
if (Runtime.PyObject_TYPE(tp) == Runtime.PyInstanceType) {
|
||||
return real;
|
||||
}
|
||||
// Get / generate a class wrapper, instantiate it and set its
|
||||
// _inner attribute to the real new-style exception instance.
|
||||
IntPtr ct = GetExceptionClassWrapper(tp);
|
||||
Exceptions.ErrorCheck(ct);
|
||||
IntPtr op = Runtime.PyInstance_NewRaw(ct, IntPtr.Zero);
|
||||
Exceptions.ErrorCheck(op);
|
||||
IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__");
|
||||
Exceptions.ErrorCheck(d);
|
||||
Runtime.PyDict_SetItemString(d, "_inner", real);
|
||||
Runtime.Decref(d);
|
||||
return op;
|
||||
}
|
||||
|
||||
internal static IntPtr UnwrapExceptionClass(IntPtr op) {
|
||||
// In some cases its necessary to recognize an exception *class*,
|
||||
// and obtain the inner (wrapped) exception class. This method
|
||||
// returns the inner class if found, or a null pointer.
|
||||
|
||||
IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__");
|
||||
if (d == IntPtr.Zero) {
|
||||
Exceptions.Clear();
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
IntPtr c = Runtime.PyDict_GetItemString(d, "_class");
|
||||
Runtime.Decref(d);
|
||||
if (c == IntPtr.Zero) {
|
||||
Exceptions.Clear();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// GetException Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Retrieve Python exception information as a PythonException
|
||||
/// instance. The properties of the PythonException may be used
|
||||
/// to access the exception type, value and traceback info.
|
||||
/// </remarks>
|
||||
|
||||
public static PythonException GetException() {
|
||||
// TODO: implement this.
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExceptionMatches Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the current Python exception matches the given
|
||||
/// Python object. This is a wrapper for PyErr_ExceptionMatches.
|
||||
/// </remarks>
|
||||
|
||||
public static bool ExceptionMatches(IntPtr ob) {
|
||||
return Runtime.PyErr_ExceptionMatches(ob) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExceptionMatches Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given Python exception matches the given
|
||||
/// Python object. This is a wrapper for PyErr_GivenExceptionMatches.
|
||||
/// </remarks>
|
||||
|
||||
public static bool ExceptionMatches(IntPtr exc, IntPtr ob) {
|
||||
int i = Runtime.PyErr_GivenExceptionMatches(exc, ob);
|
||||
return (i != 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetError Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the current Python exception given a native string.
|
||||
/// This is a wrapper for the Python PyErr_SetString call.
|
||||
/// </remarks>
|
||||
|
||||
public static void SetError(IntPtr ob, string value) {
|
||||
Runtime.PyErr_SetString(ob, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetError Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the current Python exception given a Python object.
|
||||
/// This is a wrapper for the Python PyErr_SetObject call.
|
||||
/// </remarks>
|
||||
|
||||
public static void SetError(IntPtr ob, IntPtr value) {
|
||||
Runtime.PyErr_SetObject(ob, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetError Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the current Python exception given a CLR exception
|
||||
/// object. The CLR exception instance is wrapped as a Python
|
||||
/// object, allowing it to be handled naturally from Python.
|
||||
/// </remarks>
|
||||
|
||||
public static void SetError(Exception e) {
|
||||
|
||||
// Because delegates allow arbitrary nestings of Python calling
|
||||
// managed calling Python calling... etc. it is possible that we
|
||||
// might get a managed exception raised that is a wrapper for a
|
||||
// Python exception. In that case we'd rather have the real thing.
|
||||
|
||||
PythonException pe = e as PythonException;
|
||||
if (pe != null) {
|
||||
Runtime.PyErr_SetObject(pe.PyType, pe.PyValue);
|
||||
return;
|
||||
}
|
||||
|
||||
IntPtr op = CLRObject.GetInstHandle(e);
|
||||
|
||||
// XXX - hack to raise a compatible old-style exception ;(
|
||||
if (Runtime.wrap_exceptions) {
|
||||
op = GetExceptionInstanceWrapper(op);
|
||||
}
|
||||
IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__");
|
||||
Runtime.PyErr_SetObject(etype, op);
|
||||
Runtime.Decref(etype);
|
||||
Runtime.Decref(op);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ErrorOccurred Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if an exception occurred in the Python runtime.
|
||||
/// This is a wrapper for the Python PyErr_Occurred call.
|
||||
/// </remarks>
|
||||
|
||||
public static bool ErrorOccurred() {
|
||||
return Runtime.PyErr_Occurred() != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Clear any exception that has been set in the Python runtime.
|
||||
/// </remarks>
|
||||
|
||||
public static void Clear() {
|
||||
Runtime.PyErr_Clear();
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// helper methods for raising warnings
|
||||
//====================================================================
|
||||
|
||||
/// <summary>
|
||||
/// Alias for Python's warnings.warn() function.
|
||||
/// </summary>
|
||||
public static void warn(string message, IntPtr exception, int stacklevel)
|
||||
{
|
||||
if ((exception == IntPtr.Zero) ||
|
||||
(Runtime.PyObject_IsSubclass(exception, Exceptions.Warning) != 1)) {
|
||||
Exceptions.RaiseTypeError("Invalid exception");
|
||||
}
|
||||
|
||||
Runtime.Incref(warnings_module);
|
||||
IntPtr warn = Runtime.PyObject_GetAttrString(warnings_module, "warn");
|
||||
Runtime.Decref(warnings_module);
|
||||
Exceptions.ErrorCheck(warn);
|
||||
|
||||
IntPtr args = Runtime.PyTuple_New(3);
|
||||
IntPtr msg = Runtime.PyString_FromString(message);
|
||||
Runtime.Incref(exception); // PyTuple_SetItem steals a reference
|
||||
IntPtr level = Runtime.PyInt_FromInt32(stacklevel);
|
||||
Runtime.PyTuple_SetItem(args, 0, msg);
|
||||
Runtime.PyTuple_SetItem(args, 1, exception);
|
||||
Runtime.PyTuple_SetItem(args, 2, level);
|
||||
|
||||
IntPtr result = Runtime.PyObject_CallObject(warn, args);
|
||||
Exceptions.ErrorCheck(result);
|
||||
|
||||
Runtime.Decref(warn);
|
||||
Runtime.Decref(result);
|
||||
Runtime.Decref(args);
|
||||
}
|
||||
|
||||
public static void warn(string message, IntPtr exception)
|
||||
{
|
||||
warn(message, exception, 1);
|
||||
}
|
||||
|
||||
public static void deprecation(string message, int stacklevel)
|
||||
{
|
||||
warn(message, Exceptions.DeprecationWarning, stacklevel);
|
||||
}
|
||||
|
||||
public static void deprecation(string message)
|
||||
{
|
||||
deprecation(message, 1);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Internal helper methods for common error handling scenarios.
|
||||
//====================================================================
|
||||
|
||||
internal static IntPtr RaiseTypeError(string message) {
|
||||
Exceptions.SetError(Exceptions.TypeError, message);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// 2010-11-16: Arranged in python (2.6 & 2.7) source header file order
|
||||
/* Predefined exceptions are
|
||||
puplic static variables on the Exceptions class filled in from
|
||||
the python class using reflection in Initialize() looked up by
|
||||
name, not posistion. */
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
public static IntPtr BaseException;
|
||||
#endif
|
||||
public static IntPtr Exception;
|
||||
public static IntPtr StopIteration;
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
public static IntPtr GeneratorExit;
|
||||
#endif
|
||||
public static IntPtr StandardError;
|
||||
public static IntPtr ArithmeticError;
|
||||
public static IntPtr LookupError;
|
||||
|
||||
public static IntPtr AssertionError;
|
||||
public static IntPtr AttributeError;
|
||||
public static IntPtr EOFError;
|
||||
public static IntPtr FloatingPointError;
|
||||
public static IntPtr EnvironmentError;
|
||||
public static IntPtr IOError;
|
||||
public static IntPtr OSError;
|
||||
public static IntPtr ImportError;
|
||||
public static IntPtr IndexError;
|
||||
public static IntPtr KeyError;
|
||||
public static IntPtr KeyboardInterrupt;
|
||||
public static IntPtr MemoryError;
|
||||
public static IntPtr NameError;
|
||||
public static IntPtr OverflowError;
|
||||
public static IntPtr RuntimeError;
|
||||
public static IntPtr NotImplementedError;
|
||||
public static IntPtr SyntaxError;
|
||||
public static IntPtr IndentationError;
|
||||
public static IntPtr TabError;
|
||||
public static IntPtr ReferenceError;
|
||||
public static IntPtr SystemError;
|
||||
public static IntPtr SystemExit;
|
||||
public static IntPtr TypeError;
|
||||
public static IntPtr UnboundLocalError;
|
||||
public static IntPtr UnicodeError;
|
||||
public static IntPtr UnicodeEncodeError;
|
||||
public static IntPtr UnicodeDecodeError;
|
||||
public static IntPtr UnicodeTranslateError;
|
||||
public static IntPtr ValueError;
|
||||
public static IntPtr ZeroDivisionError;
|
||||
//#ifdef MS_WINDOWS
|
||||
//public static IntPtr WindowsError;
|
||||
//#endif
|
||||
//#ifdef __VMS
|
||||
//public static IntPtr VMSError;
|
||||
//#endif
|
||||
|
||||
//PyAPI_DATA(PyObject *) PyExc_BufferError;
|
||||
|
||||
//PyAPI_DATA(PyObject *) PyExc_MemoryErrorInst;
|
||||
//PyAPI_DATA(PyObject *) PyExc_RecursionErrorInst;
|
||||
|
||||
|
||||
/* Predefined warning categories */
|
||||
public static IntPtr Warning;
|
||||
public static IntPtr UserWarning;
|
||||
public static IntPtr DeprecationWarning;
|
||||
public static IntPtr PendingDeprecationWarning;
|
||||
public static IntPtr SyntaxWarning;
|
||||
public static IntPtr RuntimeWarning;
|
||||
public static IntPtr FutureWarning;
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
public static IntPtr ImportWarning;
|
||||
public static IntPtr UnicodeWarning;
|
||||
//PyAPI_DATA(PyObject *) PyExc_BytesWarning;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
129
Pythonnet.Runtime/extensiontype.cs
Normal file
129
Pythonnet.Runtime/extensiontype.cs
Normal file
@ -0,0 +1,129 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Base class for extensions whose instances *share* a single Python
|
||||
/// type object, such as the types that represent CLR methods, fields,
|
||||
/// etc. Instances implemented by this class do not support subtyping.
|
||||
/// </summary>
|
||||
|
||||
internal abstract class ExtensionType : ManagedType {
|
||||
|
||||
public ExtensionType() : base() {
|
||||
|
||||
// Create a new PyObject whose type is a generated type that is
|
||||
// implemented by the particuar concrete ExtensionType subclass.
|
||||
// The Python instance object is related to an instance of a
|
||||
// particular concrete subclass with a hidden CLR gchandle.
|
||||
|
||||
IntPtr tp = TypeManager.GetTypeHandle(this.GetType());
|
||||
|
||||
// int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt);
|
||||
// if (rc > 1050) {
|
||||
// DebugUtil.Print("tp is: ", tp);
|
||||
// DebugUtil.DumpType(tp);
|
||||
// }
|
||||
|
||||
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
|
||||
|
||||
GCHandle gc = GCHandle.Alloc(this);
|
||||
Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)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(py);
|
||||
|
||||
this.tpHandle = tp;
|
||||
this.pyHandle = py;
|
||||
this.gcHandle = gc;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Common finalization code to support custom tp_deallocs.
|
||||
//====================================================================
|
||||
|
||||
public static void FinalizeObject(ManagedType self) {
|
||||
Runtime.PyObject_GC_Del(self.pyHandle);
|
||||
Runtime.Decref(self.tpHandle);
|
||||
self.gcHandle.Free();
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Type __setattr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static int tp_setattro(IntPtr ob, IntPtr key, IntPtr val) {
|
||||
string message = "type does not support setting attributes";
|
||||
if (val == IntPtr.Zero) {
|
||||
message = "readonly attribute";
|
||||
}
|
||||
Exceptions.SetError(Exceptions.TypeError, message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// 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) {
|
||||
string message = "attribute is read-only";
|
||||
Exceptions.SetError(Exceptions.AttributeError, message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Required Python GC support.
|
||||
//====================================================================
|
||||
|
||||
public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public static int tp_clear(IntPtr ob) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public static int tp_is_gc(IntPtr type) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Default dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
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);
|
||||
FinalizeObject(self);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
150
Pythonnet.Runtime/fieldobject.cs
Normal file
150
Pythonnet.Runtime/fieldobject.cs
Normal file
@ -0,0 +1,150 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python descriptor type that provides access to CLR fields.
|
||||
//========================================================================
|
||||
|
||||
internal class FieldObject : ExtensionType {
|
||||
|
||||
FieldInfo info;
|
||||
|
||||
public FieldObject(FieldInfo info) : base() {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __get__ implementation. This method returns the
|
||||
// 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) {
|
||||
FieldObject self = (FieldObject)GetManagedObject(ds);
|
||||
Object result;
|
||||
|
||||
if (self == null) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
FieldInfo info = self.info;
|
||||
|
||||
if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) {
|
||||
if (!info.IsStatic) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"instance attribute must be accessed " +
|
||||
"through a class instance"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
try {
|
||||
result = info.GetValue(null);
|
||||
return Converter.ToPython(result, info.FieldType);
|
||||
}
|
||||
catch(Exception e) {
|
||||
Exceptions.SetError(Exceptions.TypeError, e.Message);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
CLRObject co = (CLRObject)GetManagedObject(ob);
|
||||
result = info.GetValue(co.inst);
|
||||
return Converter.ToPython(result, info.FieldType);
|
||||
}
|
||||
catch(Exception e) {
|
||||
Exceptions.SetError(Exceptions.TypeError, e.Message);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __set__ implementation. This method sets the value of
|
||||
// a field based on the given Python value. The Python value must be
|
||||
// convertible to the type of the field.
|
||||
//====================================================================
|
||||
|
||||
public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
|
||||
FieldObject self = (FieldObject)GetManagedObject(ds);
|
||||
Object newval;
|
||||
|
||||
if (self == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (val == IntPtr.Zero) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"cannot delete field"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
FieldInfo info = self.info;
|
||||
|
||||
if (info.IsLiteral || info.IsInitOnly) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"field is read-only"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool is_static = info.IsStatic;
|
||||
|
||||
if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) {
|
||||
if (!is_static) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"instance attribute must be set " +
|
||||
"through a class instance"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Converter.ToManaged(val, info.FieldType, out newval,
|
||||
true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!is_static) {
|
||||
CLRObject co = (CLRObject)GetManagedObject(ob);
|
||||
info.SetValue(co.inst, newval);
|
||||
}
|
||||
else {
|
||||
info.SetValue(null, newval);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
catch(Exception e) {
|
||||
Exceptions.SetError(Exceptions.TypeError, e.Message);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
FieldObject self = (FieldObject)GetManagedObject(ob);
|
||||
string s = String.Format("<field '{0}'>", self.info.Name);
|
||||
return Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
100
Pythonnet.Runtime/generictype.cs
Normal file
100
Pythonnet.Runtime/generictype.cs
Normal file
@ -0,0 +1,100 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Implements reflected generic types. Note that the Python behavior
|
||||
/// is the same for both generic type definitions and constructed open
|
||||
/// generic types. Both are essentially factories for creating closed
|
||||
/// types based on the required generic type parameters.
|
||||
/// </summary>
|
||||
|
||||
internal class GenericType : ClassBase {
|
||||
|
||||
internal GenericType(Type tp) : base(tp) {}
|
||||
|
||||
//====================================================================
|
||||
// Implements __new__ for reflected generic types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"cannot instantiate an open generic type"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements __call__ for reflected generic types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"object is not callable");
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Implements subscript syntax for reflected generic types. A closed
|
||||
// type is created by binding the generic type via subscript syntax:
|
||||
// inst = List[str]()
|
||||
//====================================================================
|
||||
|
||||
public override IntPtr type_subscript(IntPtr idx) {
|
||||
Type[] types = Runtime.PythonArgsToTypeArray(idx);
|
||||
if (types == null) {
|
||||
return Exceptions.RaiseTypeError("type(s) expected");
|
||||
}
|
||||
if (!this.type.IsGenericTypeDefinition) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"type is not a generic type definition"
|
||||
);
|
||||
}
|
||||
|
||||
// This is a little tricky, because an instance of GenericType
|
||||
// may represent either a specific generic type, or act as an
|
||||
// alias for one or more generic types with the same base name.
|
||||
|
||||
if (this.type.ContainsGenericParameters) {
|
||||
Type[] args = this.type.GetGenericArguments();
|
||||
Type target = null;
|
||||
|
||||
if (args.Length == types.Length) {
|
||||
target = this.type;
|
||||
}
|
||||
else {
|
||||
foreach (Type t in
|
||||
GenericUtil.GenericsForType(this.type)) {
|
||||
if (t.GetGenericArguments().Length == types.Length) {
|
||||
target = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target != null) {
|
||||
Type t = target.MakeGenericType(types);
|
||||
ManagedType c = (ManagedType)ClassManager.GetClass(t);
|
||||
Runtime.Incref(c.pyHandle);
|
||||
return c.pyHandle;
|
||||
}
|
||||
return Exceptions.RaiseTypeError("no type matches params");
|
||||
}
|
||||
|
||||
return Exceptions.RaiseTypeError("unsubscriptable object");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
138
Pythonnet.Runtime/genericutil.cs
Normal file
138
Pythonnet.Runtime/genericutil.cs
Normal file
@ -0,0 +1,138 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Security;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// This class is responsible for efficiently maintaining the bits
|
||||
/// of information we need to support aliases with 'nice names'.
|
||||
/// </summary>
|
||||
|
||||
internal class GenericUtil {
|
||||
|
||||
static Dictionary<string, Dictionary<string, List<string>>> mapping;
|
||||
|
||||
private GenericUtil() {}
|
||||
|
||||
static GenericUtil() {
|
||||
mapping = new
|
||||
Dictionary<string, Dictionary<string, List<string>>>();
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Register a generic type that appears in a given namespace.
|
||||
//====================================================================
|
||||
|
||||
internal static void Register(Type t) {
|
||||
Dictionary<string, List<string>> nsmap = null;
|
||||
mapping.TryGetValue(t.Namespace, out nsmap);
|
||||
if (nsmap == null) {
|
||||
nsmap = new Dictionary<string, List<string>>();
|
||||
mapping[t.Namespace] = nsmap;
|
||||
}
|
||||
string basename = t.Name;
|
||||
int tick = basename.IndexOf("`");
|
||||
if (tick > -1) {
|
||||
basename = basename.Substring(0, tick);
|
||||
}
|
||||
List<string> gnames = null;
|
||||
nsmap.TryGetValue(basename, out gnames);
|
||||
if (gnames == null) {
|
||||
gnames = new List<string>();
|
||||
nsmap[basename] = gnames;
|
||||
}
|
||||
gnames.Add(t.Name);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// xxx
|
||||
//====================================================================
|
||||
|
||||
public static List<string> GetGenericBaseNames(string ns) {
|
||||
Dictionary<string, List<string>> nsmap = null;
|
||||
mapping.TryGetValue(ns, out nsmap);
|
||||
if (nsmap == null) {
|
||||
return null;
|
||||
}
|
||||
List<string> names = new List<string>();
|
||||
foreach (string key in nsmap.Keys) {
|
||||
names.Add(key);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// xxx
|
||||
//====================================================================
|
||||
|
||||
public static List<Type> GenericsForType(Type t) {
|
||||
Dictionary<string, List<string>> nsmap = null;
|
||||
mapping.TryGetValue(t.Namespace, out nsmap);
|
||||
if (nsmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
string basename = t.Name;
|
||||
int tick = basename.IndexOf("`");
|
||||
if (tick > -1) {
|
||||
basename = basename.Substring(0, tick);
|
||||
}
|
||||
|
||||
List<string> names = null;
|
||||
nsmap.TryGetValue(basename, out names);
|
||||
if (names == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Type> result = new List<Type>();
|
||||
foreach (string name in names) {
|
||||
string qname = t.Namespace + "." + name;
|
||||
Type o = AssemblyManager.LookupType(qname);
|
||||
if (o != null) {
|
||||
result.Add(o);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// xxx
|
||||
//====================================================================
|
||||
|
||||
public static string GenericNameForBaseName(string ns, string name) {
|
||||
Dictionary<string, List<string>> nsmap = null;
|
||||
mapping.TryGetValue(ns, out nsmap);
|
||||
if (nsmap == null) {
|
||||
return null;
|
||||
}
|
||||
List<string> gnames = null;
|
||||
nsmap.TryGetValue(name, out gnames);
|
||||
if (gnames == null) {
|
||||
return null;
|
||||
}
|
||||
if (gnames.Count > 0) {
|
||||
return gnames[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
243
Pythonnet.Runtime/importhook.cs
Normal file
243
Pythonnet.Runtime/importhook.cs
Normal file
@ -0,0 +1,243 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements the "import hook" used to integrate Python with the CLR.
|
||||
//========================================================================
|
||||
|
||||
internal class ImportHook {
|
||||
|
||||
static IntPtr py_import;
|
||||
static CLRModule root;
|
||||
static MethodWrapper hook;
|
||||
|
||||
//===================================================================
|
||||
// Initialization performed on startup of the Python runtime.
|
||||
//===================================================================
|
||||
|
||||
internal static void Initialize() {
|
||||
|
||||
// Initialize the Python <--> CLR module hook. We replace the
|
||||
// built-in Python __import__ with our own. This isn't ideal,
|
||||
// but it provides the most "Pythonic" way of dealing with CLR
|
||||
// modules (Python doesn't provide a way to emulate packages).
|
||||
|
||||
IntPtr dict = Runtime.PyImport_GetModuleDict();
|
||||
IntPtr mod = Runtime.PyDict_GetItemString(dict, "__builtin__");
|
||||
py_import = Runtime.PyObject_GetAttrString(mod, "__import__");
|
||||
|
||||
hook = new MethodWrapper(typeof(ImportHook), "__import__");
|
||||
Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
|
||||
Runtime.Decref(hook.ptr);
|
||||
|
||||
root = new CLRModule();
|
||||
Runtime.Incref(root.pyHandle); // we are using the module two times
|
||||
Runtime.PyDict_SetItemString(dict, "CLR", root.pyHandle);
|
||||
Runtime.PyDict_SetItemString(dict, "clr", root.pyHandle);
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Cleanup resources upon shutdown of the Python runtime.
|
||||
//===================================================================
|
||||
|
||||
internal static void Shutdown() {
|
||||
Runtime.Decref(root.pyHandle);
|
||||
Runtime.Decref(root.pyHandle);
|
||||
Runtime.Decref(py_import);
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// The actual import hook that ties Python to the managed world.
|
||||
//===================================================================
|
||||
|
||||
public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) {
|
||||
|
||||
// Replacement for the builtin __import__. The original import
|
||||
// hook is saved as this.py_import. This version handles CLR
|
||||
// import and defers to the normal builtin for everything else.
|
||||
|
||||
int num_args = Runtime.PyTuple_Size(args);
|
||||
if (num_args < 1) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"__import__() takes at least 1 argument (0 given)"
|
||||
);
|
||||
}
|
||||
|
||||
// borrowed reference
|
||||
IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0);
|
||||
if ((py_mod_name == IntPtr.Zero) ||
|
||||
(!Runtime.IsStringType(py_mod_name))) {
|
||||
return Exceptions.RaiseTypeError("string expected");
|
||||
}
|
||||
|
||||
// Check whether the import is of the form 'from x import y'.
|
||||
// This determines whether we return the head or tail module.
|
||||
|
||||
IntPtr fromList = IntPtr.Zero;
|
||||
bool fromlist = false;
|
||||
if (num_args >= 4) {
|
||||
fromList = Runtime.PyTuple_GetItem(args, 3);
|
||||
if ((fromList != IntPtr.Zero) &&
|
||||
(Runtime.PyObject_IsTrue(fromList) == 1)) {
|
||||
fromlist = true;
|
||||
}
|
||||
}
|
||||
|
||||
string mod_name = Runtime.GetManagedString(py_mod_name);
|
||||
// Check these BEFORE the built-in import runs; may as well
|
||||
// do the Incref()ed return here, since we've already found
|
||||
// the module.
|
||||
if (mod_name == "clr") {
|
||||
root.InitializePreload();
|
||||
Runtime.Incref(root.pyHandle);
|
||||
return root.pyHandle;
|
||||
}
|
||||
if (mod_name == "CLR") {
|
||||
Exceptions.deprecation("The CLR module is deprecated. " +
|
||||
"Please use 'clr'.");
|
||||
root.InitializePreload();
|
||||
Runtime.Incref(root.pyHandle);
|
||||
return root.pyHandle;
|
||||
}
|
||||
string realname = mod_name;
|
||||
if (mod_name.StartsWith("CLR.")) {
|
||||
realname = mod_name.Substring(4);
|
||||
string msg = String.Format("Importing from the CLR.* namespace "+
|
||||
"is deprecated. Please import '{0}' directly.", realname);
|
||||
Exceptions.deprecation(msg);
|
||||
}
|
||||
else {
|
||||
// 2010-08-15: Always seemed smart to let python try first...
|
||||
// This shaves off a few tenths of a second on test_module.py
|
||||
// and works around a quirk where 'sys' is found by the
|
||||
// LoadImplicit() deprecation logic.
|
||||
// Turns out that the AssemblyManager.ResolveHandler() checks to see if any
|
||||
// Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
|
||||
// little sense to me.
|
||||
IntPtr res = Runtime.PyObject_Call(py_import, args, kw);
|
||||
if (res != IntPtr.Zero) {
|
||||
// There was no error.
|
||||
return res;
|
||||
}
|
||||
// There was an error
|
||||
if (!Exceptions.ExceptionMatches(Exceptions.ImportError)) {
|
||||
// and it was NOT an ImportError; bail out here.
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
// Otherwise, just clear the it.
|
||||
Exceptions.Clear();
|
||||
}
|
||||
|
||||
string[] names = realname.Split('.');
|
||||
|
||||
// Now we need to decide if the name refers to a CLR module,
|
||||
// and may have to do an implicit load (for b/w compatibility)
|
||||
// using the AssemblyManager. The assembly manager tries
|
||||
// really hard not to use Python objects or APIs, because
|
||||
// parts of it can run recursively and on strange threads.
|
||||
//
|
||||
// It does need an opportunity from time to time to check to
|
||||
// see if sys.path has changed, in a context that is safe. Here
|
||||
// we know we have the GIL, so we'll let it update if needed.
|
||||
|
||||
AssemblyManager.UpdatePath();
|
||||
if (!AssemblyManager.IsValidNamespace(realname)) {
|
||||
bool fromFile = false;
|
||||
if (AssemblyManager.LoadImplicit(realname, out fromFile)) {
|
||||
if (true == fromFile) {
|
||||
string deprWarning = String.Format("\nThe module was found, but not in a referenced namespace.\n" +
|
||||
"Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", realname);
|
||||
Exceptions.deprecation(deprWarning);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// May be called when a module being imported imports a module.
|
||||
// In particular, I've seen decimal import copy import org.python.core
|
||||
return Runtime.PyObject_Call(py_import, args, kw);
|
||||
}
|
||||
}
|
||||
|
||||
// See if sys.modules for this interpreter already has the
|
||||
// requested module. If so, just return the exising module.
|
||||
|
||||
IntPtr modules = Runtime.PyImport_GetModuleDict();
|
||||
IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name);
|
||||
|
||||
if (module != IntPtr.Zero) {
|
||||
if (fromlist) {
|
||||
Runtime.Incref(module);
|
||||
return module;
|
||||
}
|
||||
module = Runtime.PyDict_GetItemString(modules, names[0]);
|
||||
Runtime.Incref(module);
|
||||
return module;
|
||||
}
|
||||
Exceptions.Clear();
|
||||
|
||||
// Traverse the qualified module name to get the named module
|
||||
// and place references in sys.modules as we go. Note that if
|
||||
// we are running in interactive mode we pre-load the names in
|
||||
// each module, which is often useful for introspection. If we
|
||||
// are not interactive, we stick to just-in-time creation of
|
||||
// objects at lookup time, which is much more efficient.
|
||||
// NEW: The clr got a new module variable preload. You can
|
||||
// enable preloading in a non-interactive python processing by
|
||||
// setting clr.preload = True
|
||||
|
||||
ModuleObject head = (mod_name == realname) ? null : root;
|
||||
ModuleObject tail = root;
|
||||
root.InitializePreload();
|
||||
|
||||
for (int i = 0; i < names.Length; i++) {
|
||||
string name = names[i];
|
||||
ManagedType mt = tail.GetAttribute(name, true);
|
||||
if (!(mt is ModuleObject)) {
|
||||
string error = String.Format("No module named {0}", name);
|
||||
Exceptions.SetError(Exceptions.ImportError, error);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
if (head == null) {
|
||||
head = (ModuleObject)mt;
|
||||
}
|
||||
tail = (ModuleObject) mt;
|
||||
if (CLRModule.preload) {
|
||||
tail.LoadNames();
|
||||
}
|
||||
Runtime.PyDict_SetItemString(modules, tail.moduleName,
|
||||
tail.pyHandle
|
||||
);
|
||||
}
|
||||
|
||||
ModuleObject mod = fromlist ? tail : head;
|
||||
|
||||
if (fromlist && Runtime.PySequence_Size(fromList) == 1) {
|
||||
IntPtr fp = Runtime.PySequence_GetItem(fromList, 0);
|
||||
if ((!CLRModule.preload) && Runtime.GetManagedString(fp) == "*") {
|
||||
mod.LoadNames();
|
||||
}
|
||||
Runtime.Decref(fp);
|
||||
}
|
||||
|
||||
Runtime.Incref(mod.pyHandle);
|
||||
return mod.pyHandle;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
68
Pythonnet.Runtime/indexer.cs
Normal file
68
Pythonnet.Runtime/indexer.cs
Normal file
@ -0,0 +1,68 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Bundles the information required to support an indexer property.
|
||||
//========================================================================
|
||||
|
||||
internal class Indexer {
|
||||
|
||||
public MethodBinder GetterBinder;
|
||||
public MethodBinder SetterBinder;
|
||||
|
||||
public Indexer() {
|
||||
GetterBinder = new MethodBinder();
|
||||
SetterBinder = new MethodBinder();
|
||||
}
|
||||
|
||||
|
||||
public bool CanGet {
|
||||
get {
|
||||
return GetterBinder.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanSet {
|
||||
get {
|
||||
return SetterBinder.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void AddProperty(PropertyInfo pi) {
|
||||
MethodInfo getter = pi.GetGetMethod(true);
|
||||
MethodInfo setter = pi.GetSetMethod(true);
|
||||
if (getter != null) {
|
||||
GetterBinder.AddMethod(getter);
|
||||
}
|
||||
if (setter != null) {
|
||||
SetterBinder.AddMethod(setter);
|
||||
}
|
||||
}
|
||||
|
||||
internal IntPtr GetItem(IntPtr inst, IntPtr args) {
|
||||
return GetterBinder.Invoke(inst, args, IntPtr.Zero);
|
||||
}
|
||||
|
||||
|
||||
internal void SetItem(IntPtr inst, IntPtr args) {
|
||||
SetterBinder.Invoke(inst, args, IntPtr.Zero);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
89
Pythonnet.Runtime/interfaceobject.cs
Normal file
89
Pythonnet.Runtime/interfaceobject.cs
Normal file
@ -0,0 +1,89 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Provides the implementation for reflected interface types. Managed
|
||||
/// interfaces are represented in Python by actual Python type objects.
|
||||
/// Each of those type objects is associated with an instance of this
|
||||
/// class, which provides the implementation for the Python type.
|
||||
/// </summary>
|
||||
|
||||
internal class InterfaceObject : ClassBase {
|
||||
|
||||
internal ConstructorInfo ctor;
|
||||
|
||||
internal InterfaceObject(Type tp) : base(tp) {
|
||||
CoClassAttribute coclass = (CoClassAttribute)
|
||||
Attribute.GetCustomAttribute(tp, cc_attr);
|
||||
if (coclass != null) {
|
||||
ctor = coclass.CoClass.GetConstructor(Type.EmptyTypes);
|
||||
}
|
||||
}
|
||||
|
||||
static Type cc_attr;
|
||||
|
||||
static InterfaceObject() {
|
||||
cc_attr = typeof(CoClassAttribute);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Implements __new__ for reflected interface types.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
InterfaceObject self = (InterfaceObject)GetManagedObject(tp);
|
||||
int nargs = Runtime.PyTuple_Size(args);
|
||||
Type type = self.type;
|
||||
Object obj;
|
||||
|
||||
if (nargs == 1) {
|
||||
IntPtr inst = Runtime.PyTuple_GetItem(args, 0);
|
||||
CLRObject co = GetManagedObject(inst) as CLRObject;
|
||||
|
||||
if ((co == null) || (!type.IsInstanceOfType(co.inst))) {
|
||||
string msg = "object does not implement " + type.Name;
|
||||
Exceptions.SetError(Exceptions.TypeError, msg);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
obj = co.inst;
|
||||
}
|
||||
|
||||
else if ((nargs == 0) && (self.ctor != null)) {
|
||||
obj = self.ctor.Invoke(null);
|
||||
|
||||
if (obj == null || !type.IsInstanceOfType(obj)) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"CoClass default constructor failed"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"interface takes exactly one argument"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return CLRObject.GetInstHandle(obj, self.pyHandle);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
40
Pythonnet.Runtime/interfaces.cs
Normal file
40
Pythonnet.Runtime/interfaces.cs
Normal file
@ -0,0 +1,40 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// xxx
|
||||
/// </summary>
|
||||
|
||||
internal interface IReflectedType {
|
||||
string PythonTypeName();
|
||||
Type GetReflectedType();
|
||||
}
|
||||
|
||||
internal interface IReflectedClass : IReflectedType {
|
||||
bool IsException();
|
||||
}
|
||||
|
||||
internal interface IReflectedInterface : IReflectedType {
|
||||
|
||||
}
|
||||
|
||||
internal interface IReflectedArray : IReflectedType {
|
||||
}
|
||||
|
||||
internal interface IReflectedGenericClass : IReflectedClass {
|
||||
}
|
||||
|
||||
|
||||
}
|
545
Pythonnet.Runtime/interop.cs
Normal file
545
Pythonnet.Runtime/interop.cs
Normal file
@ -0,0 +1,545 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
|
||||
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
|
||||
// when moving to new Python versions.
|
||||
//=======================================================================
|
||||
|
||||
[Serializable()]
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
public class DocStringAttribute : Attribute {
|
||||
public DocStringAttribute(string docStr) {
|
||||
DocString = docStr;
|
||||
}
|
||||
public string DocString {
|
||||
get { return docStr; }
|
||||
set { docStr = value; }
|
||||
}
|
||||
private string docStr;
|
||||
}
|
||||
|
||||
[Serializable()]
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)]
|
||||
internal class PythonMethodAttribute : Attribute {
|
||||
public PythonMethodAttribute() {}
|
||||
}
|
||||
|
||||
[Serializable()]
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)]
|
||||
internal class ModuleFunctionAttribute : Attribute {
|
||||
public ModuleFunctionAttribute() {}
|
||||
}
|
||||
|
||||
[Serializable()]
|
||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)]
|
||||
internal class ForbidPythonThreadsAttribute : Attribute {
|
||||
public ForbidPythonThreadsAttribute() { }
|
||||
}
|
||||
|
||||
|
||||
[Serializable()]
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
internal class ModulePropertyAttribute : Attribute {
|
||||
public ModulePropertyAttribute() {}
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
|
||||
internal class ObjectOffset {
|
||||
|
||||
static ObjectOffset() {
|
||||
int size = IntPtr.Size;
|
||||
int n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD
|
||||
#if (Py_DEBUG)
|
||||
_ob_next = 0;
|
||||
_ob_prev = 1 * size;
|
||||
n = 2;
|
||||
#endif
|
||||
ob_refcnt = (n+0) * size;
|
||||
ob_type = (n+1) * size;
|
||||
ob_dict = (n+2) * size;
|
||||
ob_data = (n+3) * size;
|
||||
}
|
||||
|
||||
public static int magic() {
|
||||
return ob_data;
|
||||
}
|
||||
|
||||
public static int Size() {
|
||||
#if (Py_DEBUG)
|
||||
return 6 * IntPtr.Size;
|
||||
#else
|
||||
return 4 * IntPtr.Size;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (Py_DEBUG)
|
||||
public static int _ob_next;
|
||||
public static int _ob_prev;
|
||||
#endif
|
||||
public static int ob_refcnt;
|
||||
public static int ob_type;
|
||||
public static int ob_dict;
|
||||
public static int ob_data;
|
||||
}
|
||||
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
/* The *real* layout of a type object when allocated on the heap */
|
||||
//typedef struct _heaptypeobject {
|
||||
#if (Py_DEBUG) // #ifdef Py_TRACE_REFS
|
||||
/* _PyObject_HEAD_EXTRA defines pointers to support a doubly-linked list of all live heap objects. */
|
||||
public static int _ob_next = 0;
|
||||
public static int _ob_prev = 0;
|
||||
#endif
|
||||
// PyObject_VAR_HEAD {
|
||||
// PyObject_HEAD {
|
||||
public static int ob_refcnt = 0;
|
||||
public static int ob_type = 0;
|
||||
// }
|
||||
public static int ob_size = 0; /* Number of items in _VAR_iable part */
|
||||
// }
|
||||
public static int tp_name = 0; /* For printing, in format "<module>.<name>" */
|
||||
public static int tp_basicsize = 0; /* For allocation */
|
||||
public static int tp_itemsize = 0;
|
||||
|
||||
/* Methods to implement standard operations */
|
||||
public static int tp_dealloc = 0;
|
||||
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_repr = 0;
|
||||
|
||||
/* Method suites for standard classes */
|
||||
public static int tp_as_number = 0;
|
||||
public static int tp_as_sequence = 0;
|
||||
public static int tp_as_mapping = 0;
|
||||
|
||||
/* More standard operations (here for binary compatibility) */
|
||||
public static int tp_hash = 0;
|
||||
public static int tp_call = 0;
|
||||
public static int tp_str = 0;
|
||||
public static int tp_getattro = 0;
|
||||
public static int tp_setattro = 0;
|
||||
|
||||
/* Functions to access object as input/output buffer */
|
||||
public static int tp_as_buffer = 0;
|
||||
|
||||
/* Flags to define presence of optional/expanded features */
|
||||
public static int tp_flags = 0;
|
||||
|
||||
public static int tp_doc = 0; /* Documentation string */
|
||||
|
||||
/* Assigned meaning in release 2.0 */
|
||||
/* call function for all accessible objects */
|
||||
public static int tp_traverse = 0;
|
||||
/* delete references to contained objects */
|
||||
public static int tp_clear = 0;
|
||||
|
||||
/* Assigned meaning in release 2.1 */
|
||||
/* rich comparisons */
|
||||
public static int tp_richcompare = 0;
|
||||
/* weak reference enabler */
|
||||
public static int tp_weaklistoffset = 0;
|
||||
|
||||
/* Added in release 2.2 */
|
||||
/* Iterators */
|
||||
public static int tp_iter = 0;
|
||||
public static int tp_iternext = 0;
|
||||
/* Attribute descriptor and subclassing stuff */
|
||||
public static int tp_methods = 0;
|
||||
public static int tp_members = 0;
|
||||
public static int tp_getset = 0;
|
||||
public static int tp_base = 0;
|
||||
public static int tp_dict = 0;
|
||||
public static int tp_descr_get = 0;
|
||||
public static int tp_descr_set = 0;
|
||||
public static int tp_dictoffset = 0;
|
||||
public static int tp_init = 0;
|
||||
public static int tp_alloc = 0;
|
||||
public static int tp_new = 0;
|
||||
public static int tp_free = 0; /* Low-level free-memory routine */
|
||||
public static int tp_is_gc = 0; /* For PyObject_IS_GC */
|
||||
public static int tp_bases = 0;
|
||||
public static int tp_mro = 0; /* method resolution order */
|
||||
public static int tp_cache = 0;
|
||||
public static int tp_subclasses = 0;
|
||||
public static int tp_weaklist = 0;
|
||||
public static int tp_del = 0;
|
||||
#if (PYTHON26 || PYTHON27)
|
||||
/* Type attribute cache version tag. Added in version 2.6 */
|
||||
public static int tp_version_tag;
|
||||
#endif
|
||||
// COUNT_ALLOCS adds some more stuff to PyTypeObject
|
||||
#if (Py_COUNT_ALLOCS)
|
||||
/* these must be last and never explicitly initialized */
|
||||
public static int tp_allocs = 0;
|
||||
public static int tp_frees = 0;
|
||||
public static int tp_maxalloc = 0;
|
||||
public static int tp_prev = 0;
|
||||
public static int tp_next = 0;
|
||||
#endif
|
||||
//} PyTypeObject;
|
||||
//typedef struct {
|
||||
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_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_float = 0;
|
||||
public static int nb_oct = 0;
|
||||
public static int nb_hex = 0;
|
||||
/* Added in release 2.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;
|
||||
public static int nb_inplace_rshift = 0;
|
||||
public static int nb_inplace_and = 0;
|
||||
public static int nb_inplace_xor = 0;
|
||||
public static int nb_inplace_or = 0;
|
||||
/* Added in release 2.2 */
|
||||
/* The following require the Py_TPFLAGS_HAVE_CLASS flag */
|
||||
public static int nb_floor_divide = 0;
|
||||
public static int nb_true_divide = 0;
|
||||
public static int nb_inplace_floor_divide = 0;
|
||||
public static int nb_inplace_true_divide = 0;
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
/* Added in release 2.5 */
|
||||
public static int nb_index = 0;
|
||||
#endif
|
||||
//} PyNumberMethods;
|
||||
//typedef struct {
|
||||
public static int mp_length = 0;
|
||||
public static int mp_subscript = 0;
|
||||
public static int mp_ass_subscript = 0;
|
||||
//} PyMappingMethods;
|
||||
//typedef struct {
|
||||
public static int sq_length = 0;
|
||||
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 sq_ass_item = 0;
|
||||
public static int sq_ass_slice = 0;
|
||||
public static int sq_contains = 0;
|
||||
/* Added in release 2.0 */
|
||||
public static int sq_inplace_concat = 0;
|
||||
public static int sq_inplace_repeat = 0;
|
||||
//} PySequenceMethods;
|
||||
//typedef struct {
|
||||
public static int bf_getreadbuffer = 0;
|
||||
public static int bf_getwritebuffer = 0;
|
||||
public static int bf_getsegcount = 0;
|
||||
public static int bf_getcharbuffer = 0;
|
||||
#if (PYTHON26 || PYTHON27)
|
||||
// This addition is not actually noted in the 2.6.5 object.h
|
||||
public static int bf_getbuffer = 0;
|
||||
public static int bf_releasebuffer = 0;
|
||||
//} PyBufferProcs;
|
||||
#endif
|
||||
//PyObject *ht_name, *ht_slots;
|
||||
public static int name = 0;
|
||||
public static int slots = 0;
|
||||
/* here are optional user slots, followed by the members. */
|
||||
public static int members = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TypeFlags(): The actual bit values for the Type Flags stored
|
||||
/// in a class.
|
||||
/// Note that the two values reserved for stackless have been put
|
||||
/// to good use as PythonNet specific flags (Managed and Subclass)
|
||||
/// </summary>
|
||||
internal class TypeFlags {
|
||||
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);
|
||||
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);
|
||||
// 15 and 16 are reserved for stackless
|
||||
public static int HaveStacklessExtension = 0;
|
||||
/* XXX Reusing reserved constants */
|
||||
public static int Managed = (1 << 15); // PythonNet specific
|
||||
public static int Subclass = (1 << 16); // PythonNet specific
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
public static int HaveIndex = (1 << 17);
|
||||
#endif
|
||||
#if (PYTHON26 || PYTHON27)
|
||||
/* 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);
|
||||
// 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);
|
||||
#endif
|
||||
public static int Default = (HaveGetCharBuffer |
|
||||
HaveSequenceIn |
|
||||
HaveInPlaceOps |
|
||||
HaveRichCompare |
|
||||
HaveWeakRefs |
|
||||
HaveIter |
|
||||
HaveClass |
|
||||
HaveStacklessExtension |
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
HaveIndex |
|
||||
#endif
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
// This class defines the function prototypes (delegates) used for low
|
||||
// level integration with the CPython runtime. It also provides name
|
||||
// based lookup of the correct prototype for a particular Python type
|
||||
// slot and utilities for generating method thunks for managed methods.
|
||||
|
||||
internal class Interop {
|
||||
|
||||
static ArrayList keepAlive;
|
||||
static Hashtable pmap;
|
||||
|
||||
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++) {
|
||||
Type item = items[i];
|
||||
p[item.Name] = item;
|
||||
}
|
||||
|
||||
keepAlive = new ArrayList();
|
||||
Marshal.AllocHGlobal(IntPtr.Size);
|
||||
pmap = new Hashtable();
|
||||
|
||||
pmap["tp_dealloc"] = p["DestructorFunc"];
|
||||
pmap["tp_print"] = p["PrintFunc"];
|
||||
pmap["tp_getattr"] = p["BinaryFunc"];
|
||||
pmap["tp_setattr"] = p["ObjObjArgFunc"];
|
||||
pmap["tp_compare"] = p["ObjObjFunc"];
|
||||
pmap["tp_repr"] = p["UnaryFunc"];
|
||||
pmap["tp_hash"] = p["UnaryFunc"];
|
||||
pmap["tp_call"] = p["TernaryFunc"];
|
||||
pmap["tp_str"] = p["UnaryFunc"];
|
||||
pmap["tp_getattro"] = p["BinaryFunc"];
|
||||
pmap["tp_setattro"] = p["ObjObjArgFunc"];
|
||||
pmap["tp_traverse"] = p["ObjObjArgFunc"];
|
||||
pmap["tp_clear"] = p["InquiryFunc"];
|
||||
pmap["tp_richcompare"] = p["RichCmpFunc"];
|
||||
pmap["tp_iter"] = p["UnaryFunc"];
|
||||
pmap["tp_iternext"] = p["UnaryFunc"];
|
||||
pmap["tp_descr_get"] = p["TernaryFunc"];
|
||||
pmap["tp_descr_set"] = p["ObjObjArgFunc"];
|
||||
pmap["tp_init"] = p["ObjObjArgFunc"];
|
||||
pmap["tp_alloc"] = p["IntArgFunc"];
|
||||
pmap["tp_new"] = p["TernaryFunc"];
|
||||
pmap["tp_free"] = p["DestructorFunc"];
|
||||
pmap["tp_is_gc"] = p["InquiryFunc"];
|
||||
|
||||
pmap["nb_add"] = p["BinaryFunc"];
|
||||
pmap["nb_subtract"] = p["BinaryFunc"];
|
||||
pmap["nb_multiply"] = p["BinaryFunc"];
|
||||
pmap["nb_divide"] = p["BinaryFunc"];
|
||||
pmap["nb_remainder"] = p["BinaryFunc"];
|
||||
pmap["nb_divmod"] = p["BinaryFunc"];
|
||||
pmap["nb_power"] = p["TernaryFunc"];
|
||||
pmap["nb_negative"] = p["UnaryFunc"];
|
||||
pmap["nb_positive"] = p["UnaryFunc"];
|
||||
pmap["nb_absolute"] = p["UnaryFunc"];
|
||||
pmap["nb_nonzero"] = p["InquiryFunc"];
|
||||
pmap["nb_invert"] = p["UnaryFunc"];
|
||||
pmap["nb_lshift"] = p["BinaryFunc"];
|
||||
pmap["nb_rshift"] = p["BinaryFunc"];
|
||||
pmap["nb_and"] = p["BinaryFunc"];
|
||||
pmap["nb_xor"] = p["BinaryFunc"];
|
||||
pmap["nb_or"] = p["BinaryFunc"];
|
||||
pmap["nb_coerce"] = p["ObjObjFunc"];
|
||||
pmap["nb_int"] = p["UnaryFunc"];
|
||||
pmap["nb_long"] = p["UnaryFunc"];
|
||||
pmap["nb_float"] = p["UnaryFunc"];
|
||||
pmap["nb_oct"] = p["UnaryFunc"];
|
||||
pmap["nb_hex"] = p["UnaryFunc"];
|
||||
pmap["nb_inplace_add"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_subtract"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_multiply"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_divide"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_remainder"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_power"] = p["TernaryFunc"];
|
||||
pmap["nb_inplace_lshift"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_rshift"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_and"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_xor"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_or"] = p["BinaryFunc"];
|
||||
pmap["nb_floor_divide"] = p["BinaryFunc"];
|
||||
pmap["nb_true_divide"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_floor_divide"] = p["BinaryFunc"];
|
||||
pmap["nb_inplace_true_divide"] = p["BinaryFunc"];
|
||||
#if (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
pmap["nb_index"] = p["UnaryFunc"];
|
||||
#endif
|
||||
|
||||
pmap["sq_length"] = p["InquiryFunc"];
|
||||
pmap["sq_concat"] = p["BinaryFunc"];
|
||||
pmap["sq_repeat"] = p["IntArgFunc"];
|
||||
pmap["sq_item"] = p["IntArgFunc"];
|
||||
pmap["sq_slice"] = p["IntIntArgFunc"];
|
||||
pmap["sq_ass_item"] = p["IntObjArgFunc"];
|
||||
pmap["sq_ass_slice"] = p["IntIntObjArgFunc"];
|
||||
pmap["sq_contains"] = p["ObjObjFunc"];
|
||||
pmap["sq_inplace_concat"] = p["BinaryFunc"];
|
||||
pmap["sq_inplace_repeat"] = p["IntArgFunc"];
|
||||
|
||||
pmap["mp_length"] = p["InquiryFunc"];
|
||||
pmap["mp_subscript"] = p["BinaryFunc"];
|
||||
pmap["mp_ass_subscript"] = p["ObjObjArgFunc"];
|
||||
|
||||
pmap["bf_getreadbuffer"] = p["IntObjArgFunc"];
|
||||
pmap["bf_getwritebuffer"] = p["IntObjArgFunc"];
|
||||
pmap["bf_getsegcount"] = p["ObjObjFunc"];
|
||||
pmap["bf_getcharbuffer"] = p["IntObjArgFunc"];
|
||||
|
||||
pmap["__import__"] = p["TernaryFunc"];
|
||||
}
|
||||
|
||||
internal static Type GetPrototype(string name) {
|
||||
return pmap[name] as Type;
|
||||
}
|
||||
|
||||
internal static IntPtr GetThunk(MethodInfo method) {
|
||||
Type dt = Interop.GetPrototype(method.Name);
|
||||
if (dt != null) {
|
||||
IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size);
|
||||
Delegate d = Delegate.CreateDelegate(dt, method);
|
||||
Thunk cb = new Thunk(d);
|
||||
Marshal.StructureToPtr(cb, tmp, false);
|
||||
IntPtr fp = Marshal.ReadIntPtr(tmp, 0);
|
||||
Marshal.FreeHGlobal(tmp);
|
||||
keepAlive.Add(d);
|
||||
return fp;
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr UnaryFunc(IntPtr ob);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr BinaryFunc(IntPtr ob, IntPtr arg);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr TernaryFunc(IntPtr ob, IntPtr a1, IntPtr a2);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int InquiryFunc(IntPtr ob);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr IntArgFunc(IntPtr ob, int arg);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr IntIntArgFunc(IntPtr ob, int a1, int a2);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int IntObjArgFunc(IntPtr ob, int a1, IntPtr a2);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int IntIntObjArgFunc(IntPtr o, int a, int b, IntPtr c);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int ObjObjArgFunc(IntPtr o, IntPtr a, IntPtr b);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int ObjObjFunc(IntPtr ob, IntPtr arg);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void DestructorFunc(IntPtr ob);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate int PrintFunc(IntPtr ob, IntPtr a, int b);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr RichCmpFunc(IntPtr ob, IntPtr a, int b);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
|
||||
internal struct Thunk {
|
||||
public Delegate fn;
|
||||
|
||||
public Thunk(Delegate d) {
|
||||
fn = d;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
52
Pythonnet.Runtime/iterator.cs
Normal file
52
Pythonnet.Runtime/iterator.cs
Normal file
@ -0,0 +1,52 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a generic Python iterator for IEnumerable objects and
|
||||
// managed array objects. This supports 'for i in object:' in Python.
|
||||
//========================================================================
|
||||
|
||||
internal class Iterator : ExtensionType {
|
||||
|
||||
IEnumerator iter;
|
||||
|
||||
public Iterator(IEnumerator e) : base() {
|
||||
this.iter = e;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Implements support for the Python iteration protocol.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_iternext(IntPtr ob) {
|
||||
Iterator self = GetManagedObject(ob) as Iterator;
|
||||
if (!self.iter.MoveNext()) {
|
||||
Exceptions.SetError(Exceptions.StopIteration, Runtime.PyNone);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
object item = self.iter.Current;
|
||||
return Converter.ToPythonImplicit(item);
|
||||
}
|
||||
|
||||
public static IntPtr tp_iter(IntPtr ob) {
|
||||
Runtime.Incref(ob);
|
||||
return ob;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
97
Pythonnet.Runtime/managedtype.cs
Normal file
97
Pythonnet.Runtime/managedtype.cs
Normal file
@ -0,0 +1,97 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Common base class for all objects that are implemented in managed
|
||||
// code. It defines the common fields that associate CLR and Python
|
||||
// objects and common utilities to convert between those identities.
|
||||
//========================================================================
|
||||
|
||||
internal abstract class ManagedType {
|
||||
|
||||
internal GCHandle gcHandle; // Native handle
|
||||
internal IntPtr pyHandle; // PyObject *
|
||||
internal IntPtr tpHandle; // PyType *
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a Python object, return the associated managed object or null.
|
||||
//====================================================================
|
||||
|
||||
internal static ManagedType GetManagedObject(IntPtr ob) {
|
||||
if (ob != IntPtr.Zero) {
|
||||
IntPtr tp = Runtime.PyObject_TYPE(ob);
|
||||
if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) {
|
||||
tp = ob;
|
||||
}
|
||||
|
||||
int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
|
||||
if ((flags & TypeFlags.Managed) != 0) {
|
||||
IntPtr op = (tp == ob) ?
|
||||
Marshal.ReadIntPtr(tp, TypeOffset.magic()) :
|
||||
Marshal.ReadIntPtr(ob, ObjectOffset.magic());
|
||||
GCHandle gc = (GCHandle)op;
|
||||
return (ManagedType)gc.Target;
|
||||
}
|
||||
|
||||
// In certain situations, we need to recognize a wrapped
|
||||
// exception class and be willing to unwrap the class :(
|
||||
|
||||
if (Runtime.wrap_exceptions) {
|
||||
IntPtr e = Exceptions.UnwrapExceptionClass(ob);
|
||||
if ((e != IntPtr.Zero) && (e != ob)) {
|
||||
ManagedType m = GetManagedObject(e);
|
||||
Runtime.Decref(e);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
internal static ManagedType GetManagedObjectErr(IntPtr ob) {
|
||||
ManagedType result = GetManagedObject(ob);
|
||||
if (result == null) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"invalid argument, expected CLR type"
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
internal static bool IsManagedType(IntPtr ob) {
|
||||
if (ob != IntPtr.Zero) {
|
||||
IntPtr tp = Runtime.PyObject_TYPE(ob);
|
||||
if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) {
|
||||
tp = ob;
|
||||
}
|
||||
|
||||
int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
|
||||
if ((flags & TypeFlags.Managed) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
265
Pythonnet.Runtime/metatype.cs
Normal file
265
Pythonnet.Runtime/metatype.cs
Normal file
@ -0,0 +1,265 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// The managed metatype. This object implements the type of all reflected
|
||||
// types. It also provides support for single-inheritance from reflected
|
||||
// managed types.
|
||||
//========================================================================
|
||||
|
||||
internal class MetaType : ManagedType {
|
||||
|
||||
static IntPtr PyCLRMetaType;
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Metatype initialization. This bootstraps the CLR metatype to life.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr Initialize() {
|
||||
PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType));
|
||||
return PyCLRMetaType;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Metatype __new__ implementation. This is called to create a new
|
||||
// class / type when a reflected class is subclassed.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
int len = Runtime.PyTuple_Size(args);
|
||||
if (len < 3) {
|
||||
return Exceptions.RaiseTypeError("invalid argument list");
|
||||
}
|
||||
|
||||
//IntPtr name = Runtime.PyTuple_GetItem(args, 0);
|
||||
IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
|
||||
IntPtr dict = Runtime.PyTuple_GetItem(args, 2);
|
||||
|
||||
// We do not support multiple inheritance, so the bases argument
|
||||
// should be a 1-item tuple containing the type we are subtyping.
|
||||
// That type must itself have a managed implementation. We check
|
||||
// that by making sure its metatype is the CLR metatype.
|
||||
|
||||
if (Runtime.PyTuple_Size(bases) != 1) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"cannot use multiple inheritance with managed classes"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0);
|
||||
IntPtr mt = Runtime.PyObject_TYPE(base_type);
|
||||
|
||||
if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType))) {
|
||||
return Exceptions.RaiseTypeError("invalid metatype");
|
||||
}
|
||||
|
||||
// Ensure that the reflected type is appropriate for subclassing,
|
||||
// disallowing subclassing of delegates, enums and array types.
|
||||
|
||||
ClassBase cb = GetManagedObject(base_type) as ClassBase;
|
||||
if (cb != null) {
|
||||
if (! cb.CanSubclass() ) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"delegates, enums and array types cannot be subclassed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__");
|
||||
if (slots != IntPtr.Zero) {
|
||||
return Exceptions.RaiseTypeError(
|
||||
"subclasses of managed classes do not support __slots__"
|
||||
);
|
||||
}
|
||||
|
||||
// hack for now... fix for 1.0
|
||||
//return TypeManager.CreateSubType(args);
|
||||
|
||||
|
||||
// right way
|
||||
|
||||
IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType,
|
||||
TypeOffset.tp_new);
|
||||
IntPtr type = NativeCall.Call_3(func, tp, args, kw);
|
||||
if (type == IntPtr.Zero) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
int flags = TypeFlags.Default;
|
||||
flags |= TypeFlags.Managed;
|
||||
flags |= TypeFlags.HeapType;
|
||||
flags |= TypeFlags.BaseType;
|
||||
flags |= TypeFlags.Subclass;
|
||||
flags |= TypeFlags.HaveGC;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
|
||||
|
||||
TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc);
|
||||
|
||||
// Hmm - the standard subtype_traverse, clear look at ob_size to
|
||||
// do things, so to allow gc to work correctly we need to move
|
||||
// our hidden handle out of ob_size. Then, in theory we can
|
||||
// comment this out and still not crash.
|
||||
TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse);
|
||||
TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear);
|
||||
|
||||
|
||||
// for now, move up hidden handle...
|
||||
IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic());
|
||||
Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
|
||||
|
||||
//DebugUtil.DumpType(base_type);
|
||||
//DebugUtil.DumpType(type);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
public static IntPtr tp_alloc(IntPtr mt, int n) {
|
||||
IntPtr type = Runtime.PyType_GenericAlloc(mt, n);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
public static void tp_free(IntPtr tp) {
|
||||
Runtime.PyObject_GC_Del(tp);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Metatype __call__ implementation. This is needed to ensure correct
|
||||
// initialization (__init__ support), because the tp_call we inherit
|
||||
// from PyType_Type won't call __init__ for metatypes it doesnt know.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) {
|
||||
IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new);
|
||||
if (func == IntPtr.Zero) {
|
||||
return Exceptions.RaiseTypeError("invalid object");
|
||||
}
|
||||
|
||||
IntPtr obj = NativeCall.Call_3(func, tp, args, kw);
|
||||
if (obj == IntPtr.Zero) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
IntPtr py__init__ = Runtime.PyString_FromString("__init__");
|
||||
IntPtr type = Runtime.PyObject_TYPE(obj);
|
||||
IntPtr init = Runtime._PyType_Lookup(type, py__init__);
|
||||
Runtime.Decref(py__init__);
|
||||
Runtime.PyErr_Clear();
|
||||
|
||||
if (init != IntPtr.Zero) {
|
||||
IntPtr bound = Runtime.GetBoundArgTuple(obj, args);
|
||||
if (bound == IntPtr.Zero) {
|
||||
Runtime.Decref(obj);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
IntPtr result = Runtime.PyObject_Call(init, bound, kw);
|
||||
Runtime.Decref(bound);
|
||||
|
||||
if (result == IntPtr.Zero) {
|
||||
Runtime.Decref(obj);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
Runtime.Decref(result);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Type __setattr__ implementation for reflected types. Note that this
|
||||
// is slightly different than the standard setattr implementation for
|
||||
// the normal Python metatype (PyTypeType). We need to look first in
|
||||
// the type object of a reflected type for a descriptor in order to
|
||||
// support the right setattr behavior for static fields and properties.
|
||||
//====================================================================
|
||||
|
||||
public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) {
|
||||
IntPtr descr = Runtime._PyType_Lookup(tp, name);
|
||||
|
||||
if (descr != IntPtr.Zero) {
|
||||
IntPtr dt = Runtime.PyObject_TYPE(descr);
|
||||
IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set);
|
||||
if (fp != IntPtr.Zero) {
|
||||
return NativeCall.Impl.Int_Call_3(fp, descr, name, value);
|
||||
}
|
||||
Exceptions.SetError(Exceptions.AttributeError,
|
||||
"attribute is read-only");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (Runtime.PyObject_GenericSetAttr(tp, name, value) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// The metatype has to implement [] semantics for generic types, so
|
||||
// here we just delegate to the generic type def implementation. Its
|
||||
// own mp_subscript
|
||||
//====================================================================
|
||||
public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) {
|
||||
ClassBase cb = GetManagedObject(tp) as ClassBase;
|
||||
if (cb != null) {
|
||||
return cb.type_subscript(idx);
|
||||
}
|
||||
return Exceptions.RaiseTypeError("unsubscriptable object");
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Dealloc implementation. This is called when a Python type generated
|
||||
// by this metatype is no longer referenced from the Python runtime.
|
||||
//====================================================================
|
||||
|
||||
public static void tp_dealloc(IntPtr tp) {
|
||||
// Fix this when we dont cheat on the handle for subclasses!
|
||||
|
||||
int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
|
||||
if ((flags & TypeFlags.Subclass) == 0) {
|
||||
IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic());
|
||||
((GCHandle)gc).Free();
|
||||
}
|
||||
|
||||
IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type);
|
||||
Runtime.Decref(op);
|
||||
|
||||
// Delegate the rest of finalization the Python metatype. Note
|
||||
// that the PyType_Type implementation of tp_dealloc will call
|
||||
// tp_free on the type of the type being deallocated - in this
|
||||
// case our CLR metatype. That is why we implement tp_free.
|
||||
|
||||
op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc);
|
||||
NativeCall.Void_Call_1(op, tp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
465
Pythonnet.Runtime/methodbinder.cs
Normal file
465
Pythonnet.Runtime/methodbinder.cs
Normal file
@ -0,0 +1,465 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// A MethodBinder encapsulates information about a (possibly overloaded)
|
||||
// managed method, and is responsible for selecting the right method given
|
||||
// a set of Python arguments. This is also used as a base class for the
|
||||
// ConstructorBinder, a minor variation used to invoke constructors.
|
||||
//========================================================================
|
||||
|
||||
internal class MethodBinder {
|
||||
|
||||
public ArrayList list;
|
||||
public MethodBase[] methods;
|
||||
public bool init = false;
|
||||
public bool allow_threads = true;
|
||||
|
||||
internal MethodBinder () {
|
||||
this.list = new ArrayList();
|
||||
}
|
||||
|
||||
internal MethodBinder(MethodInfo mi) : base () {
|
||||
this.list = new ArrayList();
|
||||
this.list.Add(mi);
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get { return this.list.Count; }
|
||||
}
|
||||
|
||||
internal void AddMethod(MethodBase m) {
|
||||
this.list.Add(m);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Given a sequence of MethodInfo and a sequence of types, return the
|
||||
// MethodInfo that matches the signature represented by those types.
|
||||
//====================================================================
|
||||
|
||||
internal static MethodInfo MatchSignature(MethodInfo[] mi, Type[] tp) {
|
||||
int count = tp.Length;
|
||||
for (int i = 0; i < mi.Length; i++) {
|
||||
ParameterInfo[] pi = mi[i].GetParameters();
|
||||
if (pi.Length != count) {
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < pi.Length; n++) {
|
||||
if (tp[n]!= pi[n].ParameterType) {
|
||||
break;
|
||||
}
|
||||
if (n == (pi.Length - 1)) {
|
||||
return mi[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Given a sequence of MethodInfo and a sequence of type parameters,
|
||||
// return the MethodInfo that represents the matching closed generic.
|
||||
//====================================================================
|
||||
|
||||
internal static MethodInfo MatchParameters(MethodInfo[] mi,Type[] tp) {
|
||||
int count = tp.Length;
|
||||
for (int i = 0; i < mi.Length; i++) {
|
||||
if (!mi[i].IsGenericMethodDefinition) {
|
||||
continue;
|
||||
}
|
||||
Type[] args = mi[i].GetGenericArguments();
|
||||
if (args.Length != count) {
|
||||
continue;
|
||||
}
|
||||
return mi[i].MakeGenericMethod(tp);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a sequence of MethodInfo and two sequences of type parameters,
|
||||
// return the MethodInfo that matches the signature and the closed generic.
|
||||
//====================================================================
|
||||
|
||||
internal static MethodInfo MatchSignatureAndParameters(MethodInfo[] mi, Type[] genericTp, Type[] sigTp)
|
||||
{
|
||||
int genericCount = genericTp.Length;
|
||||
int signatureCount = sigTp.Length;
|
||||
for (int i = 0; i < mi.Length; i++)
|
||||
{
|
||||
if (!mi[i].IsGenericMethodDefinition)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Type[] genericArgs = mi[i].GetGenericArguments();
|
||||
if (genericArgs.Length != genericCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ParameterInfo[] pi = mi[i].GetParameters();
|
||||
if (pi.Length != signatureCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int n = 0; n < pi.Length; n++)
|
||||
{
|
||||
if (sigTp[n] != pi[n].ParameterType)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (n == (pi.Length - 1))
|
||||
{
|
||||
MethodInfo match = mi[i];
|
||||
if (match.IsGenericMethodDefinition)
|
||||
{
|
||||
Type[] typeArgs = match.GetGenericArguments();
|
||||
return match.MakeGenericMethod(genericTp);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Return the array of MethodInfo for this method. The result array
|
||||
// is arranged in order of precendence (done lazily to avoid doing it
|
||||
// at all for methods that are never called).
|
||||
//====================================================================
|
||||
|
||||
internal MethodBase[] GetMethods() {
|
||||
if (!init) {
|
||||
// I'm sure this could be made more efficient.
|
||||
list.Sort(new MethodSorter());
|
||||
methods = (MethodBase[])list.ToArray(typeof(MethodBase));
|
||||
init = true;
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Precedence algorithm largely lifted from jython - the concerns are
|
||||
// generally the same so we'll start w/this and tweak as necessary.
|
||||
//====================================================================
|
||||
|
||||
internal static int GetPrecedence(MethodBase mi) {
|
||||
ParameterInfo[] pi = mi.GetParameters();
|
||||
int val = mi.IsStatic ? 3000 : 0;
|
||||
int num = pi.Length;
|
||||
|
||||
val += (mi.IsGenericMethod ? 1 : 0);
|
||||
for (int i = 0; i < num; i++) {
|
||||
val += ArgPrecedence(pi[i].ParameterType);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Return a precedence value for a particular Type object.
|
||||
//====================================================================
|
||||
|
||||
internal static int ArgPrecedence(Type t) {
|
||||
Type objectType = typeof(Object);
|
||||
if (t == objectType) return 3000;
|
||||
|
||||
TypeCode tc = Type.GetTypeCode(t);
|
||||
if (tc == TypeCode.Object) return 1;
|
||||
if (tc == TypeCode.UInt64) return 10;
|
||||
if (tc == TypeCode.UInt32) return 11;
|
||||
if (tc == TypeCode.UInt16) return 12;
|
||||
if (tc == TypeCode.Int64) return 13;
|
||||
if (tc == TypeCode.Int32) return 14;
|
||||
if (tc == TypeCode.Int16) return 15;
|
||||
if (tc == TypeCode.Char) return 16;
|
||||
if (tc == TypeCode.SByte) return 17;
|
||||
if (tc == TypeCode.Byte) return 18;
|
||||
if (tc == TypeCode.Single) return 20;
|
||||
if (tc == TypeCode.Double) return 21;
|
||||
if (tc == TypeCode.String) return 30;
|
||||
if (tc == TypeCode.Boolean) return 40;
|
||||
|
||||
if (t.IsArray) {
|
||||
Type e = t.GetElementType();
|
||||
if (e == objectType)
|
||||
return 2500;
|
||||
return 100 + ArgPrecedence(e);
|
||||
}
|
||||
|
||||
return 2000;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Bind the given Python instance and arguments to a particular method
|
||||
// overload and return a structure that contains the converted Python
|
||||
// instance, converted arguments and the correct method to call.
|
||||
//====================================================================
|
||||
|
||||
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw) {
|
||||
return this.Bind(inst, args, kw, null, null);
|
||||
}
|
||||
|
||||
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
|
||||
MethodBase info) {
|
||||
return this.Bind(inst, args, kw, info, null);
|
||||
}
|
||||
|
||||
internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
|
||||
MethodBase info, MethodInfo[] methodinfo) {
|
||||
// loop to find match, return invoker w/ or /wo error
|
||||
MethodBase[] _methods = null;
|
||||
int pynargs = Runtime.PyTuple_Size(args);
|
||||
object arg;
|
||||
bool isGeneric = false;
|
||||
|
||||
if (info != null) {
|
||||
_methods = (MethodBase[])Array.CreateInstance(
|
||||
typeof(MethodBase), 1
|
||||
);
|
||||
_methods.SetValue(info, 0);
|
||||
}
|
||||
else {
|
||||
_methods = GetMethods();
|
||||
}
|
||||
|
||||
for (int i = 0; i < _methods.Length; i++) {
|
||||
MethodBase mi = _methods[i];
|
||||
if (mi.IsGenericMethod) { isGeneric = true; }
|
||||
ParameterInfo[] pi = mi.GetParameters();
|
||||
int clrnargs = pi.Length;
|
||||
bool match = false;
|
||||
int arrayStart = -1;
|
||||
int outs = 0;
|
||||
|
||||
if (pynargs == clrnargs) {
|
||||
match = true;
|
||||
} else if ((pynargs > clrnargs) && (clrnargs > 0) &&
|
||||
(pi[clrnargs-1].ParameterType.IsArray)) {
|
||||
// The last argument of the mananged functions seems to
|
||||
// accept multiple arguments as a array. Hopefully it's a
|
||||
// spam(params object[] egg) style method
|
||||
match = true;
|
||||
arrayStart = clrnargs - 1;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
Object[] margs = new Object[clrnargs];
|
||||
|
||||
for (int n = 0; n < clrnargs; n++) {
|
||||
IntPtr op;
|
||||
if (arrayStart == n) {
|
||||
// map remaining Python arguments to a tuple since
|
||||
// the managed function accepts it - hopefully :]
|
||||
op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
|
||||
}
|
||||
else {
|
||||
op = Runtime.PyTuple_GetItem(args, n);
|
||||
}
|
||||
Type type = pi[n].ParameterType;
|
||||
if (pi[n].IsOut || type.IsByRef) {
|
||||
outs++;
|
||||
}
|
||||
|
||||
if (!Converter.ToManaged(op, type, out arg, false)) {
|
||||
Exceptions.Clear();
|
||||
margs = null;
|
||||
break;
|
||||
}
|
||||
if (arrayStart == n) {
|
||||
// GetSlice() creates a new reference but GetItem()
|
||||
// returns only a borrow reference.
|
||||
Runtime.Decref(op);
|
||||
}
|
||||
margs[n] = arg;
|
||||
}
|
||||
|
||||
if (margs == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object target = null;
|
||||
if ((!mi.IsStatic) && (inst != IntPtr.Zero)) {
|
||||
//CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst);
|
||||
// InvalidCastException: Unable to cast object of type
|
||||
// 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject'
|
||||
CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject;
|
||||
|
||||
// Sanity check: this ensures a graceful exit if someone does
|
||||
// something intentionally wrong like call a non-static method
|
||||
// on the class rather than on an instance of the class.
|
||||
// XXX maybe better to do this before all the other rigmarole.
|
||||
if (co == null) {
|
||||
return null;
|
||||
}
|
||||
target = co.inst;
|
||||
}
|
||||
|
||||
return new Binding(mi, target, margs, outs);
|
||||
}
|
||||
}
|
||||
// We weren't able to find a matching method but at least one
|
||||
// is a generic method and info is null. That happens when a generic
|
||||
// method was not called using the [] syntax. Let's introspect the
|
||||
// type of the arguments and use it to construct the correct method.
|
||||
if (isGeneric && (info == null) && (methodinfo != null))
|
||||
{
|
||||
Type[] types = Runtime.PythonArgsToTypeArray(args, true);
|
||||
MethodInfo mi = MethodBinder.MatchParameters(methodinfo, types);
|
||||
return Bind(inst, args, kw, mi, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) {
|
||||
return this.Invoke(inst, args, kw, null, null);
|
||||
|
||||
}
|
||||
|
||||
internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw,
|
||||
MethodBase info) {
|
||||
return this.Invoke(inst, args, kw, info, null);
|
||||
}
|
||||
|
||||
internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw,
|
||||
MethodBase info, MethodInfo[] methodinfo) {
|
||||
Binding binding = this.Bind(inst, args, kw, info, methodinfo);
|
||||
Object result;
|
||||
IntPtr ts = IntPtr.Zero;
|
||||
|
||||
if (binding == null) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"No method matches given arguments"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (allow_threads) {
|
||||
ts = PythonEngine.BeginAllowThreads();
|
||||
}
|
||||
|
||||
try {
|
||||
result = binding.info.Invoke(binding.inst,
|
||||
BindingFlags.Default,
|
||||
null,
|
||||
binding.args,
|
||||
null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (e.InnerException != null) {
|
||||
e = e.InnerException;
|
||||
}
|
||||
if (allow_threads) {
|
||||
PythonEngine.EndAllowThreads(ts);
|
||||
}
|
||||
Exceptions.SetError(e);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (allow_threads) {
|
||||
PythonEngine.EndAllowThreads(ts);
|
||||
}
|
||||
|
||||
// If there are out parameters, we return a tuple containing
|
||||
// the result followed by the out parameters. If there is only
|
||||
// one out parameter and the return type of the method is void,
|
||||
// we return the out parameter as the result to Python (for
|
||||
// code compatibility with ironpython).
|
||||
|
||||
MethodInfo mi = (MethodInfo)binding.info;
|
||||
|
||||
if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) {
|
||||
|
||||
}
|
||||
|
||||
if (binding.outs > 0) {
|
||||
ParameterInfo[] pi = mi.GetParameters();
|
||||
int c = pi.Length;
|
||||
int n = 0;
|
||||
|
||||
IntPtr t = Runtime.PyTuple_New(binding.outs + 1);
|
||||
IntPtr v = Converter.ToPython(result, mi.ReturnType);
|
||||
Runtime.PyTuple_SetItem(t, n, v);
|
||||
n++;
|
||||
|
||||
for (int i=0; i < c; i++) {
|
||||
Type pt = pi[i].ParameterType;
|
||||
if (pi[i].IsOut || pt.IsByRef) {
|
||||
v = Converter.ToPython(binding.args[i], pt);
|
||||
Runtime.PyTuple_SetItem(t, n, v);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) {
|
||||
v = Runtime.PyTuple_GetItem(t, 1);
|
||||
Runtime.Incref(v);
|
||||
Runtime.Decref(t);
|
||||
return v;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
return Converter.ToPython(result, mi.ReturnType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//========================================================================
|
||||
// Utility class to sort method info by parameter type precedence.
|
||||
//========================================================================
|
||||
|
||||
internal class MethodSorter : IComparer {
|
||||
|
||||
int IComparer.Compare(Object m1, Object m2) {
|
||||
int p1 = MethodBinder.GetPrecedence((MethodBase)m1);
|
||||
int p2 = MethodBinder.GetPrecedence((MethodBase)m2);
|
||||
if (p1 < p2) return -1;
|
||||
if (p1 > p2) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//========================================================================
|
||||
// A Binding is a utility instance that bundles together a MethodInfo
|
||||
// representing a method to call, a (possibly null) target instance for
|
||||
// the call, and the arguments for the call (all as managed values).
|
||||
//========================================================================
|
||||
|
||||
internal class Binding {
|
||||
|
||||
public MethodBase info;
|
||||
public Object[] args;
|
||||
public Object inst;
|
||||
public int outs;
|
||||
|
||||
internal Binding(MethodBase info, Object inst, Object[] args,
|
||||
int outs) {
|
||||
this.info = info;
|
||||
this.inst = inst;
|
||||
this.args = args;
|
||||
this.outs = outs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
193
Pythonnet.Runtime/methodbinding.cs
Normal file
193
Pythonnet.Runtime/methodbinding.cs
Normal file
@ -0,0 +1,193 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python binding type for CLR methods. These work much like
|
||||
// standard Python method bindings, but the same type is used to bind
|
||||
// both static and instance methods.
|
||||
//========================================================================
|
||||
|
||||
internal class MethodBinding : ExtensionType {
|
||||
|
||||
internal MethodInfo info;
|
||||
internal MethodObject m;
|
||||
internal IntPtr target;
|
||||
|
||||
public MethodBinding(MethodObject m, IntPtr target) : base() {
|
||||
Runtime.Incref(target);
|
||||
this.target = target;
|
||||
this.info = null;
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Implement binding of generic methods using the subscript syntax [].
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) {
|
||||
MethodBinding self = (MethodBinding)GetManagedObject(tp);
|
||||
|
||||
Type[] types = Runtime.PythonArgsToTypeArray(idx);
|
||||
if (types == null) {
|
||||
return Exceptions.RaiseTypeError("type(s) expected");
|
||||
}
|
||||
|
||||
MethodInfo mi = MethodBinder.MatchParameters(self.m.info, types);
|
||||
if (mi == null) {
|
||||
string e = "No match found for given type params";
|
||||
return Exceptions.RaiseTypeError(e);
|
||||
}
|
||||
|
||||
MethodBinding mb = new MethodBinding(self.m, self.target);
|
||||
mb.info = mi;
|
||||
Runtime.Incref(mb.pyHandle);
|
||||
return mb.pyHandle;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// MethodBinding __getattribute__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_getattro(IntPtr ob, IntPtr key) {
|
||||
MethodBinding self = (MethodBinding)GetManagedObject(ob);
|
||||
|
||||
if (!Runtime.PyString_Check(key)) {
|
||||
Exceptions.SetError(Exceptions.TypeError, "string expected");
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
string name = Runtime.GetManagedString(key);
|
||||
if (name == "__doc__") {
|
||||
IntPtr doc = self.m.GetDocString();
|
||||
Runtime.Incref(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
// XXX deprecate __overloads__ soon...
|
||||
if (name == "__overloads__" || name == "Overloads") {
|
||||
OverloadMapper om = new OverloadMapper(self.m, self.target);
|
||||
Runtime.Incref(om.pyHandle);
|
||||
return om.pyHandle;
|
||||
}
|
||||
|
||||
return Runtime.PyObject_GenericGetAttr(ob, key);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// MethodBinding __call__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
|
||||
MethodBinding self = (MethodBinding)GetManagedObject(ob);
|
||||
|
||||
// This works around a situation where the wrong generic method is picked,
|
||||
// for example this method in the tests: string Overloaded<T>(int arg1, int arg2, string arg3)
|
||||
if (self.info != null)
|
||||
{
|
||||
if (self.info.IsGenericMethod)
|
||||
{
|
||||
int len = Runtime.PyTuple_Size(args);
|
||||
Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true);
|
||||
if (sigTp != null)
|
||||
{
|
||||
Type[] genericTp = self.info.GetGenericArguments();
|
||||
MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp);
|
||||
if (betterMatch != null) self.info = betterMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This supports calling a method 'unbound', passing the instance
|
||||
// as the first argument. Note that this is not supported if any
|
||||
// of the overloads are static since we can't know if the intent
|
||||
// was to call the static method or the unbound instance method.
|
||||
|
||||
if ((self.target == IntPtr.Zero) && (!self.m.IsStatic()))
|
||||
{
|
||||
int len = Runtime.PyTuple_Size(args);
|
||||
if (len < 1)
|
||||
{
|
||||
Exceptions.SetError(Exceptions.TypeError, "not enough arguments");
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len);
|
||||
IntPtr inst = Runtime.PyTuple_GetItem(args, 0);
|
||||
Runtime.Incref(inst);
|
||||
IntPtr r = self.m.Invoke(inst, uargs, kw, self.info);
|
||||
Runtime.Decref(inst);
|
||||
Runtime.Decref(uargs);
|
||||
return r;
|
||||
}
|
||||
|
||||
return self.m.Invoke(self.target, args, kw, self.info);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// MethodBinding __hash__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_hash(IntPtr ob) {
|
||||
MethodBinding self = (MethodBinding)GetManagedObject(ob);
|
||||
long x = 0;
|
||||
long y = 0;
|
||||
|
||||
if (self.target != IntPtr.Zero) {
|
||||
x = Runtime.PyObject_Hash(self.target).ToInt64();
|
||||
if (x == -1) {
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
}
|
||||
|
||||
y = Runtime.PyObject_Hash(self.m.pyHandle).ToInt64();
|
||||
if (y == -1) {
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
|
||||
x ^= y;
|
||||
|
||||
if (x == -1) {
|
||||
x = -1;
|
||||
}
|
||||
|
||||
return new IntPtr(x);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// MethodBinding __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
MethodBinding self = (MethodBinding)GetManagedObject(ob);
|
||||
string type = (self.target == IntPtr.Zero) ? "unbound" : "bound";
|
||||
string s = String.Format("<{0} method '{1}'>", type, self.m.name);
|
||||
return Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// MethodBinding dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new void tp_dealloc(IntPtr ob) {
|
||||
MethodBinding self = (MethodBinding)GetManagedObject(ob);
|
||||
Runtime.Decref(self.target);
|
||||
ExtensionType.FinalizeObject(self);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
189
Pythonnet.Runtime/methodobject.cs
Normal file
189
Pythonnet.Runtime/methodobject.cs
Normal file
@ -0,0 +1,189 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python type that represents a CLR method. Method objects
|
||||
// support a subscript syntax [] to allow explicit overload selection.
|
||||
//========================================================================
|
||||
// TODO: ForbidPythonThreadsAttribute per method info
|
||||
|
||||
internal class MethodObject : ExtensionType {
|
||||
|
||||
internal MethodInfo[] info;
|
||||
internal string name;
|
||||
internal MethodBinding unbound;
|
||||
internal MethodBinder binder;
|
||||
internal bool is_static = false;
|
||||
internal IntPtr doc;
|
||||
|
||||
public MethodObject(string name, MethodInfo[] info) : base() {
|
||||
_MethodObject(name, info);
|
||||
}
|
||||
|
||||
public MethodObject(string name, MethodInfo[] info, bool allow_threads) : base()
|
||||
{
|
||||
_MethodObject(name, info);
|
||||
binder.allow_threads = allow_threads;
|
||||
}
|
||||
|
||||
private void _MethodObject(string name, MethodInfo[] info)
|
||||
{
|
||||
this.name = name;
|
||||
this.info = info;
|
||||
binder = new MethodBinder();
|
||||
for (int i = 0; i < info.Length; i++)
|
||||
{
|
||||
MethodInfo item = (MethodInfo)info[i];
|
||||
binder.AddMethod(item);
|
||||
if (item.IsStatic)
|
||||
{
|
||||
this.is_static = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) {
|
||||
return this.Invoke(inst, args, kw, null);
|
||||
}
|
||||
|
||||
public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw,
|
||||
MethodBase info) {
|
||||
return binder.Invoke(target, args, kw, info, this.info);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Helper to get docstrings from reflected method / param info.
|
||||
//====================================================================
|
||||
|
||||
internal IntPtr GetDocString() {
|
||||
if (doc != IntPtr.Zero) {
|
||||
return doc;
|
||||
}
|
||||
string str = "";
|
||||
Type marker = typeof(DocStringAttribute);
|
||||
MethodBase[] methods = binder.GetMethods();
|
||||
foreach (MethodBase method in methods) {
|
||||
if (str.Length > 0)
|
||||
str += Environment.NewLine;
|
||||
Attribute[] attrs = (Attribute[]) method.GetCustomAttributes(marker, false);
|
||||
if (attrs.Length == 0) {
|
||||
str += method.ToString();
|
||||
}
|
||||
else {
|
||||
DocStringAttribute attr = (DocStringAttribute)attrs[0];
|
||||
str += attr.DocString;
|
||||
}
|
||||
}
|
||||
doc = Runtime.PyString_FromString(str);
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// This is a little tricky: a class can actually have a static method
|
||||
// and instance methods all with the same name. That makes it tough
|
||||
// to support calling a method 'unbound' (passing the instance as the
|
||||
// first argument), because in this case we can't know whether to call
|
||||
// the instance method unbound or call the static method.
|
||||
//
|
||||
// The rule we is that if there are both instance and static methods
|
||||
// with the same name, then we always call the static method. So this
|
||||
// method returns true if any of the methods that are represented by
|
||||
// the descriptor are static methods (called by MethodBinding).
|
||||
//====================================================================
|
||||
|
||||
internal bool IsStatic() {
|
||||
return this.is_static;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __getattribute__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_getattro(IntPtr ob, IntPtr key) {
|
||||
MethodObject self = (MethodObject)GetManagedObject(ob);
|
||||
|
||||
if (!Runtime.PyString_Check(key)) {
|
||||
return Exceptions.RaiseTypeError("string expected");
|
||||
}
|
||||
|
||||
string name = Runtime.GetManagedString(key);
|
||||
if (name == "__doc__") {
|
||||
IntPtr doc = self.GetDocString();
|
||||
Runtime.Incref(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
return Runtime.PyObject_GenericGetAttr(ob, key);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __get__ implementation. Accessing a CLR method returns
|
||||
// a "bound" method similar to a Python bound method.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) {
|
||||
MethodObject self = (MethodObject)GetManagedObject(ds);
|
||||
MethodBinding binding;
|
||||
|
||||
// If the method is accessed through its type (rather than via
|
||||
// an instance) we return an 'unbound' MethodBinding that will
|
||||
// cached for future accesses through the type.
|
||||
|
||||
if (ob == IntPtr.Zero) {
|
||||
if (self.unbound == null) {
|
||||
self.unbound = new MethodBinding(self, IntPtr.Zero);
|
||||
}
|
||||
binding = self.unbound;
|
||||
Runtime.Incref(binding.pyHandle);;
|
||||
return binding.pyHandle;
|
||||
}
|
||||
|
||||
if (Runtime.PyObject_IsInstance(ob, tp) < 1) {
|
||||
return Exceptions.RaiseTypeError("invalid argument");
|
||||
}
|
||||
|
||||
binding = new MethodBinding(self, ob);
|
||||
return binding.pyHandle;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
MethodObject self = (MethodObject)GetManagedObject(ob);
|
||||
string s = String.Format("<method '{0}'>", self.name);
|
||||
return Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Descriptor dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new void tp_dealloc(IntPtr ob) {
|
||||
MethodObject self = (MethodObject)GetManagedObject(ob);
|
||||
Runtime.Decref(self.doc);
|
||||
if (self.unbound != null) {
|
||||
Runtime.Decref(self.unbound.pyHandle);
|
||||
}
|
||||
ExtensionType.FinalizeObject(self);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
61
Pythonnet.Runtime/methodwrapper.cs
Normal file
61
Pythonnet.Runtime/methodwrapper.cs
Normal file
@ -0,0 +1,61 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// A MethodWrapper wraps a static method of a managed type,
|
||||
/// making it callable by Python as a PyCFunction object. This is
|
||||
/// currently used mainly to implement special cases like the CLR
|
||||
/// import hook.
|
||||
/// </summary>
|
||||
|
||||
internal class MethodWrapper {
|
||||
|
||||
public IntPtr mdef;
|
||||
public IntPtr ptr;
|
||||
|
||||
public MethodWrapper(Type type, string name) {
|
||||
|
||||
// Turn the managed method into a function pointer
|
||||
|
||||
IntPtr fp = Interop.GetThunk(type.GetMethod(name));
|
||||
|
||||
// XXX - here we create a Python string object, then take the
|
||||
// char * of the internal string to pass to our methoddef
|
||||
// structure. Its a hack, and the name is leaked!
|
||||
|
||||
IntPtr ps = Runtime.PyString_FromString(name);
|
||||
IntPtr sp = Runtime.PyString_AS_STRING(ps);
|
||||
|
||||
// Allocate and initialize a PyMethodDef structure to represent
|
||||
// the managed method, then create a PyCFunction.
|
||||
|
||||
mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size);
|
||||
Marshal.WriteIntPtr(mdef, sp);
|
||||
Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), fp);
|
||||
Marshal.WriteIntPtr(mdef, (2 * IntPtr.Size), (IntPtr)0x0002);
|
||||
Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), IntPtr.Zero);
|
||||
ptr = Runtime.PyCFunction_New(mdef, IntPtr.Zero);
|
||||
}
|
||||
|
||||
public IntPtr Call(IntPtr args, IntPtr kw) {
|
||||
return Runtime.PyCFunction_Call(ptr, args, kw);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
58
Pythonnet.Runtime/modulefunctionobject.cs
Normal file
58
Pythonnet.Runtime/modulefunctionobject.cs
Normal file
@ -0,0 +1,58 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Module level functions
|
||||
/// </summary>
|
||||
internal class ModuleFunctionObject : MethodObject
|
||||
{
|
||||
|
||||
public ModuleFunctionObject(string name, MethodInfo[] info, bool allow_threads)
|
||||
: base(name, info, allow_threads)
|
||||
{
|
||||
for (int i = 0; i < info.Length; i++)
|
||||
{
|
||||
MethodInfo item = (MethodInfo)info[i];
|
||||
if (!item.IsStatic)
|
||||
{
|
||||
throw new Exception("Module function must be static.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// __call__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw)
|
||||
{
|
||||
ModuleFunctionObject self = (ModuleFunctionObject)GetManagedObject(ob);
|
||||
return self.Invoke(ob, args, kw);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new IntPtr tp_repr(IntPtr ob)
|
||||
{
|
||||
ModuleFunctionObject self = (ModuleFunctionObject)GetManagedObject(ob);
|
||||
string s = String.Format("<CLRModuleFunction '{0}'>", self.name);
|
||||
return Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
432
Pythonnet.Runtime/moduleobject.cs
Normal file
432
Pythonnet.Runtime/moduleobject.cs
Normal file
@ -0,0 +1,432 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python type that provides access to CLR namespaces. The
|
||||
// type behaves like a Python module, and can contain other sub-modules.
|
||||
//========================================================================
|
||||
|
||||
internal class ModuleObject : ExtensionType {
|
||||
|
||||
Dictionary<string, ManagedType> cache;
|
||||
internal string moduleName;
|
||||
internal IntPtr dict;
|
||||
protected string _namespace;
|
||||
|
||||
public ModuleObject(string name) : base() {
|
||||
if (name == String.Empty)
|
||||
{
|
||||
throw new ArgumentException("Name must not be empty!");
|
||||
}
|
||||
moduleName = name;
|
||||
cache = new Dictionary<string, ManagedType>();
|
||||
_namespace = name;
|
||||
|
||||
dict = Runtime.PyDict_New();
|
||||
IntPtr pyname = Runtime.PyString_FromString(moduleName);
|
||||
Runtime.PyDict_SetItemString(dict, "__name__", pyname);
|
||||
Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone);
|
||||
Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone);
|
||||
Runtime.Decref(pyname);
|
||||
|
||||
Marshal.WriteIntPtr(this.pyHandle, ObjectOffset.ob_dict, dict);
|
||||
|
||||
InitializeModuleMembers();
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Returns a ClassBase object representing a type that appears in
|
||||
// this module's namespace or a ModuleObject representing a child
|
||||
// namespace (or null if the name is not found). This method does
|
||||
// not increment the Python refcount of the returned object.
|
||||
//===================================================================
|
||||
|
||||
public ManagedType GetAttribute(string name, bool guess) {
|
||||
ManagedType cached = null;
|
||||
this.cache.TryGetValue(name, out cached);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
ModuleObject m;
|
||||
ClassBase c;
|
||||
Type type;
|
||||
|
||||
//if (AssemblyManager.IsValidNamespace(name))
|
||||
//{
|
||||
// IntPtr py_mod_name = Runtime.PyString_FromString(name);
|
||||
// IntPtr modules = Runtime.PyImport_GetModuleDict();
|
||||
// IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name);
|
||||
// if (module != IntPtr.Zero)
|
||||
// return (ManagedType)this;
|
||||
// return null;
|
||||
//}
|
||||
|
||||
string qname = (_namespace == String.Empty) ? name :
|
||||
_namespace + "." + name;
|
||||
|
||||
// If the fully-qualified name of the requested attribute is
|
||||
// a namespace exported by a currently loaded assembly, return
|
||||
// a new ModuleObject representing that namespace.
|
||||
|
||||
if (AssemblyManager.IsValidNamespace(qname)) {
|
||||
m = new ModuleObject(qname);
|
||||
StoreAttribute(name, m);
|
||||
return (ManagedType) m;
|
||||
}
|
||||
|
||||
// Look for a type in the current namespace. Note that this
|
||||
// includes types, delegates, enums, interfaces and structs.
|
||||
// Only public namespace members are exposed to Python.
|
||||
|
||||
type = AssemblyManager.LookupType(qname);
|
||||
if (type != null) {
|
||||
if (!type.IsPublic) {
|
||||
return null;
|
||||
}
|
||||
c = ClassManager.GetClass(type);
|
||||
StoreAttribute(name, c);
|
||||
return (ManagedType) c;
|
||||
}
|
||||
|
||||
// This is a little repetitive, but it ensures that the right
|
||||
// thing happens with implicit assembly loading at a reasonable
|
||||
// cost. Ask the AssemblyManager to do implicit loading for each
|
||||
// of the steps in the qualified name, then try it again.
|
||||
bool fromFile;
|
||||
if (AssemblyManager.LoadImplicit(qname, out fromFile)) {
|
||||
bool ignore = name.StartsWith("__");
|
||||
if (true == fromFile && (!ignore)) {
|
||||
string deprWarning = String.Format("\nThe module was found, but not in a referenced namespace.\n" +
|
||||
"Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", qname);
|
||||
Exceptions.deprecation(deprWarning);
|
||||
}
|
||||
if (AssemblyManager.IsValidNamespace(qname)) {
|
||||
m = new ModuleObject(qname);
|
||||
StoreAttribute(name, m);
|
||||
return (ManagedType) m;
|
||||
}
|
||||
|
||||
type = AssemblyManager.LookupType(qname);
|
||||
if (type != null) {
|
||||
if (!type.IsPublic) {
|
||||
return null;
|
||||
}
|
||||
c = ClassManager.GetClass(type);
|
||||
StoreAttribute(name, c);
|
||||
return (ManagedType) c;
|
||||
}
|
||||
}
|
||||
|
||||
// We didn't find the name, so we may need to see if there is a
|
||||
// generic type with this base name. If so, we'll go ahead and
|
||||
// return it. Note that we store the mapping of the unmangled
|
||||
// name to generic type - it is technically possible that some
|
||||
// future assembly load could contribute a non-generic type to
|
||||
// the current namespace with the given basename, but unlikely
|
||||
// enough to complicate the implementation for now.
|
||||
|
||||
if (guess) {
|
||||
string gname = GenericUtil.GenericNameForBaseName(
|
||||
_namespace, name);
|
||||
if (gname != null) {
|
||||
ManagedType o = GetAttribute(gname, false);
|
||||
if (o != null) {
|
||||
StoreAttribute(name, o);
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Stores an attribute in the instance dict for future lookups.
|
||||
//===================================================================
|
||||
|
||||
private void StoreAttribute(string name, ManagedType ob) {
|
||||
Runtime.PyDict_SetItemString(dict, name, ob.pyHandle);
|
||||
cache[name] = ob;
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
// Preloads all currently-known names for the module namespace. This
|
||||
// can be called multiple times, to add names from assemblies that
|
||||
// may have been loaded since the last call to the method.
|
||||
//===================================================================
|
||||
|
||||
public void LoadNames() {
|
||||
ManagedType m = null;
|
||||
foreach (string name in AssemblyManager.GetNames(_namespace)) {
|
||||
this.cache.TryGetValue(name, out m);
|
||||
if (m == null) {
|
||||
ManagedType attr = this.GetAttribute(name, true);
|
||||
if (Runtime.wrap_exceptions) {
|
||||
if (attr is ExceptionClassObject) {
|
||||
ExceptionClassObject c = attr as ExceptionClassObject;
|
||||
if (c != null) {
|
||||
IntPtr p = attr.pyHandle;
|
||||
IntPtr r =Exceptions.GetExceptionClassWrapper(p);
|
||||
Runtime.PyDict_SetItemString(dict, name, r);
|
||||
Runtime.Incref(r);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize module level functions and attributes
|
||||
/// </summary>
|
||||
internal void InitializeModuleMembers()
|
||||
{
|
||||
Type funcmarker = typeof(ModuleFunctionAttribute);
|
||||
Type propmarker = typeof(ModulePropertyAttribute);
|
||||
Type ftmarker = typeof(ForbidPythonThreadsAttribute);
|
||||
Type type = this.GetType();
|
||||
|
||||
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
MethodInfo[] methods = type.GetMethods(flags);
|
||||
for (int i = 0; i < methods.Length; i++)
|
||||
{
|
||||
MethodInfo method = methods[i];
|
||||
object[] attrs = method.GetCustomAttributes(funcmarker, false);
|
||||
object[] forbid = method.GetCustomAttributes(ftmarker, false);
|
||||
bool allow_threads = (forbid.Length == 0);
|
||||
if (attrs.Length > 0)
|
||||
{
|
||||
string name = method.Name;
|
||||
MethodInfo[] mi = new MethodInfo[1];
|
||||
mi[0] = method;
|
||||
ModuleFunctionObject m = new ModuleFunctionObject(name, mi, allow_threads);
|
||||
StoreAttribute(name, m);
|
||||
}
|
||||
}
|
||||
|
||||
PropertyInfo[] properties = type.GetProperties();
|
||||
for (int i = 0; i < properties.Length; i++)
|
||||
{
|
||||
PropertyInfo property = properties[i];
|
||||
object[] attrs = property.GetCustomAttributes(propmarker, false);
|
||||
if (attrs.Length > 0)
|
||||
{
|
||||
string name = property.Name;
|
||||
ModulePropertyObject p = new ModulePropertyObject(property);
|
||||
StoreAttribute(name, p);
|
||||
}
|
||||
}
|
||||
type = type.BaseType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// ModuleObject __getattribute__ implementation. Module attributes
|
||||
// are always either classes or sub-modules representing subordinate
|
||||
// namespaces. CLR modules implement a lazy pattern - the sub-modules
|
||||
// and classes are created when accessed and cached for future use.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_getattro(IntPtr ob, IntPtr key) {
|
||||
ModuleObject self = (ModuleObject)GetManagedObject(ob);
|
||||
|
||||
if (!Runtime.PyString_Check(key)) {
|
||||
Exceptions.SetError(Exceptions.TypeError, "string expected");
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
IntPtr op = Runtime.PyDict_GetItem(self.dict, key);
|
||||
if (op != IntPtr.Zero) {
|
||||
Runtime.Incref(op);
|
||||
return op;
|
||||
}
|
||||
|
||||
string name = Runtime.GetManagedString(key);
|
||||
if (name == "__dict__") {
|
||||
Runtime.Incref(self.dict);
|
||||
return self.dict;
|
||||
}
|
||||
|
||||
ManagedType attr = self.GetAttribute(name, true);
|
||||
|
||||
if (attr == null) {
|
||||
Exceptions.SetError(Exceptions.AttributeError, name);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
// XXX - hack required to recognize exception types. These types
|
||||
// may need to be wrapped in old-style class wrappers in versions
|
||||
// of Python where new-style classes cannot be used as exceptions.
|
||||
|
||||
if (Runtime.wrap_exceptions) {
|
||||
if (attr is ExceptionClassObject) {
|
||||
ExceptionClassObject c = attr as ExceptionClassObject;
|
||||
if (c != null) {
|
||||
IntPtr p = attr.pyHandle;
|
||||
IntPtr r = Exceptions.GetExceptionClassWrapper(p);
|
||||
Runtime.PyDict_SetItemString(self.dict, name, r);
|
||||
Runtime.Incref(r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Runtime.Incref(attr.pyHandle);
|
||||
return attr.pyHandle;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// ModuleObject __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
ModuleObject self = (ModuleObject)GetManagedObject(ob);
|
||||
string s = String.Format("<module '{0}'>", self.moduleName);
|
||||
return Runtime.PyString_FromString(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The CLR module is the root handler used by the magic import hook
|
||||
/// to import assemblies. It has a fixed module name "clr" and doesn't
|
||||
/// provide a namespace.
|
||||
/// </summary>
|
||||
internal class CLRModule : ModuleObject
|
||||
{
|
||||
protected static bool hacked = false;
|
||||
protected static bool interactive_preload = true;
|
||||
internal static bool preload;
|
||||
// XXX Test performance of new features //
|
||||
internal static bool _SuppressDocs = false;
|
||||
internal static bool _SuppressOverloads = false;
|
||||
|
||||
public CLRModule() : base("clr") {
|
||||
_namespace = String.Empty;
|
||||
|
||||
// This hackery is required in order to allow a plain Python to
|
||||
// import the managed runtime via the CLR bootstrapper module.
|
||||
// The standard Python machinery in control at the time of the
|
||||
// import requires the module to pass PyModule_Check. :(
|
||||
if (!hacked)
|
||||
{
|
||||
IntPtr type = this.tpHandle;
|
||||
IntPtr mro = Marshal.ReadIntPtr(type, TypeOffset.tp_mro);
|
||||
IntPtr ext = Runtime.ExtendTuple(mro, Runtime.PyModuleType);
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_mro, ext);
|
||||
Runtime.Decref(mro);
|
||||
hacked = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The initializing of the preload hook has to happen as late as
|
||||
/// possible since sys.ps1 is created after the CLR module is
|
||||
/// created.
|
||||
/// </summary>
|
||||
internal void InitializePreload() {
|
||||
if (interactive_preload) {
|
||||
interactive_preload = false;
|
||||
if (Runtime.PySys_GetObject("ps1") != IntPtr.Zero) {
|
||||
preload = true;
|
||||
} else {
|
||||
Exceptions.Clear();
|
||||
preload = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[ModuleFunctionAttribute()]
|
||||
public static bool getPreload() {
|
||||
return preload;
|
||||
}
|
||||
|
||||
[ModuleFunctionAttribute()]
|
||||
public static void setPreload(bool preloadFlag)
|
||||
{
|
||||
preload = preloadFlag;
|
||||
}
|
||||
|
||||
//[ModulePropertyAttribute]
|
||||
public static bool SuppressDocs {
|
||||
get { return _SuppressDocs; }
|
||||
set { _SuppressDocs = value; }
|
||||
}
|
||||
|
||||
//[ModulePropertyAttribute]
|
||||
public static bool SuppressOverloads {
|
||||
get { return _SuppressOverloads; }
|
||||
set { _SuppressOverloads = value; }
|
||||
}
|
||||
|
||||
[ModuleFunctionAttribute()]
|
||||
[ForbidPythonThreadsAttribute()]
|
||||
public static Assembly AddReference(string name)
|
||||
{
|
||||
AssemblyManager.UpdatePath();
|
||||
Assembly assembly = null;
|
||||
assembly = AssemblyManager.LoadAssemblyPath(name);
|
||||
if (assembly == null)
|
||||
{
|
||||
assembly = AssemblyManager.LoadAssembly(name);
|
||||
}
|
||||
if (assembly == null)
|
||||
{
|
||||
string msg = String.Format("Unable to find assembly '{0}'.", name);
|
||||
throw new System.IO.FileNotFoundException(msg);
|
||||
}
|
||||
return assembly ;
|
||||
}
|
||||
|
||||
[ModuleFunctionAttribute()]
|
||||
[ForbidPythonThreadsAttribute()]
|
||||
public static string FindAssembly(string name)
|
||||
{
|
||||
AssemblyManager.UpdatePath();
|
||||
return AssemblyManager.FindAssembly(name);
|
||||
}
|
||||
|
||||
[ModuleFunctionAttribute()]
|
||||
public static String[] ListAssemblies(bool verbose)
|
||||
{
|
||||
AssemblyName[] assnames = AssemblyManager.ListAssemblies();
|
||||
String[] names = new String[assnames.Length];
|
||||
for (int i = 0; i < assnames.Length; i++)
|
||||
{
|
||||
if (verbose)
|
||||
names[i] = assnames[i].FullName;
|
||||
else
|
||||
names[i] = assnames[i].Name;
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
30
Pythonnet.Runtime/modulepropertyobject.cs
Normal file
30
Pythonnet.Runtime/modulepropertyobject.cs
Normal file
@ -0,0 +1,30 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Module level properties (attributes)
|
||||
/// </summary>
|
||||
internal class ModulePropertyObject : ExtensionType {
|
||||
|
||||
public ModulePropertyObject(PropertyInfo md) : base()
|
||||
{
|
||||
throw new NotImplementedException("ModulePropertyObject");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
60
Pythonnet.Runtime/monosupport.cs
Normal file
60
Pythonnet.Runtime/monosupport.cs
Normal file
@ -0,0 +1,60 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
#if (UCS4)
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace Python.Runtime {
|
||||
// The Utf32Marshaler was written Jonathan Pryor and has been placed
|
||||
// in the PUBLIC DOMAIN.
|
||||
public class Utf32Marshaler : ICustomMarshaler {
|
||||
private static Utf32Marshaler instance = new
|
||||
Utf32Marshaler ();
|
||||
|
||||
public static ICustomMarshaler GetInstance (string s)
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void CleanUpManagedData (object o)
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUpNativeData (IntPtr pNativeData)
|
||||
{
|
||||
UnixMarshal.FreeHeap (pNativeData);
|
||||
}
|
||||
|
||||
public int GetNativeDataSize ()
|
||||
{
|
||||
return IntPtr.Size;
|
||||
}
|
||||
|
||||
public IntPtr MarshalManagedToNative (object obj)
|
||||
{
|
||||
string s = obj as string;
|
||||
if (s == null)
|
||||
return IntPtr.Zero;
|
||||
return UnixMarshal.StringToHeap (s,
|
||||
Encoding.UTF32);
|
||||
}
|
||||
|
||||
public object MarshalNativeToManaged (IntPtr
|
||||
pNativeData)
|
||||
{
|
||||
return UnixMarshal.PtrToString (pNativeData,
|
||||
Encoding.UTF32);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
166
Pythonnet.Runtime/nativecall.cs
Normal file
166
Pythonnet.Runtime/nativecall.cs
Normal file
@ -0,0 +1,166 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Provides support for calling native code indirectly through
|
||||
/// function pointers. Most of the important parts of the Python
|
||||
/// C API can just be wrapped with p/invoke, but there are some
|
||||
/// situations (specifically, calling functions through Python
|
||||
/// type structures) where we need to call functions indirectly.
|
||||
///
|
||||
/// This class uses Reflection.Emit to generate IJW thunks that
|
||||
/// support indirect calls to native code using various common
|
||||
/// call signatures. This is mainly a workaround for the fact
|
||||
/// that you can't spell an indirect call in C# (but can in IL).
|
||||
///
|
||||
/// Another approach that would work is for this to be turned
|
||||
/// into a separate utility program that could be run during the
|
||||
/// build process to generate the thunks as a separate assembly
|
||||
/// that could then be referenced by the main Python runtime.
|
||||
/// </summary>
|
||||
|
||||
internal class NativeCall {
|
||||
|
||||
static AssemblyBuilder aBuilder;
|
||||
static ModuleBuilder mBuilder;
|
||||
|
||||
public static INativeCall Impl;
|
||||
|
||||
static NativeCall() {
|
||||
|
||||
// The static constructor is responsible for generating the
|
||||
// assembly and the methods that implement the IJW thunks.
|
||||
//
|
||||
// To do this, we actually use reflection on the INativeCall
|
||||
// interface (defined below) and generate the required thunk
|
||||
// code based on the method signatures.
|
||||
|
||||
AssemblyName aname = new AssemblyName();
|
||||
aname.Name = "e__NativeCall_Assembly";
|
||||
AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run;
|
||||
|
||||
aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa);
|
||||
mBuilder = aBuilder.DefineDynamicModule("e__NativeCall_Module");
|
||||
|
||||
TypeAttributes ta = TypeAttributes.Public;
|
||||
TypeBuilder tBuilder = mBuilder.DefineType("e__NativeCall", ta);
|
||||
|
||||
Type iType = typeof(INativeCall);
|
||||
tBuilder.AddInterfaceImplementation(iType);
|
||||
|
||||
// Use reflection to loop over the INativeCall interface methods,
|
||||
// calling GenerateThunk to create a managed thunk for each one.
|
||||
|
||||
foreach (MethodInfo method in iType.GetMethods()) {
|
||||
GenerateThunk(tBuilder, method);
|
||||
}
|
||||
|
||||
Type theType = tBuilder.CreateType();
|
||||
|
||||
Impl = (INativeCall)Activator.CreateInstance(theType);
|
||||
|
||||
}
|
||||
|
||||
private static void GenerateThunk(TypeBuilder tb, MethodInfo method) {
|
||||
|
||||
ParameterInfo[] pi = method.GetParameters();
|
||||
int count = pi.Length;
|
||||
int argc = count - 1;
|
||||
|
||||
Type[] args = new Type[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
args[i] = pi[i].ParameterType;
|
||||
}
|
||||
|
||||
MethodBuilder mb = tb.DefineMethod(
|
||||
method.Name,
|
||||
MethodAttributes.Public |
|
||||
MethodAttributes.Virtual,
|
||||
method.ReturnType,
|
||||
args
|
||||
);
|
||||
|
||||
// Build the method signature for the actual native function.
|
||||
// This is essentially the signature of the wrapper method
|
||||
// minus the first argument (the passed in function pointer).
|
||||
|
||||
Type[] nargs = new Type[argc];
|
||||
for (int i = 1; i < count; i++) {
|
||||
nargs[(i - 1)] = args[i];
|
||||
}
|
||||
|
||||
// IL generation: the (implicit) first argument of the method
|
||||
// is the 'this' pointer and the second is the function pointer.
|
||||
// This code pushes the real args onto the stack, followed by
|
||||
// the function pointer, then the calli opcode to make the call.
|
||||
|
||||
ILGenerator il = mb.GetILGenerator();
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
il.Emit(OpCodes.Ldarg_S, (i + 2));
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
il.EmitCalli(OpCodes.Calli,
|
||||
CallingConvention.Cdecl,
|
||||
method.ReturnType,
|
||||
nargs
|
||||
);
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
tb.DefineMethodOverride(mb, method);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
public static void Void_Call_1(IntPtr fp, IntPtr a1) {
|
||||
Impl.Void_Call_1(fp, a1);
|
||||
}
|
||||
|
||||
public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2,
|
||||
IntPtr a3) {
|
||||
return Impl.Call_3(fp, a1, a2, a3);
|
||||
}
|
||||
|
||||
public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2,
|
||||
IntPtr a3) {
|
||||
return Impl.Int_Call_3(fp, a1, a2, a3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Defines native call signatures to be generated by NativeCall.
|
||||
/// </summary>
|
||||
|
||||
public interface INativeCall {
|
||||
|
||||
void Void_Call_0(IntPtr funcPtr);
|
||||
|
||||
void Void_Call_1(IntPtr funcPtr, IntPtr arg1);
|
||||
|
||||
int Int_Call_3(IntPtr funcPtr, IntPtr t, IntPtr n, IntPtr v);
|
||||
|
||||
IntPtr Call_3(IntPtr funcPtr, IntPtr a1, IntPtr a2, IntPtr a3);
|
||||
|
||||
}
|
||||
|
||||
}
|
274
Pythonnet.Runtime/oldmodule.il
Normal file
274
Pythonnet.Runtime/oldmodule.il
Normal file
@ -0,0 +1,274 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
//============================================================================
|
||||
// This file is a hand-maintained stub - it implements clr.dll, which can be
|
||||
// loaded by a standard CPython interpreter as an extension module. When it
|
||||
// is loaded, it bootstraps the managed runtime integration layer and defers
|
||||
// to it to do initialization and put the clr module into sys.modules, etc.
|
||||
|
||||
// The "USE_PYTHON_RUNTIME_*" defines control what extra evidence is used
|
||||
// to help the CLR find the appropriate Python.Runtime assembly.
|
||||
|
||||
// If defined, the "pythonRuntimeVersionString" variable must be set to
|
||||
// Python.Runtime's current version.
|
||||
#define USE_PYTHON_RUNTIME_VERSION
|
||||
|
||||
// If defined, the "PythonRuntimePublicKeyTokenData" data array must be
|
||||
// set to Python.Runtime's public key token.
|
||||
//#define USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
|
||||
// If DEBUG_PRINT is defined, a few System.Console.WriteLine calls are made
|
||||
// to indicate what's going on during the load...
|
||||
//#define DEBUG_PRINT
|
||||
//============================================================================
|
||||
|
||||
.assembly extern mscorlib
|
||||
{
|
||||
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
|
||||
.ver 2:0:0:0
|
||||
}
|
||||
|
||||
.assembly clr
|
||||
{
|
||||
.hash algorithm 0x00008004
|
||||
.ver 2:0:0:2
|
||||
}
|
||||
|
||||
.module clr.dll
|
||||
.imagebase 0x00400000
|
||||
.subsystem 0x00000003
|
||||
.file alignment 512
|
||||
|
||||
// This includes the platform-specific IL. The include search path
|
||||
// is set depending on whether we're compiling 32 or 64 bit.
|
||||
// This MUST come before any other .data directives!
|
||||
// Why, oh why, can't ilasm support command line #defines? :(
|
||||
#include "clrmodule-platform.il"
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
.data PythonRuntimePublicKeyTokenData = bytearray (64 e1 4e 84 5a bf 2e 60)
|
||||
#endif
|
||||
|
||||
.class public auto ansi beforefieldinit clrModule extends [mscorlib]System.Object
|
||||
{
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
.field static assembly int64 PythonRuntimePublicKeyToken at PythonRuntimePublicKeyTokenData
|
||||
#endif
|
||||
|
||||
.method public hidebysig specialname rtspecialname instance void
|
||||
.ctor() cil managed
|
||||
{
|
||||
.maxstack 1
|
||||
ldarg.0
|
||||
call instance void [mscorlib]System.Object::.ctor()
|
||||
ret
|
||||
}
|
||||
|
||||
.method public hidebysig static void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)
|
||||
initclr() cil managed
|
||||
{
|
||||
.vtentry 1:1
|
||||
.export [1] as initclr
|
||||
|
||||
.maxstack 6
|
||||
.locals init (
|
||||
class [mscorlib]System.Reflection.Assembly pythonRuntime,
|
||||
class [mscorlib]System.Reflection.Assembly executingAssembly,
|
||||
class [mscorlib]System.Reflection.AssemblyName pythonRuntimeName,
|
||||
class [mscorlib]System.Type pythonEngineType,
|
||||
int8[] publicKeyToken,
|
||||
string assemblyDirectory,
|
||||
string pythonRuntimeVersionString,
|
||||
string pythonRuntimeDllPath)
|
||||
|
||||
// pythonRuntime = null;
|
||||
ldnull
|
||||
stloc pythonRuntime
|
||||
|
||||
.try
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Attempting to load Python.Runtime using standard binding rules... "
|
||||
call void [mscorlib]System.Console::Write(string)
|
||||
#endif
|
||||
|
||||
// Attempt to find and load Python.Runtime using standard assembly binding rules.
|
||||
// This roughly translates into looking in order:
|
||||
// - GAC
|
||||
// - ApplicationBase
|
||||
// - A PrivateBinPath under ApplicationBase
|
||||
// With an unsigned assembly, the GAC is skipped.
|
||||
|
||||
// System.Reflection.AssemblyName pythonRuntimeName = new System.Reflection.AssemblyName();
|
||||
newobj instance void [mscorlib]System.Reflection.AssemblyName::.ctor()
|
||||
stloc pythonRuntimeName
|
||||
|
||||
// pythonRuntimeName.Name = "Python.Runtime";
|
||||
ldloc pythonRuntimeName
|
||||
ldstr "Python.Runtime"
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Name(string)
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_VERSION
|
||||
// pythonRuntimeVersionString = "...";
|
||||
ldstr "2.0.0.2"
|
||||
stloc pythonRuntimeVersionString
|
||||
|
||||
// pythonRuntimeName.Version = new Version(pythonRuntimeVersionString);
|
||||
ldloc pythonRuntimeName
|
||||
ldloc pythonRuntimeVersionString
|
||||
newobj instance void [mscorlib]System.Version::.ctor(string)
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Version(class [mscorlib]System.Version)
|
||||
#endif
|
||||
|
||||
#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN
|
||||
// publicKeyToken = new byte[] { ... };
|
||||
ldc.i4.8
|
||||
newarr [mscorlib]System.Byte
|
||||
dup
|
||||
ldtoken field int64 clrModule::PythonRuntimePublicKeyToken
|
||||
call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
|
||||
stloc publicKeyToken
|
||||
|
||||
// pythonRuntimeName.SetPublicKeyToken(publicKeyToken);
|
||||
ldloc pythonRuntimeName
|
||||
ldloc publicKeyToken
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::SetPublicKeyToken(uint8[])
|
||||
#endif
|
||||
|
||||
// pythonRuntimeName.CultureInfo = System.Globalization.CultureInfo.InvariantCulture;
|
||||
ldloc pythonRuntimeName
|
||||
call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
|
||||
callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_CultureInfo(class [mscorlib]System.Globalization.CultureInfo)
|
||||
|
||||
// return System.Reflection.Assembly.Load(pythonRuntimeName);
|
||||
ldloc pythonRuntimeName
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::Load(class [mscorlib]System.Reflection.AssemblyName)
|
||||
stloc pythonRuntime
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Success!"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s LOADED_PYTHON_RUNTIME
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Failed."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_CLR_LOAD
|
||||
}
|
||||
EXIT_CLR_LOAD: nop
|
||||
|
||||
.try
|
||||
{
|
||||
// If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll"
|
||||
// from the directory this assembly is running in. "This assembly" is probably "clr.pyd",
|
||||
// sitting somewhere in PYTHONPATH. This is using Assembly.LoadFrom, and inherits all the
|
||||
// caveats of that call. See MSDN docs for details.
|
||||
// Suzanne Cook's blog is also an excellent source of info on this:
|
||||
// http://blogs.msdn.com/suzcook/
|
||||
// http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx
|
||||
// http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx
|
||||
// executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly()
|
||||
stloc executingAssembly
|
||||
|
||||
// assemblyDirectory = System.IO.Path.GetDirectoryName(executingAssembly.Location);
|
||||
ldloc executingAssembly
|
||||
callvirt instance string [mscorlib]System.Reflection.Assembly::get_Location()
|
||||
call string [mscorlib]System.IO.Path::GetDirectoryName(string)
|
||||
stloc assemblyDirectory
|
||||
|
||||
// pythonRuntimeDllPath = System.IO.Path.Combine(assemblyDirectory, "Python.Runtime.dll");
|
||||
ldloc assemblyDirectory
|
||||
ldstr "Python.Runtime.dll"
|
||||
call string [mscorlib]System.IO.Path::Combine(string, string)
|
||||
stloc pythonRuntimeDllPath
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Attempting to load Python.Runtime from: '{0}'... "
|
||||
ldloc pythonRuntimeDllPath
|
||||
call void [mscorlib]System.Console::Write(string, object)
|
||||
#endif
|
||||
|
||||
// pythonRuntime = System.Reflection.Assembly.LoadFrom(pythonRuntimeDllPath);
|
||||
ldloc pythonRuntimeDllPath
|
||||
call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::LoadFrom(string)
|
||||
stloc pythonRuntime
|
||||
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Success!"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s LOADED_PYTHON_RUNTIME
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Failed."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_PYTHONPATH_LOAD
|
||||
}
|
||||
EXIT_PYTHONPATH_LOAD: nop
|
||||
|
||||
// If we get here, we haven't loaded Python.Runtime, so bail.
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Could not load Python.Runtime, so sad."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
ret;
|
||||
|
||||
// Once here, we've successfully loaded SOME version of Python.Runtime
|
||||
// So now we get the PythonEngine and execute the InitExt method on it.
|
||||
LOADED_PYTHON_RUNTIME: nop
|
||||
.try
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Running Python.Runtime.PythonEngine.InitExt()"
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
// pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine");
|
||||
ldloc pythonRuntime
|
||||
ldstr "Python.Runtime.PythonEngine"
|
||||
callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string)
|
||||
stloc pythonEngineType
|
||||
|
||||
// pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null);
|
||||
ldloc pythonEngineType
|
||||
ldstr "InitExt"
|
||||
ldc.i4 0x100
|
||||
ldnull
|
||||
ldnull
|
||||
ldnull
|
||||
callvirt instance object [mscorlib]System.Type::InvokeMember( string,
|
||||
valuetype [mscorlib]System.Reflection.BindingFlags,
|
||||
class [mscorlib]System.Reflection.Binder,
|
||||
object,
|
||||
object[])
|
||||
pop
|
||||
leave.s EXIT_TRY_INVOKE
|
||||
}
|
||||
catch [mscorlib]System.Object
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
ldstr "Error calling Python.Runtime.PythonEngine.InitExt()."
|
||||
call void [mscorlib]System.Console::WriteLine(string)
|
||||
#endif
|
||||
leave.s EXIT_TRY_INVOKE
|
||||
}
|
||||
EXIT_TRY_INVOKE: nop
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
83
Pythonnet.Runtime/overload.cs
Normal file
83
Pythonnet.Runtime/overload.cs
Normal file
@ -0,0 +1,83 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements the __overloads__ attribute of method objects. This object
|
||||
// supports the [] syntax to explicitly select an overload by signature.
|
||||
//========================================================================
|
||||
|
||||
internal class OverloadMapper : ExtensionType {
|
||||
|
||||
MethodObject m;
|
||||
IntPtr target;
|
||||
|
||||
public OverloadMapper(MethodObject m, IntPtr target) : base() {
|
||||
Runtime.Incref(target);
|
||||
this.target = target;
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Implement explicit overload selection using subscript syntax ([]).
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) {
|
||||
OverloadMapper self = (OverloadMapper)GetManagedObject(tp);
|
||||
|
||||
// Note: if the type provides a non-generic method with N args
|
||||
// and a generic method that takes N params, then we always
|
||||
// prefer the non-generic version in doing overload selection.
|
||||
|
||||
Type[] types = Runtime.PythonArgsToTypeArray(idx);
|
||||
if (types == null) {
|
||||
return Exceptions.RaiseTypeError("type(s) expected");
|
||||
}
|
||||
|
||||
MethodInfo mi = MethodBinder.MatchSignature(self.m.info, types);
|
||||
if (mi == null) {
|
||||
string e = "No match found for signature";
|
||||
return Exceptions.RaiseTypeError(e);
|
||||
}
|
||||
|
||||
MethodBinding mb = new MethodBinding(self.m, self.target);
|
||||
mb.info = mi;
|
||||
Runtime.Incref(mb.pyHandle);
|
||||
return mb.pyHandle;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// OverloadMapper __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr op) {
|
||||
OverloadMapper self = (OverloadMapper)GetManagedObject(op);
|
||||
IntPtr doc = self.m.GetDocString();
|
||||
Runtime.Incref(doc);
|
||||
return doc;
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// OverloadMapper dealloc implementation.
|
||||
//====================================================================
|
||||
|
||||
public static new void tp_dealloc(IntPtr ob) {
|
||||
OverloadMapper self = (OverloadMapper)GetManagedObject(ob);
|
||||
Runtime.Decref(self.target);
|
||||
ExtensionType.FinalizeObject(self);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
164
Pythonnet.Runtime/propertyobject.cs
Normal file
164
Pythonnet.Runtime/propertyobject.cs
Normal file
@ -0,0 +1,164 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python descriptor type that manages CLR properties.
|
||||
//========================================================================
|
||||
|
||||
internal class PropertyObject : ExtensionType {
|
||||
|
||||
PropertyInfo info;
|
||||
MethodInfo getter;
|
||||
MethodInfo setter;
|
||||
|
||||
[StrongNameIdentityPermissionAttribute(SecurityAction.Assert)]
|
||||
public PropertyObject(PropertyInfo md) : base() {
|
||||
getter = md.GetGetMethod(true);
|
||||
setter = md.GetSetMethod(true);
|
||||
info = md;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// 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) {
|
||||
PropertyObject self = (PropertyObject)GetManagedObject(ds);
|
||||
MethodInfo getter = self.getter;
|
||||
Object result;
|
||||
|
||||
|
||||
if (getter == null) {
|
||||
return Exceptions.RaiseTypeError("property cannot be read");
|
||||
}
|
||||
|
||||
if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) {
|
||||
if (!(getter.IsStatic)) {
|
||||
Exceptions.SetError(Exceptions.TypeError,
|
||||
"instance property must be accessed through " +
|
||||
"a class instance"
|
||||
);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
try {
|
||||
result = self.info.GetValue(null, null);
|
||||
return Converter.ToPython(result, self.info.PropertyType);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return Exceptions.RaiseTypeError(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
CLRObject co = GetManagedObject(ob) as CLRObject;
|
||||
if (co == null) {
|
||||
return Exceptions.RaiseTypeError("invalid target");
|
||||
}
|
||||
|
||||
try {
|
||||
result = self.info.GetValue(co.inst, null);
|
||||
return Converter.ToPython(result, self.info.PropertyType);
|
||||
}
|
||||
catch(Exception e) {
|
||||
if (e.InnerException != null) {
|
||||
e = e.InnerException;
|
||||
}
|
||||
Exceptions.SetError(e);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __set__ implementation. This method sets the value of
|
||||
// a property based on the given Python value. The Python value must
|
||||
// be convertible to the type of the property.
|
||||
//====================================================================
|
||||
|
||||
public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) {
|
||||
PropertyObject self = (PropertyObject)GetManagedObject(ds);
|
||||
MethodInfo setter = self.setter;
|
||||
Object newval;
|
||||
|
||||
if (val == IntPtr.Zero) {
|
||||
Exceptions.RaiseTypeError("cannot delete property");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setter == null) {
|
||||
Exceptions.RaiseTypeError("property is read-only");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (!Converter.ToManaged(val, self.info.PropertyType, out newval,
|
||||
true)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool is_static = setter.IsStatic;
|
||||
|
||||
if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) {
|
||||
if (!(is_static)) {
|
||||
Exceptions.RaiseTypeError(
|
||||
"instance property must be set on an instance"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!is_static) {
|
||||
CLRObject co = GetManagedObject(ob) as CLRObject;
|
||||
if (co == null) {
|
||||
Exceptions.RaiseTypeError("invalid target");
|
||||
return -1;
|
||||
}
|
||||
self.info.SetValue(co.inst, newval, null);
|
||||
}
|
||||
else {
|
||||
self.info.SetValue(null, newval, null);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
catch(Exception e) {
|
||||
if (e.InnerException != null) {
|
||||
e = e.InnerException;
|
||||
}
|
||||
Exceptions.SetError(e);
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Descriptor __repr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
public static IntPtr tp_repr(IntPtr ob) {
|
||||
PropertyObject self = (PropertyObject)GetManagedObject(ob);
|
||||
string s = String.Format("<property '{0}'>", self.info.Name);
|
||||
return Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
82
Pythonnet.Runtime/pyansistring.cs
Normal file
82
Pythonnet.Runtime/pyansistring.cs
Normal file
@ -0,0 +1,82 @@
|
||||
// ==========================================================================
|
||||
// This is a user contribution to the pythondotnet project.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
public class PyAnsiString : PySequence
|
||||
{
|
||||
/// <summary>
|
||||
/// PyAnsiString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyAnsiString from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyAnsiString(IntPtr ptr) : base(ptr) { }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyAnsiString from a generic PyObject.
|
||||
/// An ArgumentException will be thrown if the given object is not
|
||||
/// a Python string object.
|
||||
/// </remarks>
|
||||
|
||||
public PyAnsiString(PyObject o)
|
||||
: base()
|
||||
{
|
||||
if (!IsStringType(o))
|
||||
{
|
||||
throw new ArgumentException("object is not a string");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyAnsiString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a Python string from a managed string.
|
||||
/// </remarks>
|
||||
|
||||
public PyAnsiString(string s)
|
||||
: base()
|
||||
{
|
||||
obj = Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
if (obj == IntPtr.Zero)
|
||||
{
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsStringType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python string.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsStringType(PyObject value)
|
||||
{
|
||||
return Runtime.PyString_Check(value.obj);
|
||||
}
|
||||
}
|
||||
}
|
208
Pythonnet.Runtime/pydict.cs
Normal file
208
Pythonnet.Runtime/pydict.cs
Normal file
@ -0,0 +1,208 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python dictionary object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/dictObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyDict : PyObject {
|
||||
|
||||
/// <summary>
|
||||
/// PyDict Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyDict from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyDict Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python dictionary object.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict() : base() {
|
||||
obj = Runtime.PyDict_New();
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyDict Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyDict from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python dictionary object.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict(PyObject o) : base() {
|
||||
if (!IsDictType(o)) {
|
||||
throw new ArgumentException("object is not a dict");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsDictType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsDictType(PyObject value) {
|
||||
return Runtime.PyDict_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasKey Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object key appears in the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasKey(PyObject key) {
|
||||
return (Runtime.PyMapping_HasKey(obj, key.obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasKey Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the string key appears in the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasKey(string key) {
|
||||
return HasKey(new PyString(key));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Keys Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a sequence containing the keys of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Keys() {
|
||||
IntPtr items = Runtime.PyDict_Keys(obj);
|
||||
if (items == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(items);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Values Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a sequence containing the values of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Values() {
|
||||
IntPtr items = Runtime.PyDict_Values(obj);
|
||||
if (items == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(items);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Items Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a sequence containing the items of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Items() {
|
||||
IntPtr items = Runtime.PyDict_Items(obj);
|
||||
if (items == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(items);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Copy Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a copy of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict Copy() {
|
||||
IntPtr op = Runtime.PyDict_Copy(obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyDict(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Update the dictionary from another dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public void Update(PyObject other) {
|
||||
int result = Runtime.PyDict_Update(obj, other.obj);
|
||||
if (result < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clear Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Clears the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public void Clear() {
|
||||
Runtime.PyDict_Clear(obj);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
122
Pythonnet.Runtime/pyfloat.cs
Normal file
122
Pythonnet.Runtime/pyfloat.cs
Normal file
@ -0,0 +1,122 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python float object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/floatObjects.html
|
||||
/// </summary>
|
||||
|
||||
public class PyFloat : PyNumber {
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyFloat from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyFloat from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python float object.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(PyObject o) : base() {
|
||||
if (!IsFloatType(o)) {
|
||||
throw new ArgumentException("object is not a float");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python float from a double value.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(double value) : base() {
|
||||
obj = Runtime.PyFloat_FromDouble(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python float from a string value.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(string value) : base() {
|
||||
PyString s = new PyString(value);
|
||||
obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsFloatType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python float.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsFloatType(PyObject value) {
|
||||
return Runtime.PyFloat_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsFloat Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python float if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "float(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyFloat AsFloat(PyObject value) {
|
||||
IntPtr op = Runtime.PyNumber_Float(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyFloat(op);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
257
Pythonnet.Runtime/pyint.cs
Normal file
257
Pythonnet.Runtime/pyint.cs
Normal file
@ -0,0 +1,257 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python integer object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/intObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyInt : PyNumber {
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyInt from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyInt from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python int object.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(PyObject o) : base() {
|
||||
if (!IsIntType(o)) {
|
||||
throw new ArgumentException("object is not an int");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an int32 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(int value) : base() {
|
||||
obj = Runtime.PyInt_FromInt32(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a uint32 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(uint value) : base(IntPtr.Zero) {
|
||||
obj = Runtime.PyInt_FromInt64((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an int64 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(long value) : base(IntPtr.Zero) {
|
||||
obj = Runtime.PyInt_FromInt64(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a uint64 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(ulong value) : base(IntPtr.Zero) {
|
||||
obj = Runtime.PyInt_FromInt64((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an int16 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(short value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a uint16 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(ushort value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a byte value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(byte value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an sbyte value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(sbyte value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a string value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(string value) : base() {
|
||||
obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsIntType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python int.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsIntType(PyObject value) {
|
||||
return Runtime.PyInt_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsInt Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python int if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "int(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyInt AsInt(PyObject value) {
|
||||
IntPtr op = Runtime.PyNumber_Int(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyInt(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt16 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python int object as an int16.
|
||||
/// </remarks>
|
||||
|
||||
public short ToInt16() {
|
||||
return System.Convert.ToInt16(this.ToInt32());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt32 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python int object as an int32.
|
||||
/// </remarks>
|
||||
|
||||
public int ToInt32() {
|
||||
return Runtime.PyInt_AsLong(obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt64 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python int object as an int64.
|
||||
/// </remarks>
|
||||
|
||||
public long ToInt64() {
|
||||
return System.Convert.ToInt64(this.ToInt32());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
76
Pythonnet.Runtime/pyiter.cs
Normal file
76
Pythonnet.Runtime/pyiter.cs
Normal file
@ -0,0 +1,76 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Python.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a standard Python iterator object. See the documentation at
|
||||
/// http://www.python.org/doc/2.4.4/api/iterator.html for details.
|
||||
/// </summary>
|
||||
public class PyIter : PyObject, IEnumerator<object>
|
||||
{
|
||||
private PyObject _current = null;
|
||||
|
||||
/// <summary>
|
||||
/// PyIter Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyIter from an existing iterator reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyIter(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
/// <summary>
|
||||
/// PyIter Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python.
|
||||
/// </remarks>
|
||||
|
||||
public PyIter(PyObject iterable) : base()
|
||||
{
|
||||
obj = Runtime.PyObject_GetIter(iterable.obj);
|
||||
if (obj == IntPtr.Zero)
|
||||
throw new PythonException();
|
||||
}
|
||||
|
||||
#region IEnumerator Members
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
IntPtr next = Runtime.PyIter_Next(obj);
|
||||
if (next == IntPtr.Zero)
|
||||
{
|
||||
_current = null; //release reference
|
||||
return false;
|
||||
}
|
||||
_current = new PyObject(next);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
//Not supported in python.
|
||||
}
|
||||
|
||||
public object Current
|
||||
{
|
||||
get { return _current; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
189
Pythonnet.Runtime/pylist.cs
Normal file
189
Pythonnet.Runtime/pylist.cs
Normal file
@ -0,0 +1,189 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a standard Python list object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/listObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyList : PySequence {
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyList from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyList(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyList from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python list object.
|
||||
/// </remarks>
|
||||
|
||||
public PyList(PyObject o) : base() {
|
||||
if (!IsListType(o)) {
|
||||
throw new ArgumentException("object is not a list");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new empty Python list object.
|
||||
/// </remarks>
|
||||
|
||||
public PyList() : base() {
|
||||
obj = Runtime.PyList_New(0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python list object from an array of PyObjects.
|
||||
/// </remarks>
|
||||
|
||||
public PyList(PyObject[] items) : base() {
|
||||
int count = items.Length;
|
||||
obj = Runtime.PyList_New(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntPtr ptr = items[i].obj;
|
||||
Runtime.Incref(ptr);
|
||||
int r = Runtime.PyList_SetItem(obj, i, ptr);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsListType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python list.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsListType(PyObject value) {
|
||||
return Runtime.PyList_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsList Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Converts a Python object to a Python list if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "list(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyList AsList(PyObject value) {
|
||||
IntPtr op = Runtime.PySequence_List(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyList(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Append Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Append an item to the list object.
|
||||
/// </remarks>
|
||||
|
||||
public void Append(PyObject item) {
|
||||
int r = Runtime.PyList_Append(obj, item.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Insert an item in the list object at the given index.
|
||||
/// </remarks>
|
||||
|
||||
public void Insert(int index, PyObject item) {
|
||||
int r = Runtime.PyList_Insert(obj, index, item.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reverse Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Reverse the order of the list object in place.
|
||||
/// </remarks>
|
||||
|
||||
public void Reverse() {
|
||||
int r = Runtime.PyList_Reverse(obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sort Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sort the list in place.
|
||||
/// </remarks>
|
||||
|
||||
public void Sort() {
|
||||
int r = Runtime.PyList_Sort(obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
291
Pythonnet.Runtime/pylong.cs
Normal file
291
Pythonnet.Runtime/pylong.cs
Normal file
@ -0,0 +1,291 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python long int object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/longObjects.html
|
||||
/// </summary>
|
||||
|
||||
public class PyLong : PyNumber {
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyLong from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python long object.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(PyObject o) : base() {
|
||||
if (!IsLongType(o)) {
|
||||
throw new ArgumentException("object is not a long");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an int32 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(int value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a uint32 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(uint value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an int64 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(long value) : base() {
|
||||
obj = Runtime.PyLong_FromLongLong(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a uint64 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(ulong value) : base() {
|
||||
obj = Runtime.PyLong_FromUnsignedLongLong(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an int16 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(short value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an uint16 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(ushort value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a byte value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(byte value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an sbyte value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(sbyte value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an double value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(double value) : base() {
|
||||
obj = Runtime.PyLong_FromDouble(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a string value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(string value) : base() {
|
||||
obj = Runtime.PyLong_FromString(value, IntPtr.Zero, 0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsLongType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python long.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsLongType(PyObject value) {
|
||||
return Runtime.PyLong_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsLong Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python long if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "long(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyLong AsLong(PyObject value) {
|
||||
IntPtr op = Runtime.PyNumber_Long(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyLong(op);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ToInt16 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python long object as an int16.
|
||||
/// </remarks>
|
||||
|
||||
public short ToInt16()
|
||||
{
|
||||
return System.Convert.ToInt16(this.ToInt64());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt32 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python long object as an int32.
|
||||
/// </remarks>
|
||||
|
||||
public int ToInt32()
|
||||
{
|
||||
return System.Convert.ToInt32(this.ToInt64());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt64 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python long object as an int64.
|
||||
/// </remarks>
|
||||
|
||||
public long ToInt64()
|
||||
{
|
||||
return Runtime.PyLong_AsLongLong(obj);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
47
Pythonnet.Runtime/pynumber.cs
Normal file
47
Pythonnet.Runtime/pynumber.cs
Normal file
@ -0,0 +1,47 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generic Python number. The methods of this class are
|
||||
/// equivalent to the Python "abstract number API". See
|
||||
/// http://www.python.org/doc/current/api/number.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyNumber : PyObject {
|
||||
|
||||
protected PyNumber(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
protected PyNumber() : base() {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsNumberType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python numeric type.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsNumberType(PyObject value) {
|
||||
return Runtime.PyNumber_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
// TODO: add all of the PyNumber_XXX methods.
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
869
Pythonnet.Runtime/pyobject.cs
Normal file
869
Pythonnet.Runtime/pyobject.cs
Normal file
@ -0,0 +1,869 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generic Python object. The methods of this class are
|
||||
/// generally equivalent to the Python "abstract object API". See
|
||||
/// http://www.python.org/doc/current/api/object.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyObject : IDisposable {
|
||||
|
||||
protected internal IntPtr obj = IntPtr.Zero;
|
||||
private bool disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// PyObject Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyObject from an IntPtr object reference. Note that
|
||||
/// the PyObject instance assumes ownership of the object reference
|
||||
/// and the reference will be DECREFed when the PyObject is garbage
|
||||
/// collected or explicitly disposed.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject(IntPtr ptr) {
|
||||
obj = ptr;
|
||||
}
|
||||
|
||||
// Protected default constructor to allow subclasses to manage
|
||||
// initialization in different ways as appropriate.
|
||||
|
||||
protected PyObject() {}
|
||||
|
||||
// Ensure that encapsulated Python object is decref'ed appropriately
|
||||
// when the managed wrapper is garbage-collected.
|
||||
|
||||
~PyObject() {
|
||||
Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Gets the native handle of the underlying Python object. This
|
||||
/// value is generally for internal use by the PythonNet runtime.
|
||||
/// </remarks>
|
||||
|
||||
public IntPtr Handle {
|
||||
get { return obj; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// FromManagedObject Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given an arbitrary managed object, return a Python instance that
|
||||
/// reflects the managed object.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject FromManagedObject(object ob) {
|
||||
// Special case: if ob is null, we return None.
|
||||
if (ob == null) {
|
||||
Runtime.Incref(Runtime.PyNone);
|
||||
return new PyObject(Runtime.PyNone);
|
||||
}
|
||||
IntPtr op = CLRObject.GetInstHandle(ob);
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsManagedObject Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a managed object of the given type, based on the
|
||||
/// value of the Python object.
|
||||
/// </remarks>
|
||||
|
||||
public object AsManagedObject(Type t) {
|
||||
Object result;
|
||||
if (!Converter.ToManaged(this.Handle, t, out result, false)) {
|
||||
throw new InvalidCastException("cannot convert object to target type");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// The Dispose method provides a way to explicitly release the
|
||||
/// Python object represented by a PyObject instance. It is a good
|
||||
/// idea to call Dispose on PyObjects that wrap resources that are
|
||||
/// limited or need strict lifetime control. Otherwise, references
|
||||
/// to Python objects will not be released until a managed garbage
|
||||
/// collection occurs.
|
||||
/// </remarks>
|
||||
|
||||
public void Dispose() {
|
||||
if (!disposed) {
|
||||
if (Runtime.Py_IsInitialized() > 0) {
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
Runtime.Decref(obj);
|
||||
obj = IntPtr.Zero;
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetPythonType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the Python type of the object. This method is equivalent
|
||||
/// to the Python expression: type(object).
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetPythonType() {
|
||||
IntPtr tp = Runtime.PyObject_Type(obj);
|
||||
return new PyObject(tp);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// TypeCheck Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object o is of type typeOrClass or a subtype
|
||||
/// of typeOrClass.
|
||||
/// </remarks>
|
||||
|
||||
public bool TypeCheck(PyObject typeOrClass) {
|
||||
return Runtime.PyObject_TypeCheck(obj, typeOrClass.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object has an attribute with the given name.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasAttr(string name) {
|
||||
return (Runtime.PyObject_HasAttrString(obj, name) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object has an attribute with the given name,
|
||||
/// where name is a PyObject wrapping a string or unicode object.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasAttr(PyObject name) {
|
||||
return (Runtime.PyObject_HasAttr(obj, name.obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object, or raises a
|
||||
/// PythonException if the attribute access fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(string name) {
|
||||
IntPtr op = Runtime.PyObject_GetAttrString(obj, name);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object, or the given
|
||||
/// default object if the attribute access fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(string name, PyObject _default) {
|
||||
IntPtr op = Runtime.PyObject_GetAttrString(obj, name);
|
||||
if (op == IntPtr.Zero) {
|
||||
Runtime.PyErr_Clear();
|
||||
return _default;
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object or raises a
|
||||
/// PythonException if the attribute access fails. The name argument
|
||||
/// is a PyObject wrapping a Python string or unicode object.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(PyObject name) {
|
||||
IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object, or the given
|
||||
/// default object if the attribute access fails. The name argument
|
||||
/// is a PyObject wrapping a Python string or unicode object.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(PyObject name, PyObject _default) {
|
||||
IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
Runtime.PyErr_Clear();
|
||||
return _default;
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Set an attribute of the object with the given name and value. This
|
||||
/// method throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void SetAttr(string name, PyObject value) {
|
||||
int r = Runtime.PyObject_SetAttrString(obj, name, value.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Set an attribute of the object with the given name and value,
|
||||
/// where the name is a Python string or unicode object. This method
|
||||
/// throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void SetAttr(PyObject name, PyObject value) {
|
||||
int r = Runtime.PyObject_SetAttr(obj, name.obj, value.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Delete the named attribute of the Python object. This method
|
||||
/// throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void DelAttr(string name) {
|
||||
int r = Runtime.PyObject_SetAttrString(obj, name, IntPtr.Zero);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Delete the named attribute of the Python object, where name is a
|
||||
/// PyObject wrapping a Python string or unicode object. This method
|
||||
/// throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void DelAttr(PyObject name) {
|
||||
int r = Runtime.PyObject_SetAttr(obj, name.obj, IntPtr.Zero);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// return the item at the given object index. This method raises a
|
||||
/// PythonException if the indexing operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject GetItem(PyObject key) {
|
||||
IntPtr op = Runtime.PyObject_GetItem(obj, key.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// return the item at the given string index. This method raises a
|
||||
/// PythonException if the indexing operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject GetItem(string key) {
|
||||
return GetItem(new PyString(key));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// return the item at the given numeric index. This method raises a
|
||||
/// PythonException if the indexing operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject GetItem(int index) {
|
||||
PyInt key = new PyInt(index);
|
||||
return GetItem((PyObject)key);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// set the item at the given object index to the given value. This
|
||||
/// method raises a PythonException if the set operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void SetItem(PyObject key, PyObject value) {
|
||||
int r = Runtime.PyObject_SetItem(obj, key.obj, value.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// set the item at the given string index to the given value. This
|
||||
/// method raises a PythonException if the set operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void SetItem(string key, PyObject value) {
|
||||
SetItem(new PyString(key), value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// set the item at the given numeric index to the given value. This
|
||||
/// method raises a PythonException if the set operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void SetItem(int index, PyObject value) {
|
||||
SetItem(new PyInt(index), value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// delete the item at the given object index. This method raises a
|
||||
/// PythonException if the delete operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void DelItem(PyObject key) {
|
||||
int r = Runtime.PyObject_DelItem(obj, key.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// delete the item at the given string index. This method raises a
|
||||
/// PythonException if the delete operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void DelItem(string key) {
|
||||
DelItem(new PyString(key));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// delete the item at the given numeric index. This method raises a
|
||||
/// PythonException if the delete operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void DelItem(int index) {
|
||||
DelItem(new PyInt(index));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Length Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the length for objects that support the Python sequence
|
||||
/// protocol, or 0 if the object does not support the protocol.
|
||||
/// </remarks>
|
||||
|
||||
public virtual int Length() {
|
||||
int s = Runtime.PyObject_Size(obj);
|
||||
if (s < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// String Indexer
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Provides a shorthand for the string versions of the GetItem and
|
||||
/// SetItem methods.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject this[string key] {
|
||||
get { return GetItem(key); }
|
||||
set { SetItem(key, value); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyObject Indexer
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Provides a shorthand for the object versions of the GetItem and
|
||||
/// SetItem methods.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject this[PyObject key] {
|
||||
get { return GetItem(key); }
|
||||
set { SetItem(key, value); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Numeric Indexer
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Provides a shorthand for the numeric versions of the GetItem and
|
||||
/// SetItem methods.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject this[int index] {
|
||||
get { return GetItem(index); }
|
||||
set { SetItem(index, value); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetIterator Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a new (Python) iterator for the object. This is equivalent
|
||||
/// to the Python expression "iter(object)". A PythonException will be
|
||||
/// raised if the object cannot be iterated.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetIterator() {
|
||||
IntPtr r = Runtime.PyObject_GetIter(obj);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given arguments, passed as a
|
||||
/// PyObject[]. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(params PyObject[] args) {
|
||||
PyTuple t = new PyTuple(args);
|
||||
IntPtr r = Runtime.PyObject_Call(obj, t.obj, IntPtr.Zero);
|
||||
t.Dispose();
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given arguments, passed as a
|
||||
/// Python tuple. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(PyTuple args) {
|
||||
IntPtr r = Runtime.PyObject_Call(obj, args.obj, IntPtr.Zero);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given positional and keyword
|
||||
/// arguments. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(PyObject[] args, PyDict kw) {
|
||||
PyTuple t = new PyTuple(args);
|
||||
IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw.obj);
|
||||
t.Dispose();
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given positional and keyword
|
||||
/// arguments. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(PyTuple args, PyDict kw) {
|
||||
IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw.obj);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, params PyObject[] args) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, PyTuple args) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments
|
||||
/// and keyword arguments. Keyword args are passed as a PyDict object.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args, kw);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments
|
||||
/// and keyword arguments. Keyword args are passed as a PyDict object.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, PyTuple args, PyDict kw) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args, kw);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsInstance Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the object is an instance of the given Python type
|
||||
/// or class. This method always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsInstance(PyObject typeOrClass) {
|
||||
int r = Runtime.PyObject_IsInstance(obj, typeOrClass.obj);
|
||||
if (r < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
return (r != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsSubclass Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the object is identical to or derived from the
|
||||
/// given Python type or class. This method always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsSubclass(PyObject typeOrClass) {
|
||||
int r = Runtime.PyObject_IsSubclass(obj, typeOrClass.obj);
|
||||
if (r < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
return (r != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsCallable Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object is a callable object. This method
|
||||
/// always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsCallable() {
|
||||
return (Runtime.PyCallable_Check(obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsTrue Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the object is true according to Python semantics.
|
||||
/// This method always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsTrue() {
|
||||
return (Runtime.PyObject_IsTrue(obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dir Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a list of the names of the attributes of the object. This
|
||||
/// is equivalent to the Python expression "dir(object)".
|
||||
/// </remarks>
|
||||
|
||||
public PyList Dir() {
|
||||
IntPtr r = Runtime.PyObject_Dir(obj);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyList(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Repr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a string representation of the object. This method is
|
||||
/// the managed equivalent of the Python expression "repr(object)".
|
||||
/// </remarks>
|
||||
|
||||
public string Repr() {
|
||||
IntPtr strval = Runtime.PyObject_Repr(obj);
|
||||
string result = Runtime.GetManagedString(strval);
|
||||
Runtime.Decref(strval);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToString Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the string representation of the object. This method is
|
||||
/// the managed equivalent of the Python expression "str(object)".
|
||||
/// </remarks>
|
||||
|
||||
public override string ToString() {
|
||||
IntPtr strval = Runtime.PyObject_Unicode(obj);
|
||||
string result = Runtime.GetManagedString(strval);
|
||||
Runtime.Decref(strval);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Equals Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if this object is equal to the given object. This
|
||||
/// method is based on Python equality semantics.
|
||||
/// </remarks>
|
||||
|
||||
public override bool Equals(object o) {
|
||||
if (!(o is PyObject)) {
|
||||
return false;
|
||||
}
|
||||
if (obj == ((PyObject) o).obj) {
|
||||
return true;
|
||||
}
|
||||
int r = Runtime.PyObject_Compare(obj, ((PyObject) o).obj);
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return (r == 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetHashCode Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a hashcode based on the Python object. This returns the
|
||||
/// hash as computed by Python, equivalent to the Python expression
|
||||
/// "hash(obj)".
|
||||
/// </remarks>
|
||||
|
||||
public override int GetHashCode() {
|
||||
return Runtime.PyObject_Hash(obj).ToInt32();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
172
Pythonnet.Runtime/pysequence.cs
Normal file
172
Pythonnet.Runtime/pysequence.cs
Normal file
@ -0,0 +1,172 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generic Python sequence. The methods of this class are
|
||||
/// equivalent to the Python "abstract sequence API". See
|
||||
/// http://www.python.org/doc/current/api/sequence.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PySequence : PyObject, IEnumerable {
|
||||
|
||||
protected PySequence(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
protected PySequence() : base() {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsSequenceType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object implements the sequence protocol.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsSequenceType(PyObject value) {
|
||||
return Runtime.PySequence_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetSlice Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the slice of the sequence with the given indices.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetSlice(int i1, int i2) {
|
||||
IntPtr op = Runtime.PySequence_GetSlice(obj, i1, i2);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetSlice Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the slice of the sequence with the given indices.
|
||||
/// </remarks>
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelSlice Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Deletes the slice of the sequence with the given indices.
|
||||
/// </remarks>
|
||||
|
||||
public void DelSlice(int i1, int i2) {
|
||||
int r = Runtime.PySequence_DelSlice(obj, i1, i2);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Index Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the index of the given item in the sequence, or -1 if
|
||||
/// the item does not appear in the sequence.
|
||||
/// </remarks>
|
||||
|
||||
public int Index(PyObject item) {
|
||||
int r = Runtime.PySequence_Index(obj, item.obj);
|
||||
if (r < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the sequence contains the given item. This method
|
||||
/// throws a PythonException if an error occurs during the check.
|
||||
/// </remarks>
|
||||
|
||||
public bool Contains(PyObject item) {
|
||||
int r = Runtime.PySequence_Contains(obj, item.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return (r != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Concat Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the concatenation of the sequence object with the passed in
|
||||
/// sequence object.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Concat(PyObject other) {
|
||||
IntPtr op = Runtime.PySequence_Concat(obj, other.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Repeat Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the sequence object repeated N times. This is equivalent
|
||||
/// to the Python expression "object * count".
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Repeat(int count) {
|
||||
IntPtr op = Runtime.PySequence_Repeat(obj, count);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
#region IEnumerable Members
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return new PyIter(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
85
Pythonnet.Runtime/pystring.cs
Normal file
85
Pythonnet.Runtime/pystring.cs
Normal file
@ -0,0 +1,85 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python (ansi) string object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/stringObjects.html for details.
|
||||
/// 2011-01-29: ...Then why does the string constructor call PyUnicode_FromUnicode()???
|
||||
/// </summary>
|
||||
|
||||
public class PyString : PySequence {
|
||||
|
||||
/// <summary>
|
||||
/// PyString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyString from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyString(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyString from a generic PyObject.
|
||||
/// An ArgumentException will be thrown if the given object is not
|
||||
/// a Python string object.
|
||||
/// </remarks>
|
||||
|
||||
public PyString(PyObject o) : base() {
|
||||
if (!IsStringType(o)) {
|
||||
throw new ArgumentException("object is not a string");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a Python string from a managed string.
|
||||
/// </remarks>
|
||||
|
||||
public PyString(string s) : base() {
|
||||
obj = Runtime.PyUnicode_FromUnicode(s, s.Length);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsStringType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python string.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsStringType(PyObject value) {
|
||||
return Runtime.PyString_Check(value.obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
355
Pythonnet.Runtime/pythonengine.cs
Normal file
355
Pythonnet.Runtime/pythonengine.cs
Normal file
@ -0,0 +1,355 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// This class provides the public interface of the Python runtime.
|
||||
/// </summary>
|
||||
|
||||
public class PythonEngine {
|
||||
|
||||
private static DelegateManager delegateManager;
|
||||
private static bool initialized;
|
||||
|
||||
#region Properties
|
||||
|
||||
public static bool IsInitialized {
|
||||
get {
|
||||
return initialized;
|
||||
}
|
||||
}
|
||||
|
||||
internal static DelegateManager DelegateManager {
|
||||
get {
|
||||
if (delegateManager == null) {
|
||||
throw new InvalidOperationException("DelegateManager has not yet been initialized using Python.Runtime.PythonEngine.Initialize().");
|
||||
}
|
||||
return delegateManager;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ProgramName {
|
||||
get {
|
||||
string result = Runtime.Py_GetProgramName();
|
||||
if (result == null) {
|
||||
return "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
set {
|
||||
Runtime.Py_SetProgramName(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static string PythonHome {
|
||||
get {
|
||||
string result = Runtime.Py_GetPythonHome();
|
||||
if (result == null) {
|
||||
return "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
set {
|
||||
Runtime.Py_SetPythonHome(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Version {
|
||||
get {
|
||||
return Runtime.Py_GetVersion();
|
||||
}
|
||||
}
|
||||
|
||||
public static string BuildInfo {
|
||||
get {
|
||||
return Runtime.Py_GetBuildInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public static string Platform {
|
||||
get {
|
||||
return Runtime.Py_GetPlatform();
|
||||
}
|
||||
}
|
||||
|
||||
public static string Copyright {
|
||||
get {
|
||||
return Runtime.Py_GetCopyright();
|
||||
}
|
||||
}
|
||||
|
||||
public static int RunSimpleString(string code) {
|
||||
return Runtime.PyRun_SimpleString(code);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Initialize the Python runtime. It is safe to call this method
|
||||
/// more than once, though initialization will only happen on the
|
||||
/// first call. It is *not* necessary to hold the Python global
|
||||
/// interpreter lock (GIL) to call this method.
|
||||
/// </remarks>
|
||||
|
||||
public static void Initialize() {
|
||||
if (!initialized) {
|
||||
// Creating the delegateManager MUST happen before Runtime.Initialize
|
||||
// is called. If it happens afterwards, DelegateManager's CodeGenerator
|
||||
// throws an exception in its ctor. This exception is eaten somehow
|
||||
// during an initial "import clr", and the world ends shortly thereafter.
|
||||
// This is probably masking some bad mojo happening somewhere in Runtime.Initialize().
|
||||
delegateManager = new DelegateManager();
|
||||
Runtime.Initialize();
|
||||
initialized = true;
|
||||
Exceptions.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// A helper to perform initialization from the context of an active
|
||||
// CPython interpreter process - this bootstraps the managed runtime
|
||||
// when it is imported by the CLR extension module.
|
||||
//====================================================================
|
||||
|
||||
public static void InitExt() {
|
||||
Initialize();
|
||||
|
||||
// Trickery - when the import hook is installed into an already
|
||||
// running Python, the standard import machinery is still in
|
||||
// control for the duration of the import that caused bootstrap.
|
||||
//
|
||||
// That is problematic because the std machinery tries to get
|
||||
// sub-names directly from the module __dict__ rather than going
|
||||
// through our module object's getattr hook. This workaround is
|
||||
// evil ;) We essentially climb up the stack looking for the
|
||||
// import that caused the bootstrap to happen, then re-execute
|
||||
// the import explicitly after our hook has been installed. By
|
||||
// doing this, the original outer import should work correctly.
|
||||
//
|
||||
// Note that this is only needed during the execution of the
|
||||
// first import that installs the CLR import hook. This hack
|
||||
// still doesn't work if you use the interactive interpreter,
|
||||
// since there is no line info to get the import line ;(
|
||||
|
||||
string code =
|
||||
|
||||
"import traceback\n" +
|
||||
"for item in traceback.extract_stack():\n" +
|
||||
" line = item[3]\n" +
|
||||
" if line is not None:\n" +
|
||||
" if line.startswith('import CLR') or \\\n" +
|
||||
" line.startswith('import clr') or \\\n" +
|
||||
" line.startswith('from clr') or \\\n" +
|
||||
" line.startswith('from CLR'):\n" +
|
||||
" exec line\n" +
|
||||
" break\n";
|
||||
|
||||
PyObject r = PythonEngine.RunString(code);
|
||||
if (r != null) {
|
||||
r.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Shutdown Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Shutdown and release resources held by the Python runtime. The
|
||||
/// Python runtime can no longer be used in the current process
|
||||
/// after calling the Shutdown method.
|
||||
/// </remarks>
|
||||
|
||||
public static void Shutdown() {
|
||||
if (initialized) {
|
||||
Runtime.Shutdown();
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AcquireLock Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Acquire the Python global interpreter lock (GIL). Managed code
|
||||
/// *must* call this method before using any objects or calling any
|
||||
/// methods on objects in the Python.Runtime namespace. The only
|
||||
/// exception is PythonEngine.Initialize, which may be called without
|
||||
/// first calling AcquireLock.
|
||||
///
|
||||
/// Each call to AcquireLock must be matched by a corresponding call
|
||||
/// to ReleaseLock, passing the token obtained from AcquireLock.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static IntPtr AcquireLock() {
|
||||
return Runtime.PyGILState_Ensure();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ReleaseLock Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Release the Python global interpreter lock using a token obtained
|
||||
/// from a previous call to AcquireLock.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static void ReleaseLock(IntPtr gs) {
|
||||
Runtime.PyGILState_Release(gs);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// BeginAllowThreads Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Release the Python global interpreter lock to allow other threads
|
||||
/// to run. This is equivalent to the Py_BEGIN_ALLOW_THREADS macro
|
||||
/// provided by the C Python API.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static IntPtr BeginAllowThreads() {
|
||||
return Runtime.PyEval_SaveThread();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// EndAllowThreads Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Re-aquire the Python global interpreter lock for the current
|
||||
/// thread. This is equivalent to the Py_END_ALLOW_THREADS macro
|
||||
/// provided by the C Python API.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static void EndAllowThreads(IntPtr ts) {
|
||||
Runtime.PyEval_RestoreThread(ts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ImportModule Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given a fully-qualified module or package name, import the
|
||||
/// module and return the resulting module object as a PyObject
|
||||
/// or null if an exception is raised.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject ImportModule(string name) {
|
||||
IntPtr op = Runtime.PyImport_ImportModule(name);
|
||||
if (op == IntPtr.Zero) {
|
||||
return null;
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ReloadModule Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given a PyObject representing a previously loaded module, reload
|
||||
/// the module.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject ReloadModule(PyObject module) {
|
||||
IntPtr op = Runtime.PyImport_ReloadModule(module.Handle);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ModuleFromString Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given a string module name and a string containing Python code,
|
||||
/// execute the code in and return a module of the given name.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject ModuleFromString(string name, string code) {
|
||||
IntPtr c = Runtime.Py_CompileString(code, "none", (IntPtr)257);
|
||||
if (c == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
IntPtr m = Runtime.PyImport_ExecCodeModule(name, c);
|
||||
if (m == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(m);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// RunString Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Run a string containing Python code. Returns the result of
|
||||
/// executing the code string as a PyObject instance, or null if
|
||||
/// an exception was raised.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject RunString(string code) {
|
||||
IntPtr globals = Runtime.PyEval_GetGlobals();
|
||||
IntPtr locals = Runtime.PyDict_New();
|
||||
|
||||
IntPtr builtins = Runtime.PyEval_GetBuiltins();
|
||||
Runtime.PyDict_SetItemString(locals, "__builtins__", builtins);
|
||||
|
||||
IntPtr flag = (IntPtr)257; /* Py_file_input */
|
||||
IntPtr result = Runtime.PyRun_String(code, flag, globals, locals);
|
||||
Runtime.Decref(locals);
|
||||
if (result == IntPtr.Zero) {
|
||||
return null;
|
||||
}
|
||||
return new PyObject(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
150
Pythonnet.Runtime/pythonexception.cs
Normal file
150
Pythonnet.Runtime/pythonexception.cs
Normal file
@ -0,0 +1,150 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Provides a managed interface to exceptions thrown by the Python
|
||||
/// runtime.
|
||||
/// </summary>
|
||||
|
||||
public class PythonException : System.Exception {
|
||||
|
||||
private IntPtr _pyType = IntPtr.Zero;
|
||||
private IntPtr _pyValue = IntPtr.Zero;
|
||||
private IntPtr _pyTB = IntPtr.Zero;
|
||||
private string _tb = "";
|
||||
private string _message = "";
|
||||
private bool disposed = false;
|
||||
|
||||
public PythonException() : base()
|
||||
{
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
Runtime.PyErr_Fetch(ref _pyType, ref _pyValue, ref _pyTB);
|
||||
Runtime.Incref(_pyType);
|
||||
Runtime.Incref(_pyValue);
|
||||
Runtime.Incref(_pyTB);
|
||||
if ((_pyType != IntPtr.Zero) && (_pyValue != IntPtr.Zero))
|
||||
{
|
||||
string type = new PyObject(_pyType).GetAttr("__name__").ToString();
|
||||
string message = Runtime.GetManagedString(_pyValue);
|
||||
_message = type + " : " + message;
|
||||
}
|
||||
if (_pyTB != IntPtr.Zero)
|
||||
{
|
||||
PyObject tb_module = PythonEngine.ImportModule("traceback");
|
||||
_tb = tb_module.InvokeMethod("format_tb", new PyObject(_pyTB)).ToString();
|
||||
}
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
}
|
||||
|
||||
// Ensure that encapsulated Python objects are decref'ed appropriately
|
||||
// when the managed exception wrapper is garbage-collected.
|
||||
|
||||
~PythonException() {
|
||||
Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyType Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the exception type as a Python object.
|
||||
/// </remarks>
|
||||
|
||||
public IntPtr PyType
|
||||
{
|
||||
get { return _pyType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PyValue Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the exception value as a Python object.
|
||||
/// </remarks>
|
||||
|
||||
public IntPtr PyValue
|
||||
{
|
||||
get { return _pyValue; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// A string representing the python exception message.
|
||||
/// </remarks>
|
||||
|
||||
public override string Message
|
||||
{
|
||||
get { return _message; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// StackTrace Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// A string representing the python exception stack trace.
|
||||
/// </remarks>
|
||||
|
||||
public override string StackTrace
|
||||
{
|
||||
get { return _tb; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// The Dispose method provides a way to explicitly release the
|
||||
/// Python objects represented by a PythonException.
|
||||
/// </remarks>
|
||||
|
||||
public void Dispose() {
|
||||
if (!disposed) {
|
||||
if (Runtime.Py_IsInitialized() > 0) {
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
Runtime.Decref(_pyType);
|
||||
Runtime.Decref(_pyValue);
|
||||
// XXX Do we ever get TraceBack? //
|
||||
if (_pyTB != IntPtr.Zero) {
|
||||
Runtime.Decref(_pyTB);
|
||||
}
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Matches Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the Python exception type represented by the
|
||||
/// PythonException instance matches the given exception type.
|
||||
/// </remarks>
|
||||
|
||||
public static bool Matches(IntPtr ob) {
|
||||
return Runtime.PyErr_ExceptionMatches(ob) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
126
Pythonnet.Runtime/pytuple.cs
Normal file
126
Pythonnet.Runtime/pytuple.cs
Normal file
@ -0,0 +1,126 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python tuple object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/tupleObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyTuple : PySequence {
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyTuple from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyTuple from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python tuple object.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple(PyObject o) : base() {
|
||||
if (!IsTupleType(o)) {
|
||||
throw new ArgumentException("object is not a tuple");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new empty PyTuple.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple() : base() {
|
||||
obj = Runtime.PyTuple_New(0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyTuple from an array of PyObject instances.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple(PyObject[] items) : base() {
|
||||
int count = items.Length;
|
||||
obj = Runtime.PyTuple_New(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntPtr ptr = items[i].obj;
|
||||
Runtime.Incref(ptr);
|
||||
int r = Runtime.PyTuple_SetItem(obj, i, ptr);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsTupleType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python tuple.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsTupleType(PyObject value) {
|
||||
return Runtime.PyTuple_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsTuple Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python tuple if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "tuple(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyTuple AsTuple(PyObject value) {
|
||||
IntPtr op = Runtime.PySequence_Tuple(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyTuple(op);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
1601
Pythonnet.Runtime/runtime.cs
Normal file
1601
Pythonnet.Runtime/runtime.cs
Normal file
File diff suppressed because it is too large
Load Diff
452
Pythonnet.Runtime/typemanager.cs
Normal file
452
Pythonnet.Runtime/typemanager.cs
Normal file
@ -0,0 +1,452 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection.Emit;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//=======================================================================
|
||||
// The TypeManager class is responsible for building binary-compatible
|
||||
// Python type objects that are implemented in managed code.
|
||||
//=======================================================================
|
||||
|
||||
internal class TypeManager {
|
||||
|
||||
static BindingFlags tbFlags;
|
||||
static Dictionary<Type, IntPtr> cache;
|
||||
static int obSize;
|
||||
|
||||
static TypeManager() {
|
||||
tbFlags = BindingFlags.Public | BindingFlags.Static;
|
||||
obSize = 5 * IntPtr.Size;
|
||||
cache = new Dictionary<Type, IntPtr>(128);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a managed Type derived from ExtensionType, get the handle to
|
||||
// a Python type object that delegates its implementation to the Type
|
||||
// object. These Python type instances are used to implement internal
|
||||
// descriptor and utility types like ModuleObject, PropertyObject, etc.
|
||||
//====================================================================
|
||||
|
||||
internal static IntPtr GetTypeHandle(Type type) {
|
||||
// Note that these types are cached with a refcount of 1, so they
|
||||
// effectively exist until the CPython runtime is finalized.
|
||||
IntPtr handle = IntPtr.Zero;
|
||||
cache.TryGetValue(type, out handle);
|
||||
if (handle != IntPtr.Zero) {
|
||||
return handle;
|
||||
}
|
||||
handle = CreateType(type);
|
||||
cache[type] = handle;
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Get the handle of a Python type that reflects the given CLR 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) {
|
||||
IntPtr handle = IntPtr.Zero;
|
||||
cache.TryGetValue(type, out handle);
|
||||
if (handle != IntPtr.Zero) {
|
||||
return handle;
|
||||
}
|
||||
handle = CreateType(obj, type);
|
||||
cache[type] = handle;
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// The following CreateType implementations do the necessary work to
|
||||
// create Python types to represent managed extension types, reflected
|
||||
// types, subclasses of reflected types and the managed metatype. The
|
||||
// dance is slightly different for each kind of type due to different
|
||||
// behavior needed and the desire to have the existing Python runtime
|
||||
// do as much of the allocation and initialization work as possible.
|
||||
//====================================================================
|
||||
|
||||
internal static IntPtr CreateType(Type impl) {
|
||||
|
||||
IntPtr type = AllocateTypeObject(impl.Name);
|
||||
|
||||
// Set tp_basicsize to the size of our managed instance objects.
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
|
||||
|
||||
IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
|
||||
|
||||
InitializeSlots(type, impl);
|
||||
|
||||
int flags = TypeFlags.Default | TypeFlags.Managed |
|
||||
TypeFlags.HeapType | TypeFlags.HaveGC;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
|
||||
|
||||
Runtime.PyType_Ready(type);
|
||||
|
||||
IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
|
||||
IntPtr mod = Runtime.PyString_FromString("CLR");
|
||||
Runtime.PyDict_SetItemString(dict, "__module__", mod);
|
||||
|
||||
InitMethods(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);
|
||||
}
|
||||
|
||||
IntPtr base_ = IntPtr.Zero;
|
||||
// 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 (PYTHON25 || PYTHON26 || PYTHON27)
|
||||
if (clrType == typeof(System.Exception)) {
|
||||
base_ = Exceptions.Exception;
|
||||
Runtime.Incref(base_);
|
||||
} else
|
||||
#endif
|
||||
if (clrType.BaseType != null) {
|
||||
ClassBase bc = ClassManager.GetClass(clrType.BaseType);
|
||||
base_ = bc.pyHandle;
|
||||
}
|
||||
|
||||
IntPtr type = AllocateTypeObject(name);
|
||||
|
||||
Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType);
|
||||
Runtime.Incref(Runtime.PyCLRMetaType);
|
||||
|
||||
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);
|
||||
|
||||
InitializeSlots(type, impl.GetType());
|
||||
|
||||
if (base_ != IntPtr.Zero) {
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
|
||||
Runtime.Incref(base_);
|
||||
}
|
||||
|
||||
int flags = TypeFlags.Default;
|
||||
flags |= TypeFlags.Managed;
|
||||
flags |= TypeFlags.HeapType;
|
||||
flags |= TypeFlags.BaseType;
|
||||
flags |= TypeFlags.HaveGC;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)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);
|
||||
|
||||
IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
|
||||
string mn = clrType.Namespace != null ? 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;
|
||||
impl.pyHandle = type;
|
||||
|
||||
//DebugUtil.DumpType(type);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
internal static IntPtr CreateSubType(IntPtr args) {
|
||||
|
||||
IntPtr py_name = Runtime.PyTuple_GetItem(args, 0);
|
||||
IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
|
||||
IntPtr dict = Runtime.PyTuple_GetItem(args, 2);
|
||||
IntPtr base_ = Runtime.PyTuple_GetItem(bases, 0);
|
||||
|
||||
string name = Runtime.GetManagedString(py_name);
|
||||
IntPtr type = AllocateTypeObject(name);
|
||||
|
||||
Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType);
|
||||
Runtime.Incref(Runtime.PyCLRMetaType);
|
||||
|
||||
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.Incref(base_);
|
||||
|
||||
int flags = TypeFlags.Default;
|
||||
flags |= TypeFlags.Managed;
|
||||
flags |= TypeFlags.HeapType;
|
||||
flags |= TypeFlags.BaseType;
|
||||
flags |= TypeFlags.Subclass;
|
||||
flags |= TypeFlags.HaveGC;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
|
||||
|
||||
CopySlot(base_, type, TypeOffset.tp_traverse);
|
||||
CopySlot(base_, type, TypeOffset.tp_clear);
|
||||
CopySlot(base_, type, TypeOffset.tp_is_gc);
|
||||
|
||||
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);
|
||||
|
||||
// for now, move up hidden handle...
|
||||
IntPtr gc = Marshal.ReadIntPtr(base_, TypeOffset.magic());
|
||||
Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
internal static IntPtr CreateMetaType(Type impl) {
|
||||
|
||||
// The managed metatype is functionally little different than the
|
||||
// standard Python metatype (PyType_Type). It overrides certain of
|
||||
// the standard type slots, and has to subclass PyType_Type for
|
||||
// certain functions in the C runtime to work correctly with it.
|
||||
|
||||
IntPtr type = AllocateTypeObject("CLR Metatype");
|
||||
IntPtr py_type = Runtime.PyTypeType;
|
||||
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type);
|
||||
Runtime.Incref(py_type);
|
||||
|
||||
// Copy gc and other type slots from the base Python metatype.
|
||||
|
||||
CopySlot(py_type, type, TypeOffset.tp_basicsize);
|
||||
CopySlot(py_type, type, TypeOffset.tp_itemsize);
|
||||
|
||||
CopySlot(py_type, type, TypeOffset.tp_dictoffset);
|
||||
CopySlot(py_type, type, TypeOffset.tp_weaklistoffset);
|
||||
|
||||
CopySlot(py_type, type, TypeOffset.tp_traverse);
|
||||
CopySlot(py_type, type, TypeOffset.tp_clear);
|
||||
CopySlot(py_type, type, TypeOffset.tp_is_gc);
|
||||
|
||||
// Override type slots with those of the managed implementation.
|
||||
|
||||
InitializeSlots(type, impl);
|
||||
|
||||
int flags = TypeFlags.Default;
|
||||
flags |= TypeFlags.Managed;
|
||||
flags |= TypeFlags.HeapType;
|
||||
flags |= TypeFlags.HaveGC;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
|
||||
|
||||
Runtime.PyType_Ready(type);
|
||||
|
||||
IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
|
||||
IntPtr mod = Runtime.PyString_FromString("CLR");
|
||||
Runtime.PyDict_SetItemString(dict, "__module__", mod);
|
||||
|
||||
//DebugUtil.DumpType(type);
|
||||
|
||||
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.Incref(base_);
|
||||
|
||||
int flags = TypeFlags.Default;
|
||||
flags |= TypeFlags.Managed;
|
||||
flags |= TypeFlags.HeapType;
|
||||
flags |= TypeFlags.HaveGC;
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)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) {
|
||||
IntPtr type = Runtime.PyType_GenericAlloc(Runtime.PyTypeType, 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.
|
||||
|
||||
IntPtr temp = Runtime.PyString_FromString(name);
|
||||
IntPtr raw = Runtime.PyString_AS_STRING(temp);
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_name, raw);
|
||||
Marshal.WriteIntPtr(type, TypeOffset.name, temp);
|
||||
|
||||
long ptr = type.ToInt64(); // 64-bit safe
|
||||
|
||||
temp = new IntPtr(ptr + TypeOffset.nb_add);
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_as_number, temp);
|
||||
|
||||
temp = new IntPtr(ptr + TypeOffset.sq_length);
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_as_sequence, temp);
|
||||
|
||||
temp = new IntPtr(ptr + TypeOffset.mp_length);
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_as_mapping, temp);
|
||||
|
||||
temp = new IntPtr(ptr + TypeOffset.bf_getreadbuffer);
|
||||
Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a newly allocated Python type object and a managed Type that
|
||||
// provides the implementation for the type, connect the type slots of
|
||||
// the Python object to the managed methods of the implementing Type.
|
||||
//====================================================================
|
||||
|
||||
internal static void InitializeSlots(IntPtr type, Type impl) {
|
||||
Hashtable seen = new Hashtable(8);
|
||||
Type offsetType = typeof(TypeOffset);
|
||||
|
||||
while (impl != null) {
|
||||
MethodInfo[] methods = impl.GetMethods(tbFlags);
|
||||
for (int i = 0; i < methods.Length; i++) {
|
||||
MethodInfo method = methods[i];
|
||||
string name = method.Name;
|
||||
if (! (name.StartsWith("tp_") ||
|
||||
name.StartsWith("nb_") ||
|
||||
name.StartsWith("sq_") ||
|
||||
name.StartsWith("mp_") ||
|
||||
name.StartsWith("bf_")
|
||||
) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (seen[name] != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FieldInfo fi = offsetType.GetField(name);
|
||||
int offset = (int)fi.GetValue(offsetType);
|
||||
|
||||
IntPtr slot = Interop.GetThunk(method);
|
||||
Marshal.WriteIntPtr(type, offset, slot);
|
||||
|
||||
seen[name] = 1;
|
||||
}
|
||||
|
||||
impl = impl.BaseType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a newly allocated Python type object and a managed Type that
|
||||
// implements it, initialize any methods defined by the Type that need
|
||||
// to appear in the Python type __dict__ (based on custom attribute).
|
||||
//====================================================================
|
||||
|
||||
private static void InitMethods(IntPtr pytype, Type type) {
|
||||
IntPtr dict = Marshal.ReadIntPtr(pytype, TypeOffset.tp_dict);
|
||||
Type marker = typeof(PythonMethodAttribute);
|
||||
|
||||
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
|
||||
|
||||
while (type != null) {
|
||||
MethodInfo[] methods = type.GetMethods(flags);
|
||||
for (int i = 0; i < methods.Length; i++) {
|
||||
MethodInfo method = methods[i];
|
||||
object[] attrs = method.GetCustomAttributes(marker, false);
|
||||
if (attrs.Length > 0) {
|
||||
string method_name = method.Name;
|
||||
MethodInfo[] mi = new MethodInfo[1];
|
||||
mi[0] = method;
|
||||
MethodObject m = new TypeMethod(method_name, mi);
|
||||
Runtime.PyDict_SetItemString(dict, method_name,
|
||||
m.pyHandle);
|
||||
}
|
||||
}
|
||||
type = type.BaseType;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Utility method to copy slots from a given type to another type.
|
||||
//====================================================================
|
||||
|
||||
internal static void CopySlot(IntPtr from, IntPtr to, int offset) {
|
||||
IntPtr fp = Marshal.ReadIntPtr(from, offset);
|
||||
Marshal.WriteIntPtr(to, offset, fp);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
54
Pythonnet.Runtime/typemethod.cs
Normal file
54
Pythonnet.Runtime/typemethod.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Python.Runtime {
|
||||
|
||||
//========================================================================
|
||||
// Implements a Python type that provides access to CLR object methods.
|
||||
//========================================================================
|
||||
|
||||
internal class TypeMethod : MethodObject {
|
||||
|
||||
public TypeMethod(string name, MethodInfo[] info) :
|
||||
base(name, info) {}
|
||||
|
||||
public TypeMethod(string name, MethodInfo[] info, bool allow_threads) :
|
||||
base(name, info, allow_threads) { }
|
||||
|
||||
public override IntPtr Invoke(IntPtr ob, IntPtr args, IntPtr kw) {
|
||||
MethodInfo mi = this.info[0];
|
||||
Object[] arglist = new Object[3];
|
||||
arglist[0] = ob;
|
||||
arglist[1] = args;
|
||||
arglist[2] = kw;
|
||||
|
||||
try {
|
||||
Object inst = null;
|
||||
if (ob != IntPtr.Zero) {
|
||||
inst = GetManagedObject(ob);
|
||||
}
|
||||
return (IntPtr)mi.Invoke(inst, BindingFlags.Default, null, arglist,
|
||||
null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Exceptions.SetError(e);
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
11
Pythonnet.Runtime/x86/clrmodule-platform.il
Normal file
11
Pythonnet.Runtime/x86/clrmodule-platform.il
Normal file
@ -0,0 +1,11 @@
|
||||
// ==========================================================================
|
||||
// This software is subject to the provisions of the Zope Public License,
|
||||
// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
// FOR A PARTICULAR PURPOSE.
|
||||
// ==========================================================================
|
||||
|
||||
.vtfixup [1] int32 fromunmanaged at VT_01
|
||||
.data VT_01 = int32(0)
|
63
WinAlfred.Test/PyImportTest.cs
Normal file
63
WinAlfred.Test/PyImportTest.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using Python.Runtime;
|
||||
|
||||
namespace WinAlfred.Test
|
||||
{
|
||||
[TestFixture]
|
||||
public class PyImportTest
|
||||
{
|
||||
private IntPtr gs;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
PythonEngine.Initialize();
|
||||
gs = PythonEngine.AcquireLock();
|
||||
|
||||
//string here = Environment.CurrentDirectory;
|
||||
// trunk\pythonnet\src\embed_tests\bin\Debug
|
||||
|
||||
/*
|
||||
* Append the tests directory to sys.path
|
||||
* using reflection to circumvent the private modifires placed on most Runtime methods.
|
||||
*/
|
||||
string s = @"d:\github\pythonnet\pythonnet\src\tests";
|
||||
|
||||
Type RTClass = typeof(Runtime);
|
||||
|
||||
/* pyStrPtr = PyString_FromString(s); */
|
||||
MethodInfo PyString_FromString = RTClass.GetMethod("PyString_FromString", BindingFlags.Public | BindingFlags.Static);
|
||||
object[] funcArgs = new object[1];
|
||||
funcArgs[0] = s;
|
||||
IntPtr pyStrPtr = (IntPtr)PyString_FromString.Invoke(null, funcArgs);
|
||||
|
||||
/* SysDotPath = sys.path */
|
||||
MethodInfo PySys_GetObject = RTClass.GetMethod("PySys_GetObject", BindingFlags.Public | BindingFlags.Static);
|
||||
funcArgs[0] = "path";
|
||||
IntPtr SysDotPath = (IntPtr)PySys_GetObject.Invoke(null, funcArgs);
|
||||
|
||||
/* SysDotPath.append(*pyStrPtr) */
|
||||
MethodInfo PyList_Append = RTClass.GetMethod("PyList_Append", BindingFlags.Public | BindingFlags.Static);
|
||||
funcArgs = new object[2];
|
||||
funcArgs[0] = SysDotPath;
|
||||
funcArgs[1] = pyStrPtr;
|
||||
int r = (int)PyList_Append.Invoke(null, funcArgs);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
PythonEngine.Shutdown();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDottedName()
|
||||
{
|
||||
PyObject module = PythonEngine.ImportModule("PyImportTest.test.one");
|
||||
Assert.IsNotNull(module, ">>> import PyImportTest.test.one # FAILED");
|
||||
}
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="PyImportTest.cs" />
|
||||
<Compile Include="QueryTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
@ -50,6 +51,10 @@
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Pythonnet.Runtime\Python.Runtime.csproj">
|
||||
<Project>{097B4AC0-74E9-4C58-BCF8-C69746EC8271}</Project>
|
||||
<Name>Python.Runtime</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\WinAlfred.Plugin\WinAlfred.Plugin.csproj">
|
||||
<Project>{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}</Project>
|
||||
<Name>WinAlfred.Plugin</Name>
|
||||
|
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Python.Runtime;
|
||||
using WinAlfred.Helper;
|
||||
using WinAlfred.Plugin;
|
||||
using WinAlfred.PluginLoader;
|
||||
@ -9,6 +11,9 @@ namespace WinAlfred.Commands
|
||||
{
|
||||
public class PluginCommand : BaseCommand
|
||||
{
|
||||
private string currentPythonModulePath = string.Empty;
|
||||
private IntPtr GIL;
|
||||
|
||||
public PluginCommand(MainWindow mainWindow)
|
||||
: base(mainWindow)
|
||||
{
|
||||
@ -17,36 +22,56 @@ namespace WinAlfred.Commands
|
||||
|
||||
public override void Dispatch(Query q)
|
||||
{
|
||||
|
||||
foreach (PluginPair pair in Plugins.AllPlugins)
|
||||
PluginPair thirdPlugin = Plugins.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == q.ActionName);
|
||||
if (thirdPlugin != null && !string.IsNullOrEmpty(thirdPlugin.Metadata.ActionKeyword))
|
||||
{
|
||||
if (pair.Metadata.ActionKeyword == q.ActionName)
|
||||
if (thirdPlugin.Metadata.Language == AllowedLanguage.Python)
|
||||
{
|
||||
PluginPair pair1 = pair;
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Result> r = pair1.Plugin.Query(q);
|
||||
r.ForEach(o =>
|
||||
{
|
||||
o.PluginDirectory = pair1.Metadata.PluginDirecotry;
|
||||
o.OriginQuery = q;
|
||||
});
|
||||
UpdateResultView(r);
|
||||
}
|
||||
catch (Exception queryException)
|
||||
{
|
||||
Log.Error(string.Format("Plugin {0} query failed: {1}", pair1.Metadata.Name,
|
||||
queryException.Message));
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
});
|
||||
SwitchPythonEnv(thirdPlugin);
|
||||
}
|
||||
ThreadPool.QueueUserWorkItem(t =>
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Result> r = thirdPlugin.Plugin.Query(q);
|
||||
r.ForEach(o =>
|
||||
{
|
||||
o.PluginDirectory = thirdPlugin.Metadata.PluginDirecotry;
|
||||
o.OriginQuery = q;
|
||||
});
|
||||
UpdateResultView(r);
|
||||
}
|
||||
catch (Exception queryException)
|
||||
{
|
||||
Log.Error(string.Format("Plugin {0} query failed: {1}", thirdPlugin.Metadata.Name,
|
||||
queryException.Message));
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchPythonEnv(PluginPair thirdPlugin)
|
||||
{
|
||||
if (currentPythonModulePath != thirdPlugin.Metadata.PluginDirecotry)
|
||||
{
|
||||
//this must initial in main thread
|
||||
currentPythonModulePath = thirdPlugin.Metadata.PluginDirecotry;
|
||||
|
||||
if (GIL != IntPtr.Zero)
|
||||
{
|
||||
Runtime.PyEval_RestoreThread(GIL);
|
||||
PythonEngine.Shutdown();
|
||||
}
|
||||
PythonEngine.Initialize();
|
||||
IntPtr pyStrPtr = Runtime.PyString_FromString(thirdPlugin.Metadata.PluginDirecotry);
|
||||
IntPtr SysDotPath = Runtime.PySys_GetObject("path");
|
||||
Runtime.PyList_Append(SysDotPath, pyStrPtr);
|
||||
GIL = PythonEngine.BeginAllowThreads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,5 +117,16 @@ namespace WinAlfred.PluginLoader
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Change python execute file name to unique file name using GUID
|
||||
///// this is because if two pythong plugin use the same
|
||||
///// </summary>
|
||||
///// <param name="metadata"></param>
|
||||
///// <returns></returns>
|
||||
//private static PluginMetadata filterPythonMetadata(PluginMetadata metadata)
|
||||
//{
|
||||
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
@ -19,15 +19,18 @@ namespace WinAlfred.PluginLoader
|
||||
foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin))
|
||||
{
|
||||
IPlugin plugin1 = plugin;
|
||||
ThreadPool.QueueUserWorkItem(o => plugin1.Init(new PluginInitContext()
|
||||
ThreadPool.QueueUserWorkItem(o =>
|
||||
{
|
||||
Plugins = plugins,
|
||||
ChangeQuery = s => window.ChangeQuery(s),
|
||||
CloseApp = window.CloseApp,
|
||||
HideApp = window.HideApp,
|
||||
ShowApp = window.ShowApp,
|
||||
ShowMsg = (title, subTitle, iconPath) => window.ShowMsg(title, subTitle, iconPath)
|
||||
}));
|
||||
plugin1.Init(new PluginInitContext()
|
||||
{
|
||||
Plugins = plugins,
|
||||
ChangeQuery = s => window.ChangeQuery(s),
|
||||
CloseApp = window.CloseApp,
|
||||
HideApp = window.HideApp,
|
||||
ShowApp = window.ShowApp,
|
||||
ShowMsg = (title, subTitle, iconPath) => window.ShowMsg(title, subTitle, iconPath)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Python.Runtime;
|
||||
using WinAlfred.Plugin;
|
||||
|
||||
namespace WinAlfred.PluginLoader
|
||||
{
|
||||
public class PythonPluginLoader : BasePluginLoader
|
||||
{
|
||||
|
||||
static PythonPluginLoader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override List<PluginPair> LoadPlugin()
|
||||
{
|
||||
List<PluginPair> plugins = new List<PluginPair>();
|
||||
|
@ -1,19 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Documents;
|
||||
using Newtonsoft.Json;
|
||||
using Python.Runtime;
|
||||
using WinAlfred.Plugin;
|
||||
|
||||
namespace WinAlfred.PluginLoader
|
||||
{
|
||||
public class PythonPluginWrapper : IPlugin
|
||||
{
|
||||
private PluginMetadata metadata;
|
||||
|
||||
[DllImport("PyWinAlfred.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
private extern static IntPtr ExecPython(string directory, string file, string method, string para);
|
||||
[DllImport("PyWinAlfred.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||
private extern static void InitPythonEnv();
|
||||
private PluginMetadata metadata;
|
||||
|
||||
public PythonPluginWrapper(PluginMetadata metadata)
|
||||
{
|
||||
@ -24,24 +22,20 @@ namespace WinAlfred.PluginLoader
|
||||
{
|
||||
try
|
||||
{
|
||||
string s = Marshal.PtrToStringAnsi(ExecPython(metadata.PluginDirecotry, metadata.ExecuteFileName.Replace(".py", ""), "query", query.RawQuery));
|
||||
if (string.IsNullOrEmpty(s))
|
||||
string jsonResult = InvokeFunc(metadata.PluginDirecotry, metadata.ExecuteFileName.Replace(".py", ""), "query", query.RawQuery);
|
||||
if (string.IsNullOrEmpty(jsonResult))
|
||||
{
|
||||
return new List<Result>();
|
||||
}
|
||||
|
||||
if (s.StartsWith("PYTHONERROR"))
|
||||
{
|
||||
throw new ArgumentException(s);
|
||||
}
|
||||
List<PythonResult> o = JsonConvert.DeserializeObject<List<PythonResult>>(s);
|
||||
List<PythonResult> o = JsonConvert.DeserializeObject<List<PythonResult>>(jsonResult);
|
||||
List<Result> r = new List<Result>();
|
||||
foreach (PythonResult pythonResult in o)
|
||||
{
|
||||
PythonResult ps = pythonResult;
|
||||
if (!string.IsNullOrEmpty(ps.ActionName))
|
||||
{
|
||||
ps.Action = () => ExecPython(metadata.PluginDirecotry, metadata.ExecuteFileName.Replace(".py", ""), ps.ActionName, ps.ActionPara);
|
||||
ps.Action = () => InvokeFunc(metadata.PluginDirecotry, metadata.ExecuteFileName.Replace(".py", ""), ps.ActionName, ps.ActionPara);
|
||||
}
|
||||
r.Add(ps);
|
||||
}
|
||||
@ -49,15 +43,31 @@ namespace WinAlfred.PluginLoader
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
throw;
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string InvokeFunc(string path, string moduleName, string func, string para)
|
||||
{
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
|
||||
PyObject module = PythonEngine.ImportModule(moduleName);
|
||||
PyObject res = module.InvokeMethod(func, new PyString(para));
|
||||
string json = Runtime.GetManagedString(res.Handle);
|
||||
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
InitPythonEnv();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user