diff --git a/.gitignore b/.gitignore
index ee40d233aa..4a1393835a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,6 +62,8 @@ _ReSharper*
# Installshield output folder
[Ee]xpress
+.idea
+
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
diff --git a/Plugins/WinAlfred.Plugin.DouBan/main.py b/Plugins/WinAlfred.Plugin.DouBan/main.py
index ef19d229ef..bb47feeda7 100644
--- a/Plugins/WinAlfred.Plugin.DouBan/main.py
+++ b/Plugins/WinAlfred.Plugin.DouBan/main.py
@@ -3,22 +3,27 @@ import requests
from bs4 import BeautifulSoup
import json
-class PyWinAlfred():
- def query(self,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 a"):
- res = {}
- t = i.text.strip().replace(" ","")
- res["Title"] = t.replace("\\n","")
- results.append(res)
- return json.dumps(results)
+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
+ res["SubTitle"] = score
+ res["ActionName"] = "openUrl"
+ res["ActionPara"] = i.select("a[href]")[0]["href"]
+ results.append(res)
+ return json.dumps(results)
+
+def openUrl(url):
+ pass
if __name__ == "__main__":
- p = PyWinAlfred()
- print p.query("movie geo")
+ print query("movie geo")
diff --git a/Python.Runtime.dll b/Python.Runtime.dll
new file mode 100644
index 0000000000..abbd5f37a1
Binary files /dev/null and b/Python.Runtime.dll differ
diff --git a/Pythonnet.Runtime/Python.Runtime.csproj b/Pythonnet.Runtime/Python.Runtime.csproj
new file mode 100644
index 0000000000..ca785225b0
--- /dev/null
+++ b/Pythonnet.Runtime/Python.Runtime.csproj
@@ -0,0 +1,170 @@
+
+
+
+ Debug
+ AnyCPU
+ {097B4AC0-74E9-4C58-BCF8-C69746EC8271}
+ Library
+ false
+ Python.Runtime
+ Python.Runtime
+ OnBuildSuccess
+ v3.5
+
+
+
+ true
+ full
+ true
+ .\bin\Debug\
+ TRACE;DEBUG;PYTHON27,UCS2
+ true
+
+
+ pdbonly
+ true
+ .\bin\Release\
+ TRACE;PYTHON27, UCS2
+ true
+
+
+ true
+ bin\EmbeddingTest\
+ TRACE;DEBUG;PYTHON27,UCS2
+ true
+ true
+ full
+ AnyCPU
+
+
+ true
+ bin\UnitTests\
+ TRACE;DEBUG;PYTHON27,UCS2
+ true
+ true
+ full
+ AnyCPU
+
+
+ true
+ bin\x64\Debug\
+ TRACE;DEBUG;PYTHON26,UCS2
+ true
+ true
+ full
+ x64
+ 1607
+
+
+ bin\x64\Release\
+ TRACE;PYTHON26,UCS2
+ true
+ true
+ pdbonly
+ x64
+ 1607
+
+
+ true
+ bin\x64\EmbeddingTest\
+ TRACE;DEBUG;PYTHON26,UCS2
+ true
+ true
+ full
+ x64
+ 1607
+
+
+ true
+ bin\x64\UnitTests\
+ TRACE;DEBUG;PYTHON26,UCS2
+ true
+ true
+ full
+ x64
+ 1607
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ call "$(ProjectDir)buildclrmodule.bat" $(Platform) "$(ProjectDir)" "$(TargetDir)clr.pyd"
+copy "$(TargetPath)" "$(SolutionDir)"
+copy "$(TargetDir)*.pdb" "$(SolutionDir)"
+copy "$(TargetDir)clr.pyd" "$(SolutionDir)"
+
+ del "$(TargetDir)clr.pyd"
+
+
\ No newline at end of file
diff --git a/Pythonnet.Runtime/Python.Runtime.mdp b/Pythonnet.Runtime/Python.Runtime.mdp
new file mode 100644
index 0000000000..845407ec2f
--- /dev/null
+++ b/Pythonnet.Runtime/Python.Runtime.mdp
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Pythonnet.Runtime/arrayobject.cs b/Pythonnet.Runtime/arrayobject.cs
new file mode 100644
index 0000000000..c96fbd23c4
--- /dev/null
+++ b/Pythonnet.Runtime/arrayobject.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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;
+ }
+
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/assemblyinfo.cs b/Pythonnet.Runtime/assemblyinfo.cs
new file mode 100644
index 0000000000..2e15409e73
--- /dev/null
+++ b/Pythonnet.Runtime/assemblyinfo.cs
@@ -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
diff --git a/Pythonnet.Runtime/assemblymanager.cs b/Pythonnet.Runtime/assemblymanager.cs
new file mode 100644
index 0000000000..e723ca6590
--- /dev/null
+++ b/Pythonnet.Runtime/assemblymanager.cs
@@ -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 {
+
+ ///
+ /// The AssemblyManager maintains information about loaded assemblies
+ /// namespaces and provides an interface for name-based type lookup.
+ ///
+
+ internal class AssemblyManager {
+
+ static Dictionary> namespaces;
+ //static Dictionary> generics;
+ static AssemblyLoadEventHandler lhandler;
+ static ResolveEventHandler rhandler;
+ static Dictionary probed;
+ static List assemblies;
+ internal static List 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>(32);
+ probed = new Dictionary(32);
+ //generics = new Dictionary>();
+ assemblies = new List(16);
+ pypath = new List(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()
+ );
+ }
+ }
+ }
+
+ 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 GetNames(string nsname) {
+ //Dictionary seen = new Dictionary();
+ List names = new List(8);
+
+ List 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;
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/buildclrmodule.bat b/Pythonnet.Runtime/buildclrmodule.bat
new file mode 100644
index 0000000000..a7a7c7a8fb
--- /dev/null
+++ b/Pythonnet.Runtime/buildclrmodule.bat
@@ -0,0 +1,36 @@
+:: Call with buildclrmodule.bat
+
+@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%
diff --git a/Pythonnet.Runtime/classbase.cs b/Pythonnet.Runtime/classbase.cs
new file mode 100644
index 0000000000..1541b12cd2
--- /dev/null
+++ b/Pythonnet.Runtime/classbase.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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();
+ }
+
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/classmanager.cs b/Pythonnet.Runtime/classmanager.cs
new file mode 100644
index 0000000000..088905b380
--- /dev/null
+++ b/Pythonnet.Runtime/classmanager.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ internal class ClassManager {
+
+ static Dictionary cache;
+ static Type dtype;
+
+ private ClassManager() {}
+
+ static ClassManager() {
+ cache = new Dictionary(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;
+ }
+
+
+
+}
diff --git a/Pythonnet.Runtime/classobject.cs b/Pythonnet.Runtime/classobject.cs
new file mode 100644
index 0000000000..c331637be0
--- /dev/null
+++ b/Pythonnet.Runtime/classobject.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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 [] 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 [] 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);
+ }
+
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/clrmodule.il b/Pythonnet.Runtime/clrmodule.il
new file mode 100644
index 0000000000..be57f06549
--- /dev/null
+++ b/Pythonnet.Runtime/clrmodule.il
@@ -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
+ }
+}
+
diff --git a/Pythonnet.Runtime/clrmodule.pp.il b/Pythonnet.Runtime/clrmodule.pp.il
new file mode 100644
index 0000000000..59b2893793
--- /dev/null
+++ b/Pythonnet.Runtime/clrmodule.pp.il
@@ -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
+ }
+}
+
diff --git a/Pythonnet.Runtime/clrobject.cs b/Pythonnet.Runtime/clrobject.cs
new file mode 100644
index 0000000000..c61f9523db
--- /dev/null
+++ b/Pythonnet.Runtime/clrobject.cs
@@ -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;
+ }
+
+
+ }
+
+
+}
+
diff --git a/Pythonnet.Runtime/codegenerator.cs b/Pythonnet.Runtime/codegenerator.cs
new file mode 100644
index 0000000000..4305471e09
--- /dev/null
+++ b/Pythonnet.Runtime/codegenerator.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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);
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/constructorbinder.cs b/Pythonnet.Runtime/constructorbinder.cs
new file mode 100644
index 0000000000..4dc1f1457a
--- /dev/null
+++ b/Pythonnet.Runtime/constructorbinder.cs
@@ -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);
+ }
+ ///
+ /// 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)
+ ///
+ /// (possibly null) instance
+ /// PyObject* to the arg tuple
+ /// PyObject* to the keyword args dict
+ /// The sole ContructorInfo to use or null
+ /// The result of the constructor call with converted params
+ ///
+ /// 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).
+ ///
+ 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;
+ }
+ }
+}
diff --git a/Pythonnet.Runtime/constructorbinding.cs b/Pythonnet.Runtime/constructorbinding.cs
new file mode 100644
index 0000000000..c5f014469f
--- /dev/null
+++ b/Pythonnet.Runtime/constructorbinding.cs
@@ -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 {
+
+ ///
+ /// Implements a Python type that wraps a CLR ctor call. Constructor objects
+ /// support a .Overloads[] syntax to allow explicit ctor overload selection.
+ ///
+ ///
+ /// 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.
+ ///
+ 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;
+ }
+
+ ///
+ /// 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.
+ ///
+ /// PyObject* to a Constructors wrapper
+ /// the instance that the attribute was accessed through,
+ /// or None when the attribute is accessed through the owner
+ /// always the owner class
+ /// a CtorMapper (that borrows a reference to this python type and the
+ /// ClassObject's ConstructorBinder) wrapper.
+ ///
+ ///
+ /// 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.
+ ///
+ 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 ([]).
+ //====================================================================
+ ///
+ /// 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].
+ ///
+ ///
+ ///
+ ///
+ 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);
+ }
+ }
+
+ ///
+ /// Implements a Python type that constucts the given Type given a particular ContructorInfo.
+ ///
+ ///
+ /// 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.
+ ///
+ 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;
+ }
+
+ ///
+ /// BoundContructor.__call__(PyObject *callable_object, PyObject *args, PyObject *kw)
+ ///
+ /// PyObject *callable_object
+ /// PyObject *args
+ /// PyObject *kw
+ /// A reference to a new instance of the class by invoking the selected ctor().
+ 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);
+ }
+ }
+}
diff --git a/Pythonnet.Runtime/converter.cs b/Pythonnet.Runtime/converter.cs
new file mode 100644
index 0000000000..af7acd972a
--- /dev/null
+++ b/Pythonnet.Runtime/converter.cs
@@ -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;
+
+ }
+
+
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/debughelper.cs b/Pythonnet.Runtime/debughelper.cs
new file mode 100644
index 0000000000..2c7c6a054f
--- /dev/null
+++ b/Pythonnet.Runtime/debughelper.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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;
+ }
+
+
+ }
+
+
+}
+
+
diff --git a/Pythonnet.Runtime/delegatemanager.cs b/Pythonnet.Runtime/delegatemanager.cs
new file mode 100644
index 0000000000..ddbabf8724
--- /dev/null
+++ b/Pythonnet.Runtime/delegatemanager.cs
@@ -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 {
+
+ ///
+ /// The DelegateManager class manages the creation of true managed
+ /// delegate instances that dispatch calls to Python methods.
+ ///
+
+ 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) {}
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/delegateobject.cs b/Pythonnet.Runtime/delegateobject.cs
new file mode 100644
index 0000000000..839fb71e59
--- /dev/null
+++ b/Pythonnet.Runtime/delegateobject.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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;
+ }
+
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/eventbinding.cs b/Pythonnet.Runtime/eventbinding.cs
new file mode 100644
index 0000000000..6135c1d68e
--- /dev/null
+++ b/Pythonnet.Runtime/eventbinding.cs
@@ -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);
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/eventobject.cs b/Pythonnet.Runtime/eventobject.cs
new file mode 100644
index 0000000000..0e9122f492
--- /dev/null
+++ b/Pythonnet.Runtime/eventobject.cs
@@ -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("", 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;
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/exceptions.cs b/Pythonnet.Runtime/exceptions.cs
new file mode 100644
index 0000000000..f08217dac6
--- /dev/null
+++ b/Pythonnet.Runtime/exceptions.cs
@@ -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 {
+
+ ///
+ /// Base class for Python types that reflect managed exceptions based on
+ /// System.Exception
+ ///
+ ///
+ /// 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.
+ ///
+ 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)
+ }
+
+ ///
+ /// Encapsulates the Python exception APIs.
+ ///
+ ///
+ /// Readability of the Exceptions class improvements as we look toward version 2.7 ...
+ ///
+
+ 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);
+ }
+
+ ///
+ /// Shortcut for (pointer == NULL) -> throw PythonException
+ ///
+ /// Pointer to a Python object
+ internal unsafe static void ErrorCheck(IntPtr pointer) {
+ if (pointer == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+ ///
+ /// Shortcut for (pointer == NULL or ErrorOccurred()) -> throw PythonException
+ ///
+ /// 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.
+
+ ///
+ /// Conditionally initialized variables!
+ ///
+ static IntPtr ns_exc; // new-style class for System.Exception
+ static IntPtr os_exc; // old-style class for System.Exception
+ static Hashtable cache;
+
+ ///
+ /// the lines
+ /// // XXX - hack to raise a compatible old-style exception ;(
+ /// if (Runtime.wrap_exceptions) {
+ /// CallOneOfTheseMethods();
+ ///
+ ///
+ 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;
+ }
+
+ ///
+ /// GetException Method
+ ///
+ ///
+ ///
+ /// 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.
+ ///
+
+ public static PythonException GetException() {
+ // TODO: implement this.
+ return null;
+ }
+
+ ///
+ /// ExceptionMatches Method
+ ///
+ ///
+ ///
+ /// Returns true if the current Python exception matches the given
+ /// Python object. This is a wrapper for PyErr_ExceptionMatches.
+ ///
+
+ public static bool ExceptionMatches(IntPtr ob) {
+ return Runtime.PyErr_ExceptionMatches(ob) != 0;
+ }
+
+ ///
+ /// ExceptionMatches Method
+ ///
+ ///
+ ///
+ /// Returns true if the given Python exception matches the given
+ /// Python object. This is a wrapper for PyErr_GivenExceptionMatches.
+ ///
+
+ public static bool ExceptionMatches(IntPtr exc, IntPtr ob) {
+ int i = Runtime.PyErr_GivenExceptionMatches(exc, ob);
+ return (i != 0);
+ }
+
+ ///
+ /// SetError Method
+ ///
+ ///
+ ///
+ /// Sets the current Python exception given a native string.
+ /// This is a wrapper for the Python PyErr_SetString call.
+ ///
+
+ public static void SetError(IntPtr ob, string value) {
+ Runtime.PyErr_SetString(ob, value);
+ }
+
+ ///
+ /// SetError Method
+ ///
+ ///
+ ///
+ /// Sets the current Python exception given a Python object.
+ /// This is a wrapper for the Python PyErr_SetObject call.
+ ///
+
+ public static void SetError(IntPtr ob, IntPtr value) {
+ Runtime.PyErr_SetObject(ob, value);
+ }
+
+ ///
+ /// SetError Method
+ ///
+ ///
+ ///
+ /// 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.
+ ///
+
+ 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);
+ }
+
+ ///
+ /// ErrorOccurred Method
+ ///
+ ///
+ ///
+ /// Returns true if an exception occurred in the Python runtime.
+ /// This is a wrapper for the Python PyErr_Occurred call.
+ ///
+
+ public static bool ErrorOccurred() {
+ return Runtime.PyErr_Occurred() != 0;
+ }
+
+ ///
+ /// Clear Method
+ ///
+ ///
+ ///
+ /// Clear any exception that has been set in the Python runtime.
+ ///
+
+ public static void Clear() {
+ Runtime.PyErr_Clear();
+ }
+
+ //====================================================================
+ // helper methods for raising warnings
+ //====================================================================
+
+ ///
+ /// Alias for Python's warnings.warn() function.
+ ///
+ 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
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/extensiontype.cs b/Pythonnet.Runtime/extensiontype.cs
new file mode 100644
index 0000000000..b0499bb0ae
--- /dev/null
+++ b/Pythonnet.Runtime/extensiontype.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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);
+ }
+
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/fieldobject.cs b/Pythonnet.Runtime/fieldobject.cs
new file mode 100644
index 0000000000..ee9d3392a5
--- /dev/null
+++ b/Pythonnet.Runtime/fieldobject.cs
@@ -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("", self.info.Name);
+ return Runtime.PyString_FromStringAndSize(s, s.Length);
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/generictype.cs b/Pythonnet.Runtime/generictype.cs
new file mode 100644
index 0000000000..082bc768ce
--- /dev/null
+++ b/Pythonnet.Runtime/generictype.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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");
+ }
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/genericutil.cs b/Pythonnet.Runtime/genericutil.cs
new file mode 100644
index 0000000000..c3de0aa564
--- /dev/null
+++ b/Pythonnet.Runtime/genericutil.cs
@@ -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 {
+
+ ///
+ /// This class is responsible for efficiently maintaining the bits
+ /// of information we need to support aliases with 'nice names'.
+ ///
+
+ internal class GenericUtil {
+
+ static Dictionary>> mapping;
+
+ private GenericUtil() {}
+
+ static GenericUtil() {
+ mapping = new
+ Dictionary>>();
+ }
+
+ //====================================================================
+ // Register a generic type that appears in a given namespace.
+ //====================================================================
+
+ internal static void Register(Type t) {
+ Dictionary> nsmap = null;
+ mapping.TryGetValue(t.Namespace, out nsmap);
+ if (nsmap == null) {
+ nsmap = new Dictionary>();
+ mapping[t.Namespace] = nsmap;
+ }
+ string basename = t.Name;
+ int tick = basename.IndexOf("`");
+ if (tick > -1) {
+ basename = basename.Substring(0, tick);
+ }
+ List gnames = null;
+ nsmap.TryGetValue(basename, out gnames);
+ if (gnames == null) {
+ gnames = new List();
+ nsmap[basename] = gnames;
+ }
+ gnames.Add(t.Name);
+ }
+
+ //====================================================================
+ // xxx
+ //====================================================================
+
+ public static List GetGenericBaseNames(string ns) {
+ Dictionary> nsmap = null;
+ mapping.TryGetValue(ns, out nsmap);
+ if (nsmap == null) {
+ return null;
+ }
+ List names = new List();
+ foreach (string key in nsmap.Keys) {
+ names.Add(key);
+ }
+ return names;
+ }
+
+ //====================================================================
+ // xxx
+ //====================================================================
+
+ public static List GenericsForType(Type t) {
+ Dictionary> 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 names = null;
+ nsmap.TryGetValue(basename, out names);
+ if (names == null) {
+ return null;
+ }
+
+ List result = new List();
+ 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> nsmap = null;
+ mapping.TryGetValue(ns, out nsmap);
+ if (nsmap == null) {
+ return null;
+ }
+ List gnames = null;
+ nsmap.TryGetValue(name, out gnames);
+ if (gnames == null) {
+ return null;
+ }
+ if (gnames.Count > 0) {
+ return gnames[0];
+ }
+ return null;
+ }
+
+
+ }
+
+
+
+}
diff --git a/Pythonnet.Runtime/importhook.cs b/Pythonnet.Runtime/importhook.cs
new file mode 100644
index 0000000000..9d618b60dd
--- /dev/null
+++ b/Pythonnet.Runtime/importhook.cs
@@ -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;
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/indexer.cs b/Pythonnet.Runtime/indexer.cs
new file mode 100644
index 0000000000..8118dc339b
--- /dev/null
+++ b/Pythonnet.Runtime/indexer.cs
@@ -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);
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/interfaceobject.cs b/Pythonnet.Runtime/interfaceobject.cs
new file mode 100644
index 0000000000..7c2aead1fe
--- /dev/null
+++ b/Pythonnet.Runtime/interfaceobject.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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);
+ }
+
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/interfaces.cs b/Pythonnet.Runtime/interfaces.cs
new file mode 100644
index 0000000000..484a9ad5d2
--- /dev/null
+++ b/Pythonnet.Runtime/interfaces.cs
@@ -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 {
+
+ ///
+ /// xxx
+ ///
+
+ 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 {
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/interop.cs b/Pythonnet.Runtime/interop.cs
new file mode 100644
index 0000000000..9aad4c6e40
--- /dev/null
+++ b/Pythonnet.Runtime/interop.cs
@@ -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 "." */
+ 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;
+ }
+
+ ///
+ /// 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)
+ ///
+ 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;
+ }
+ }
+
+}
diff --git a/Pythonnet.Runtime/iterator.cs b/Pythonnet.Runtime/iterator.cs
new file mode 100644
index 0000000000..3d34760c39
--- /dev/null
+++ b/Pythonnet.Runtime/iterator.cs
@@ -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;
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/managedtype.cs b/Pythonnet.Runtime/managedtype.cs
new file mode 100644
index 0000000000..670bcd2b36
--- /dev/null
+++ b/Pythonnet.Runtime/managedtype.cs
@@ -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;
+ }
+
+
+ }
+
+
+}
+
diff --git a/Pythonnet.Runtime/metatype.cs b/Pythonnet.Runtime/metatype.cs
new file mode 100644
index 0000000000..305437c84e
--- /dev/null
+++ b/Pythonnet.Runtime/metatype.cs
@@ -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;
+ }
+
+
+
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/methodbinder.cs b/Pythonnet.Runtime/methodbinder.cs
new file mode 100644
index 0000000000..80d3968fd4
--- /dev/null
+++ b/Pythonnet.Runtime/methodbinder.cs
@@ -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;
+ }
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/methodbinding.cs b/Pythonnet.Runtime/methodbinding.cs
new file mode 100644
index 0000000000..0459d36b29
--- /dev/null
+++ b/Pythonnet.Runtime/methodbinding.cs
@@ -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(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);
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/methodobject.cs b/Pythonnet.Runtime/methodobject.cs
new file mode 100644
index 0000000000..15a5cd5478
--- /dev/null
+++ b/Pythonnet.Runtime/methodobject.cs
@@ -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("", 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);
+ }
+
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/methodwrapper.cs b/Pythonnet.Runtime/methodwrapper.cs
new file mode 100644
index 0000000000..04a49d5924
--- /dev/null
+++ b/Pythonnet.Runtime/methodwrapper.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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);
+ }
+
+
+ }
+
+
+}
+
diff --git a/Pythonnet.Runtime/modulefunctionobject.cs b/Pythonnet.Runtime/modulefunctionobject.cs
new file mode 100644
index 0000000000..5c9a4de21c
--- /dev/null
+++ b/Pythonnet.Runtime/modulefunctionobject.cs
@@ -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
+{
+ ///
+ /// Module level functions
+ ///
+ 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("", self.name);
+ return Runtime.PyString_FromStringAndSize(s, s.Length);
+ }
+
+ }
+}
+
diff --git a/Pythonnet.Runtime/moduleobject.cs b/Pythonnet.Runtime/moduleobject.cs
new file mode 100644
index 0000000000..3a39919477
--- /dev/null
+++ b/Pythonnet.Runtime/moduleobject.cs
@@ -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 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();
+ _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);
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Initialize module level functions and attributes
+ ///
+ 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("", self.moduleName);
+ return Runtime.PyString_FromString(s);
+ }
+
+
+
+ }
+
+ ///
+ /// 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.
+ ///
+ 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;
+ }
+ }
+
+ ///
+ /// The initializing of the preload hook has to happen as late as
+ /// possible since sys.ps1 is created after the CLR module is
+ /// created.
+ ///
+ 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;
+ }
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/modulepropertyobject.cs b/Pythonnet.Runtime/modulepropertyobject.cs
new file mode 100644
index 0000000000..f833696bf8
--- /dev/null
+++ b/Pythonnet.Runtime/modulepropertyobject.cs
@@ -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 {
+
+ ///
+ /// Module level properties (attributes)
+ ///
+ internal class ModulePropertyObject : ExtensionType {
+
+ public ModulePropertyObject(PropertyInfo md) : base()
+ {
+ throw new NotImplementedException("ModulePropertyObject");
+ }
+
+ }
+
+}
+
diff --git a/Pythonnet.Runtime/monosupport.cs b/Pythonnet.Runtime/monosupport.cs
new file mode 100644
index 0000000000..6208b498ec
--- /dev/null
+++ b/Pythonnet.Runtime/monosupport.cs
@@ -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
+
diff --git a/Pythonnet.Runtime/nativecall.cs b/Pythonnet.Runtime/nativecall.cs
new file mode 100644
index 0000000000..d2c4bf5b3a
--- /dev/null
+++ b/Pythonnet.Runtime/nativecall.cs
@@ -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 {
+
+ ///
+ /// 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.
+ ///
+
+ 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);
+ }
+
+ }
+
+
+ ///
+ /// Defines native call signatures to be generated by NativeCall.
+ ///
+
+ 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);
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/oldmodule.il b/Pythonnet.Runtime/oldmodule.il
new file mode 100644
index 0000000000..6ecd2c1363
--- /dev/null
+++ b/Pythonnet.Runtime/oldmodule.il
@@ -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
+ }
+}
+
diff --git a/Pythonnet.Runtime/overload.cs b/Pythonnet.Runtime/overload.cs
new file mode 100644
index 0000000000..0b7ef248cc
--- /dev/null
+++ b/Pythonnet.Runtime/overload.cs
@@ -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);
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/propertyobject.cs b/Pythonnet.Runtime/propertyobject.cs
new file mode 100644
index 0000000000..d61dc01344
--- /dev/null
+++ b/Pythonnet.Runtime/propertyobject.cs
@@ -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("", self.info.Name);
+ return Runtime.PyString_FromStringAndSize(s, s.Length);
+ }
+
+ }
+
+
+}
diff --git a/Pythonnet.Runtime/pyansistring.cs b/Pythonnet.Runtime/pyansistring.cs
new file mode 100644
index 0000000000..db8e249a16
--- /dev/null
+++ b/Pythonnet.Runtime/pyansistring.cs
@@ -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
+ {
+ ///
+ /// PyAnsiString Constructor
+ ///
+ ///
+ ///
+ /// 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.
+ ///
+
+ public PyAnsiString(IntPtr ptr) : base(ptr) { }
+
+
+ ///
+ /// PyString Constructor
+ ///
+ ///
+ ///
+ /// Copy constructor - obtain a PyAnsiString from a generic PyObject.
+ /// An ArgumentException will be thrown if the given object is not
+ /// a Python string object.
+ ///
+
+ public PyAnsiString(PyObject o)
+ : base()
+ {
+ if (!IsStringType(o))
+ {
+ throw new ArgumentException("object is not a string");
+ }
+ Runtime.Incref(o.obj);
+ obj = o.obj;
+ }
+
+
+ ///
+ /// PyAnsiString Constructor
+ ///
+ ///
+ ///
+ /// Creates a Python string from a managed string.
+ ///
+
+ public PyAnsiString(string s)
+ : base()
+ {
+ obj = Runtime.PyString_FromStringAndSize(s, s.Length);
+ if (obj == IntPtr.Zero)
+ {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// IsStringType Method
+ ///
+ ///
+ ///
+ /// Returns true if the given object is a Python string.
+ ///
+
+ public static bool IsStringType(PyObject value)
+ {
+ return Runtime.PyString_Check(value.obj);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Pythonnet.Runtime/pydict.cs b/Pythonnet.Runtime/pydict.cs
new file mode 100644
index 0000000000..cd85c7126d
--- /dev/null
+++ b/Pythonnet.Runtime/pydict.cs
@@ -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 {
+
+ ///
+ /// Represents a Python dictionary object. See the documentation at
+ /// http://www.python.org/doc/current/api/dictObjects.html for details.
+ ///
+
+ public class PyDict : PyObject {
+
+ ///
+ /// PyDict Constructor
+ ///
+ ///
+ ///
+ /// 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.
+ ///
+
+ public PyDict(IntPtr ptr) : base(ptr) {}
+
+
+ ///
+ /// PyDict Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python dictionary object.
+ ///
+
+ public PyDict() : base() {
+ obj = Runtime.PyDict_New();
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// PyDict Constructor
+ ///
+ ///
+ ///
+ /// Copy constructor - obtain a PyDict from a generic PyObject. An
+ /// ArgumentException will be thrown if the given object is not a
+ /// Python dictionary object.
+ ///
+
+ public PyDict(PyObject o) : base() {
+ if (!IsDictType(o)) {
+ throw new ArgumentException("object is not a dict");
+ }
+ Runtime.Incref(o.obj);
+ obj = o.obj;
+ }
+
+
+ ///
+ /// IsDictType Method
+ ///
+ ///
+ ///
+ /// Returns true if the given object is a Python dictionary.
+ ///
+
+ public static bool IsDictType(PyObject value) {
+ return Runtime.PyDict_Check(value.obj);
+ }
+
+
+ ///
+ /// HasKey Method
+ ///
+ ///
+ ///
+ /// Returns true if the object key appears in the dictionary.
+ ///
+
+ public bool HasKey(PyObject key) {
+ return (Runtime.PyMapping_HasKey(obj, key.obj) != 0);
+ }
+
+
+ ///
+ /// HasKey Method
+ ///
+ ///
+ ///
+ /// Returns true if the string key appears in the dictionary.
+ ///
+
+ public bool HasKey(string key) {
+ return HasKey(new PyString(key));
+ }
+
+
+ ///
+ /// Keys Method
+ ///
+ ///
+ ///
+ /// Returns a sequence containing the keys of the dictionary.
+ ///
+
+ public PyObject Keys() {
+ IntPtr items = Runtime.PyDict_Keys(obj);
+ if (items == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ return new PyObject(items);
+ }
+
+
+ ///
+ /// Values Method
+ ///
+ ///
+ ///
+ /// Returns a sequence containing the values of the dictionary.
+ ///
+
+ public PyObject Values() {
+ IntPtr items = Runtime.PyDict_Values(obj);
+ if (items == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ return new PyObject(items);
+ }
+
+
+ ///
+ /// Items Method
+ ///
+ ///
+ ///
+ /// Returns a sequence containing the items of the dictionary.
+ ///
+
+ public PyObject Items() {
+ IntPtr items = Runtime.PyDict_Items(obj);
+ if (items == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ return new PyObject(items);
+ }
+
+
+ ///
+ /// Copy Method
+ ///
+ ///
+ ///
+ /// Returns a copy of the dictionary.
+ ///
+
+ public PyDict Copy() {
+ IntPtr op = Runtime.PyDict_Copy(obj);
+ if (op == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ return new PyDict(op);
+ }
+
+
+ ///
+ /// Update Method
+ ///
+ ///
+ ///
+ /// Update the dictionary from another dictionary.
+ ///
+
+ public void Update(PyObject other) {
+ int result = Runtime.PyDict_Update(obj, other.obj);
+ if (result < 0) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// Clear Method
+ ///
+ ///
+ ///
+ /// Clears the dictionary.
+ ///
+
+ public void Clear() {
+ Runtime.PyDict_Clear(obj);
+ }
+
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/pyfloat.cs b/Pythonnet.Runtime/pyfloat.cs
new file mode 100644
index 0000000000..960892594c
--- /dev/null
+++ b/Pythonnet.Runtime/pyfloat.cs
@@ -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 {
+
+ ///
+ /// Represents a Python float object. See the documentation at
+ /// http://www.python.org/doc/current/api/floatObjects.html
+ ///
+
+ public class PyFloat : PyNumber {
+
+ ///
+ /// PyFloat Constructor
+ ///
+ ///
+ ///
+ /// 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.
+ ///
+
+ public PyFloat(IntPtr ptr) : base(ptr) {}
+
+
+ ///
+ /// PyFloat Constructor
+ ///
+ ///
+ ///
+ /// Copy constructor - obtain a PyFloat from a generic PyObject. An
+ /// ArgumentException will be thrown if the given object is not a
+ /// Python float object.
+ ///
+
+ public PyFloat(PyObject o) : base() {
+ if (!IsFloatType(o)) {
+ throw new ArgumentException("object is not a float");
+ }
+ Runtime.Incref(o.obj);
+ obj = o.obj;
+ }
+
+
+ ///
+ /// PyFloat Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python float from a double value.
+ ///
+
+ public PyFloat(double value) : base() {
+ obj = Runtime.PyFloat_FromDouble(value);
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// PyFloat Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python float from a string value.
+ ///
+
+ 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();
+ }
+ }
+
+
+ ///
+ /// IsFloatType Method
+ ///
+ ///
+ ///
+ /// Returns true if the given object is a Python float.
+ ///
+
+ public static bool IsFloatType(PyObject value) {
+ return Runtime.PyFloat_Check(value.obj);
+ }
+
+
+ ///
+ /// AsFloat Method
+ ///
+ ///
+ ///
+ ///
+ /// 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)".
+ ///
+
+ public static PyFloat AsFloat(PyObject value) {
+ IntPtr op = Runtime.PyNumber_Float(value.obj);
+ if (op == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ return new PyFloat(op);
+ }
+
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/pyint.cs b/Pythonnet.Runtime/pyint.cs
new file mode 100644
index 0000000000..7e5f07b6aa
--- /dev/null
+++ b/Pythonnet.Runtime/pyint.cs
@@ -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 {
+
+ ///
+ /// Represents a Python integer object. See the documentation at
+ /// http://www.python.org/doc/current/api/intObjects.html for details.
+ ///
+
+ public class PyInt : PyNumber {
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// 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.
+ ///
+
+ public PyInt(IntPtr ptr) : base(ptr) {}
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Copy constructor - obtain a PyInt from a generic PyObject. An
+ /// ArgumentException will be thrown if the given object is not a
+ /// Python int object.
+ ///
+
+ public PyInt(PyObject o) : base() {
+ if (!IsIntType(o)) {
+ throw new ArgumentException("object is not an int");
+ }
+ Runtime.Incref(o.obj);
+ obj = o.obj;
+ }
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from an int32 value.
+ ///
+
+ public PyInt(int value) : base() {
+ obj = Runtime.PyInt_FromInt32(value);
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from a uint32 value.
+ ///
+
+ [CLSCompliant(false)]
+ public PyInt(uint value) : base(IntPtr.Zero) {
+ obj = Runtime.PyInt_FromInt64((long)value);
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from an int64 value.
+ ///
+
+ public PyInt(long value) : base(IntPtr.Zero) {
+ obj = Runtime.PyInt_FromInt64(value);
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from a uint64 value.
+ ///
+
+ [CLSCompliant(false)]
+ public PyInt(ulong value) : base(IntPtr.Zero) {
+ obj = Runtime.PyInt_FromInt64((long)value);
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from an int16 value.
+ ///
+
+ public PyInt(short value) : this((int)value) {}
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from a uint16 value.
+ ///
+
+ [CLSCompliant(false)]
+ public PyInt(ushort value) : this((int)value) {}
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from a byte value.
+ ///
+
+ public PyInt(byte value) : this((int)value) {}
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from an sbyte value.
+ ///
+
+ [CLSCompliant(false)]
+ public PyInt(sbyte value) : this((int)value) {}
+
+
+ ///
+ /// PyInt Constructor
+ ///
+ ///
+ ///
+ /// Creates a new Python int from a string value.
+ ///
+
+ public PyInt(string value) : base() {
+ obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0);
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ }
+
+
+ ///
+ /// IsIntType Method
+ ///
+ ///
+ ///
+ /// Returns true if the given object is a Python int.
+ ///
+
+ public static bool IsIntType(PyObject value) {
+ return Runtime.PyInt_Check(value.obj);
+ }
+
+
+ ///
+ /// AsInt Method
+ ///
+ ///
+ ///
+ ///
+ /// 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)".
+ ///
+
+ public static PyInt AsInt(PyObject value) {
+ IntPtr op = Runtime.PyNumber_Int(value.obj);
+ if (op == IntPtr.Zero) {
+ throw new PythonException();
+ }
+ return new PyInt(op);
+ }
+
+
+ ///
+ /// ToInt16 Method
+ ///
+ ///
+ ///
+ /// Return the value of the Python int object as an int16.
+ ///
+
+ public short ToInt16() {
+ return System.Convert.ToInt16(this.ToInt32());
+ }
+
+
+ ///
+ /// ToInt32 Method
+ ///
+ ///
+ ///
+ /// Return the value of the Python int object as an int32.
+ ///
+
+ public int ToInt32() {
+ return Runtime.PyInt_AsLong(obj);
+ }
+
+
+ ///
+ /// ToInt64 Method
+ ///
+ ///
+ ///
+ /// Return the value of the Python int object as an int64.
+ ///
+
+ public long ToInt64() {
+ return System.Convert.ToInt64(this.ToInt32());
+ }
+
+
+
+ }
+
+}
diff --git a/Pythonnet.Runtime/pyiter.cs b/Pythonnet.Runtime/pyiter.cs
new file mode 100644
index 0000000000..8d8ad44d7d
--- /dev/null
+++ b/Pythonnet.Runtime/pyiter.cs
@@ -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
+{
+ ///
+ /// Represents a standard Python iterator object. See the documentation at
+ /// http://www.python.org/doc/2.4.4/api/iterator.html for details.
+ ///
+ public class PyIter : PyObject, IEnumerator