Merge branch 'PythonPlugin'

This commit is contained in:
qianlifeng 2014-01-12 16:31:06 +08:00
commit 53120faeba
79 changed files with 14520 additions and 360 deletions

2
.gitignore vendored
View File

@ -62,6 +62,8 @@ _ReSharper*
# Installshield output folder
[Ee]xpress
.idea
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -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")

View File

@ -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();
}

View File

@ -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>

View File

@ -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

Binary file not shown.

View 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>

View 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>

View 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;
}
}
}

View 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

View 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;
}
}
}

View 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%

View 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();
}
}
}

View 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;
}
}

View 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);
}
}
}

View 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
}
}

View 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
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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) {}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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");
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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 {
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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");
}
}
}

View 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

View 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);
}
}

View 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
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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
View 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);
}
}
}

View 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
View 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());
}
}
}

View 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
View 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
View 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);
}
}
}

View 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.
}
}

View 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();
}
}
}

View 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
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View 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;
}
}
}
}

View 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)

View 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");
}
}
}

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -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)
//{
//}
}
}

View File

@ -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)
});
});
}
}

View File

@ -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>();

View File

@ -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();
}
}
}

BIN
clr.pyd Normal file

Binary file not shown.