diff --git a/.travis.yml b/.travis.yml
index 6355ce73d..5581f1329 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,8 @@ language: python
python:
- 2.6
- 2.7
+ - 3.2
+ - 3.4
before_install:
- sudo apt-get install software-properties-common
- sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ trusty main universe"
@@ -12,7 +14,8 @@ before_install:
- yes | sudo certmgr -ssl -m https://nugetgallery.blob.core.windows.net
- yes | sudo certmgr -ssl -m https://nuget.org
install:
+ - pip install six
- python setup.py build_ext --inplace
script:
- - export PYTHONPATH=`pwd`
- - ./npython src/tests/runtests.py
+ - export PYTHONPATH=`pwd`:$PYTHONPATH
+ - python src/tests/runtests.py
diff --git a/Python.Runtime.dll.config b/Python.Runtime.dll.config
index 11b4fb0fe..e9821a8a9 100644
--- a/Python.Runtime.dll.config
+++ b/Python.Runtime.dll.config
@@ -14,10 +14,16 @@ For more information read:
+
+
+
+
+
+
diff --git a/Python.Test.csproj b/Python.Test.csproj
new file mode 100644
index 000000000..11591e091
--- /dev/null
+++ b/Python.Test.csproj
@@ -0,0 +1,190 @@
+
+
+
+ Debug
+ AnyCPU
+ {6F401A34-273B-450F-9A4C-13550BE0767B}
+ Library
+ false
+ Python.Test
+ Python.Test
+ OnBuildSuccess
+
+
+
+
+ 3.5
+ v4.0
+
+
+
+ true
+ full
+ false
+ .\bin\Debug\
+ DEBUG;TRACE
+
+
+ pdbonly
+ true
+ .\bin\Release\
+ TRACE
+
+
+ true
+ bin\EmbeddingTest\
+ DEBUG;TRACE
+ full
+ AnyCPU
+
+
+ true
+ bin\UnitTests\
+ DEBUG;TRACE
+ full
+ AnyCPU
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ true
+ false
+
+
+ bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ false
+ false
+ false
+
+
+ true
+ bin\x86\EmbeddingTest\
+ DEBUG;TRACE
+ full
+ x86
+ false
+ true
+ true
+
+
+ true
+ bin\x86\UnitTests\
+ DEBUG;TRACE
+ full
+ x86
+ true
+ true
+
+
+ true
+ bin\DebugMono_x86\
+ DEBUG;TRACE
+ full
+ AnyCPU
+ true
+ true
+
+
+ true
+ bin\x86\DebugMono_x86\
+ DEBUG;TRACE
+ full
+ x86
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ true
+ false
+ false
+
+
+ bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ false
+
+
+ true
+ bin\x64\EmbeddingTest\
+ DEBUG;TRACE
+ full
+ x64
+ false
+ true
+ true
+
+
+ true
+ bin\x64\UnitTests\
+ DEBUG;TRACE
+ full
+ x64
+ true
+ true
+
+
+ true
+ bin\x64\DebugMono_x86\
+ DEBUG;TRACE
+ full
+ x64
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3.5
+
+
+
+
+
+ {097B4AC0-74E9-4C58-BCF8-C69746EC8271}
+ Python.Runtime
+
+
+
+
+
+
+
+ copy "$(TargetPath)" "$(SolutionDir)"
+copy "$(TargetDir)*.pdb" "$(SolutionDir)"
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 8b88ac0e9..f6196e5d9 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,63 @@
pythonnet
=========
-Python for .NET is a package that gives Python programmers nearly seamless integration with the .NET Common Language Runtime (CLR) and provides a powerful application scripting tool for .NET developers.
+Python for .NET is a package that gives Python programmers nearly seamless integration with the .NET Common Language Runtime (CLR) and provides a powerful application scripting tool for .NET developers. It allows Python code to interact with the CLR, and may also be used to embed Python into a .NET application.
-[](https://travis-ci.org/pythonnet/pythonnet)
+[](https://travis-ci.org/pythonnet/pythonnet)
-[](https://ci.appveyor.com/project/davidanthoff/pythonnet)
+[](https://ci.appveyor.com/project/TonyRoberts/pythonnet-480xs)
+
+**Calling .NET code from Python**
+
+Python for .NET allows CLR namespaces to be treated essentially as Python packages.
+
+```python
+ import clr
+ from System import String
+ from System.Collections import *
+```
+To load an assembly, use the "AddReference" function in the "clr" module:
+
+```python
+ import clr
+ clr.AddReference("System.Windows.Forms")
+ from System.Windows.Forms import Form
+```
+
+**Embedding Python in .NET**
+
++ All calls to python should be inside a "using (Py.GIL()) {/* Your code here */}" block.
++ Import python modules using dynamic mod = Py.Import("mod"), then you can call functions as normal, eg mod.func(args).
++ Use mod.func(args, Py.kw("keywordargname", keywordargvalue)) to apply keyword arguments.
++ All python objects should be declared as 'dynamic' type.
++ Mathematical operations involving python and literal/managed types must have the python object first, eg np.pi*2 works, 2*np.pi doesn't
+
+EG:
+```csharp
+static void Main(string[] args)
+{
+ using (Py.GIL()) {
+ dynamic np = Py.Import("numpy");
+ dynamic sin = np.sin;
+ Console.WriteLine(np.cos(np.pi*2));
+ Console.WriteLine(sin(5));
+ double c = np.cos(5) + sin(5);
+ Console.WriteLine(c);
+ dynamic a = np.array(new List { 1, 2, 3 });
+ dynamic b = np.array(new List { 6, 5, 4 }, Py.kw("dtype", np.int32));
+ Console.WriteLine(a.dtype);
+ Console.WriteLine(b.dtype);
+ Console.WriteLine(a * b);
+ Console.ReadKey();
+ }
+}
+```
+outputs:
+```
+1.0
+-0.958924274663
+-0.6752620892
+float64
+int32
+[ 6. 10. 12.]
+```
diff --git a/appveyor.yml b/appveyor.yml
index 18f9761c0..d7d46a7c0 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -9,6 +9,10 @@ environment:
- pythonurl: http://www.python.org/ftp/python/2.7.6/python-2.7.6.msi
- pythonurl: http://www.python.org/ftp/python/2.6.6/python-2.6.6.msi
- pythonurl: http://www.python.org/ftp/python/2.6.6/python-2.6.6.amd64.msi
+ - pythonurl: http://www.python.org/ftp/python/3.2.3/python-3.2.3.msi
+ - pythonurl: http://www.python.org/ftp/python/3.2.3/python-3.2.3.amd64.msi
+ - pythonurl: http://www.python.org/ftp/python/3.4.2/python-3.4.2.msi
+ - pythonurl: http://www.python.org/ftp/python/3.4.2/python-3.4.2.amd64.msi
install:
- ps: (new-object net.webclient).DownloadFile($env:pythonurl, 'C:\python.msi')
@@ -19,6 +23,7 @@ install:
- set PATH=C:\Python;%PATH%
- C:\Python\python.exe c:\get-pip.py
- C:\Python\Scripts\pip.exe install wheel
+ - C:\Python\Scripts\pip.exe install six
build_script:
- C:\python\python.exe setup.py bdist_wheel
@@ -28,4 +33,3 @@ test_script:
- mkdir c:\testdir
- ps: copy-item (gci -path build -re -include Python.Test.dll)[0].FullName c:\testdir
- c:\python\python.exe src\tests\runtests.py
- - c:\python\scripts\npython.exe src\tests\runtests.py
diff --git a/setup.py b/setup.py
index dc7e9620b..4c2817cc7 100644
--- a/setup.py
+++ b/setup.py
@@ -4,7 +4,6 @@
"""
from setuptools import setup, Extension
from distutils.command.build_ext import build_ext
-from distutils.command.build_scripts import build_scripts
from distutils.command.install_lib import install_lib
from distutils.command.install_data import install_data
from distutils.sysconfig import get_config_var
@@ -12,19 +11,21 @@
from subprocess import Popen, CalledProcessError, PIPE, check_call
from glob import glob
import fnmatch
-import shutil
import sys
import os
-CONFIG = "Release" # Release or Debug
+CONFIG = "Release" # Release or Debug
DEVTOOLS = "MsDev" if sys.platform == "win32" else "Mono"
-VERBOSITY = "minimal" # quiet, minimal, normal, detailed, diagnostic
+VERBOSITY = "minimal" # quiet, minimal, normal, detailed, diagnostic
PLATFORM = "x64" if architecture()[0] == "64bit" else "x86"
def _find_msbuild_tool(tool="msbuild.exe", use_windows_sdk=False):
"""Return full path to one of the microsoft build tools"""
- import _winreg
+ try:
+ import _winreg
+ except ImportError:
+ import winreg as _winreg
if use_windows_sdk:
value_name = "InstallationFolder"
@@ -79,13 +80,11 @@ def _find_msbuild_tool(tool="msbuild.exe", use_windows_sdk=False):
_xbuild = "\"%s\"" % _find_msbuild_tool("msbuild.exe")
_defines_sep = ";"
_config = "%sWin" % CONFIG
- _npython_exe = "nPython.exe"
elif DEVTOOLS == "Mono":
_xbuild = "xbuild"
_defines_sep = ","
_config = "%sMono" % CONFIG
- _npython_exe = "npython"
else:
raise NotImplementedError("DevTools %s not supported (use MsDev or Mono)" % DEVTOOLS)
@@ -108,14 +107,41 @@ def build_extension(self, ext):
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
+ # Up to Python 3.2 sys.maxunicode is used to determine the size of Py_UNICODE
+ # but from 3.3 onwards Py_UNICODE is a typedef of wchar_t.
+ if sys.version_info[:2] <= (3, 2):
+ unicode_width = 2 if sys.maxunicode < 0x10FFFF else 4
+ else:
+ import ctypes
+ unicode_width = ctypes.sizeof(ctypes.c_wchar)
+
defines = [
"PYTHON%d%s" % (sys.version_info[:2]),
- "UCS2" if sys.maxunicode < 0x10FFFF else "UCS4",
+ "UCS%d" % unicode_width,
]
if CONFIG == "Debug":
defines.extend(["DEBUG", "TRACE"])
+ if sys.platform != "win32" and DEVTOOLS == "Mono":
+ if sys.platform == "darwin":
+ defines.append("MONO_OSX")
+ else:
+ defines.append("MONO_LINUX")
+
+ # Check if --enable-shared was set when Python was built
+ enable_shared = get_config_var("Py_ENABLE_SHARED")
+ if enable_shared == 0:
+ defines.append("PYTHON_WITHOUT_ENABLE_SHARED")
+
+ if hasattr(sys, "abiflags"):
+ if "d" in sys.abiflags:
+ defines.append("PYTHON_WITH_PYDEBUG")
+ if "m" in sys.abiflags:
+ defines.append("PYTHON_WITH_PYMALLOC")
+ if "u" in sys.abiflags:
+ defines.append("PYTHON_WITH_WIDE_UNICODE")
+
cmd = [
_xbuild,
"pythonnet.sln",
@@ -138,7 +164,6 @@ def build_extension(self, ext):
if DEVTOOLS == "Mono":
self._build_monoclr(ext)
-
def _get_manifest(self, build_dir):
if DEVTOOLS == "MsDev" and sys.version_info[:2] > (2,5):
mt = _find_msbuild_tool("mt.exe", use_windows_sdk=True)
@@ -148,7 +173,6 @@ def _get_manifest(self, build_dir):
check_call(" ".join(cmd), shell=False)
return manifest
-
def _build_monoclr(self, ext):
mono_libs = _check_output("pkg-config --libs mono-2", shell=True)
mono_cflags = _check_output("pkg-config --cflags mono-2", shell=True)
@@ -168,45 +192,6 @@ def _build_monoclr(self, ext):
build_ext.build_extension(self, clr_ext)
- # build the clr python executable
- sources = [
- "src/monoclr/pynetinit.c",
- "src/monoclr/python.c",
- ]
-
- macros = ext.define_macros[:]
- for undef in ext.undef_macros:
- macros.append((undef,))
-
- objects = self.compiler.compile(sources,
- output_dir=self.build_temp,
- macros=macros,
- include_dirs=ext.include_dirs,
- debug=self.debug,
- extra_postargs=cflags.split(" "),
- depends=ext.depends)
-
- output_dir = os.path.dirname(self.get_ext_fullpath(ext.name))
- py_libs = get_config_var("BLDLIBRARY")
- libs += " " + py_libs
-
- # Include the directories python's shared libs were installed to. This
- # is case python was built with --enable-shared as then npython will need
- # to be able to find libpythonX.X.so.
- runtime_library_dirs = (get_config_var("DESTDIRS") or "").split(" ")
- if ext.runtime_library_dirs:
- runtime_library_dirs.extend(ext.runtime_library_dirs)
-
- self.compiler.link_executable(objects,
- _npython_exe,
- output_dir=output_dir,
- libraries=self.get_libraries(ext),
- library_dirs=ext.library_dirs,
- runtime_library_dirs=runtime_library_dirs,
- extra_postargs=libs.split(" "),
- debug=self.debug)
-
-
def _install_packages(self):
"""install packages using nuget"""
nuget = os.path.join("tools", "nuget", "nuget.exe")
@@ -255,25 +240,6 @@ def run(self):
self.data_files[i] = dest, data_files[1]
return install_data.run(self)
-
-
-class PythonNET_BuildScripts(build_scripts):
-
- def run(self):
- build_scripts.finalize_options(self)
-
- # fixup scripts to look in the build_ext output folder
- if self.scripts:
- build_ext = self.get_finalized_command("build_ext")
- output_dir = os.path.dirname(build_ext.get_ext_fullpath("clr"))
- scripts = []
- for script in self.scripts:
- if os.path.exists(os.path.join(output_dir, script)):
- script = os.path.join(output_dir, script)
- scripts.append(script)
- self.scripts = scripts
-
- return build_scripts.run(self)
def _check_output(*popenargs, **kwargs):
@@ -289,6 +255,8 @@ def _check_output(*popenargs, **kwargs):
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd, output=output)
+ if sys.version_info[0] > 2:
+ return output.decode("ascii")
return output
@@ -328,11 +296,9 @@ def _check_output(*popenargs, **kwargs):
"{build_lib}/Python.Runtime.dll",
"Python.Runtime.dll.config"]),
],
- scripts=[_npython_exe],
zip_safe=False,
cmdclass={
"build_ext" : PythonNET_BuildExt,
- "build_scripts" : PythonNET_BuildScripts,
"install_lib" : PythonNET_InstallLib,
"install_data": PythonNET_InstallData,
}
diff --git a/src/clrmodule/ClrModule.cs b/src/clrmodule/ClrModule.cs
index 3347d55a9..be4da01a7 100644
--- a/src/clrmodule/ClrModule.cs
+++ b/src/clrmodule/ClrModule.cs
@@ -30,7 +30,7 @@
// If DEBUG_PRINT is defined in the Build Properties, a few System.Console.WriteLine
// calls are made to indicate what's going on during the load...
//============================================================================
-
+using System;
// ReSharper disable CheckNamespace
// ReSharper disable InconsistentNaming
@@ -38,10 +38,14 @@ public class clrModule
// ReSharper restore InconsistentNaming
// ReSharper restore CheckNamespace
{
-
- [RGiesecke.DllExport.DllExport("initclr", System.Runtime.InteropServices.CallingConvention.StdCall)]
// ReSharper disable InconsistentNaming
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [RGiesecke.DllExport.DllExport("PyInit_clr", System.Runtime.InteropServices.CallingConvention.StdCall)]
+ public static IntPtr PyInit_clr()
+#else
+ [RGiesecke.DllExport.DllExport("initclr", System.Runtime.InteropServices.CallingConvention.StdCall)]
public static void initclr()
+#endif
// ReSharper restore InconsistentNaming
{
#if DEBUG_PRINT
@@ -76,7 +80,7 @@ public static void initclr()
System.Console.WriteLine("Success!");
#endif
}
- catch (System.IO.FileNotFoundException)
+ catch (System.IO.IOException)
{
try
{
@@ -103,13 +107,22 @@ public static void initclr()
#if DEBUG_PRINT
System.Console.WriteLine("Could not load Python.Runtime, so sad.");
#endif
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ return IntPtr.Zero;
+#else
return;
+#endif
}
}
// Once here, we've successfully loaded SOME version of Python.Runtime
// So now we get the PythonEngine and execute the InitExt method on it.
var pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine");
+
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ return (IntPtr)pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null);
+#else
pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null);
+#endif
}
}
diff --git a/src/clrmodule/clrmodule.csproj b/src/clrmodule/clrmodule.csproj
index 92dc2a945..f6d1a41b5 100644
--- a/src/clrmodule/clrmodule.csproj
+++ b/src/clrmodule/clrmodule.csproj
@@ -1,126 +1,131 @@
-
-
-
- Debug
- x86
- 8.0.30703
- 2.0
- {86E834DE-1139-4511-96CC-69636A56E7AC}
- Library
- Properties
- clrmodule
- clrmodule
- v4.0
- 512
- ..\..\
- $(SolutionDir)
- true
-
-
- true
- bin\x86\DebugMono\
- DEBUG;TRACE
- full
- x86
- prompt
- true
- true
- false
-
-
- true
- bin\x64\DebugMono\
- DEBUG;TRACE
- full
- x64
- prompt
- true
- true
- false
-
-
- bin\x86\ReleaseMono\
-
- true
- pdbonly
- x86
- prompt
- true
- true
- false
-
-
- bin\x64\ReleaseMono\
-
- true
- pdbonly
- x64
- prompt
- true
- true
- false
-
-
- true
- bin\x86\DebugWin\
- TRACE;DEBUG;DEBUG_PRINT
- full
- x86
- prompt
- true
- false
- false
-
-
- true
- bin\x64\DebugWin\
- DEBUG;TRACE
- full
- x64
- prompt
- true
- true
- false
-
-
- bin\x86\ReleaseWin\
-
- true
- pdbonly
- x86
- prompt
- true
- true
- false
-
-
- bin\x64\ReleaseWin\
-
- true
- pdbonly
- x64
- prompt
- true
- true
- false
-
-
-
- ..\..\packages\UnmanagedExports.1.2.6\lib\net\RGiesecke.DllExport.Metadata.dll
- False
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+ Debug
+ x86
+ 8.0.30703
+ 2.0
+ {86E834DE-1139-4511-96CC-69636A56E7AC}
+ Library
+ Properties
+ clrmodule
+ clrmodule
+ v4.0
+ 512
+ ..\..\
+ $(SolutionDir)
+ true
+
+
+ true
+ bin\x86\DebugMono\
+ DEBUG;TRACE
+ full
+ x86
+ prompt
+ true
+ true
+ false
+
+
+ true
+ bin\x64\DebugMono\
+ DEBUG;TRACE
+ full
+ x64
+ prompt
+ true
+ true
+ false
+
+
+ bin\x86\ReleaseMono\
+
+ true
+ pdbonly
+ x86
+ prompt
+ true
+ true
+ false
+
+
+ bin\x64\ReleaseMono\
+
+ true
+ pdbonly
+ x64
+ prompt
+ true
+ true
+ false
+
+
+ true
+ bin\x86\DebugWin\
+ TRACE;DEBUG;DEBUG_PRINT
+ full
+ x86
+ prompt
+ true
+ false
+ false
+
+
+ true
+ bin\x64\DebugWin\
+ DEBUG;TRACE
+ full
+ x64
+ prompt
+ true
+ true
+ false
+
+
+ bin\x86\ReleaseWin\
+
+ true
+ pdbonly
+ x86
+ prompt
+ true
+ true
+ false
+
+
+ bin\x64\ReleaseWin\
+
+ true
+ pdbonly
+ x64
+ prompt
+ true
+ true
+ false
+
+
+
+ ..\..\packages\UnmanagedExports.1.2.6\lib\net\RGiesecke.DllExport.Metadata.dll
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+ $(TargetPath)
+ $(TargetDir)$(TargetName).pdb
+
+
+
+
+
+
+
diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj
index 14f97f5fb..e4a9750b8 100644
--- a/src/embed_tests/Python.EmbeddingTest.csproj
+++ b/src/embed_tests/Python.EmbeddingTest.csproj
@@ -172,7 +172,12 @@
+
+ $(TargetPath)
+ $(TargetDir)$(TargetName).pdb
+
-
+
+
diff --git a/src/monoclr/clrmod.c b/src/monoclr/clrmod.c
index 8b809b28f..c6de71eeb 100644
--- a/src/monoclr/clrmod.c
+++ b/src/monoclr/clrmod.c
@@ -25,21 +25,54 @@ PyDoc_STRVAR(clr_module_doc,
static PyNet_Args *pn_args;
char** environ = NULL;
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef clrdef = {
+ PyModuleDef_HEAD_INIT,
+ "clr", /* m_name */
+ clr_module_doc, /* m_doc */
+ -1, /* m_size */
+ clr_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+#endif
+
+static PyObject *_initclr() {
+ PyObject *m;
+
+ /* Create the module and add the functions */
+#if PY_MAJOR_VERSION >= 3
+ m = PyModule_Create(&clrdef);
+#else
+ m = Py_InitModule3("clr", clr_methods, clr_module_doc);
+#endif
+ if (m == NULL)
+ return NULL;
+ PyModule_AddObject(m, "facade", Py_True);
+ Py_INCREF(Py_True);
+
+ pn_args = PyNet_Init(1);
+ if (pn_args->error) {
+ return NULL;
+ }
+
+ if (NULL != pn_args->module)
+ return pn_args->module;
+
+ return m;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC
+PyInit_clr(void) {
+ return _initclr();
+}
+#else
PyMODINIT_FUNC
-initclr(void)
-{
- PyObject *m;
-
- /* Create the module and add the functions */
- m = Py_InitModule3("clr", clr_methods, clr_module_doc);
- if (m == NULL)
- return;
- PyModule_AddObject(m, "facade", Py_True);
- Py_INCREF(Py_True);
-
- pn_args = PyNet_Init(1);
- if (pn_args->error) {
- return;
- }
+initclr(void) {
+ _initclr();
}
+#endif
diff --git a/src/monoclr/clrpython.c b/src/monoclr/clrpython.c
deleted file mode 100644
index 5fddabf22..000000000
--- a/src/monoclr/clrpython.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// ==========================================================================
-// This software is subject to the provisions of the Zope Public License,
-// Version 2.1 (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.
-// ==========================================================================
-//
-// Example how to integrate Python, PythonNet and Mono into a C application
-// It provides a command prompt equal to PythonNet's console but using a
-// different path.
-//
-// Author: Christian Heimes
-//
-
-#include "pynetclr.h"
-
-int main(int argc, char **argv) {
- PyNet_Args *pn_args;
- pn_args = PyNet_Init(0);
- if (pn_args->error) {
- exit(1);
- }
- int rc = Py_Main(argc, argv);
- PyNet_Finalize(pn_args);
- exit(rc);
-}
-
diff --git a/src/monoclr/pynetclr.h b/src/monoclr/pynetclr.h
index c97db10cb..3a6a60c9c 100644
--- a/src/monoclr/pynetclr.h
+++ b/src/monoclr/pynetclr.h
@@ -32,6 +32,7 @@ typedef struct {
char *error;
char *init_name;
char *shutdown_name;
+ PyObject* module;
} PyNet_Args;
PyNet_Args* PyNet_Init(int);
diff --git a/src/monoclr/pynetinit.c b/src/monoclr/pynetinit.c
index eaa1d9c8b..f6487802c 100644
--- a/src/monoclr/pynetinit.c
+++ b/src/monoclr/pynetinit.c
@@ -10,11 +10,16 @@
// Author: Christian Heimes
#include "pynetclr.h"
+#include "stdlib.h"
#ifndef _WIN32
#include "dirent.h"
+#include "dlfcn.h"
+#include "libgen.h"
+#include "alloca.h"
#endif
+
// initialize Mono and PythonNet
PyNet_Args* PyNet_Init(int ext) {
PyNet_Args *pn_args;
@@ -22,6 +27,7 @@ PyNet_Args* PyNet_Init(int ext) {
pn_args->pr_file = PR_ASSEMBLY;
pn_args->error = NULL;
pn_args->shutdown = NULL;
+ pn_args->module = NULL;
if (ext == 0) {
pn_args->init_name = "Python.Runtime:Initialize()";
@@ -91,8 +97,29 @@ void main_thread_handler (gpointer user_data) {
MonoImage *pr_image;
MonoClass *pythonengine;
MonoObject *exception = NULL;
+ MonoObject *init_result;
#ifndef _WIN32
+ // Get the filename of the python shared object and set
+ // LD_LIBRARY_PATH so Mono can find it.
+ Dl_info dlinfo = {0};
+ if (0 != dladdr(&Py_Initialize, &dlinfo)) {
+ char* fname = alloca(strlen(dlinfo.dli_fname) + 1);
+ strcpy(fname, dlinfo.dli_fname);
+ char* py_libdir = dirname(fname);
+ char* ld_library_path = getenv("LD_LIBRARY_PATH");
+ if (NULL == ld_library_path) {
+ setenv("LD_LIBRARY_PATH", py_libdir, 1);
+ } else {
+ char* new_ld_library_path = alloca(strlen(py_libdir)
+ + strlen(ld_library_path)
+ + 2);
+ strcpy(new_ld_library_path, py_libdir);
+ strcat(new_ld_library_path, ":");
+ strcat(new_ld_library_path, ld_library_path);
+ setenv("LD_LIBRARY_PATH", py_libdir, 1);
+ }
+ }
//get python path system variable
PyObject* syspath = PySys_GetObject("path");
@@ -102,11 +129,25 @@ void main_thread_handler (gpointer user_data) {
int ii = 0;
for (ii = 0; ii < PyList_Size(syspath); ++ii) {
+#if PY_MAJOR_VERSION > 2
+ Py_ssize_t wlen;
+ wchar_t *wstr = PyUnicode_AsWideCharString(PyList_GetItem(syspath, ii), &wlen);
+ char* pydir = (char*)malloc(wlen + 1);
+ size_t mblen = wcstombs(pydir, wstr, wlen + 1);
+ if (mblen > wlen)
+ pydir[wlen] = '\0';
+ PyMem_Free(wstr);
+#else
const char* pydir = PyString_AsString(PyList_GetItem(syspath, ii));
+#endif
char* curdir = (char*) malloc(1024);
strncpy(curdir, strlen(pydir) > 0 ? pydir : ".", 1024);
strncat(curdir, slash, 1024);
+#if PY_MAJOR_VERSION > 2
+ free(pydir);
+#endif
+
//look in this directory for the pn_args->pr_file
DIR* dirp = opendir(curdir);
if (dirp != NULL) {
@@ -170,11 +211,17 @@ void main_thread_handler (gpointer user_data) {
return;
}
- mono_runtime_invoke(init, NULL, NULL, &exception);
+ init_result = mono_runtime_invoke(init, NULL, NULL, &exception);
if (exception) {
pn_args->error = PyNet_ExceptionToString(exception);
return;
}
+
+#if PY_MAJOR_VERSION >= 3
+ if (NULL != init_result)
+ pn_args->module = *(PyObject**)mono_object_unbox(init_result);
+#endif
+
}
// Get string from a Mono exception
diff --git a/src/monoclr/python.c b/src/monoclr/python.c
deleted file mode 100644
index aa340491f..000000000
--- a/src/monoclr/python.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// ==========================================================================
-// This software is subject to the provisions of the Zope Public License,
-// Version 2.1 (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.
-// ==========================================================================
-//
-// python.c provides a python executable with is dynamically linked agaist
-// libpython2.x.so. For example Ubuntu's python executables aren't linked
-// against libpython :(
-//
-// Author: Christian Heimes
-//
-
-#include
-
-int main(int argc, char **argv) {
- return Py_Main(argc, argv);
-}
-
diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj
index f5bf3378a..80f911734 100644
--- a/src/runtime/Python.Runtime.csproj
+++ b/src/runtime/Python.Runtime.csproj
@@ -1,190 +1,202 @@
-
-
-
- Debug
- x86
- {097B4AC0-74E9-4C58-BCF8-C69746EC8271}
- Library
- false
- Python.Runtime
- Python.Runtime
- ..\..\
- $(SolutionDir)
-
-
- bin\x86\ReleaseMono\
- PYTHON27, UCS4
- true
- true
- pdbonly
- x86
- false
- true
-
-
- bin\x64\ReleaseMono\
- PYTHON27, UCS4
- true
- true
- pdbonly
- x64
- false
- true
-
-
- bin\x86\ReleaseWin\
- PYTHON27, UCS2
- true
- true
- pdbonly
- x86
- false
- true
-
-
- bin\x64\ReleaseWin\
- PYTHON27, UCS2
- true
- true
- pdbonly
- x64
- false
- true
-
-
- true
- bin\x86\DebugMono\
- TRACE;DEBUG;PYTHON27,UCS4
- true
- false
- full
- x86
- false
- false
- false
-
-
- true
- bin\x64\DebugMono\
- TRACE;DEBUG;PYTHON27,UCS4
- true
- false
- full
- x64
-
-
- true
- bin\x86\DebugWin\
- TRACE;DEBUG;PYTHON27,UCS2
- true
- false
- full
- x86
- false
- false
- false
-
-
- true
- bin\x64\DebugWin\
- TRACE;DEBUG;PYTHON27,UCS2
- true
- false
- full
- x64
-
-
-
-
-
- False
- ..\..\packages\MonoGAC\Mono.Posix\4.0.0.0__0738eb9f132ed756\Mono.Posix.dll
-
-
-
-
-
-
- False
- ..\..\packages\MonoGAC\Mono.Posix\4.0.0.0__0738eb9f132ed756\Mono.Posix.dll
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Debug
+ x86
+ {097B4AC0-74E9-4C58-BCF8-C69746EC8271}
+ Library
+ false
+ Python.Runtime
+ Python.Runtime
+ ..\..\
+ $(SolutionDir)
+
+
+ bin\x86\ReleaseMono\
+ PYTHON27, UCS4
+ true
+ true
+ pdbonly
+ x86
+ false
+ true
+ PYTHON27,UCS2
+
+
+ bin\x64\ReleaseMono\
+ PYTHON27, UCS4
+ true
+ true
+ pdbonly
+ x64
+ false
+ true
+
+
+ bin\x86\ReleaseWin\
+ PYTHON27, UCS2
+ true
+ true
+ pdbonly
+ x86
+ false
+ true
+
+
+ bin\x64\ReleaseWin\
+ PYTHON27, UCS2
+ true
+ true
+ pdbonly
+ x64
+ false
+ true
+
+
+ true
+ bin\x86\DebugMono\
+ TRACE;DEBUG;PYTHON27,UCS4
+ true
+ false
+ full
+ x86
+ false
+ false
+ false
+
+
+ true
+ bin\x64\DebugMono\
+ TRACE;DEBUG;PYTHON27,UCS4
+ true
+ false
+ full
+ x64
+
+
+ true
+ bin\x86\DebugWin\
+ TRACE;DEBUG;PYTHON27,UCS2
+ true
+ false
+ full
+ x86
+ false
+ false
+ false
+
+
+ true
+ bin\x64\DebugWin\
+ TRACE;DEBUG;PYTHON27,UCS2
+ true
+ false
+ full
+ x64
+
+
+
+
+
+ False
+ ..\..\packages\MonoGAC\Mono.Posix\4.0.0.0__0738eb9f132ed756\Mono.Posix.dll
+
+
+
+
+
+
+ False
+ ..\..\packages\MonoGAC\Mono.Posix\4.0.0.0__0738eb9f132ed756\Mono.Posix.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clr.py
+
+
+
+
+
+
+
+ $(TargetPath)
+ $(TargetDir)$(TargetName).pdb
+
+
+
+
+
+
diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs
index 583b5c945..35badb71a 100644
--- a/src/runtime/assemblymanager.cs
+++ b/src/runtime/assemblymanager.cs
@@ -282,7 +282,7 @@ public static bool LoadImplicit(string name, bool warn=true) {
// be valid namespaces (to better match Python import semantics).
//===================================================================
- static void ScanAssembly(Assembly assembly) {
+ internal 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
@@ -291,8 +291,8 @@ static void ScanAssembly(Assembly 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 ns = t.Namespace ?? "";
+ if (!namespaces.ContainsKey(ns)) {
string[] names = ns.Split('.');
string s = "";
for (int n = 0; n < names.Length; n++) {
@@ -336,6 +336,16 @@ public static bool IsValidNamespace(string name) {
return namespaces.ContainsKey(name);
}
+ //===================================================================
+ // Returns list of assemblies that declare types in a given namespace
+ //===================================================================
+
+ public static IEnumerable GetAssemblies(string nsname) {
+ if (!namespaces.ContainsKey(nsname))
+ return new List();
+
+ return namespaces[nsname].Keys;
+ }
//===================================================================
// Returns the current list of valid names for the input namespace.
@@ -357,7 +367,7 @@ public static List GetNames(string nsname) {
Type[] types = a.GetTypes();
for (int i = 0; i < types.Length; i++) {
Type t = types[i];
- if (t.Namespace == nsname) {
+ if ((t.Namespace ?? "") == nsname) {
names.Add(t.Name);
}
}
diff --git a/src/runtime/buildclrmodule.bat b/src/runtime/buildclrmodule.bat
index 125ff9090..549902d7f 100644
--- a/src/runtime/buildclrmodule.bat
+++ b/src/runtime/buildclrmodule.bat
@@ -1,36 +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%==x86 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 or 3.5
-:::%windir%\Microsoft.NET\Framework\v2.0.50727\ilasm /nologo /quiet /dll %ILASM_EXTRA_ARGS% /include=%INCLUDE_PATH% /output=%OUTPUT_PATH% %INPUT_PATH%
+:: 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%==x86 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 or 3.5
+:::%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/src/runtime/classbase.cs b/src/runtime/classbase.cs
index 1541b12cd..09c4d65b5 100644
--- a/src/runtime/classbase.cs
+++ b/src/runtime/classbase.cs
@@ -57,7 +57,48 @@ public virtual IntPtr type_subscript(IntPtr idx) {
//====================================================================
// Standard comparison implementation for instances of reflected types.
//====================================================================
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ public static IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) {
+ if (op != Runtime.Py_EQ && op != Runtime.Py_NE)
+ {
+ Runtime.Incref(Runtime.PyNotImplemented);
+ return Runtime.PyNotImplemented;
+ }
+
+ IntPtr pytrue = Runtime.PyTrue;
+ IntPtr pyfalse = Runtime.PyFalse;
+
+ // swap true and false for NE
+ if (op != Runtime.Py_EQ)
+ {
+ pytrue = Runtime.PyFalse;
+ pyfalse = Runtime.PyTrue;
+ }
+
+ if (ob == other) {
+ Runtime.Incref(pytrue);
+ return pytrue;
+ }
+
+ CLRObject co1 = GetManagedObject(ob) as CLRObject;
+ CLRObject co2 = GetManagedObject(other) as CLRObject;
+ if (null == co2) {
+ Runtime.Incref(pyfalse);
+ return pyfalse;
+ }
+ Object o1 = co1.inst;
+ Object o2 = co2.inst;
+
+ if (Object.Equals(o1, o2)) {
+ Runtime.Incref(pytrue);
+ return pytrue;
+ }
+
+ Runtime.Incref(pyfalse);
+ return pyfalse;
+ }
+#else
public static int tp_compare(IntPtr ob, IntPtr other) {
if (ob == other) {
return 0;
@@ -73,6 +114,7 @@ public static int tp_compare(IntPtr ob, IntPtr other) {
}
return -1;
}
+#endif
//====================================================================
@@ -128,7 +170,17 @@ public static IntPtr tp_str(IntPtr ob) {
if (co == null) {
return Exceptions.RaiseTypeError("invalid object");
}
- return Runtime.PyString_FromString(co.inst.ToString());
+ try {
+ return Runtime.PyString_FromString(co.inst.ToString());
+ }
+ catch (Exception e)
+ {
+ if (e.InnerException != null) {
+ e = e.InnerException;
+ }
+ Exceptions.SetError(e);
+ return IntPtr.Zero;
+ }
}
@@ -154,7 +206,7 @@ public static int tp_is_gc(IntPtr type) {
public static void tp_dealloc(IntPtr ob) {
ManagedType self = GetManagedObject(ob);
- IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.ob_dict);
+ IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.DictOffset(ob));
if (dict != IntPtr.Zero) {
Runtime.Decref(dict);
}
diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs
new file mode 100644
index 000000000..685becef9
--- /dev/null
+++ b/src/runtime/classderived.cs
@@ -0,0 +1,855 @@
+// ==========================================================================
+// 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.Reflection;
+using System.Reflection.Emit;
+using System.Collections.Generic;
+using System.Threading;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+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.
+ ///
+
+ // interface used to idenfity which C# types were dynamically created as python subclasses
+ public interface IPythonDerivedType
+ {
+ }
+
+ internal class ClassDerivedObject : ClassObject
+ {
+ static private Dictionary assemblyBuilders;
+ static private Dictionary, ModuleBuilder> moduleBuilders;
+
+ static ClassDerivedObject()
+ {
+ assemblyBuilders = new Dictionary();
+ moduleBuilders = new Dictionary, ModuleBuilder>();
+ }
+
+ internal ClassDerivedObject(Type tp)
+ : base(tp)
+ {
+ }
+
+ ///
+ /// Implements __new__ for derived classes of reflected classes.
+ ///
+ new public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw)
+ {
+ ClassDerivedObject cls = GetManagedObject(tp) as ClassDerivedObject;
+
+ // call the managed constructor
+ Object obj = cls.binder.InvokeRaw(IntPtr.Zero, args, kw);
+ if (obj == null)
+ return IntPtr.Zero;
+
+ // return the pointer to the python object
+ // (this indirectly calls ClassDerivedObject.ToPython)
+ return Converter.ToPython(obj, cls.GetType());
+ }
+
+ new public static void tp_dealloc(IntPtr ob)
+ {
+ CLRObject self = (CLRObject)GetManagedObject(ob);
+
+ // don't let the python GC destroy this object
+ Runtime.PyObject_GC_UnTrack(self.pyHandle);
+
+ // The python should now have a ref count of 0, but we don't actually want to
+ // deallocate the object until the C# object that references it is destroyed.
+ // So we don't call PyObject_GC_Del here and instead we set the python
+ // reference to a weak reference so that the C# object can be collected.
+ GCHandle gc = GCHandle.Alloc(self, GCHandleType.Weak);
+ Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc);
+ self.gcHandle.Free();
+ self.gcHandle = gc;
+ }
+
+ // Called from Converter.ToPython for types that are python subclasses of managed types.
+ // The referenced python object is returned instead of a new wrapper.
+ internal static IntPtr ToPython(IPythonDerivedType obj)
+ {
+ // derived types have a __pyobj__ field that gets set to the python
+ // object in the overriden constructor
+ FieldInfo fi = obj.GetType().GetField("__pyobj__");
+ CLRObject self = (CLRObject)fi.GetValue(obj);
+
+ Runtime.Incref(self.pyHandle);
+
+ // when the C# constructor creates the python object it starts as a weak
+ // reference with a reference count of 0. Now we're passing this object
+ // to Python the reference count needs to be incremented and the reference
+ // needs to be replaced with a strong reference to stop the C# object being
+ // collected while Python still has a reference to it.
+ if (Runtime.Refcount(self.pyHandle) == 1)
+ {
+ GCHandle gc = GCHandle.Alloc(self, GCHandleType.Normal);
+ Marshal.WriteIntPtr(self.pyHandle, ObjectOffset.magic(self.tpHandle), (IntPtr)gc);
+ self.gcHandle.Free();
+ self.gcHandle = gc;
+
+ // now the object has a python reference it's safe for the python GC to track it
+ Runtime.PyObject_GC_Track(self.pyHandle);
+ }
+
+ return self.pyHandle;
+ }
+
+ ///
+ /// Creates a new managed type derived from a base type with any virtual
+ /// methods overriden to call out to python if the associated python
+ /// object has overriden the method.
+ ///
+ internal static Type CreateDerivedType(string name,
+ Type baseType,
+ IntPtr py_dict,
+ string namespaceStr,
+ string assemblyName,
+ string moduleName="Python.Runtime.Dynamic.dll")
+ {
+ if (null != namespaceStr)
+ name = namespaceStr + "." + name;
+
+ if (null == assemblyName)
+ assemblyName = Assembly.GetExecutingAssembly().FullName;
+
+ ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName);
+ TypeBuilder typeBuilder;
+
+ Type baseClass = baseType;
+ List interfaces = new List { typeof(IPythonDerivedType) };
+
+ // if the base type is an interface then use System.Object as the base class
+ // and add the base type to the list of interfaces this new class will implement.
+ if (baseType.IsInterface)
+ {
+ interfaces.Add(baseType);
+ baseClass = typeof(System.Object);
+ }
+
+ typeBuilder = moduleBuilder.DefineType(name,
+ TypeAttributes.Public | TypeAttributes.Class,
+ baseClass,
+ interfaces.ToArray());
+
+ // add a field for storing the python object pointer
+ FieldBuilder fb = typeBuilder.DefineField("__pyobj__", typeof(CLRObject), FieldAttributes.Public);
+
+ // override any constructors
+ ConstructorInfo[] constructors = baseClass.GetConstructors();
+ foreach (ConstructorInfo ctor in constructors)
+ {
+ AddConstructor(ctor, baseType, typeBuilder);
+ }
+
+ // Override any properties explicitly overriden in python
+ HashSet pyProperties = new HashSet();
+ if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict))
+ {
+ Runtime.Incref(py_dict);
+ using (PyDict dict = new PyDict(py_dict))
+ using (PyObject keys = dict.Keys())
+ {
+ foreach (PyObject pyKey in keys)
+ {
+ using (PyObject value = dict[pyKey])
+ if (value.HasAttr("_clr_property_type_"))
+ {
+ string propertyName = pyKey.ToString();
+ pyProperties.Add(propertyName);
+
+ // Add the property to the type
+ AddPythonProperty(propertyName, value, typeBuilder);
+ }
+ }
+ }
+ }
+
+ // override any virtual methods not already overriden by the properties above
+ MethodInfo[] methods = baseType.GetMethods();
+ HashSet virtualMethods = new HashSet();
+ foreach (MethodInfo method in methods)
+ {
+ if (!method.Attributes.HasFlag(MethodAttributes.Virtual) | method.Attributes.HasFlag(MethodAttributes.Final))
+ continue;
+
+ // skip if this property has already been overriden
+ if ((method.Name.StartsWith("get_") || method.Name.StartsWith("set_"))
+ && pyProperties.Contains(method.Name.Substring(4)))
+ continue;
+
+ // keep track of the virtual methods redirected to the python instance
+ virtualMethods.Add(method.Name);
+
+ // override the virtual method to call out to the python method, if there is one.
+ AddVirtualMethod(method, baseType, typeBuilder);
+ }
+
+ // Add any additional methods and properties explicitly exposed from Python.
+ if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict))
+ {
+ Runtime.Incref(py_dict);
+ using (PyDict dict = new PyDict(py_dict))
+ using (PyObject keys = dict.Keys())
+ {
+ foreach (PyObject pyKey in keys)
+ {
+ using (PyObject value = dict[pyKey])
+ if (value.HasAttr("_clr_return_type_") && value.HasAttr("_clr_arg_types_"))
+ {
+ string methodName = pyKey.ToString();
+
+ // if this method has already been redirected to the python method skip it
+ if (virtualMethods.Contains(methodName))
+ continue;
+
+ // Add the method to the type
+ AddPythonMethod(methodName, value, typeBuilder);
+ }
+ }
+ }
+ }
+
+ // add the destructor so the python object created in the constructor gets destroyed
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod("Finalize",
+ MethodAttributes.Family |
+ MethodAttributes.Virtual |
+ MethodAttributes.HideBySig,
+ CallingConventions.Standard,
+ typeof(void),
+ Type.EmptyTypes);
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("Finalize"));
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Call, baseClass.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance));
+ il.Emit(OpCodes.Ret);
+
+ Type type = typeBuilder.CreateType();
+
+ // scan the assembly so the newly added class can be imported
+ Assembly assembly = Assembly.GetAssembly(type);
+ AssemblyManager.ScanAssembly(assembly);
+
+ AssemblyBuilder assemblyBuilder = assemblyBuilders[assemblyName];
+
+ return type;
+ }
+
+ ///
+ /// Add a constructor override that calls the python ctor after calling the base type constructor.
+ ///
+ /// constructor to be called before calling the python ctor
+ /// Python callable object
+ /// TypeBuilder for the new type the ctor is to be added to
+ private static void AddConstructor(ConstructorInfo ctor, Type baseType, TypeBuilder typeBuilder)
+ {
+ ParameterInfo[] parameters = ctor.GetParameters();
+ Type[] parameterTypes = (from param in parameters select param.ParameterType).ToArray();
+
+ // create a method for calling the original constructor
+ string baseCtorName = "_" + baseType.Name + "__cinit__";
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod(baseCtorName,
+ MethodAttributes.Public |
+ MethodAttributes.Final |
+ MethodAttributes.HideBySig,
+ typeof(void),
+ parameterTypes);
+
+ // emit the assembly for calling the original method using call instead of callvirt
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_0);
+ for (int i = 0; i < parameters.Length; ++i)
+ il.Emit(OpCodes.Ldarg, i + 1);
+ il.Emit(OpCodes.Call, ctor);
+ il.Emit(OpCodes.Ret);
+
+ // override the original method with a new one that dispatches to python
+ ConstructorBuilder cb = typeBuilder.DefineConstructor(MethodAttributes.Public |
+ MethodAttributes.ReuseSlot |
+ MethodAttributes.HideBySig,
+ ctor.CallingConvention,
+ parameterTypes);
+ il = cb.GetILGenerator();
+ il.DeclareLocal(typeof(Object[]));
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldstr, baseCtorName);
+ il.Emit(OpCodes.Ldc_I4, parameters.Length);
+ il.Emit(OpCodes.Newarr, typeof(System.Object));
+ il.Emit(OpCodes.Stloc_0);
+ for (int i = 0; i < parameters.Length; ++i)
+ {
+ il.Emit(OpCodes.Ldloc_0);
+ il.Emit(OpCodes.Ldc_I4, i);
+ il.Emit(OpCodes.Ldarg, i + 1);
+ if (parameterTypes[i].IsValueType)
+ il.Emit(OpCodes.Box, parameterTypes[i]);
+ il.Emit(OpCodes.Stelem, typeof(Object));
+ }
+ il.Emit(OpCodes.Ldloc_0);
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeCtor"));
+ il.Emit(OpCodes.Ret);
+ }
+
+ ///
+ /// Add a virtual method override that checks for an override on the python instance
+ /// and calls it, otherwise fall back to the base class method.
+ ///
+ /// virtual method to be overriden
+ /// Python callable object
+ /// TypeBuilder for the new type the method is to be added to
+ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuilder typeBuilder)
+ {
+
+ ParameterInfo[] parameters = method.GetParameters();
+ Type[] parameterTypes = (from param in parameters select param.ParameterType).ToArray();
+
+ // create a method for calling the original method
+ string baseMethodName = "_" + baseType.Name + "__" + method.Name;
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod(baseMethodName,
+ MethodAttributes.Public |
+ MethodAttributes.Final |
+ MethodAttributes.HideBySig,
+ method.ReturnType,
+ parameterTypes);
+
+ // emit the assembly for calling the original method using call instead of callvirt
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_0);
+ for (int i = 0; i < parameters.Length; ++i)
+ il.Emit(OpCodes.Ldarg, i + 1);
+ il.Emit(OpCodes.Call, method);
+ il.Emit(OpCodes.Ret);
+
+ // override the original method with a new one that dispatches to python
+ methodBuilder = typeBuilder.DefineMethod(method.Name,
+ MethodAttributes.Public |
+ MethodAttributes.ReuseSlot |
+ MethodAttributes.Virtual |
+ MethodAttributes.HideBySig,
+ method.CallingConvention,
+ method.ReturnType,
+ parameterTypes);
+ il = methodBuilder.GetILGenerator();
+ il.DeclareLocal(typeof(Object[]));
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldstr, method.Name);
+ il.Emit(OpCodes.Ldstr, baseMethodName);
+ il.Emit(OpCodes.Ldc_I4, parameters.Length);
+ il.Emit(OpCodes.Newarr, typeof(System.Object));
+ il.Emit(OpCodes.Stloc_0);
+ for (int i = 0; i < parameters.Length; ++i)
+ {
+ il.Emit(OpCodes.Ldloc_0);
+ il.Emit(OpCodes.Ldc_I4, i);
+ il.Emit(OpCodes.Ldarg, i + 1);
+ if (parameterTypes[i].IsValueType)
+ il.Emit(OpCodes.Box, parameterTypes[i]);
+ il.Emit(OpCodes.Stelem, typeof(Object));
+ }
+ il.Emit(OpCodes.Ldloc_0);
+ if (method.ReturnType == typeof(void))
+ {
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethodVoid"));
+ }
+ else
+ {
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethod").MakeGenericMethod(method.ReturnType));
+ }
+ il.Emit(OpCodes.Ret);
+ }
+
+ ///
+ /// Python method may have the following function attributes set to control how they're exposed:
+ /// - _clr_return_type_ - method return type (required)
+ /// - _clr_arg_types_ - list of method argument types (required)
+ /// - _clr_method_name_ - method name, if different from the python method name (optional)
+ ///
+ /// Method name to add to the type
+ /// Python callable object
+ /// TypeBuilder for the new type the method/property is to be added to
+ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilder typeBuilder)
+ {
+ if (func.HasAttr("_clr_method_name_"))
+ {
+ using (PyObject pyMethodName = func.GetAttr("_clr_method_name_"))
+ methodName = pyMethodName.ToString();
+ }
+
+ using (PyObject pyReturnType = func.GetAttr("_clr_return_type_"))
+ using (PyObject pyArgTypes = func.GetAttr("_clr_arg_types_"))
+ {
+ Type returnType = pyReturnType.AsManagedObject(typeof(Type)) as Type;
+ if (returnType == null)
+ returnType = typeof(void);
+
+ if (!pyArgTypes.IsIterable())
+ throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types");
+
+ List argTypes = new List();
+ foreach (PyObject pyArgType in pyArgTypes)
+ {
+ Type argType = pyArgType.AsManagedObject(typeof(Type)) as Type;
+ if (argType == null)
+ throw new ArgumentException("_clr_arg_types_ must be a list or tuple of CLR types");
+ argTypes.Add(argType);
+ }
+
+ // add the method to call back into python
+ MethodAttributes methodAttribs = MethodAttributes.Public |
+ MethodAttributes.Virtual |
+ MethodAttributes.ReuseSlot |
+ MethodAttributes.HideBySig;
+
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodName,
+ methodAttribs,
+ returnType,
+ argTypes.ToArray());
+
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.DeclareLocal(typeof(Object[]));
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldstr, methodName);
+ il.Emit(OpCodes.Ldnull); // don't fall back to the base type's method
+ il.Emit(OpCodes.Ldc_I4, argTypes.Count);
+ il.Emit(OpCodes.Newarr, typeof(System.Object));
+ il.Emit(OpCodes.Stloc_0);
+ for (int i = 0; i < argTypes.Count; ++i)
+ {
+ il.Emit(OpCodes.Ldloc_0);
+ il.Emit(OpCodes.Ldc_I4, i);
+ il.Emit(OpCodes.Ldarg, i + 1);
+ if (argTypes[i].IsValueType)
+ il.Emit(OpCodes.Box, argTypes[i]);
+ il.Emit(OpCodes.Stelem, typeof(Object));
+ }
+ il.Emit(OpCodes.Ldloc_0);
+ if (returnType == typeof(void))
+ {
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethodVoid"));
+ }
+ else
+ {
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethod").MakeGenericMethod(returnType));
+ }
+ il.Emit(OpCodes.Ret);
+ }
+ }
+
+ ///
+ /// Python properties may have the following function attributes set to control how they're exposed:
+ /// - _clr_property_type_ - property type (required)
+ ///
+ /// Property name to add to the type
+ /// Python property object
+ /// TypeBuilder for the new type the method/property is to be added to
+ private static void AddPythonProperty(string propertyName, PyObject func, TypeBuilder typeBuilder)
+ {
+ // add the method to call back into python
+ MethodAttributes methodAttribs = MethodAttributes.Public |
+ MethodAttributes.Virtual |
+ MethodAttributes.ReuseSlot |
+ MethodAttributes.HideBySig |
+ MethodAttributes.SpecialName;
+
+ using (PyObject pyPropertyType = func.GetAttr("_clr_property_type_"))
+ {
+ Type propertyType = pyPropertyType.AsManagedObject(typeof(Type)) as Type;
+ if (propertyType == null)
+ throw new ArgumentException("_clr_property_type must be a CLR type");
+
+ PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(propertyName,
+ PropertyAttributes.None,
+ propertyType,
+ null);
+
+ if (func.HasAttr("fget"))
+ {
+ using (PyObject pyfget = func.GetAttr("fget"))
+ if (pyfget.IsTrue())
+ {
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod("get_" + propertyName,
+ methodAttribs,
+ propertyType,
+ null);
+
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldstr, propertyName);
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeGetProperty").MakeGenericMethod(propertyType));
+ il.Emit(OpCodes.Ret);
+
+ propertyBuilder.SetGetMethod(methodBuilder);
+ }
+ }
+
+ if (func.HasAttr("fset"))
+ {
+ using (PyObject pyset = func.GetAttr("fset"))
+ if (pyset.IsTrue())
+ {
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod("set_" + propertyName,
+ methodAttribs,
+ null,
+ new Type[]{propertyType});
+
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldstr, propertyName);
+ il.Emit(OpCodes.Ldarg_1);
+ il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeSetProperty").MakeGenericMethod(propertyType));
+ il.Emit(OpCodes.Ret);
+
+ propertyBuilder.SetSetMethod(methodBuilder);
+ }
+ }
+ }
+ }
+
+ private static ModuleBuilder GetModuleBuilder(string assemblyName, string moduleName)
+ {
+ // find or create a dynamic assembly and module
+ AppDomain domain = AppDomain.CurrentDomain;
+ ModuleBuilder moduleBuilder = null;
+
+ if (moduleBuilders.ContainsKey(Tuple.Create(assemblyName, moduleName)))
+ {
+ moduleBuilder = moduleBuilders[Tuple.Create(assemblyName, moduleName)];
+ }
+ else
+ {
+ AssemblyBuilder assemblyBuilder = null;
+ if (assemblyBuilders.ContainsKey(assemblyName))
+ {
+ assemblyBuilder = assemblyBuilders[assemblyName];
+ }
+ else
+ {
+ assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName(assemblyName),
+ AssemblyBuilderAccess.Run);
+ assemblyBuilders[assemblyName] = assemblyBuilder;
+ }
+
+ moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName);
+ moduleBuilders[Tuple.Create(assemblyName, moduleName)] = moduleBuilder;
+ }
+
+ return moduleBuilder;
+ }
+ }
+
+ //
+ // PythonDerivedType contains static methods used by the dynamically created
+ // derived type that allow it to call back into python from overriden virtual
+ // methods, and also handle the construction and destruction of the python
+ // object.
+ //
+ // This has to be public as it's called from methods on dynamically built classes
+ // potentially in other assemblies.
+ //
+ public class PythonDerivedType
+ {
+ //====================================================================
+ // This is the implementaion of the overriden methods in the derived
+ // type. It looks for a python method with the same name as the method
+ // on the managed base class and if it exists and isn't the managed
+ // method binding (ie it has been overriden in the derived python
+ // class) it calls it, otherwise it calls the base method.
+ //====================================================================
+ public static T InvokeMethod(IPythonDerivedType obj, string methodName, string origMethodName, Object[] args)
+ {
+ FieldInfo fi = obj.GetType().GetField("__pyobj__");
+ CLRObject self = (CLRObject)fi.GetValue(obj);
+
+ if (null != self)
+ {
+ List disposeList = new List();
+ IntPtr gs = Runtime.PyGILState_Ensure();
+ try
+ {
+ Runtime.Incref(self.pyHandle);
+ PyObject pyself = new PyObject(self.pyHandle);
+ disposeList.Add(pyself);
+
+ Runtime.Incref(Runtime.PyNone);
+ PyObject pynone = new PyObject(Runtime.PyNone);
+ disposeList.Add(pynone);
+
+ PyObject method = pyself.GetAttr(methodName, pynone);
+ disposeList.Add(method);
+ if (method.Handle != Runtime.PyNone)
+ {
+ // if the method hasn't been overriden then it will be a managed object
+ ManagedType managedMethod = ManagedType.GetManagedObject(method.Handle);
+ if (null == managedMethod)
+ {
+ PyObject[] pyargs = new PyObject[args.Length];
+ for (int i = 0; i < args.Length; ++i)
+ {
+ pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i]));
+ disposeList.Add(pyargs[i]);
+ }
+
+ PyObject py_result = method.Invoke(pyargs);
+ disposeList.Add(py_result);
+ return (T)py_result.AsManagedObject(typeof(T));
+ }
+ }
+ }
+ finally
+ {
+ foreach (PyObject x in disposeList) {
+ if (x != null)
+ x.Dispose();
+ }
+ Runtime.PyGILState_Release(gs);
+ }
+ }
+
+ if (origMethodName == null)
+ throw new NullReferenceException("Python object does not have a '" + methodName + "' method");
+
+ return (T)obj.GetType().InvokeMember(origMethodName,
+ BindingFlags.InvokeMethod,
+ null,
+ obj,
+ args);
+ }
+
+ public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, string origMethodName, Object[] args)
+ {
+ FieldInfo fi = obj.GetType().GetField("__pyobj__");
+ CLRObject self = (CLRObject)fi.GetValue(obj);
+ if (null != self)
+ {
+ List disposeList = new List();
+ IntPtr gs = Runtime.PyGILState_Ensure();
+ try
+ {
+ Runtime.Incref(self.pyHandle);
+ PyObject pyself = new PyObject(self.pyHandle);
+ disposeList.Add(pyself);
+
+ Runtime.Incref(Runtime.PyNone);
+ PyObject pynone = new PyObject(Runtime.PyNone);
+ disposeList.Add(pynone);
+
+ PyObject method = pyself.GetAttr(methodName, pynone);
+ disposeList.Add(method);
+ if (method.Handle != Runtime.PyNone)
+ {
+ // if the method hasn't been overriden then it will be a managed object
+ ManagedType managedMethod = ManagedType.GetManagedObject(method.Handle);
+ if (null == managedMethod)
+ {
+ PyObject[] pyargs = new PyObject[args.Length];
+ for (int i = 0; i < args.Length; ++i)
+ {
+ pyargs[i] = new PyObject(Converter.ToPythonImplicit(args[i]));
+ disposeList.Add(pyargs[i]);
+ }
+
+ PyObject py_result = method.Invoke(pyargs);
+ disposeList.Add(py_result);
+ return;
+ }
+ }
+ }
+ finally
+ {
+ foreach (PyObject x in disposeList) {
+ if (x != null)
+ x.Dispose();
+ }
+ Runtime.PyGILState_Release(gs);
+ }
+ }
+
+ if (origMethodName == null)
+ throw new NullReferenceException("Python object does not have a '" + methodName + "' method");
+
+ obj.GetType().InvokeMember(origMethodName,
+ BindingFlags.InvokeMethod,
+ null,
+ obj,
+ args);
+ }
+
+ public static T InvokeGetProperty(IPythonDerivedType obj, string propertyName)
+ {
+ FieldInfo fi = obj.GetType().GetField("__pyobj__");
+ CLRObject self = (CLRObject)fi.GetValue(obj);
+
+ if (null == self)
+ throw new NullReferenceException("Instance must be specified when getting a property");
+
+ IntPtr gs = Runtime.PyGILState_Ensure();
+ try
+ {
+ Runtime.Incref(self.pyHandle);
+ using (PyObject pyself = new PyObject(self.pyHandle))
+ using (PyObject pyvalue = pyself.GetAttr(propertyName))
+ return (T)pyvalue.AsManagedObject(typeof(T));
+ }
+ finally
+ {
+ Runtime.PyGILState_Release(gs);
+ }
+ }
+
+ public static void InvokeSetProperty(IPythonDerivedType obj, string propertyName, T value)
+ {
+ FieldInfo fi = obj.GetType().GetField("__pyobj__");
+ CLRObject self = (CLRObject)fi.GetValue(obj);
+
+ if (null == self)
+ throw new NullReferenceException("Instance must be specified when setting a property");
+
+ IntPtr gs = Runtime.PyGILState_Ensure();
+ try
+ {
+ Runtime.Incref(self.pyHandle);
+ using (PyObject pyself = new PyObject(self.pyHandle))
+ using (PyObject pyvalue = new PyObject(Converter.ToPythonImplicit(value)))
+ pyself.SetAttr(propertyName, pyvalue);
+ }
+ finally
+ {
+ Runtime.PyGILState_Release(gs);
+ }
+ }
+
+ public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, Object[] args)
+ {
+ // call the base constructor
+ obj.GetType().InvokeMember(origCtorName,
+ BindingFlags.InvokeMethod,
+ null,
+ obj,
+ args);
+
+ List disposeList = new List();
+ CLRObject self = null;
+ IntPtr gs = Runtime.PyGILState_Ensure();
+ try
+ {
+ // create the python object
+ IntPtr type = TypeManager.GetTypeHandle(obj.GetType());
+ self = new CLRObject(obj, type);
+
+ // set __pyobj__ to self and deref the python object which will allow this
+ // object to be collected.
+ FieldInfo fi = obj.GetType().GetField("__pyobj__");
+ fi.SetValue(obj, self);
+
+ Runtime.Incref(self.pyHandle);
+ PyObject pyself = new PyObject(self.pyHandle);
+ disposeList.Add(pyself);
+
+ Runtime.Incref(Runtime.PyNone);
+ PyObject pynone = new PyObject(Runtime.PyNone);
+ disposeList.Add(pynone);
+
+ // call __init__
+ PyObject init = pyself.GetAttr("__init__", pynone);
+ disposeList.Add(init);
+ if (init.Handle != Runtime.PyNone)
+ {
+ // if __init__ hasn't been overriden then it will be a managed object
+ ManagedType managedMethod = ManagedType.GetManagedObject(init.Handle);
+ if (null == managedMethod)
+ {
+ PyObject[] pyargs = new PyObject[args.Length];
+ for (int i = 0; i < args.Length; ++i)
+ {
+ pyargs[i] = new PyObject(Converter.ToPython(args[i], args[i].GetType()));
+ disposeList.Add(pyargs[i]);
+ }
+
+ disposeList.Add(init.Invoke(pyargs));
+ }
+ }
+ }
+ finally
+ {
+ foreach (PyObject x in disposeList) {
+ if (x != null)
+ x.Dispose();
+ }
+
+ // Decrement the python object's reference count.
+ // This doesn't actually destroy the object, it just sets the reference to this object
+ // to be a weak reference and it will be destroyed when the C# object is destroyed.
+ if (null != self)
+ Runtime.Decref(self.pyHandle);
+
+ Runtime.PyGILState_Release(gs);
+ }
+ }
+
+ public static void Finalize(IPythonDerivedType obj)
+ {
+ FieldInfo fi = obj.GetType().GetField("__pyobj__");
+ CLRObject self = (CLRObject)fi.GetValue(obj);
+
+ // If python's been terminated then just free the gchandle.
+ lock (Runtime.IsFinalizingLock)
+ {
+ if (0 == Runtime.Py_IsInitialized() || Runtime.IsFinalizing)
+ {
+ self.gcHandle.Free();
+ return;
+ }
+ }
+
+ // delete the python object in an asnyc task as we may not be able to acquire
+ // the GIL immediately and we don't want to block the GC thread.
+ var t = Task.Factory.StartNew(() =>
+ {
+ lock (Runtime.IsFinalizingLock)
+ {
+ // If python's been terminated then just free the gchandle.
+ if (0 == Runtime.Py_IsInitialized() || Runtime.IsFinalizing)
+ {
+ self.gcHandle.Free();
+ return;
+ }
+
+ IntPtr gs = Runtime.PyGILState_Ensure();
+ try
+ {
+ // the C# object is being destroyed which must mean there are no more
+ // references to the Python object as well so now we can dealloc the
+ // python object.
+ IntPtr dict = Marshal.ReadIntPtr(self.pyHandle, ObjectOffset.DictOffset(self.pyHandle));
+ if (dict != IntPtr.Zero)
+ Runtime.Decref(dict);
+ Runtime.PyObject_GC_Del(self.pyHandle);
+ self.gcHandle.Free();
+ }
+ finally
+ {
+ Runtime.PyGILState_Release(gs);
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs
index 164c37cb6..8744de417 100644
--- a/src/runtime/classmanager.cs
+++ b/src/runtime/classmanager.cs
@@ -105,7 +105,12 @@ private static ClassBase CreateClass(Type type) {
impl = new ExceptionClassObject(type);
}
- else {
+ else if (null != type.GetField("__pyobj__")) {
+ impl = new ClassDerivedObject(type);
+ }
+
+ else
+ {
impl = new ClassObject(type);
}
@@ -345,7 +350,7 @@ private static ClassInfo GetClassInfo(Type type) {
typeof(MethodInfo)
);
- ob = new MethodObject(name, mlist);
+ ob = new MethodObject(type, name, mlist);
ci.members[name] = ob;
}
diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs
index c61f9523d..1de49aede 100644
--- a/src/runtime/clrobject.cs
+++ b/src/runtime/clrobject.cs
@@ -25,15 +25,15 @@ internal CLRObject(Object ob, IntPtr tp) : base() {
int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags);
if ((flags & TypeFlags.Subclass) != 0) {
- IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.ob_dict);
+ IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.DictOffset(tp));
if (dict == IntPtr.Zero) {
dict = Runtime.PyDict_New();
- Marshal.WriteIntPtr(py, ObjectOffset.ob_dict, dict);
+ Marshal.WriteIntPtr(py, ObjectOffset.DictOffset(tp), dict);
}
}
GCHandle gc = GCHandle.Alloc(this);
- Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc);
+ Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (IntPtr)gc);
this.tpHandle = tp;
this.pyHandle = py;
this.gcHandle = gc;
diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs
index 650a6178a..4d0c06c11 100644
--- a/src/runtime/converter.cs
+++ b/src/runtime/converter.cs
@@ -12,6 +12,7 @@
using System.Runtime.InteropServices;
using System.Globalization;
using System.Security;
+using System.Collections;
namespace Python.Runtime {
@@ -33,7 +34,7 @@ private Converter() {}
static Type int64Type;
static Type flagsType;
static Type boolType;
- //static Type typeType;
+ static Type typeType;
static Converter () {
nfi = NumberFormatInfo.InvariantInfo;
@@ -44,7 +45,7 @@ static Converter () {
doubleType = typeof(Double);
flagsType = typeof(FlagsAttribute);
boolType = typeof(Boolean);
- //typeType = typeof(Type);
+ typeType = typeof(Type);
}
@@ -91,6 +92,14 @@ internal static IntPtr ToPython(Object value, Type type) {
return result;
}
+ // it the type is a python subclass of a managed type then return the
+ // underying python object rather than construct a new wrapper object.
+ IPythonDerivedType pyderived = value as IPythonDerivedType;
+ if (null != pyderived)
+ {
+ return ClassDerivedObject.ToPython(pyderived);
+ }
+
// hmm - from Python, we almost never care what the declared
// type is. we'd rather have the object bound to the actual
// implementing class.
@@ -165,6 +174,16 @@ internal static IntPtr ToPython(Object value, Type type) {
return Runtime.PyLong_FromUnsignedLongLong((ulong)value);
default:
+ if (value is IEnumerable) {
+ using (var resultlist = new PyList()) {
+ foreach (object o in (IEnumerable)value) {
+ using (var p = new PyObject(ToPython(o, o.GetType())))
+ resultlist.Append(p);
+ }
+ Runtime.Incref(resultlist.Handle);
+ return resultlist.Handle;
+ }
+ }
result = CLRObject.GetInstHandle(value, type);
return result;
}
@@ -307,6 +326,57 @@ internal static bool ToManagedValue(IntPtr value, Type obType,
return false;
}
+ // Conversion to 'Type' is done using the same mappings as above
+ // for objects.
+
+ if (obType == typeType)
+ {
+ if (value == Runtime.PyStringType)
+ {
+ result = stringType;
+ return true;
+ }
+
+ else if (value == Runtime.PyBoolType)
+ {
+ result = boolType;
+ return true;
+ }
+
+ else if (value == Runtime.PyIntType)
+ {
+ result = int32Type;
+ return true;
+ }
+
+ else if (value == Runtime.PyLongType)
+ {
+ result = int64Type;
+ return true;
+ }
+
+ else if (value == Runtime.PyFloatType)
+ {
+ result = doubleType;
+ return true;
+ }
+
+ else if (value == Runtime.PyListType || value == Runtime.PyTupleType)
+ {
+ result = typeof(object[]);
+ return true;
+ }
+
+ if (setError)
+ {
+ Exceptions.SetError(Exceptions.TypeError,
+ "value cannot be converted to Type"
+ );
+ }
+
+ return false;
+ }
+
return ToPrimitive(value, obType, out result, setError);
}
@@ -335,6 +405,7 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.Int32:
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
// Trickery to support 64-bit platforms.
if (IntPtr.Size == 4) {
op = Runtime.PyNumber_Int(value);
@@ -357,6 +428,10 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
}
else {
+#else
+ // When using Python3 always use the PyLong API
+ {
+#endif
op = Runtime.PyNumber_Long(value);
if (op == IntPtr.Zero) {
if (Exceptions.ExceptionMatches(overflow)) {
@@ -381,6 +456,18 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.Byte:
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType))
+ {
+ if (Runtime.PyBytes_Size(value) == 1)
+ {
+ op = Runtime.PyBytes_AS_STRING(value);
+ result = (byte)Marshal.ReadByte(op);
+ return true;
+ }
+ goto type_error;
+ }
+#else
if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) {
if (Runtime.PyString_Size(value) == 1) {
op = Runtime.PyString_AS_STRING(value);
@@ -389,6 +476,7 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
}
goto type_error;
}
+#endif
op = Runtime.PyNumber_Int(value);
if (op == IntPtr.Zero) {
@@ -408,6 +496,16 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.SByte:
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) {
+ if (Runtime.PyBytes_Size(value) == 1) {
+ op = Runtime.PyBytes_AS_STRING(value);
+ result = (byte)Marshal.ReadByte(op);
+ return true;
+ }
+ goto type_error;
+ }
+#else
if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) {
if (Runtime.PyString_Size(value) == 1) {
op = Runtime.PyString_AS_STRING(value);
@@ -416,6 +514,7 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
}
goto type_error;
}
+#endif
op = Runtime.PyNumber_Int(value);
if (op == IntPtr.Zero) {
@@ -435,7 +534,16 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.Char:
-
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ if (Runtime.PyObject_TypeCheck(value, Runtime.PyBytesType)) {
+ if (Runtime.PyBytes_Size(value) == 1) {
+ op = Runtime.PyBytes_AS_STRING(value);
+ result = (byte)Marshal.ReadByte(op);
+ return true;
+ }
+ goto type_error;
+ }
+#else
if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) {
if (Runtime.PyString_Size(value) == 1) {
op = Runtime.PyString_AS_STRING(value);
@@ -444,7 +552,7 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
}
goto type_error;
}
-
+#endif
else if (Runtime.PyObject_TypeCheck(value,
Runtime.PyUnicodeType)) {
if (Runtime.PyUnicode_GetSize(value) == 1) {
@@ -713,10 +821,13 @@ static bool ToEnum(IntPtr value, Type obType, out Object result,
return false;
}
-
-
-
}
-
+ public static class ConverterExtension
+ {
+ public static PyObject ToPython(this object o)
+ {
+ return new PyObject(Converter.ToPython(o, o.GetType()));
+ }
+ }
}
diff --git a/src/runtime/delegateobject.cs b/src/runtime/delegateobject.cs
index 839fb71e5..473b2e81c 100644
--- a/src/runtime/delegateobject.cs
+++ b/src/runtime/delegateobject.cs
@@ -103,7 +103,36 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
//====================================================================
// Implements __cmp__ for reflected delegate types.
//====================================================================
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ public static new IntPtr tp_richcompare(IntPtr ob, IntPtr other, int op) {
+ if (op != Runtime.Py_EQ && op != Runtime.Py_NE)
+ {
+ Runtime.Incref(Runtime.PyNotImplemented);
+ return Runtime.PyNotImplemented;
+ }
+
+ IntPtr pytrue = Runtime.PyTrue;
+ IntPtr pyfalse = Runtime.PyFalse;
+
+ // swap true and false for NE
+ if (op != Runtime.Py_EQ)
+ {
+ pytrue = Runtime.PyFalse;
+ pyfalse = Runtime.PyTrue;
+ }
+
+ Delegate d1 = GetTrueDelegate(ob);
+ Delegate d2 = GetTrueDelegate(other);
+ if (d1 == d2)
+ {
+ Runtime.Incref(pytrue);
+ return pytrue;
+ }
+ Runtime.Incref(pyfalse);
+ return pyfalse;
+ }
+#else
public static new int tp_compare(IntPtr ob, IntPtr other) {
Delegate d1 = GetTrueDelegate(ob);
Delegate d2 = GetTrueDelegate(other);
@@ -112,7 +141,7 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
}
return -1;
}
-
+#endif
}
diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs
index f08217dac..2abf1f29d 100644
--- a/src/runtime/exceptions.cs
+++ b/src/runtime/exceptions.cs
@@ -31,7 +31,7 @@ internal class ExceptionClassObject : ClassObject {
internal ExceptionClassObject(Type tp) : base(tp) {
}
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
internal static Exception ToException(IntPtr ob) {
CLRObject co = GetManagedObject(ob) as CLRObject;
if (co == null) {
@@ -114,7 +114,7 @@ public static IntPtr tp_getattro(IntPtr ob, IntPtr key)
return Runtime.PyObject_GenericGetAttr(ob, key);
}
-#endif // (PYTHON25 || PYTHON26 || PYTHON27)
+#endif // (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
}
///
@@ -136,7 +136,11 @@ private Exceptions() {}
//===================================================================
internal static void Initialize() {
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ exceptions_module = Runtime.PyImport_ImportModule("builtins");
+#else
exceptions_module = Runtime.PyImport_ImportModule("exceptions");
+#endif
Exceptions.ErrorCheck(exceptions_module);
warnings_module = Runtime.PyImport_ImportModule("warnings");
Exceptions.ErrorCheck(warnings_module);
@@ -164,16 +168,19 @@ internal static void Initialize() {
//===================================================================
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);
+ if (0 != Runtime.Py_IsInitialized()) {
+ 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.PyObject_HasAttrString(warnings_module, "xx");
+ Runtime.Decref(warnings_module);
}
- Runtime.Decref(exceptions_module);
- Runtime.Decref(warnings_module);
}
///
@@ -565,15 +572,17 @@ internal static IntPtr RaiseTypeError(string message) {
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)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
public static IntPtr BaseException;
#endif
public static IntPtr Exception;
public static IntPtr StopIteration;
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
public static IntPtr GeneratorExit;
#endif
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
public static IntPtr StandardError;
+#endif
public static IntPtr ArithmeticError;
public static IntPtr LookupError;
@@ -628,7 +637,7 @@ puplic static variables on the Exceptions class filled in from
public static IntPtr SyntaxWarning;
public static IntPtr RuntimeWarning;
public static IntPtr FutureWarning;
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
public static IntPtr ImportWarning;
public static IntPtr UnicodeWarning;
//PyAPI_DATA(PyObject *) PyExc_BytesWarning;
diff --git a/src/runtime/extensiontype.cs b/src/runtime/extensiontype.cs
index b0499bb0a..75ac67e59 100644
--- a/src/runtime/extensiontype.cs
+++ b/src/runtime/extensiontype.cs
@@ -40,7 +40,7 @@ public ExtensionType() : base() {
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
GCHandle gc = GCHandle.Alloc(this);
- Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc);
+ Marshal.WriteIntPtr(py, ObjectOffset.magic(tp), (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
diff --git a/src/runtime/genericutil.cs b/src/runtime/genericutil.cs
index c3de0aa56..e646af098 100644
--- a/src/runtime/genericutil.cs
+++ b/src/runtime/genericutil.cs
@@ -37,6 +37,9 @@ static GenericUtil() {
//====================================================================
internal static void Register(Type t) {
+ if (null == t.Namespace || null == t.Name)
+ return;
+
Dictionary> nsmap = null;
mapping.TryGetValue(t.Namespace, out nsmap);
if (nsmap == null) {
diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index c736f0645..9b44b240c 100644
--- a/src/runtime/importhook.cs
+++ b/src/runtime/importhook.cs
@@ -23,29 +23,53 @@ internal class ImportHook {
static CLRModule root;
static MethodWrapper hook;
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ static IntPtr py_clr_module;
+ static IntPtr module_def;
+#endif
+
//===================================================================
// 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();
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ IntPtr mod = Runtime.PyImport_ImportModule("builtins");
+ py_import = Runtime.PyObject_GetAttrString(mod, "__import__");
+#else
IntPtr mod = Runtime.PyDict_GetItemString(dict, "__builtin__");
py_import = Runtime.PyObject_GetAttrString(mod, "__import__");
-
+#endif
hook = new MethodWrapper(typeof(ImportHook), "__import__");
Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
Runtime.Decref(hook.ptr);
root = new CLRModule();
+
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ // create a python module with the same methods as the clr module-like object
+ module_def = ModuleDefOffset.AllocModuleDef("clr");
+ py_clr_module = Runtime.PyModule_Create2(module_def, 3);
+
+ // both dicts are borrowed references
+ IntPtr mod_dict = Runtime.PyModule_GetDict(py_clr_module);
+ IntPtr clr_dict = Runtime._PyObject_GetDictPtr(root.pyHandle); // PyObject**
+ clr_dict = (IntPtr)Marshal.PtrToStructure(clr_dict, typeof(IntPtr));
+
+ Runtime.PyDict_Update(mod_dict, clr_dict);
+ Runtime.PyDict_SetItemString(dict, "CLR", py_clr_module);
+ Runtime.PyDict_SetItemString(dict, "clr", py_clr_module);
+#else
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);
+#endif
+
}
@@ -54,11 +78,74 @@ internal static void Initialize() {
//===================================================================
internal static void Shutdown() {
- Runtime.Decref(root.pyHandle);
- Runtime.Decref(root.pyHandle);
- Runtime.Decref(py_import);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ if (0 != Runtime.Py_IsInitialized()) {
+ Runtime.Decref(py_clr_module);
+ Runtime.Decref(root.pyHandle);
+ }
+ ModuleDefOffset.FreeModuleDef(module_def);
+#else
+ if (0 != Runtime.Py_IsInitialized()) {
+ Runtime.Decref(root.pyHandle);
+ Runtime.Decref(root.pyHandle);
+ }
+#endif
+ if (0 != Runtime.Py_IsInitialized()) {
+ Runtime.Decref(py_import);
+ }
}
+ //===================================================================
+ // Return the clr python module (new reference)
+ //===================================================================
+ public static IntPtr GetCLRModule(IntPtr? fromList=null) {
+ root.InitializePreload();
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ // update the module dictionary with the contents of the root dictionary
+ root.LoadNames();
+ IntPtr py_mod_dict = Runtime.PyModule_GetDict(py_clr_module);
+ IntPtr clr_dict = Runtime._PyObject_GetDictPtr(root.pyHandle); // PyObject**
+ clr_dict = (IntPtr)Marshal.PtrToStructure(clr_dict, typeof(IntPtr));
+ Runtime.PyDict_Update(py_mod_dict, clr_dict);
+
+ // find any items from the fromlist and get them from the root if they're not
+ // aleady in the module dictionary
+ if (fromList != null && fromList != IntPtr.Zero) {
+ if (Runtime.PyTuple_Check(fromList.GetValueOrDefault()))
+ {
+ Runtime.Incref(py_mod_dict);
+ using(PyDict mod_dict = new PyDict(py_mod_dict)) {
+ Runtime.Incref(fromList.GetValueOrDefault());
+ using (PyTuple from = new PyTuple(fromList.GetValueOrDefault())) {
+ foreach (PyObject item in from) {
+ if (mod_dict.HasKey(item))
+ continue;
+
+ string s = item.AsManagedObject(typeof(string)) as string;
+ if (null == s)
+ continue;
+
+ ManagedType attr = root.GetAttribute(s, true);
+ if (null == attr)
+ continue;
+
+ Runtime.Incref(attr.pyHandle);
+ using (PyObject obj = new PyObject(attr.pyHandle)) {
+ mod_dict.SetItem(s, obj);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Runtime.Incref(py_clr_module);
+ return py_clr_module;
+#else
+ Runtime.Incref(root.pyHandle);
+ return root.pyHandle;
+#endif
+ }
//===================================================================
// The actual import hook that ties Python to the managed world.
@@ -102,19 +189,31 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) {
// 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;
+ IntPtr clr_module = GetCLRModule(fromList);
+ if (clr_module != IntPtr.Zero) {
+ IntPtr sys_modules = Runtime.PyImport_GetModuleDict();
+ if (sys_modules != IntPtr.Zero) {
+ Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module);
+ }
+ }
+ return clr_module;
}
if (mod_name == "CLR") {
Exceptions.deprecation("The CLR module is deprecated. " +
"Please use 'clr'.");
- root.InitializePreload();
- Runtime.Incref(root.pyHandle);
- return root.pyHandle;
+ IntPtr clr_module = GetCLRModule(fromList);
+ if (clr_module != IntPtr.Zero) {
+ IntPtr sys_modules = Runtime.PyImport_GetModuleDict();
+ if (sys_modules != IntPtr.Zero) {
+ Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module);
+ }
+ }
+ return clr_module;
}
string realname = mod_name;
+ string clr_prefix = null;
if (mod_name.StartsWith("CLR.")) {
+ clr_prefix = "CLR."; // prepend when adding the module to sys.modules
realname = mod_name.Substring(4);
string msg = String.Format("Importing from the CLR.* namespace "+
"is deprecated. Please import '{0}' directly.", realname);
@@ -174,6 +273,9 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) {
Runtime.Incref(module);
return module;
}
+ if (clr_prefix != null) {
+ return GetCLRModule(fromList);
+ }
module = Runtime.PyDict_GetItemString(modules, names[0]);
Runtime.Incref(module);
return module;
@@ -209,9 +311,18 @@ public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) {
if (CLRModule.preload) {
tail.LoadNames();
}
- Runtime.PyDict_SetItemString(modules, tail.moduleName,
- tail.pyHandle
- );
+
+ // Add the module to sys.modules
+ Runtime.PyDict_SetItemString(modules,
+ tail.moduleName,
+ tail.pyHandle);
+
+ // If imported from CLR add CLR. to sys.modules as well
+ if (clr_prefix != null) {
+ Runtime.PyDict_SetItemString(modules,
+ clr_prefix + tail.moduleName,
+ tail.pyHandle);
+ }
}
ModuleObject mod = fromlist ? tail : head;
diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs
index 9aad4c6e4..401926082 100644
--- a/src/runtime/interop.cs
+++ b/src/runtime/interop.cs
@@ -12,6 +12,7 @@
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using System.Reflection;
+using System.Text;
namespace Python.Runtime {
@@ -77,11 +78,37 @@ static ObjectOffset() {
ob_data = (n+3) * size;
}
- public static int magic() {
+ public static int magic(IntPtr ob) {
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) ||
+ (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException))))
+ {
+ return ExceptionOffset.ob_data;
+ }
+#endif
return ob_data;
}
- public static int Size() {
+ public static int DictOffset(IntPtr ob)
+ {
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) ||
+ (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException))))
+ {
+ return ExceptionOffset.ob_dict;
+ }
+#endif
+ return ob_dict;
+ }
+
+ public static int Size(IntPtr ob) {
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ if ((Runtime.PyObject_TypeCheck(ob, Exceptions.BaseException) ||
+ (Runtime.PyType_Check(ob) && Runtime.PyType_IsSubtype(ob, Exceptions.BaseException))))
+ {
+ return ExceptionOffset.Size();
+ }
+#endif
#if (Py_DEBUG)
return 6 * IntPtr.Size;
#else
@@ -95,10 +122,43 @@ public static int Size() {
#endif
public static int ob_refcnt;
public static int ob_type;
+ private static int ob_dict;
+ private static int ob_data;
+ }
+
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ internal class ExceptionOffset
+ {
+ static ExceptionOffset()
+ {
+ Type type = typeof(ExceptionOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++)
+ {
+ fi[i].SetValue(null, (i * size) + ObjectOffset.ob_type + size);
+ }
+ }
+
+ public static int Size()
+ {
+ return ob_data + IntPtr.Size;
+ }
+
+ // PyException_HEAD
+ // (start after PyObject_HEAD)
+ public static int dict = 0;
+ public static int args = 0;
+ public static int traceback = 0;
+ public static int context = 0;
+ public static int cause = 0;
+
+ // extra c# data
public static int ob_dict;
public static int ob_data;
}
-
+#endif
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
internal class TypeOffset {
@@ -139,7 +199,7 @@ public static int magic() {
public static int tp_print = 0;
public static int tp_getattr = 0;
public static int tp_setattr = 0;
- public static int tp_compare = 0;
+ public static int tp_compare = 0; /* tp_reserved in Python 3 */
public static int tp_repr = 0;
/* Method suites for standard classes */
@@ -198,9 +258,12 @@ public static int magic() {
public static int tp_subclasses = 0;
public static int tp_weaklist = 0;
public static int tp_del = 0;
-#if (PYTHON26 || PYTHON27)
+#if (PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
/* Type attribute cache version tag. Added in version 2.6 */
public static int tp_version_tag;
+#endif
+#if (PYTHON34)
+ public static int tp_finalize = 0;
#endif
// COUNT_ALLOCS adds some more stuff to PyTypeObject
#if (Py_COUNT_ALLOCS)
@@ -212,11 +275,14 @@ public static int magic() {
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;
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
public static int nb_divide = 0;
+#endif
public static int nb_remainder = 0;
public static int nb_divmod = 0;
public static int nb_power = 0;
@@ -230,17 +296,23 @@ public static int magic() {
public static int nb_and = 0;
public static int nb_xor = 0;
public static int nb_or = 0;
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
public static int nb_coerce = 0;
+#endif
public static int nb_int = 0;
public static int nb_long = 0;
public static int nb_float = 0;
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
public static int nb_oct = 0;
public static int nb_hex = 0;
+#endif
/* 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;
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
public static int nb_inplace_divide = 0;
+#endif
public static int nb_inplace_remainder = 0;
public static int nb_inplace_power = 0;
public static int nb_inplace_lshift = 0;
@@ -254,7 +326,7 @@ public static int magic() {
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)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
/* Added in release 2.5 */
public static int nb_index = 0;
#endif
@@ -278,11 +350,13 @@ public static int magic() {
public static int sq_inplace_repeat = 0;
//} PySequenceMethods;
//typedef struct {
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
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)
+#endif
+#if (PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
// 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;
@@ -291,10 +365,107 @@ public static int magic() {
//PyObject *ht_name, *ht_slots;
public static int name = 0;
public static int slots = 0;
+
+#if (PYTHON33 || PYTHON34)
+ public static int qualname = 0;
+ public static int cached_keys;
+#endif
+
/* here are optional user slots, followed by the members. */
public static int members = 0;
}
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ internal class BytesOffset
+ {
+ static BytesOffset()
+ {
+ Type type = typeof(BytesOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++)
+ {
+ fi[i].SetValue(null, i * 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 ob_shash = 0;
+ public static int ob_sval = 0; /* start of data */
+
+ /* Invariants:
+ * ob_sval contains space for 'ob_size+1' elements.
+ * ob_sval[ob_size] == 0.
+ * ob_shash is the hash of the string or -1 if not computed yet.
+ */
+ //} PyBytesObject;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
+ internal class ModuleDefOffset
+ {
+ static ModuleDefOffset()
+ {
+ Type type = typeof(ModuleDefOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++)
+ {
+ fi[i].SetValue(null, (i * size) + TypeOffset.ob_size);
+ }
+ }
+
+ public static IntPtr AllocModuleDef(string modulename) {
+ byte[] ascii = Encoding.ASCII.GetBytes(modulename);
+ int size = name + ascii.Length + 1;
+ IntPtr ptr = Marshal.AllocHGlobal(size);
+ for (int i = 0; i <= m_free; i += IntPtr.Size)
+ Marshal.WriteIntPtr(ptr, i, IntPtr.Zero);
+ Marshal.Copy(ascii, 0, (IntPtr)(ptr + name), ascii.Length);
+ Marshal.WriteIntPtr(ptr, m_name, (IntPtr)(ptr + name));
+ Marshal.WriteByte(ptr, name + ascii.Length, 0);
+ return ptr;
+ }
+
+ public static void FreeModuleDef(IntPtr ptr) {
+ Marshal.FreeHGlobal(ptr);
+ }
+
+ // typedef struct PyModuleDef{
+ // typedef struct PyModuleDef_Base {
+ // starts after PyObject_HEAD (TypeOffset.ob_type + 1)
+ public static int m_init = 0;
+ public static int m_index = 0;
+ public static int m_copy = 0;
+ // } PyModuleDef_Base
+ public static int m_name = 0;
+ public static int m_doc = 0;
+ public static int m_size = 0;
+ public static int m_methods = 0;
+ public static int m_reload = 0;
+ public static int m_traverse = 0;
+ public static int m_clear = 0;
+ public static int m_free = 0;
+ // } PyModuleDef
+
+ public static int name = 0;
+ }
+#endif // PYTHON3
+
///
/// TypeFlags(): The actual bit values for the Type Flags stored
/// in a class.
@@ -302,6 +473,8 @@ public static int magic() {
/// to good use as PythonNet specific flags (Managed and Subclass)
///
internal class TypeFlags {
+#if (PYTHON23 || PYTHON24 || PYTHON25 || PYTHON26 || PYTHON27)
+ // these flags were removed in Python 3
public static int HaveGetCharBuffer = (1 << 0);
public static int HaveSequenceIn = (1 << 1);
public static int GC = 0;
@@ -311,6 +484,7 @@ internal class TypeFlags {
public static int HaveWeakRefs = (1 << 6);
public static int HaveIter = (1 << 7);
public static int HaveClass = (1 << 8);
+#endif
public static int HeapType = (1 << 9);
public static int BaseType = (1 << 10);
public static int Ready = (1 << 12);
@@ -321,10 +495,10 @@ internal class TypeFlags {
/* XXX Reusing reserved constants */
public static int Managed = (1 << 15); // PythonNet specific
public static int Subclass = (1 << 16); // PythonNet specific
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
public static int HaveIndex = (1 << 17);
#endif
-#if (PYTHON26 || PYTHON27)
+#if (PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
/* Objects support nb_index in PyNumberMethods */
public static int HaveVersionTag = (1 << 18);
public static int ValidVersionTag = (1 << 19);
@@ -341,7 +515,11 @@ internal class TypeFlags {
public static int BaseExceptionSubclass = (1 << 30);
public static int TypeSubclass = (1 << 31);
#endif
- public static int Default = (HaveGetCharBuffer |
+
+// Default flags for Python 2
+#if (PYTHON23 || PYTHON24 || PYTHON25 || PYTHON26 || PYTHON27)
+ public static int Default = (
+ HaveGetCharBuffer |
HaveSequenceIn |
HaveInPlaceOps |
HaveRichCompare |
@@ -349,10 +527,19 @@ internal class TypeFlags {
HaveIter |
HaveClass |
HaveStacklessExtension |
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+ #if (PYTHON25 || PYTHON26 || PYTHON27)
HaveIndex |
-#endif
+ #endif
0);
+#endif
+
+// Default flags for Python 3
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ public static int Default = (
+ HaveStacklessExtension |
+ HaveVersionTag);
+#endif
+
}
@@ -410,7 +597,9 @@ static Interop() {
pmap["nb_add"] = p["BinaryFunc"];
pmap["nb_subtract"] = p["BinaryFunc"];
pmap["nb_multiply"] = p["BinaryFunc"];
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
pmap["nb_divide"] = p["BinaryFunc"];
+#endif
pmap["nb_remainder"] = p["BinaryFunc"];
pmap["nb_divmod"] = p["BinaryFunc"];
pmap["nb_power"] = p["TernaryFunc"];
@@ -433,7 +622,9 @@ static Interop() {
pmap["nb_inplace_add"] = p["BinaryFunc"];
pmap["nb_inplace_subtract"] = p["BinaryFunc"];
pmap["nb_inplace_multiply"] = p["BinaryFunc"];
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
pmap["nb_inplace_divide"] = p["BinaryFunc"];
+#endif
pmap["nb_inplace_remainder"] = p["BinaryFunc"];
pmap["nb_inplace_power"] = p["TernaryFunc"];
pmap["nb_inplace_lshift"] = p["BinaryFunc"];
@@ -445,7 +636,7 @@ static Interop() {
pmap["nb_true_divide"] = p["BinaryFunc"];
pmap["nb_inplace_floor_divide"] = p["BinaryFunc"];
pmap["nb_inplace_true_divide"] = p["BinaryFunc"];
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
pmap["nb_index"] = p["UnaryFunc"];
#endif
@@ -541,5 +732,4 @@ public Thunk(Delegate d) {
fn = d;
}
}
-
}
diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs
index 670bcd2b3..78e29c2b6 100644
--- a/src/runtime/managedtype.cs
+++ b/src/runtime/managedtype.cs
@@ -42,7 +42,7 @@ internal static ManagedType GetManagedObject(IntPtr ob) {
if ((flags & TypeFlags.Managed) != 0) {
IntPtr op = (tp == ob) ?
Marshal.ReadIntPtr(tp, TypeOffset.magic()) :
- Marshal.ReadIntPtr(ob, ObjectOffset.magic());
+ Marshal.ReadIntPtr(ob, ObjectOffset.magic(ob));
GCHandle gc = (GCHandle)op;
return (ManagedType)gc.Target;
}
diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs
index 305437c84..881723e8f 100644
--- a/src/runtime/metatype.cs
+++ b/src/runtime/metatype.cs
@@ -46,7 +46,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
return Exceptions.RaiseTypeError("invalid argument list");
}
- //IntPtr name = Runtime.PyTuple_GetItem(args, 0);
+ IntPtr name = Runtime.PyTuple_GetItem(args, 0);
IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
IntPtr dict = Runtime.PyTuple_GetItem(args, 2);
@@ -88,12 +88,19 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
);
}
- // hack for now... fix for 1.0
- //return TypeManager.CreateSubType(args);
-
-
- // right way
+ // If __assembly__ or __namespace__ are in the class dictionary then create
+ // a managed sub type.
+ // This creates a new managed type that can be used from .net to call back
+ // into python.
+ if (IntPtr.Zero != dict) {
+ Runtime.Incref(dict);
+ using (PyDict clsDict = new PyDict(dict)) {
+ if (clsDict.HasKey("__assembly__") || clsDict.HasKey("__namespace__"))
+ return TypeManager.CreateSubType(name, base_type, dict);
+ }
+ }
+ // otherwise just create a basic type without reflecting back into the managed side.
IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType,
TypeOffset.tp_new);
IntPtr type = NativeCall.Call_3(func, tp, args, kw);
@@ -123,9 +130,6 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) {
IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic());
Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
- //DebugUtil.DumpType(base_type);
- //DebugUtil.DumpType(type);
-
return type;
}
diff --git a/src/runtime/methodbinding.cs b/src/runtime/methodbinding.cs
index 0459d36b2..64ab3edbe 100644
--- a/src/runtime/methodbinding.cs
+++ b/src/runtime/methodbinding.cs
@@ -9,6 +9,7 @@
using System;
using System.Reflection;
+using System.Collections.Generic;
namespace Python.Runtime {
@@ -23,14 +24,25 @@ internal class MethodBinding : ExtensionType {
internal MethodInfo info;
internal MethodObject m;
internal IntPtr target;
+ internal IntPtr targetType;
- public MethodBinding(MethodObject m, IntPtr target) : base() {
+ public MethodBinding(MethodObject m, IntPtr target, IntPtr targetType) : base() {
Runtime.Incref(target);
this.target = target;
+
+ Runtime.Incref(targetType);
+ if (targetType == IntPtr.Zero)
+ targetType = Runtime.PyObject_Type(target);
+ this.targetType = targetType;
+
this.info = null;
this.m = m;
}
+ public MethodBinding(MethodObject m, IntPtr target) : this(m, target, IntPtr.Zero)
+ {
+ }
+
//====================================================================
// Implement binding of generic methods using the subscript syntax [].
//====================================================================
@@ -114,25 +126,63 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
// 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.
+ List disposeList = new List();
+ try
+ {
+ IntPtr target = self.target;
+
+ if ((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;
+ }
+ target = Runtime.PyTuple_GetItem(args, 0);
+ Runtime.Incref(target);
+ disposeList.Add(target);
+
+ args = Runtime.PyTuple_GetSlice(args, 1, len);
+ disposeList.Add(args);
+ }
- 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;
- }
+ // if the class is a IPythonDerivedClass and target is not the same as self.targetType
+ // (eg if calling the base class method) then call the original base class method instead
+ // of the target method.
+ IntPtr superType = IntPtr.Zero;
+ if (Runtime.PyObject_TYPE(target) != self.targetType)
+ {
+ CLRObject inst = CLRObject.GetManagedObject(target) as CLRObject;
+ if (inst != null && (inst.inst as IPythonDerivedType) != null)
+ {
+ ClassBase baseType = GetManagedObject(self.targetType) as ClassBase;
+ if (baseType != null)
+ {
+ string baseMethodName = "_" + baseType.type.Name + "__" + self.m.name;
+ IntPtr baseMethod = Runtime.PyObject_GetAttrString(target, baseMethodName);
+ if (baseMethod != IntPtr.Zero)
+ {
+ MethodBinding baseSelf = GetManagedObject(baseMethod) as MethodBinding;
+ if (baseSelf != null)
+ self = baseSelf;
+ Runtime.Decref(baseMethod);
+ }
+ else
+ {
+ Runtime.PyErr_Clear();
+ }
+ }
+ }
+ }
- return self.m.Invoke(self.target, args, kw, self.info);
+ return self.m.Invoke(target, args, kw, self.info);
+ }
+ finally
+ {
+ foreach (IntPtr ptr in disposeList)
+ Runtime.Decref(ptr);
+ }
}
@@ -184,6 +234,7 @@ public static IntPtr tp_repr(IntPtr ob) {
public static new void tp_dealloc(IntPtr ob) {
MethodBinding self = (MethodBinding)GetManagedObject(ob);
Runtime.Decref(self.target);
+ Runtime.Decref(self.targetType);
ExtensionType.FinalizeObject(self);
}
diff --git a/src/runtime/methodobject.cs b/src/runtime/methodobject.cs
index 15a5cd547..45e7de709 100644
--- a/src/runtime/methodobject.cs
+++ b/src/runtime/methodobject.cs
@@ -27,19 +27,21 @@ internal class MethodObject : ExtensionType {
internal MethodBinder binder;
internal bool is_static = false;
internal IntPtr doc;
+ internal Type type;
- public MethodObject(string name, MethodInfo[] info) : base() {
- _MethodObject(name, info);
+ public MethodObject(Type type, string name, MethodInfo[] info) : base() {
+ _MethodObject(type, name, info);
}
- public MethodObject(string name, MethodInfo[] info, bool allow_threads) : base()
+ public MethodObject(Type type, string name, MethodInfo[] info, bool allow_threads) : base()
{
- _MethodObject(name, info);
+ _MethodObject(type, name, info);
binder.allow_threads = allow_threads;
}
- private void _MethodObject(string name, MethodInfo[] info)
+ private void _MethodObject(Type type, string name, MethodInfo[] info)
{
+ this.type = type;
this.name = name;
this.info = info;
binder = new MethodBinder();
@@ -144,7 +146,7 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) {
if (ob == IntPtr.Zero) {
if (self.unbound == null) {
- self.unbound = new MethodBinding(self, IntPtr.Zero);
+ self.unbound = new MethodBinding(self, IntPtr.Zero, tp);
}
binding = self.unbound;
Runtime.Incref(binding.pyHandle);;
@@ -155,7 +157,22 @@ public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) {
return Exceptions.RaiseTypeError("invalid argument");
}
- binding = new MethodBinding(self, ob);
+ // If the object this descriptor is being called with is a subclass of the type
+ // this descriptor was defined on then it will be because the base class method
+ // is being called via super(Derived, self).method(...).
+ // In which case create a MethodBinding bound to the base class.
+ CLRObject obj = GetManagedObject(ob) as CLRObject;
+ if (obj != null
+ && obj.inst.GetType() != self.type
+ && obj.inst is IPythonDerivedType
+ && self.type.IsAssignableFrom(obj.inst.GetType()))
+ {
+ ClassBase basecls = ClassManager.GetClass(self.type);
+ binding = new MethodBinding(self, ob, basecls.pyHandle);
+ return binding.pyHandle;
+ }
+
+ binding = new MethodBinding(self, ob, tp);
return binding.pyHandle;
}
diff --git a/src/runtime/methodwrapper.cs b/src/runtime/methodwrapper.cs
index 04a49d592..486e5c59d 100644
--- a/src/runtime/methodwrapper.cs
+++ b/src/runtime/methodwrapper.cs
@@ -34,9 +34,13 @@ public MethodWrapper(Type type, string 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!
-
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ IntPtr ps = Runtime.PyBytes_FromString(name);
+ IntPtr sp = Runtime.PyBytes_AS_STRING(ps);
+#else
IntPtr ps = Runtime.PyString_FromString(name);
IntPtr sp = Runtime.PyString_AS_STRING(ps);
+#endif
// Allocate and initialize a PyMethodDef structure to represent
// the managed method, then create a PyCFunction.
@@ -44,9 +48,9 @@ public MethodWrapper(Type type, string name) {
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, (2 * IntPtr.Size), (IntPtr)0x0003); // METH_VARARGS | METH_KEYWORDS
Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), IntPtr.Zero);
- ptr = Runtime.PyCFunction_New(mdef, IntPtr.Zero);
+ ptr = Runtime.PyCFunction_NewEx(mdef, IntPtr.Zero, IntPtr.Zero);
}
public IntPtr Call(IntPtr args, IntPtr kw) {
diff --git a/src/runtime/modulefunctionobject.cs b/src/runtime/modulefunctionobject.cs
index 5c9a4de21..2aa8c2306 100644
--- a/src/runtime/modulefunctionobject.cs
+++ b/src/runtime/modulefunctionobject.cs
@@ -19,8 +19,8 @@ namespace Python.Runtime
internal class ModuleFunctionObject : MethodObject
{
- public ModuleFunctionObject(string name, MethodInfo[] info, bool allow_threads)
- : base(name, info, allow_threads)
+ public ModuleFunctionObject(Type type, string name, MethodInfo[] info, bool allow_threads)
+ : base(type, name, info, allow_threads)
{
for (int i = 0; i < info.Length; i++)
{
diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs
index c5735ca4a..5cd6f2af5 100644
--- a/src/runtime/moduleobject.cs
+++ b/src/runtime/moduleobject.cs
@@ -37,14 +37,29 @@ public ModuleObject(string name) : base() {
cache = new Dictionary();
_namespace = name;
+ // Use the filename from any of the assemblies just so there's something for
+ // anything that expects __file__ to be set.
+ string filename = "unknown";
+ string docstring = "Namespace containing types from the following assemblies:\n\n";
+ foreach (Assembly a in AssemblyManager.GetAssemblies(name)) {
+ filename = a.Location;
+ docstring += "- " + a.FullName + "\n";
+ }
+
dict = Runtime.PyDict_New();
IntPtr pyname = Runtime.PyString_FromString(moduleName);
+ IntPtr pyfilename = Runtime.PyString_FromString(filename);
+ IntPtr pydocstring = Runtime.PyString_FromString(docstring);
+ IntPtr pycls = TypeManager.GetTypeHandle(this.GetType());
Runtime.PyDict_SetItemString(dict, "__name__", pyname);
- Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone);
- Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone);
+ Runtime.PyDict_SetItemString(dict, "__file__", pyfilename);
+ Runtime.PyDict_SetItemString(dict, "__doc__", pydocstring);
+ Runtime.PyDict_SetItemString(dict, "__class__", pycls);
Runtime.Decref(pyname);
+ Runtime.Decref(pyfilename);
+ Runtime.Decref(pydocstring);
- Marshal.WriteIntPtr(this.pyHandle, ObjectOffset.ob_dict, dict);
+ Marshal.WriteIntPtr(this.pyHandle, ObjectOffset.DictOffset(this.pyHandle), dict);
InitializeModuleMembers();
}
@@ -216,7 +231,7 @@ internal void InitializeModuleMembers()
string name = method.Name;
MethodInfo[] mi = new MethodInfo[1];
mi[0] = method;
- ModuleFunctionObject m = new ModuleFunctionObject(name, mi, allow_threads);
+ ModuleFunctionObject m = new ModuleFunctionObject(type, name, mi, allow_threads);
StoreAttribute(name, m);
}
}
@@ -425,6 +440,12 @@ public static String[] ListAssemblies(bool verbose)
return names;
}
+ [ModuleFunctionAttribute()]
+ public static int _AtExit()
+ {
+ return Runtime.AtExit();
+ }
+
}
}
diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs
index cd85c7126..e2ceaa6d6 100644
--- a/src/runtime/pydict.cs
+++ b/src/runtime/pydict.cs
@@ -102,7 +102,8 @@ public bool HasKey(PyObject key) {
///
public bool HasKey(string key) {
- return HasKey(new PyString(key));
+ using (PyString str = new PyString(key))
+ return HasKey(str);
}
diff --git a/src/runtime/pyfloat.cs b/src/runtime/pyfloat.cs
index 960892594..c6995887c 100644
--- a/src/runtime/pyfloat.cs
+++ b/src/runtime/pyfloat.cs
@@ -76,10 +76,11 @@ public PyFloat(double value) : base() {
///
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();
+ using (PyString s = new PyString(value)) {
+ obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero);
+ if (obj == IntPtr.Zero) {
+ throw new PythonException();
+ }
}
}
diff --git a/src/runtime/pyiter.cs b/src/runtime/pyiter.cs
index 8d8ad44d7..c8599c2a3 100644
--- a/src/runtime/pyiter.cs
+++ b/src/runtime/pyiter.cs
@@ -21,42 +21,57 @@ public class PyIter : PyObject, IEnumerator
+ ///
+ ///
+ /// Creates a new PyIter from an existing iterator reference. Note
+ /// that the instance assumes ownership of the object reference.
+ /// The object reference is not checked for type-correctness.
+ ///
- public PyIter(IntPtr ptr) : base(ptr) {}
+ public PyIter(IntPtr ptr) : base(ptr) {}
///
- /// PyIter Constructor
- ///
- ///
- ///
- /// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python.
- ///
+ /// PyIter Constructor
+ ///
+ ///
+ ///
+ /// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python.
+ ///
- public PyIter(PyObject iterable) : base()
+ public PyIter(PyObject iterable) : base()
{
obj = Runtime.PyObject_GetIter(iterable.obj);
if (obj == IntPtr.Zero)
throw new PythonException();
}
+ protected override void Dispose(bool disposing)
+ {
+ if (null != _current)
+ {
+ _current.Dispose();
+ _current = null;
+ }
+ base.Dispose(disposing);
+ }
+
#region IEnumerator Members
public bool MoveNext()
{
+ // dispose of the previous object, if there was one
+ if (null != _current)
+ {
+ _current.Dispose();
+ _current = null;
+ }
+
IntPtr next = Runtime.PyIter_Next(obj);
if (next == IntPtr.Zero)
- {
- _current = null; //release reference
return false;
- }
+
_current = new PyObject(next);
return true;
}
diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs
index 099b9fdf4..33c716599 100644
--- a/src/runtime/pyobject.cs
+++ b/src/runtime/pyobject.cs
@@ -8,6 +8,9 @@
// ==========================================================================
using System;
+using System.Dynamic;
+using System.Linq.Expressions;
+using System.Collections;
namespace Python.Runtime {
@@ -17,7 +20,7 @@ namespace Python.Runtime {
/// http://www.python.org/doc/current/api/object.html for details.
///
- public class PyObject : IDisposable {
+ public class PyObject : DynamicObject, IDisposable {
protected internal IntPtr obj = IntPtr.Zero;
private bool disposed = false;
@@ -95,7 +98,7 @@ public static PyObject FromManagedObject(object ob) {
public object AsManagedObject(Type t) {
Object result;
- if (!Converter.ToManaged(this.Handle, t, out result, false)) {
+ if (!Converter.ToManaged(this.obj, t, out result, false)) {
throw new InvalidCastException("cannot convert object to target type");
}
return result;
@@ -115,19 +118,23 @@ public object AsManagedObject(Type t) {
/// collection occurs.
///
- public void Dispose() {
+ protected virtual void Dispose(bool disposing) {
if (!disposed) {
if (Runtime.Py_IsInitialized() > 0) {
IntPtr gs = PythonEngine.AcquireLock();
Runtime.Decref(obj);
- obj = IntPtr.Zero;
+ obj = IntPtr.Zero;
PythonEngine.ReleaseLock(gs);
}
- GC.SuppressFinalize(this);
disposed = true;
}
}
+ public void Dispose() {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
///
/// GetPythonType Method
@@ -361,7 +368,8 @@ public virtual PyObject GetItem(PyObject key) {
///
public virtual PyObject GetItem(string key) {
- return GetItem(new PyString(key));
+ using (PyString pyKey = new PyString(key))
+ return GetItem(pyKey);
}
@@ -410,7 +418,8 @@ public virtual void SetItem(PyObject key, PyObject value) {
///
public virtual void SetItem(string key, PyObject value) {
- SetItem(new PyString(key), value);
+ using (PyString pyKey = new PyString(key))
+ SetItem(pyKey, value);
}
@@ -425,7 +434,9 @@ public virtual void SetItem(string key, PyObject value) {
///
public virtual void SetItem(int index, PyObject value) {
- SetItem(new PyInt(index), value);
+ using (PyInt pyindex = new PyInt(index)) {
+ SetItem(pyindex, value);
+ }
}
@@ -458,7 +469,8 @@ public virtual void DelItem(PyObject key) {
///
public virtual void DelItem(string key) {
- DelItem(new PyString(key));
+ using (PyString pyKey = new PyString(key))
+ DelItem(pyKey);
}
@@ -473,7 +485,8 @@ public virtual void DelItem(string key) {
///
public virtual void DelItem(int index) {
- DelItem(new PyInt(index));
+ using (PyInt pyindex = new PyInt(index))
+ DelItem(pyindex);
}
@@ -559,6 +572,21 @@ public PyObject GetIterator() {
return new PyObject(r);
}
+ ///
+ /// GetEnumerator Method
+ ///
+ ///
+ ///
+ /// Return a new PyIter object for the object. This allows any iterable
+ /// python object to be iterated over in C#. A PythonException will be
+ /// raised if the object is not iterable.
+ ///
+
+ public IEnumerator GetEnumerator()
+ {
+ return new PyIter(this);
+ }
+
///
/// Invoke Method
@@ -609,7 +637,7 @@ public PyObject Invoke(PyTuple args) {
public PyObject Invoke(PyObject[] args, PyDict kw) {
PyTuple t = new PyTuple(args);
- IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw.obj);
+ IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw != null ? kw.obj : IntPtr.Zero);
t.Dispose();
if (r == IntPtr.Zero) {
throw new PythonException();
@@ -628,7 +656,7 @@ public PyObject Invoke(PyObject[] args, PyDict kw) {
///
public PyObject Invoke(PyTuple args, PyDict kw) {
- IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw.obj);
+ IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw != null ? kw.obj : IntPtr.Zero);
if (r == IntPtr.Zero) {
throw new PythonException();
}
@@ -758,6 +786,22 @@ public bool IsCallable() {
}
+ ///
+ /// IsIterable Method
+ ///
+ ///
+ ///
+ /// Returns true if the object is iterable object. This method
+ /// always succeeds.
+ ///
+
+ public bool IsIterable()
+ {
+ return Runtime.PyIter_Check(obj);
+ }
+
+
+
///
/// IsTrue Method
///
@@ -862,8 +906,242 @@ public override int GetHashCode() {
return Runtime.PyObject_Hash(obj).ToInt32();
}
+ public override bool TryGetMember(GetMemberBinder binder, out object result)
+ {
+ if (this.HasAttr(binder.Name))
+ {
+ result = this.GetAttr(binder.Name);
+ return true;
+ }
+ else
+ return base.TryGetMember(binder, out result);
+ }
+
+ public override bool TrySetMember(SetMemberBinder binder, object value)
+ {
+ if (this.HasAttr(binder.Name))
+ {
+ this.SetAttr(binder.Name, (PyObject)value);
+ return true;
+ }
+ else
+ return base.TrySetMember(binder, value);
+ }
+ private void GetArgs(object[] inargs, out PyTuple args, out PyDict kwargs)
+ {
+ int arg_count;
+ for (arg_count = 0; arg_count < inargs.Length && !(inargs[arg_count] is Py.KeywordArguments); ++arg_count);
+ IntPtr argtuple = Runtime.PyTuple_New(arg_count);
+ for (int i = 0; i < arg_count; i++)
+ {
+ IntPtr ptr;
+ if (inargs[i] is PyObject)
+ {
+ ptr = ((PyObject)inargs[i]).Handle;
+ Runtime.Incref(ptr);
+ }
+ else
+ {
+ ptr = Converter.ToPython(inargs[i], inargs[i].GetType());
+ }
+ if (Runtime.PyTuple_SetItem(argtuple, i, ptr) < 0)
+ throw new PythonException();
+ }
+ args = new PyTuple(argtuple);
+ kwargs = null;
+ for (int i = arg_count; i < inargs.Length; i++)
+ {
+ if (!(inargs[i] is Py.KeywordArguments))
+ throw new ArgumentException("Keyword arguments must come after normal arguments.");
+ if (kwargs == null)
+ kwargs = (Py.KeywordArguments)inargs[i];
+ else
+ kwargs.Update((Py.KeywordArguments)inargs[i]);
+ }
}
+ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
+ {
+ if (this.HasAttr(binder.Name) && this.GetAttr(binder.Name).IsCallable())
+ {
+ PyTuple pyargs = null;
+ PyDict kwargs = null;
+ try
+ {
+ GetArgs(args, out pyargs, out kwargs);
+ result = InvokeMethod(binder.Name, pyargs, kwargs);
+ }
+ finally
+ {
+ if (null != pyargs)
+ pyargs.Dispose();
+ if (null != kwargs)
+ kwargs.Dispose();
+ }
+ return true;
+ }
+ else
+ return base.TryInvokeMember(binder, args, out result);
+ }
+ public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
+ {
+ if (this.IsCallable())
+ {
+ PyTuple pyargs = null;
+ PyDict kwargs = null;
+ try
+ {
+ GetArgs(args, out pyargs, out kwargs);
+ result = Invoke(pyargs, kwargs);
+ }
+ finally
+ {
+ if (null != pyargs)
+ pyargs.Dispose();
+ if (null != kwargs)
+ kwargs.Dispose();
+ }
+ return true;
+ }
+ else
+ return base.TryInvoke(binder, args, out result);
+ }
+
+ public override bool TryConvert(ConvertBinder binder, out object result)
+ {
+ return Converter.ToManaged(this.obj, binder.Type, out result, false);
+ }
+
+ public override bool TryBinaryOperation(BinaryOperationBinder binder, Object arg, out Object result) {
+ IntPtr res;
+ if (!(arg is PyObject))
+ arg = arg.ToPython();
+
+ switch (binder.Operation)
+ {
+ case ExpressionType.Add:
+ res = Runtime.PyNumber_Add(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.AddAssign:
+ res = Runtime.PyNumber_InPlaceAdd(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.Subtract:
+ res = Runtime.PyNumber_Subtract(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.SubtractAssign:
+ res = Runtime.PyNumber_InPlaceSubtract(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.Multiply:
+ res = Runtime.PyNumber_Multiply(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.MultiplyAssign:
+ res = Runtime.PyNumber_InPlaceMultiply(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.Divide:
+ res = Runtime.PyNumber_Divide(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.DivideAssign:
+ res = Runtime.PyNumber_InPlaceDivide(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.And:
+ res = Runtime.PyNumber_And(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.AndAssign:
+ res = Runtime.PyNumber_InPlaceAnd(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.ExclusiveOr:
+ res = Runtime.PyNumber_Xor(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.ExclusiveOrAssign:
+ res = Runtime.PyNumber_InPlaceXor(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.GreaterThan:
+ result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) > 0;
+ return true;
+ case ExpressionType.GreaterThanOrEqual:
+ result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) >= 0;
+ return true;
+ case ExpressionType.LeftShift:
+ res = Runtime.PyNumber_Lshift(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.LeftShiftAssign:
+ res = Runtime.PyNumber_InPlaceLshift(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.LessThan:
+ result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) < 0;
+ return true;
+ case ExpressionType.LessThanOrEqual:
+ result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) <= 0;
+ return true;
+ case ExpressionType.Modulo:
+ res = Runtime.PyNumber_Remainder(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.ModuloAssign:
+ res = Runtime.PyNumber_InPlaceRemainder(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.NotEqual:
+ result = Runtime.PyObject_Compare(this.obj, ((PyObject)arg).obj) != 0;
+ return true;
+ case ExpressionType.Or:
+ res = Runtime.PyNumber_Or(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.OrAssign:
+ res = Runtime.PyNumber_InPlaceOr(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.Power:
+ res = Runtime.PyNumber_Power(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.RightShift:
+ res = Runtime.PyNumber_Rshift(this.obj, ((PyObject)arg).obj);
+ break;
+ case ExpressionType.RightShiftAssign:
+ res = Runtime.PyNumber_InPlaceRshift(this.obj, ((PyObject)arg).obj);
+ break;
+ default:
+ result = null;
+ return false;
+ }
+ result = new PyObject(res);
+ return true;
+ }
+
+ public override bool TryUnaryOperation(UnaryOperationBinder binder, out Object result)
+ {
+ int r;
+ IntPtr res;
+ switch (binder.Operation)
+ {
+ case ExpressionType.Negate:
+ res = Runtime.PyNumber_Negative(this.obj);
+ break;
+ case ExpressionType.UnaryPlus:
+ res = Runtime.PyNumber_Positive(this.obj);
+ break;
+ case ExpressionType.OnesComplement:
+ res = Runtime.PyNumber_Invert(this.obj);
+ break;
+ case ExpressionType.Not:
+ r = Runtime.PyObject_Not(this.obj);
+ result = r == 1;
+ return r != -1;
+ case ExpressionType.IsFalse:
+ r = Runtime.PyObject_IsTrue(this.obj);
+ result = r == 0;
+ return r != -1;
+ case ExpressionType.IsTrue:
+ r = Runtime.PyObject_IsTrue(this.obj);
+ result = r == 1;
+ return r != -1;
+ case ExpressionType.Decrement:
+ case ExpressionType.Increment:
+ default:
+ result = null;
+ return false;
+ }
+ result = new PyObject(res);
+ return true;
+ }
+ }
}
diff --git a/src/runtime/pysequence.cs b/src/runtime/pysequence.cs
index 9b41c308b..855cad72e 100644
--- a/src/runtime/pysequence.cs
+++ b/src/runtime/pysequence.cs
@@ -158,15 +158,6 @@ public PyObject Repeat(int count) {
}
return new PyObject(op);
}
-
- #region IEnumerable Members
-
- public IEnumerator GetEnumerator()
- {
- return new PyIter(this);
- }
-
- #endregion
}
}
diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs
index 07326185f..1a84eb198 100644
--- a/src/runtime/pythonengine.cs
+++ b/src/runtime/pythonengine.cs
@@ -8,7 +8,9 @@
// ==========================================================================
using System;
+using System.IO;
using System.Threading;
+using System.Reflection;
namespace Python.Runtime {
@@ -64,6 +66,22 @@ public static string PythonHome {
}
}
+ public static string PythonPath {
+ get
+ {
+ string result = Runtime.Py_GetPath();
+ if (result == null)
+ {
+ return "";
+ }
+ return result;
+ }
+ set
+ {
+ Runtime.Py_SetPath(value);
+ }
+ }
+
public static string Version {
get {
return Runtime.Py_GetVersion();
@@ -117,55 +135,122 @@ public static void Initialize() {
Runtime.Initialize();
initialized = true;
Exceptions.Clear();
+
+ // register the atexit callback (this doesn't use Py_AtExit as the C atexit
+ // callbacks are called after python is fully finalized but the python ones
+ // are called while the python engine is still running).
+ string code =
+ "import atexit, clr\n" +
+ "atexit.register(clr._AtExit)\n";
+ PyObject r = PythonEngine.RunString(code);
+ if (r != null)
+ r.Dispose();
+
+ // Load the clr.py resource into the clr module
+ IntPtr clr = Python.Runtime.ImportHook.GetCLRModule();
+ IntPtr clr_dict = Runtime.PyModule_GetDict(clr);
+
+ PyDict locals = new PyDict();
+ try
+ {
+ IntPtr module = Runtime.PyImport_AddModule("clr._extras");
+ IntPtr module_globals = Runtime.PyModule_GetDict(module);
+ IntPtr builtins = Runtime.PyEval_GetBuiltins();
+ Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins);
+
+ var assembly = Assembly.GetExecutingAssembly();
+ using (Stream stream = assembly.GetManifestResourceStream("clr.py"))
+ using (StreamReader reader = new StreamReader(stream))
+ {
+ // add the contents of clr.py to the module
+ string clr_py = reader.ReadToEnd();
+ PyObject result = RunString(clr_py, module_globals, locals.Handle);
+ if (null == result)
+ throw new PythonException();
+ result.Dispose();
+ }
+
+ // add the imported module to the clr module, and copy the API functions
+ // and decorators into the main clr module.
+ Runtime.PyDict_SetItemString(clr_dict, "_extras", module);
+ foreach (PyObject key in locals.Keys())
+ {
+ if (!key.ToString().StartsWith("_")){
+ PyObject value = locals[key];
+ Runtime.PyDict_SetItem(clr_dict, key.Handle, value.Handle);
+ value.Dispose();
+ }
+ key.Dispose();
+ }
+ }
+ finally
+ {
+ locals.Dispose();
+ }
}
}
-
//====================================================================
// A helper to perform initialization from the context of an active
// CPython interpreter process - this bootstraps the managed runtime
// when it is imported by the CLR extension module.
//====================================================================
-
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ public static IntPtr InitExt() {
+#else
public static void InitExt() {
- Initialize();
-
- // Trickery - when the import hook is installed into an already
- // running Python, the standard import machinery is still in
- // control for the duration of the import that caused bootstrap.
- //
- // That is problematic because the std machinery tries to get
- // sub-names directly from the module __dict__ rather than going
- // through our module object's getattr hook. This workaround is
- // evil ;) We essentially climb up the stack looking for the
- // import that caused the bootstrap to happen, then re-execute
- // the import explicitly after our hook has been installed. By
- // doing this, the original outer import should work correctly.
- //
- // Note that this is only needed during the execution of the
- // first import that installs the CLR import hook. This hack
- // still doesn't work if you use the interactive interpreter,
- // since there is no line info to get the import line ;(
-
- string code =
-
- "import traceback\n" +
- "for item in traceback.extract_stack():\n" +
- " line = item[3]\n" +
- " if line is not None:\n" +
- " if line.startswith('import CLR') or \\\n" +
- " line.startswith('import clr') or \\\n" +
- " line.startswith('from clr') or \\\n" +
- " line.startswith('from CLR'):\n" +
- " exec line\n" +
- " break\n";
-
- PyObject r = PythonEngine.RunString(code);
- if (r != null) {
- r.Dispose();
+#endif
+ try
+ {
+ Initialize();
+
+ // Trickery - when the import hook is installed into an already
+ // running Python, the standard import machinery is still in
+ // control for the duration of the import that caused bootstrap.
+ //
+ // That is problematic because the std machinery tries to get
+ // sub-names directly from the module __dict__ rather than going
+ // through our module object's getattr hook. This workaround is
+ // evil ;) We essentially climb up the stack looking for the
+ // import that caused the bootstrap to happen, then re-execute
+ // the import explicitly after our hook has been installed. By
+ // doing this, the original outer import should work correctly.
+ //
+ // Note that this is only needed during the execution of the
+ // first import that installs the CLR import hook. This hack
+ // still doesn't work if you use the interactive interpreter,
+ // since there is no line info to get the import line ;(
+
+ string code =
+
+ "import traceback\n" +
+ "for item in traceback.extract_stack():\n" +
+ " line = item[3]\n" +
+ " if line is not None:\n" +
+ " if line.startswith('import CLR') or \\\n" +
+ " line.startswith('import clr') or \\\n" +
+ " line.startswith('from clr') or \\\n" +
+ " line.startswith('from CLR'):\n" +
+ " exec(line)\n" +
+ " break\n";
+
+ PyObject r = PythonEngine.RunString(code);
+ if (r != null) {
+ r.Dispose();
+ }
+ }
+ catch (PythonException e)
+ {
+ e.Restore();
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ return IntPtr.Zero;
+#endif
}
- }
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ return Python.Runtime.ImportHook.GetCLRModule();
+#endif
+ }
///
/// Shutdown Method
@@ -347,9 +432,70 @@ public static PyObject RunString(string code) {
return new PyObject(result);
}
+ public static PyObject RunString(string code, IntPtr globals, IntPtr locals)
+ {
+ IntPtr flag = (IntPtr)257; /* Py_file_input */
+ IntPtr result = Runtime.PyRun_String(code, flag, globals, locals);
+ if (result == IntPtr.Zero) {
+ return null;
+ }
+ return new PyObject(result);
+ }
+ }
+ public static class Py
+ {
+ public static GILState GIL()
+ {
+ if (!PythonEngine.IsInitialized)
+ PythonEngine.Initialize();
- }
+ return new GILState();
+ }
+ public class GILState : IDisposable
+ {
+ private IntPtr state;
+ internal GILState()
+ {
+ state = PythonEngine.AcquireLock();
+ }
+ public void Dispose()
+ {
+ PythonEngine.ReleaseLock(state);
+ GC.SuppressFinalize(this);
+ }
+ ~GILState()
+ {
+ Dispose();
+ }
+ }
+
+ public class KeywordArguments : PyDict { }
+
+ public static KeywordArguments kw(params object[] kv)
+ {
+ var dict = new KeywordArguments();
+ if (kv.Length % 2 != 0)
+ throw new ArgumentException("Must have an equal number of keys and values");
+ for (int i = 0; i < kv.Length; i += 2)
+ {
+ IntPtr value;
+ if (kv[i + 1] is PyObject)
+ value = ((PyObject)kv[i + 1]).Handle;
+ else
+ value = Converter.ToPython(kv[i + 1], kv[i + 1].GetType());
+ if (Runtime.PyDict_SetItemString(dict.Handle, (string)kv[i], value) != 0)
+ throw new ArgumentException(string.Format("Cannot add key '{0}' to dictionary.", (string)kv[i]));
+ if (!(kv[i + 1] is PyObject))
+ Runtime.Decref(value);
+ }
+ return dict;
+ }
+ public static PyObject Import(string name)
+ {
+ return PythonEngine.ImportModule(name);
+ }
+ }
}
diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs
index 592e9ea37..0d0b2e3e6 100644
--- a/src/runtime/pythonexception.cs
+++ b/src/runtime/pythonexception.cs
@@ -34,14 +34,21 @@ public PythonException() : base()
Runtime.Incref(_pyTB);
if ((_pyType != IntPtr.Zero) && (_pyValue != IntPtr.Zero))
{
- string type = new PyObject(_pyType).GetAttr("__name__").ToString();
+ string type;
+ using (PyObject pyType = new PyObject(_pyType))
+ using (PyObject pyTypeName = pyType.GetAttr("__name__"))
+ {
+ type = pyTypeName.ToString();
+ }
string message = Runtime.GetManagedString(_pyValue);
_message = type + " : " + message;
}
if (_pyTB != IntPtr.Zero)
{
PyObject tb_module = PythonEngine.ImportModule("traceback");
- _tb = tb_module.InvokeMethod("format_tb", new PyObject(_pyTB)).ToString();
+ using (PyObject pyTB = new PyObject(_pyTB)) {
+ _tb = tb_module.InvokeMethod("format_tb", pyTB).ToString();
+ }
}
PythonEngine.ReleaseLock(gs);
}
@@ -53,6 +60,18 @@ public PythonException() : base()
Dispose();
}
+ ///
+ /// Restores python error.
+ ///
+ public void Restore()
+ {
+ IntPtr gs = PythonEngine.AcquireLock();
+ Runtime.PyErr_Restore(_pyType, _pyValue, _pyTB);
+ _pyType = IntPtr.Zero;
+ _pyValue = IntPtr.Zero;
+ _pyTB = IntPtr.Zero;
+ PythonEngine.ReleaseLock(gs);
+ }
///
/// PyType Property
diff --git a/src/runtime/resources/clr.py b/src/runtime/resources/clr.py
new file mode 100644
index 000000000..1fbd272b5
--- /dev/null
+++ b/src/runtime/resources/clr.py
@@ -0,0 +1,83 @@
+"""
+Code in this module gets loaded into the main clr module.
+"""
+
+class clrproperty(object):
+ """
+ Property decorator for exposing python properties to .NET.
+ The property type must be specified as the only argument to clrproperty.
+
+ e.g.::
+
+ class X(object):
+ @clrproperty(string)
+ def test(self):
+ return "x"
+
+ Properties decorated this way can be called from .NET, e.g.::
+
+ dynamic x = getX(); // get an instance of X declared in Python
+ string z = x.test; // calls into python and returns "x"
+ """
+
+ def __init__(self, type_, fget=None, fset=None):
+ self.__name__ = getattr(fget, "__name__", None)
+ self._clr_property_type_ = type_
+ self.fget = fget
+ self.fset = fset
+
+ def __call__(self, fget):
+ return self.__class__(self._clr_property_type_,
+ fget=fget,
+ fset=self.fset)
+
+ def setter(self, fset):
+ self.fset = fset
+ return self
+
+ def getter(self, fget):
+ self.fget = fget
+ return self
+
+ def __get__(self, instance, owner):
+ return self.fget.__get__(instance, owner)()
+
+ def __set__(self, instance, value):
+ if not self.fset:
+ raise AttributeError("%s is read-only" % self.__name__)
+ return self.fset.__get__(instance, None)(value)
+
+
+class clrmethod(object):
+ """
+ Method decorator for exposing python methods to .NET.
+ The argument and return types must be specified as arguments to clrmethod.
+
+ e.g.::
+
+ class X(object):
+ @clrmethod(int, [str])
+ def test(self, x):
+ return len(x)
+
+ Methods decorated this way can be called from .NET, e.g.::
+
+ dynamic x = getX(); // get an instance of X declared in Python
+ int z = x.test("hello"); // calls into python and returns len("hello")
+ """
+
+ def __init__(self, return_type, arg_types, clrname=None, func=None):
+ self.__name__ = getattr(func, "__name__", None)
+ self._clr_return_type_ = return_type
+ self._clr_arg_types_ = arg_types
+ self._clr_method_name_ = clrname or self.__name__
+ self.__func = func
+
+ def __call__(self, func):
+ return self.__class__(self._clr_return_type_,
+ self._clr_arg_types_,
+ clrname=self._clr_method_name_,
+ func=func)
+
+ def __get__(self, instance, owner):
+ return self.__func.__get__(instance, owner)
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index 19aa2ca2d..cce085223 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -15,10 +15,86 @@
using Mono.Unix;
#endif
+#if (UCS2 && (PYTHON32 || PYTHON33 || PYTHON34))
+using System.Text;
+#endif
+
namespace Python.Runtime {
[SuppressUnmanagedCodeSecurityAttribute()]
+ static class NativeMethods
+ {
+#if (MONO_LINUX || MONO_OSX)
+ static public IntPtr LoadLibrary(string fileName) {
+ return dlopen(fileName, RTLD_NOW | RTLD_SHARED);
+ }
+
+ static public void FreeLibrary(IntPtr handle) {
+ dlclose(handle);
+ }
+
+ static public IntPtr GetProcAddress(IntPtr dllHandle, string name) {
+ // look in the exe if dllHandle is NULL
+ if (IntPtr.Zero == dllHandle)
+ dllHandle = RTLD_DEFAULT;
+
+ // clear previous errors if any
+ dlerror();
+ var res = dlsym(dllHandle, name);
+ var errPtr = dlerror();
+ if (errPtr != IntPtr.Zero) {
+ throw new Exception("dlsym: " + Marshal.PtrToStringAnsi(errPtr));
+ }
+ return res;
+ }
+
+#if (MONO_OSX)
+ static int RTLD_NOW = 0x2;
+ static int RTLD_SHARED = 0x20;
+ static IntPtr RTLD_DEFAULT = new IntPtr(-2);
+
+ [DllImport("__Internal")]
+ private static extern IntPtr dlopen(String fileName, int flags);
+
+ [DllImport("__Internal")]
+ private static extern IntPtr dlsym(IntPtr handle, String symbol);
+
+ [DllImport("__Internal")]
+ private static extern int dlclose(IntPtr handle);
+
+ [DllImport("__Internal")]
+ private static extern IntPtr dlerror();
+#else
+ static int RTLD_NOW = 0x2;
+ static int RTLD_SHARED = 0x20;
+ static IntPtr RTLD_DEFAULT = IntPtr.Zero;
+
+ [DllImport("libdl.so")]
+ private static extern IntPtr dlopen(String fileName, int flags);
+
+ [DllImport("libdl.so")]
+ private static extern IntPtr dlsym(IntPtr handle, String symbol);
+
+ [DllImport("libdl.so")]
+ private static extern int dlclose(IntPtr handle);
+
+ [DllImport("libdl.so")]
+ private static extern IntPtr dlerror();
+#endif
+
+#else
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr LoadLibrary(string dllToLoad);
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool FreeLibrary(IntPtr hModule);
+#endif
+ }
+
public class Runtime {
///
@@ -37,34 +113,104 @@ public class Runtime {
#endif
#if (PYTHON23)
- public const string dll = "python23";
public const string pyversion = "2.3";
public const int pyversionnumber = 23;
#endif
#if (PYTHON24)
- public const string dll = "python24";
public const string pyversion = "2.4";
public const int pyversionnumber = 24;
#endif
#if (PYTHON25)
- public const string dll = "python25";
public const string pyversion = "2.5";
public const int pyversionnumber = 25;
#endif
#if (PYTHON26)
- public const string dll = "python26";
public const string pyversion = "2.6";
public const int pyversionnumber = 26;
#endif
#if (PYTHON27)
- public const string dll = "python27";
public const string pyversion = "2.7";
public const int pyversionnumber = 27;
#endif
-#if ! (PYTHON23 || PYTHON24 || PYTHON25 || PYTHON26 || PYTHON27)
-#error You must define one of PYTHON23 to PYTHON27
+#if (PYTHON32)
+ public const string pyversion = "3.2";
+ public const int pyversionnumber = 32;
+#endif
+#if (PYTHON33)
+ public const string pyversion = "3.3";
+ public const int pyversionnumber = 33;
+#endif
+#if (PYTHON34)
+ public const string pyversion = "3.4";
+ public const int pyversionnumber = 34;
+#endif
+#if ! (PYTHON23 || PYTHON24 || PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
+#error You must define one of PYTHON23 to PYTHON34
+#endif
+
+#if (PYTHON23)
+ internal const string dllBase = "python23";
+#endif
+#if (PYTHON24)
+ internal const string dllBase = "python24";
+#endif
+#if (PYTHON25)
+ internal const string dllBase = "python25";
+#endif
+#if (PYTHON26)
+ internal const string dllBase = "python26";
+#endif
+#if (PYTHON27)
+ internal const string dllBase = "python27";
+#endif
+#if (MONO_LINUX || MONO_OSX)
+#if (PYTHON32)
+ internal const string dllBase = "python3.2";
+#endif
+#if (PYTHON33)
+ internal const string dllBase = "python3.3";
+#endif
+#if (PYTHON34)
+ internal const string dllBase = "python3.4";
+#endif
+#else
+#if (PYTHON32)
+ internal const string dllBase = "python32";
+#endif
+#if (PYTHON33)
+ internal const string dllBase = "python33";
+#endif
+#if (PYTHON34)
+ internal const string dllBase = "python34";
+#endif
+#endif
+
+#if (PYTHON_WITH_PYDEBUG)
+ internal const string dllWithPyDebug = "d";
+#else
+ internal const string dllWithPyDebug = "";
+#endif
+#if (PYTHON_WITH_PYMALLOC)
+ internal const string dllWithPyMalloc = "m";
+#else
+ internal const string dllWithPyMalloc = "";
+#endif
+#if (PYTHON_WITH_WIDE_UNICODE)
+ internal const string dllWithWideUnicode = "u";
+#else
+ internal const string dllWithWideUnicode = "";
+#endif
+
+#if (PYTHON_WITHOUT_ENABLE_SHARED)
+ public const string dll = "__Internal";
+#else
+ public const string dll = dllBase + dllWithPyDebug + dllWithPyMalloc + dllWithWideUnicode;
#endif
+ // set to true when python is finalizing
+ internal static Object IsFinalizingLock = new Object();
+ internal static bool IsFinalizing = false;
+
internal static bool wrap_exceptions;
internal static bool is32bit;
@@ -72,19 +218,27 @@ public class Runtime {
/// Intitialize the runtime...
///
internal static void Initialize() {
-
+
is32bit = IntPtr.Size == 4;
- if (0 == Runtime.Py_IsInitialized()) {
+ if (0 == Runtime.Py_IsInitialized())
+ {
Runtime.Py_Initialize();
}
- // make sure threads are initialized even if python was initialized already
- Runtime.PyEval_InitThreads();
+ if (0 == Runtime.PyEval_ThreadsInitialized())
+ {
+ Runtime.PyEval_InitThreads();
+ }
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ IntPtr op = Runtime.PyImport_ImportModule("builtins");
+ IntPtr dict = Runtime.PyObject_GetAttrString(op, "__dict__");
+ PyNotImplemented = Runtime.PyObject_GetAttrString(op, "NotImplemented");
+#else
IntPtr dict = Runtime.PyImport_GetModuleDict();
IntPtr op = Runtime.PyDict_GetItemString(dict, "__builtin__");
-
+#endif
PyBaseObjectType = Runtime.PyObject_GetAttrString(op, "object");
PyModuleType = Runtime.PyObject_Type(op);
@@ -100,6 +254,11 @@ internal static void Initialize() {
PyMethodType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ Runtime.Decref(dict);
+ Runtime.Decref(op);
+#endif
+
op = Runtime.PyString_FromString("string");
PyStringType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
@@ -108,6 +267,12 @@ internal static void Initialize() {
PyUnicodeType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ op = Runtime.PyBytes_FromString("bytes");
+ PyBytesType = Runtime.PyObject_Type(op);
+ Runtime.Decref(op);
+#endif
+
op = Runtime.PyTuple_New(0);
PyTupleType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
@@ -132,8 +297,13 @@ internal static void Initialize() {
PyFloatType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ PyClassType = IntPtr.Zero;
+ PyInstanceType = IntPtr.Zero;
+#else
IntPtr s = Runtime.PyString_FromString("_temp");
IntPtr d = Runtime.PyDict_New();
+
IntPtr c = Runtime.PyClass_New(IntPtr.Zero, d, s);
PyClassType = Runtime.PyObject_Type(c);
@@ -144,14 +314,29 @@ internal static void Initialize() {
Runtime.Decref(i);
Runtime.Decref(c);
Runtime.Decref(d);
+#endif
Error = new IntPtr(-1);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ IntPtr dll = IntPtr.Zero;
+ if ("__Internal" != Runtime.dll) {
+ NativeMethods.LoadLibrary(Runtime.dll);
+ }
+ _PyObject_NextNotImplemented = NativeMethods.GetProcAddress(dll, "_PyObject_NextNotImplemented");
+#if !(MONO_LINUX || MONO_OSX)
+ if (IntPtr.Zero != dll) {
+ NativeMethods.FreeLibrary(dll);
+ }
+#endif
+#endif
+
+
// Determine whether we need to wrap exceptions for versions of
// of the Python runtime that do not allow new-style classes to
// be used as exceptions (Python versions 2.4 and lower).
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
wrap_exceptions = false;
#else
IntPtr m = PyImport_ImportModule("exceptions");
@@ -188,6 +373,14 @@ internal static void Shutdown() {
Py_Finalize();
}
+ // called *without* the GIL aquired by clr._AtExit
+ internal static int AtExit() {
+ lock (IsFinalizingLock) {
+ IsFinalizing = true;
+ }
+ return 0;
+ }
+
internal static IntPtr Py_single_input = (IntPtr)256;
internal static IntPtr Py_file_input = (IntPtr)257;
internal static IntPtr Py_eval_input = (IntPtr)258;
@@ -211,6 +404,17 @@ internal static void Shutdown() {
internal static IntPtr PyNoneType;
internal static IntPtr PyTypeType;
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ internal static IntPtr PyBytesType;
+ internal static IntPtr PyNotImplemented;
+ internal const int Py_LT = 0;
+ internal const int Py_LE = 1;
+ internal const int Py_EQ = 2;
+ internal const int Py_NE = 3;
+ internal const int Py_GT = 4;
+ internal static IntPtr _PyObject_NextNotImplemented;
+#endif
+
internal static IntPtr PyTrue;
internal static IntPtr PyFalse;
internal static IntPtr PyNone;
@@ -362,6 +566,17 @@ internal unsafe static void Decref(IntPtr op) {
#endif
}
+ internal unsafe static long Refcount(IntPtr op)
+ {
+ void* p = (void*)op;
+ if ((void*)0 != p)
+ {
+ if (is32bit) { return (*(int*)p); }
+ else { return (*(long*)p); }
+ }
+ return 0;
+ }
+
#if (Py_DEBUG)
// Py_IncRef and Py_DecRef are taking care of the extra payload
// in Py_DEBUG builds of Python like _Py_RefTotal
@@ -448,16 +663,28 @@ internal unsafe static extern void
internal unsafe static extern IntPtr
PyGILState_GetThisThreadState();
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ public unsafe static extern int
+ Py_Main(int argc, [MarshalAsAttribute(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)] string[] argv);
+#else
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
public unsafe static extern int
Py_Main(int argc, string[] argv);
+#endif
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern void
PyEval_InitThreads();
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern int
+ PyEval_ThreadsInitialized();
+
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern void
@@ -504,25 +731,70 @@ internal unsafe static extern IntPtr
PyEval_GetLocals();
+#if PYTHON32 || PYTHON33 || PYTHON34
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
+ [return: MarshalAs(UnmanagedType.LPWStr)]
internal unsafe static extern string
Py_GetProgramName();
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern void
- Py_SetProgramName(string name);
+ Py_SetProgramName([MarshalAsAttribute(UnmanagedType.LPWStr)]string name);
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
+ [return: MarshalAs(UnmanagedType.LPWStr)]
internal unsafe static extern string
Py_GetPythonHome();
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern void
- Py_SetPythonHome(string home);
+ Py_SetPythonHome([MarshalAsAttribute(UnmanagedType.LPWStr)]string home);
+
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ [return: MarshalAs(UnmanagedType.LPWStr)]
+ internal unsafe static extern string
+ Py_GetPath();
+
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern void
+ Py_SetPath([MarshalAsAttribute(UnmanagedType.LPWStr)]string home);
+#else
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern string
+ Py_GetProgramName();
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern void
+ Py_SetProgramName(string name);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern string
+ Py_GetPythonHome();
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern void
+ Py_SetPythonHome(string home);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern string
+ Py_GetPath();
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern void
+ Py_SetPath(string home);
+#endif
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
@@ -569,11 +841,6 @@ internal unsafe static extern IntPtr
internal unsafe static extern IntPtr
PyImport_ExecCodeModule(string name, IntPtr code);
- [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
- ExactSpelling=true, CharSet=CharSet.Ansi)]
- internal unsafe static extern IntPtr
- PyCFunction_New(IntPtr ml, IntPtr self);
-
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern IntPtr
@@ -709,10 +976,42 @@ internal unsafe static extern IntPtr
internal unsafe static extern IntPtr
PyObject_CallObject(IntPtr pointer, IntPtr args);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern int
+ PyObject_RichCompareBool(IntPtr value1, IntPtr value2, int opid);
+
+ internal static int PyObject_Compare(IntPtr value1, IntPtr value2) {
+ int res;
+ res = PyObject_RichCompareBool(value1, value2, Py_LT);
+ if (-1 == res)
+ return -1;
+ else if (1 == res)
+ return -1;
+
+ res = PyObject_RichCompareBool(value1, value2, Py_EQ);
+ if (-1 == res)
+ return -1;
+ else if (1 == res)
+ return 0;
+
+ res = PyObject_RichCompareBool(value1, value2, Py_GT);
+ if (-1 == res)
+ return -1;
+ else if (1 == res)
+ return 1;
+
+ Exceptions.SetError(Exceptions.SystemError, "Error comparing objects");
+ return -1;
+ }
+#else
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern int
PyObject_Compare(IntPtr value1, IntPtr value2);
+#endif
+
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
@@ -729,11 +1028,16 @@ internal unsafe static extern int
internal unsafe static extern int
PyCallable_Check(IntPtr pointer);
- [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
- ExactSpelling=true, CharSet=CharSet.Ansi)]
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
internal unsafe static extern int
PyObject_IsTrue(IntPtr pointer);
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern int
+ PyObject_Not(IntPtr pointer);
+
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern int
@@ -754,10 +1058,18 @@ internal unsafe static extern IntPtr
internal unsafe static extern IntPtr
PyObject_Str(IntPtr pointer);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint="PyObject_Str",
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyObject_Unicode(IntPtr pointer);
+#else
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
ExactSpelling = true, CharSet = CharSet.Ansi)]
internal unsafe static extern IntPtr
PyObject_Unicode(IntPtr pointer);
+#endif
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
@@ -769,10 +1081,18 @@ internal unsafe static extern IntPtr
// Python number API
//====================================================================
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ EntryPoint = "PyNumber_Long",
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Int(IntPtr ob);
+#else // Python 2
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern IntPtr
PyNumber_Int(IntPtr ob);
+#endif
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
@@ -799,14 +1119,8 @@ internal static bool PyBool_Check(IntPtr ob) {
return PyObject_TypeCheck(ob, Runtime.PyBoolType);
}
-
-
- [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
- ExactSpelling=true, CharSet=CharSet.Ansi)]
- private unsafe static extern IntPtr
- PyInt_FromLong(IntPtr value);
-
- internal static IntPtr PyInt_FromInt32(int value) {
+ internal static IntPtr PyInt_FromInt32(int value)
+ {
IntPtr v = new IntPtr(value);
return PyInt_FromLong(v);
}
@@ -816,22 +1130,51 @@ internal static IntPtr PyInt_FromInt64(long value) {
return PyInt_FromLong(v);
}
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyLong_FromLong",
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ private unsafe static extern IntPtr
+ PyInt_FromLong(IntPtr value);
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ EntryPoint = "PyLong_AsLong",
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern int
PyInt_AsLong(IntPtr value);
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ EntryPoint = "PyLong_FromString",
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern IntPtr
PyInt_FromString(string value, IntPtr end, int radix);
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ EntryPoint = "PyLong_GetMax",
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern int
PyInt_GetMax();
+#else // Python 2
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ private unsafe static extern IntPtr
+ PyInt_FromLong(IntPtr value);
+
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern int
+ PyInt_AsLong(IntPtr value);
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyInt_FromString(string value, IntPtr end, int radix);
+
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern int
+ PyInt_GetMax();
+#endif
internal static bool PyLong_Check(IntPtr ob) {
return PyObject_TYPE(ob) == Runtime.PyLongType;
@@ -907,6 +1250,130 @@ internal unsafe static extern IntPtr
internal unsafe static extern double
PyFloat_AsDouble(IntPtr ob);
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Add(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Subtract(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Multiply(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Divide(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_And(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Xor(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Or(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Lshift(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Rshift(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Power(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Remainder(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceAdd(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceSubtract(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceMultiply(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceDivide(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceAnd(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceXor(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceOr(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceLshift(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceRshift(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlacePower(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_InPlaceRemainder(IntPtr o1, IntPtr o2);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Negative(IntPtr o1);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Positive(IntPtr o1);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyNumber_Invert(IntPtr o1);
//====================================================================
// Python sequence API
@@ -1005,6 +1472,57 @@ internal static IntPtr PyString_FromString(string value) {
return PyString_FromStringAndSize(value, value.Length);
}
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyBytes_FromString(string op);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern int
+ PyBytes_Size(IntPtr op);
+
+ internal static IntPtr PyBytes_AS_STRING(IntPtr ob) {
+ return ob + BytesOffset.ob_sval;
+ }
+
+ internal static IntPtr PyString_FromStringAndSize(string value, int length)
+ {
+ // copy the string into an unmanaged UTF-8 buffer
+ int len = Encoding.UTF8.GetByteCount(value);
+ byte[] buffer = new byte[len + 1];
+ Encoding.UTF8.GetBytes(value, 0, value.Length, buffer, 0);
+ IntPtr nativeUtf8 = Marshal.AllocHGlobal(buffer.Length);
+ try {
+ Marshal.Copy(buffer, 0, nativeUtf8, buffer.Length);
+ return PyUnicode_FromStringAndSize(nativeUtf8, length);
+ }
+ finally {
+ Marshal.FreeHGlobal(nativeUtf8);
+ }
+ }
+
+#if (PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromStringAndSize(IntPtr value, int size);
+#elif (UCS2)
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyUnicodeUCS2_FromStringAndSize",
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromStringAndSize(IntPtr value, int size);
+#else
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyUnicodeUCS4_FromStringAndSize",
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromStringAndSize(IntPtr value, int size);
+#endif
+
+#else // Python2x
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern IntPtr
@@ -1020,12 +1538,57 @@ internal unsafe static extern IntPtr
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern int
PyString_Size(IntPtr pointer);
+#endif
internal static bool PyUnicode_Check(IntPtr ob) {
return PyObject_TYPE(ob) == Runtime.PyUnicodeType;
}
#if (UCS2)
+#if (PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromObject(IntPtr ob);
+
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint="PyUnicode_FromKindAndData",
+ ExactSpelling=true,
+ CharSet=CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromKindAndString(int kind, string s, int size);
+
+ internal static IntPtr PyUnicode_FromUnicode(string s, int size) {
+ return PyUnicode_FromKindAndString(2, s, size);
+ }
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern int
+ PyUnicode_GetSize(IntPtr ob);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern char *
+ PyUnicode_AsUnicode(IntPtr ob);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyUnicode_AsUnicode",
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_AS_UNICODE(IntPtr op);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromOrdinal(int c);
+
+#else
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
EntryPoint="PyUnicodeUCS2_FromObject",
ExactSpelling=true, CharSet=CharSet.Unicode)]
@@ -1067,6 +1630,7 @@ internal unsafe static extern IntPtr
ExactSpelling=true, CharSet=CharSet.Unicode)]
internal unsafe static extern IntPtr
PyUnicode_FromOrdinal(int c);
+#endif
internal static IntPtr PyUnicode_FromString(string s)
{
@@ -1077,6 +1641,8 @@ internal unsafe static string GetManagedString(IntPtr op)
{
IntPtr type = PyObject_TYPE(op);
+// Python 3 strings are all unicode
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
if (type == Runtime.PyStringType)
{
return Marshal.PtrToStringAnsi(
@@ -1084,6 +1650,7 @@ internal unsafe static string GetManagedString(IntPtr op)
Runtime.PyString_Size(op)
);
}
+#endif
if (type == Runtime.PyUnicodeType)
{
@@ -1097,6 +1664,52 @@ internal unsafe static string GetManagedString(IntPtr op)
#endif
#if (UCS4)
+#if (PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromObject(IntPtr ob);
+
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyUnicode_FromKindAndData",
+ ExactSpelling = true)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromKindAndString(int kind,
+ [MarshalAs (UnmanagedType.CustomMarshaler,
+ MarshalTypeRef=typeof(Utf32Marshaler))] string s,
+ int size);
+
+ internal static IntPtr PyUnicode_FromUnicode(string s, int size) {
+ return PyUnicode_FromKindAndString(4, s, size);
+ }
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern int
+ PyUnicode_GetSize(IntPtr ob);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true)]
+ internal unsafe static extern IntPtr
+ PyUnicode_AsUnicode(IntPtr ob);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ EntryPoint = "PyUnicode_AsUnicode",
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_AS_UNICODE(IntPtr op);
+
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Unicode)]
+ internal unsafe static extern IntPtr
+ PyUnicode_FromOrdinal(int c);
+
+#else
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
EntryPoint = "PyUnicodeUCS4_FromObject",
ExactSpelling = true, CharSet = CharSet.Unicode)]
@@ -1142,6 +1755,8 @@ internal unsafe static extern IntPtr
internal unsafe static extern IntPtr
PyUnicode_FromOrdinal(int c);
+#endif
+
internal static IntPtr PyUnicode_FromString(string s)
{
return PyUnicode_FromUnicode(s, (s.Length));
@@ -1151,6 +1766,8 @@ internal unsafe static string GetManagedString(IntPtr op)
{
IntPtr type = PyObject_TYPE(op);
+// Python 3 strings are all unicode
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
if (type == Runtime.PyStringType)
{
return Marshal.PtrToStringAnsi(
@@ -1158,11 +1775,16 @@ internal unsafe static string GetManagedString(IntPtr op)
Runtime.PyString_Size(op)
);
}
+#endif
if (type == Runtime.PyUnicodeType)
{
IntPtr p = Runtime.PyUnicode_AsUnicode(op);
- return UnixMarshal.PtrToString(p, Encoding.UTF32);
+ int length = Runtime.PyUnicode_GetSize(op);
+ int size = length * 4;
+ byte[] buffer = new byte[size];
+ Marshal.Copy(p, buffer, 0, size);
+ return Encoding.UTF32.GetString(buffer, 0, size);
}
return null;
@@ -1212,6 +1834,11 @@ internal unsafe static extern int
internal unsafe static extern int
PyDict_DelItem(IntPtr pointer, IntPtr key);
+ [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
+ ExactSpelling = true, CharSet = CharSet.Ansi)]
+ internal unsafe static extern int
+ PyDict_DelItemString(IntPtr pointer, string key);
+
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern int
@@ -1355,10 +1982,20 @@ internal unsafe static extern int
// Python iterator API
//====================================================================
+#if !(PYTHON32 || PYTHON33 || PYTHON34)
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
ExactSpelling = true, CharSet = CharSet.Ansi)]
internal unsafe static extern bool
PyIter_Check(IntPtr pointer);
+#else
+ internal static bool
+ PyIter_Check(IntPtr pointer)
+ {
+ IntPtr ob_type = (IntPtr)Marshal.PtrToStructure(pointer + ObjectOffset.ob_type, typeof(IntPtr));
+ IntPtr tp_iternext = ob_type + TypeOffset.tp_iternext;
+ return tp_iternext != null && tp_iternext != _PyObject_NextNotImplemented;
+ }
+#endif
[DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl,
ExactSpelling = true, CharSet = CharSet.Ansi)]
@@ -1369,6 +2006,11 @@ internal unsafe static extern IntPtr
// Python module API
//====================================================================
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyModule_New(string name);
+
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern string
@@ -1384,6 +2026,13 @@ internal unsafe static extern IntPtr
internal unsafe static extern string
PyModule_GetFilename(IntPtr module);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
+ ExactSpelling=true, CharSet=CharSet.Ansi)]
+ internal unsafe static extern IntPtr
+ PyModule_Create2(IntPtr module, int apiver);
+#endif
+
[DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl,
ExactSpelling=true, CharSet=CharSet.Ansi)]
internal unsafe static extern IntPtr
diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs
index 41b845737..866bbbb78 100644
--- a/src/runtime/typemanager.cs
+++ b/src/runtime/typemanager.cs
@@ -26,11 +26,9 @@ internal class TypeManager {
static BindingFlags tbFlags;
static Dictionary cache;
- static int obSize;
static TypeManager() {
tbFlags = BindingFlags.Public | BindingFlags.Static;
- obSize = 5 * IntPtr.Size;
cache = new Dictionary(128);
}
@@ -86,11 +84,12 @@ internal static IntPtr GetTypeHandle(ManagedType obj, Type type) {
internal static IntPtr CreateType(Type impl) {
IntPtr type = AllocateTypeObject(impl.Name);
+ int ob_size = ObjectOffset.Size(type);
// Set tp_basicsize to the size of our managed instance objects.
- Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
- IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
+ IntPtr offset = (IntPtr)ObjectOffset.DictOffset(type);
Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
InitializeSlots(type, impl);
@@ -124,11 +123,21 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) {
}
IntPtr base_ = IntPtr.Zero;
+ int ob_size = ObjectOffset.Size(Runtime.PyTypeType);
+ int tp_dictoffset = ObjectOffset.DictOffset(Runtime.PyTypeType);
+
// XXX Hack, use a different base class for System.Exception
// Python 2.5+ allows new style class exceptions but they *must*
// subclass BaseException (or better Exception).
-#if (PYTHON25 || PYTHON26 || PYTHON27)
- if (clrType == typeof(System.Exception)) {
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34)
+ if (typeof(System.Exception).IsAssignableFrom(clrType))
+ {
+ ob_size = ObjectOffset.Size(Exceptions.BaseException);
+ tp_dictoffset = ObjectOffset.DictOffset(Exceptions.BaseException);
+ }
+
+ if (clrType == typeof(System.Exception))
+ {
base_ = Exceptions.Exception;
Runtime.Incref(base_);
} else
@@ -143,11 +152,9 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) {
Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType);
Runtime.Incref(Runtime.PyCLRMetaType);
- Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)ob_size);
Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
-
- IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
- Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, (IntPtr)tp_dictoffset);
InitializeSlots(type, impl.GetType());
@@ -188,58 +195,78 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) {
return type;
}
- internal static IntPtr CreateSubType(IntPtr args) {
-
- IntPtr py_name = Runtime.PyTuple_GetItem(args, 0);
- IntPtr bases = Runtime.PyTuple_GetItem(args, 1);
- IntPtr dict = Runtime.PyTuple_GetItem(args, 2);
- IntPtr base_ = Runtime.PyTuple_GetItem(bases, 0);
-
+ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr py_dict)
+ {
+ // Utility to create a subtype of a managed type with the ability for the
+ // a python subtype able to override the managed implementation
string name = Runtime.GetManagedString(py_name);
- IntPtr type = AllocateTypeObject(name);
-
- Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType);
- Runtime.Incref(Runtime.PyCLRMetaType);
-
- Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
- Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
-
- IntPtr offset = (IntPtr)ObjectOffset.ob_dict;
- Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset);
-
- IntPtr dc = Runtime.PyDict_Copy(dict);
- Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc);
-
- Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
- Runtime.Incref(base_);
- int flags = TypeFlags.Default;
- flags |= TypeFlags.Managed;
- flags |= TypeFlags.HeapType;
- flags |= TypeFlags.BaseType;
- flags |= TypeFlags.Subclass;
- flags |= TypeFlags.HaveGC;
- Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+ // the derived class can have class attributes __assembly__ and __module__ which
+ // control the name of the assembly and module the new type is created in.
+ object assembly = null;
+ object namespaceStr = null;
+
+ List disposeList = new List();
+ try
+ {
+ PyObject assemblyKey = new PyObject(Converter.ToPython("__assembly__", typeof(String)));
+ disposeList.Add(assemblyKey);
+ if (0 != Runtime.PyMapping_HasKey(py_dict, assemblyKey.Handle))
+ {
+ PyObject pyAssembly = new PyObject(Runtime.PyDict_GetItem(py_dict, assemblyKey.Handle));
+ disposeList.Add(pyAssembly);
+ if (!Converter.ToManagedValue(pyAssembly.Handle, typeof(String), out assembly, false))
+ throw new InvalidCastException("Couldn't convert __assembly__ value to string");
+ }
- CopySlot(base_, type, TypeOffset.tp_traverse);
- CopySlot(base_, type, TypeOffset.tp_clear);
- CopySlot(base_, type, TypeOffset.tp_is_gc);
+ PyObject namespaceKey = new PyObject(Converter.ToPythonImplicit("__namespace__"));
+ disposeList.Add(namespaceKey);
+ if (0 != Runtime.PyMapping_HasKey(py_dict, namespaceKey.Handle))
+ {
+ PyObject pyNamespace = new PyObject(Runtime.PyDict_GetItem(py_dict, namespaceKey.Handle));
+ disposeList.Add(pyNamespace);
+ if (!Converter.ToManagedValue(pyNamespace.Handle, typeof(String), out namespaceStr, false))
+ throw new InvalidCastException("Couldn't convert __namespace__ value to string");
+ }
+ }
+ finally
+ {
+ foreach (PyObject o in disposeList)
+ o.Dispose();
+ }
- Runtime.PyType_Ready(type);
+ // create the new managed type subclassing the base managed type
+ ClassBase baseClass = ManagedType.GetManagedObject(py_base_type) as ClassBase;
+ if (null == baseClass)
+ {
+ return Exceptions.RaiseTypeError("invalid base class, expected CLR class type");
+ }
+ try
+ {
+ Type subType = ClassDerivedObject.CreateDerivedType(name,
+ baseClass.type,
+ py_dict,
+ (string)namespaceStr,
+ (string)assembly);
- IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
- IntPtr mod = Runtime.PyString_FromString("CLR");
- Runtime.PyDict_SetItemString(tp_dict, "__module__", mod);
+ // create the new ManagedType and python type
+ ClassBase subClass = ClassManager.GetClass(subType);
+ IntPtr py_type = GetTypeHandle(subClass, subType);
- // for now, move up hidden handle...
- IntPtr gc = Marshal.ReadIntPtr(base_, TypeOffset.magic());
- Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
+ // by default the class dict will have all the C# methods in it, but as this is a
+ // derived class we want the python overrides in there instead if they exist.
+ IntPtr cls_dict = Marshal.ReadIntPtr(py_type, TypeOffset.tp_dict);
+ Runtime.PyDict_Update(cls_dict, py_dict);
- return type;
+ return py_type;
+ }
+ catch (Exception e)
+ {
+ return Exceptions.RaiseTypeError(e.Message);
+ }
}
-
internal static IntPtr CreateMetaType(Type impl) {
// The managed metatype is functionally little different than the
@@ -338,12 +365,24 @@ internal static IntPtr AllocateTypeObject(string name) {
// Cheat a little: we'll set tp_name to the internal char * of
// the Python version of the type name - otherwise we'd have to
// allocate the tp_name and would have no way to free it.
-
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ // For python3 we leak two objects. One for the ascii representation
+ // required for tp_name, and another for the unicode representation
+ // for ht_name.
+ IntPtr temp = Runtime.PyBytes_FromString(name);
+ IntPtr raw = Runtime.PyBytes_AS_STRING(temp);
+ temp = Runtime.PyUnicode_FromString(name);
+#else
IntPtr temp = Runtime.PyString_FromString(name);
IntPtr raw = Runtime.PyString_AS_STRING(temp);
+#endif
Marshal.WriteIntPtr(type, TypeOffset.tp_name, raw);
Marshal.WriteIntPtr(type, TypeOffset.name, temp);
+#if (PYTHON33 || PYTHON34)
+ Marshal.WriteIntPtr(type, TypeOffset.qualname, temp);
+#endif
+
long ptr = type.ToInt64(); // 64-bit safe
temp = new IntPtr(ptr + TypeOffset.nb_add);
@@ -355,8 +394,13 @@ internal static IntPtr AllocateTypeObject(string name) {
temp = new IntPtr(ptr + TypeOffset.mp_length);
Marshal.WriteIntPtr(type, TypeOffset.tp_as_mapping, temp);
+#if (PYTHON32 || PYTHON33 || PYTHON34)
+ temp = new IntPtr(ptr + TypeOffset.bf_getbuffer);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp);
+#else
temp = new IntPtr(ptr + TypeOffset.bf_getreadbuffer);
Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp);
+#endif
return type;
}
@@ -416,19 +460,22 @@ private static void InitMethods(IntPtr pytype, Type type) {
Type marker = typeof(PythonMethodAttribute);
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
+ HashSet addedMethods = new HashSet();
while (type != null) {
MethodInfo[] methods = type.GetMethods(flags);
for (int i = 0; i < methods.Length; i++) {
MethodInfo method = methods[i];
- object[] attrs = method.GetCustomAttributes(marker, false);
- if (attrs.Length > 0) {
- string method_name = method.Name;
- MethodInfo[] mi = new MethodInfo[1];
- mi[0] = method;
- MethodObject m = new TypeMethod(method_name, mi);
- Runtime.PyDict_SetItemString(dict, method_name,
- m.pyHandle);
+ if (!addedMethods.Contains(method.Name)) {
+ object[] attrs = method.GetCustomAttributes(marker, false);
+ if (attrs.Length > 0) {
+ string method_name = method.Name;
+ MethodInfo[] mi = new MethodInfo[1];
+ mi[0] = method;
+ MethodObject m = new TypeMethod(type, method_name, mi);
+ Runtime.PyDict_SetItemString(dict, method_name, m.pyHandle);
+ addedMethods.Add(method_name);
+ }
}
}
type = type.BaseType;
diff --git a/src/runtime/typemethod.cs b/src/runtime/typemethod.cs
index ab95f28ed..9170e5a4c 100644
--- a/src/runtime/typemethod.cs
+++ b/src/runtime/typemethod.cs
@@ -19,11 +19,11 @@ namespace Python.Runtime {
internal class TypeMethod : MethodObject {
- public TypeMethod(string name, MethodInfo[] info) :
- base(name, info) {}
+ public TypeMethod(Type type, string name, MethodInfo[] info) :
+ base(type, name, info) {}
- public TypeMethod(string name, MethodInfo[] info, bool allow_threads) :
- base(name, info, allow_threads) { }
+ public TypeMethod(Type type, string name, MethodInfo[] info, bool allow_threads) :
+ base(type, name, info, allow_threads) { }
public override IntPtr Invoke(IntPtr ob, IntPtr args, IntPtr kw) {
MethodInfo mi = this.info[0];
diff --git a/src/testing/Python.Test.csproj b/src/testing/Python.Test.csproj
index b0c41a866..46ca484bc 100644
--- a/src/testing/Python.Test.csproj
+++ b/src/testing/Python.Test.csproj
@@ -120,6 +120,7 @@
+
@@ -140,8 +141,11 @@
$(SolutionDir)
+ $(TargetPath)
+ $(TargetDir)$(TargetName).pdb
-
+
+
diff --git a/src/testing/subclasstest.cs b/src/testing/subclasstest.cs
new file mode 100644
index 000000000..64cea87c6
--- /dev/null
+++ b/src/testing/subclasstest.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Python.Test
+{
+ public interface IInterfaceTest
+ {
+ // simple test with no arguments
+ string foo();
+
+ // test passing objects and boxing primitives
+ string bar(string s, int i);
+ }
+
+ public class SubClassTest : IInterfaceTest
+ {
+ public SubClassTest()
+ {
+ }
+
+ // simple test with no arguments
+ public virtual string foo()
+ {
+ return "foo";
+ }
+
+ // test passing objects and boxing primitives
+ public virtual string bar(string s, int i)
+ {
+ return s;
+ }
+
+ // virtual methods that aren't overriden in python still work
+ public virtual string not_overriden()
+ {
+ return "not_overriden";
+ }
+
+ public virtual IList return_list()
+ {
+ return new List { "a", "b", "c" };
+ }
+
+ public static IList test_list(SubClassTest x)
+ {
+ // calls into python if return_list is overriden
+ return x.return_list();
+ }
+ }
+
+ public class TestFunctions
+ {
+ public static string test_foo(IInterfaceTest x)
+ {
+ // calls into python if foo is overriden
+ return x.foo();
+ }
+
+ public static string test_bar(IInterfaceTest x, string s, int i)
+ {
+ // calls into python if bar is overriden
+ return x.bar(s, i);
+ }
+
+ // test instances can be constructed in managed code
+ public static IInterfaceTest create_instance(Type t)
+ {
+ return (IInterfaceTest)t.GetConstructor(new Type[] {}).Invoke(new Object[] {});
+ }
+
+ // test instances pass through managed code unchanged
+ public static IInterfaceTest pass_through(IInterfaceTest s)
+ {
+ return s;
+ }
+ }
+}
diff --git a/src/tests/runtests.py b/src/tests/runtests.py
index 452b701f8..60bf075bf 100644
--- a/src/tests/runtests.py
+++ b/src/tests/runtests.py
@@ -18,7 +18,7 @@
try:
import System
except ImportError:
- print "Load clr import hook"
+ print("Load clr import hook")
import clr
test_modules = (
@@ -69,6 +69,6 @@ def main(verbosity=1):
if __name__ == '__main__':
main(1)
if '--pause' in sys.argv:
- print "Press enter to continue"
+ print("Press enter to continue")
raw_input()
diff --git a/src/tests/test_array.py b/src/tests/test_array.py
index 3a2259e45..a545c1b4c 100644
--- a/src/tests/test_array.py
+++ b/src/tests/test_array.py
@@ -10,6 +10,11 @@
import sys, os, string, unittest, types
import Python.Test as Test
import System
+import six
+
+if six.PY3:
+ long = int
+ unichr = chr
class ArrayTests(unittest.TestCase):
@@ -422,8 +427,8 @@ def testInt64Array(self):
self.assertTrue(items[0] == 0)
self.assertTrue(items[4] == 4)
- max = 9223372036854775807L
- min = -9223372036854775808L
+ max = long(9223372036854775807)
+ min = long(-9223372036854775808)
items[0] = max
self.assertTrue(items[0] == max)
@@ -522,7 +527,7 @@ def testUInt32Array(self):
self.assertTrue(items[0] == 0)
self.assertTrue(items[4] == 4)
- max = 4294967295L
+ max = long(4294967295)
min = 0
items[0] = max
@@ -572,7 +577,7 @@ def testUInt64Array(self):
self.assertTrue(items[0] == 0)
self.assertTrue(items[4] == 4)
- max = 18446744073709551615L
+ max = long(18446744073709551615)
min = 0
items[0] = max
@@ -1056,7 +1061,7 @@ def testArrayIteration(self):
empty = Test.NullArrayTest().empty
for i in empty:
- raise TypeError, 'iteration over empty array'
+ raise TypeError('iteration over empty array')
def testTupleArrayConversion(self):
@@ -1131,7 +1136,10 @@ def testSequenceArrayConversion(self):
"""Test conversion of sequence-like objects to array arguments."""
from Python.Test import ArrayConversionTest
from Python.Test import Spam
- from UserList import UserList
+ if six.PY3:
+ from collections import UserList
+ else:
+ from UserList import UserList
items = UserList()
for i in range(10):
@@ -1146,7 +1154,10 @@ def testSequenceNestedArrayConversion(self):
"""Test conversion of sequences to array-of-array arguments."""
from Python.Test import ArrayConversionTest
from Python.Test import Spam
- from UserList import UserList
+ if six.PY3:
+ from collections import UserList
+ else:
+ from UserList import UserList
items = UserList()
for i in range(10):
@@ -1235,7 +1246,10 @@ def testSequenceArrayConversionTypeChecking(self):
"""Test error handling for sequence conversion to array arguments."""
from Python.Test import ArrayConversionTest
from Python.Test import Spam
- from UserList import UserList
+ if six.PY3:
+ from collections import UserList
+ else:
+ from UserList import UserList
# This should work, because null / None is a valid value in an
# array of reference types.
@@ -1353,9 +1367,9 @@ def testSpecialArrayCreation(self):
self.assertTrue(value[1] == 127)
self.assertTrue(value.Length == 2)
- value = Array[System.Char]([u'A', u'Z'])
- self.assertTrue(value[0] == u'A')
- self.assertTrue(value[1] == u'Z')
+ value = Array[System.Char]([six.u('A'), six.u('Z')])
+ self.assertTrue(value[0] == six.u('A'))
+ self.assertTrue(value[1] == six.u('Z'))
self.assertTrue(value.Length == 2)
value = Array[System.Char]([0, 65535])
@@ -1378,29 +1392,31 @@ def testSpecialArrayCreation(self):
self.assertTrue(value[1] == 2147483647)
self.assertTrue(value.Length == 2)
- value = Array[System.Int64]([0, 9223372036854775807L])
+ value = Array[System.Int64]([0, long(9223372036854775807)])
self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 9223372036854775807L)
+ self.assertTrue(value[1] == long(9223372036854775807))
self.assertTrue(value.Length == 2)
- value = Array[long]([0, 9223372036854775807L])
- self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 9223372036854775807L)
- self.assertTrue(value.Length == 2)
+ # there's no explicit long type in python3, use System.Int64 instead
+ if not six.PY3:
+ value = Array[long]([0, long(9223372036854775807)])
+ self.assertTrue(value[0] == 0)
+ self.assertTrue(value[1] == long(9223372036854775807))
+ self.assertTrue(value.Length == 2)
value = Array[System.UInt16]([0, 65000])
self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 65000)
+ self.assertTrue(value[1] == 65000)
self.assertTrue(value.Length == 2)
- value = Array[System.UInt32]([0, 4294967295L])
+ value = Array[System.UInt32]([0, long(4294967295)])
self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 4294967295L)
+ self.assertTrue(value[1] == long(4294967295))
self.assertTrue(value.Length == 2)
- value = Array[System.UInt64]([0, 18446744073709551615L])
+ value = Array[System.UInt64]([0, long(18446744073709551615)])
self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 18446744073709551615L)
+ self.assertTrue(value[1] == long(18446744073709551615))
self.assertTrue(value.Length == 2)
value = Array[System.Single]([0.0, 3.402823e38])
diff --git a/src/tests/test_class.py b/src/tests/test_class.py
index b87587586..da50ea876 100644
--- a/src/tests/test_class.py
+++ b/src/tests/test_class.py
@@ -11,6 +11,12 @@
import sys, os, string, unittest, types
import Python.Test as Test
import System
+import six
+
+if six.PY3:
+ DictProxyType = type(object.__dict__)
+else:
+ DictProxyType = types.DictProxyType
class ClassTests(unittest.TestCase):
@@ -32,7 +38,7 @@ def testClassStandardAttrs(self):
"""Test standard class attributes."""
self.assertTrue(ClassTest.__name__ == 'ClassTest')
self.assertTrue(ClassTest.__module__ == 'Python.Test')
- self.assertTrue(type(ClassTest.__dict__) == types.DictProxyType)
+ self.assertTrue(type(ClassTest.__dict__) == DictProxyType)
self.assertTrue(len(ClassTest.__doc__) > 0)
diff --git a/src/tests/test_compat.py b/src/tests/test_compat.py
index 7bb80d488..66c9cff16 100644
--- a/src/tests/test_compat.py
+++ b/src/tests/test_compat.py
@@ -8,6 +8,12 @@
# ===========================================================================
import sys, os, string, unittest, types
+import six
+
+if six.PY3:
+ ClassType = type
+else:
+ ClassType = types.ClassType
class CompatibilityTests(unittest.TestCase):
@@ -19,8 +25,11 @@ def isCLRModule(self, object):
return type(object).__name__ == 'ModuleObject'
def isCLRRootModule(self, object):
+ if six.PY3:
+ # in Python 3 the clr module is a normal python module
+ return object.__name__ == "clr"
return type(object).__name__ == 'CLRModule'
-
+
def isCLRClass(self, object):
return type(object).__name__ == 'CLR Metatype' # for now
@@ -36,9 +45,15 @@ def testSimpleImport(self):
self.assertTrue(type(sys) == types.ModuleType)
self.assertTrue(sys.__name__ == 'sys')
- import httplib
- self.assertTrue(type(httplib) == types.ModuleType)
- self.assertTrue(httplib.__name__ == 'httplib')
+ if six.PY3:
+ import http.client
+ self.assertTrue(type(http.client) == types.ModuleType)
+ self.assertTrue(http.client.__name__ == 'http.client')
+
+ else:
+ import httplib
+ self.assertTrue(type(httplib) == types.ModuleType)
+ self.assertTrue(httplib.__name__ == 'httplib')
def testSimpleImportWithAlias(self):
@@ -51,9 +66,15 @@ def testSimpleImportWithAlias(self):
self.assertTrue(type(mySys) == types.ModuleType)
self.assertTrue(mySys.__name__ == 'sys')
- import httplib as myHttplib
- self.assertTrue(type(myHttplib) == types.ModuleType)
- self.assertTrue(myHttplib.__name__ == 'httplib')
+ if six.PY3:
+ import http.client as myHttplib
+ self.assertTrue(type(myHttplib) == types.ModuleType)
+ self.assertTrue(myHttplib.__name__ == 'http.client')
+
+ else:
+ import httplib as myHttplib
+ self.assertTrue(type(myHttplib) == types.ModuleType)
+ self.assertTrue(myHttplib.__name__ == 'httplib')
def testDottedNameImport(self):
@@ -127,7 +148,7 @@ def testDottedNameImportFrom(self):
self.assertTrue(pulldom.__name__ == 'xml.dom.pulldom')
from xml.dom.pulldom import PullDOM
- self.assertTrue(type(PullDOM) == types.ClassType)
+ self.assertTrue(type(PullDOM) == ClassType)
self.assertTrue(PullDOM.__name__ == 'PullDOM')
@@ -146,7 +167,7 @@ def testDottedNameImportFromWithAlias(self):
self.assertTrue(myPulldom.__name__ == 'xml.dom.pulldom')
from xml.dom.pulldom import PullDOM as myPullDOM
- self.assertTrue(type(myPullDOM) == types.ClassType)
+ self.assertTrue(type(myPullDOM) == ClassType)
self.assertTrue(myPullDOM.__name__ == 'PullDOM')
@@ -178,7 +199,7 @@ def testExplicitAssemblyLoad(self):
self.assertTrue(assembly != None)
import CLR.System.Data
- self.assertTrue(sys.modules.has_key('System.Data'))
+ self.assertTrue('System.Data' in sys.modules)
assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam')
self.assertTrue(assembly == None)
@@ -265,7 +286,7 @@ def main():
try:
import System
except ImportError:
- print "Load clr import hook"
+ print("Load clr import hook")
import clr
main()
diff --git a/src/tests/test_constructors.py b/src/tests/test_constructors.py
index 4486e50bd..593b8afd8 100644
--- a/src/tests/test_constructors.py
+++ b/src/tests/test_constructors.py
@@ -55,7 +55,7 @@ class sub(System.Exception):
instance = sub()
ob = SubclassConstructorTest(instance)
- print ob
+ print(ob)
self.assertTrue(isinstance(ob.value, System.Exception))
diff --git a/src/tests/test_conversion.py b/src/tests/test_conversion.py
index 8408f6fe3..961c7b9e8 100644
--- a/src/tests/test_conversion.py
+++ b/src/tests/test_conversion.py
@@ -10,6 +10,11 @@
import sys, os, string, unittest, types
from Python.Test import ConversionTest
import System
+import six
+
+if six.PY3:
+ long = int
+ unichr = chr
class ConversionTests(unittest.TestCase):
@@ -176,16 +181,16 @@ def testCharConversion(self):
self.assertTrue(System.Char.MinValue == unichr(0))
object = ConversionTest()
- self.assertTrue(object.CharField == u'A')
+ self.assertTrue(object.CharField == six.u('A'))
object.CharField = 'B'
- self.assertTrue(object.CharField == u'B')
+ self.assertTrue(object.CharField == six.u('B'))
- object.CharField = u'B'
- self.assertTrue(object.CharField == u'B')
+ object.CharField = six.u('B')
+ self.assertTrue(object.CharField == six.u('B'))
object.CharField = 67
- self.assertTrue(object.CharField == u'C')
+ self.assertTrue(object.CharField == six.u('C'))
def test():
ConversionTest().CharField = 65536
@@ -307,23 +312,23 @@ def test():
def testInt64Conversion(self):
"""Test int64 conversion."""
- self.assertTrue(System.Int64.MaxValue == 9223372036854775807L)
- self.assertTrue(System.Int64.MinValue == -9223372036854775808L)
+ self.assertTrue(System.Int64.MaxValue == long(9223372036854775807))
+ self.assertTrue(System.Int64.MinValue == long(-9223372036854775808))
object = ConversionTest()
self.assertTrue(object.Int64Field == 0)
- object.Int64Field = 9223372036854775807L
- self.assertTrue(object.Int64Field == 9223372036854775807L)
+ object.Int64Field = long(9223372036854775807)
+ self.assertTrue(object.Int64Field == long(9223372036854775807))
- object.Int64Field = -9223372036854775808L
- self.assertTrue(object.Int64Field == -9223372036854775808L)
+ object.Int64Field = long(-9223372036854775808)
+ self.assertTrue(object.Int64Field == long(-9223372036854775808))
- object.Int64Field = System.Int64(9223372036854775807L)
- self.assertTrue(object.Int64Field == 9223372036854775807L)
+ object.Int64Field = System.Int64(long(9223372036854775807))
+ self.assertTrue(object.Int64Field == long(9223372036854775807))
- object.Int64Field = System.Int64(-9223372036854775808L)
- self.assertTrue(object.Int64Field == -9223372036854775808L)
+ object.Int64Field = System.Int64(long(-9223372036854775808))
+ self.assertTrue(object.Int64Field == long(-9223372036854775808))
def test():
ConversionTest().Int64Field = "spam"
@@ -336,22 +341,22 @@ def test():
self.assertRaises(TypeError, test)
def test():
- ConversionTest().Int64Field = 9223372036854775808L
+ ConversionTest().Int64Field = long(9223372036854775808)
self.assertRaises(OverflowError, test)
def test():
- ConversionTest().Int64Field = -9223372036854775809L
+ ConversionTest().Int64Field = long(-9223372036854775809)
self.assertRaises(OverflowError, test)
def test():
- value = System.Int64(9223372036854775808L)
+ value = System.Int64(long(9223372036854775808))
self.assertRaises(OverflowError, test)
def test():
- value = System.Int64(-9223372036854775809L)
+ value = System.Int64(long(-9223372036854775809))
self.assertRaises(OverflowError, test)
@@ -409,20 +414,20 @@ def test():
def testUInt32Conversion(self):
"""Test uint32 conversion."""
- self.assertTrue(System.UInt32.MaxValue == 4294967295L)
+ self.assertTrue(System.UInt32.MaxValue == long(4294967295))
self.assertTrue(System.UInt32.MinValue == 0)
object = ConversionTest()
self.assertTrue(object.UInt32Field == 0)
- object.UInt32Field = 4294967295L
- self.assertTrue(object.UInt32Field == 4294967295L)
+ object.UInt32Field = long(4294967295)
+ self.assertTrue(object.UInt32Field == long(4294967295))
object.UInt32Field = -0
self.assertTrue(object.UInt32Field == 0)
- object.UInt32Field = System.UInt32(4294967295L)
- self.assertTrue(object.UInt32Field == 4294967295L)
+ object.UInt32Field = System.UInt32(long(4294967295))
+ self.assertTrue(object.UInt32Field == long(4294967295))
object.UInt32Field = System.UInt32(0)
self.assertTrue(object.UInt32Field == 0)
@@ -438,7 +443,7 @@ def test():
self.assertRaises(TypeError, test)
def test():
- ConversionTest().UInt32Field = 4294967296L
+ ConversionTest().UInt32Field = long(4294967296)
self.assertRaises(OverflowError, test)
@@ -448,7 +453,7 @@ def test():
self.assertRaises(OverflowError, test)
def test():
- value = System.UInt32(4294967296L)
+ value = System.UInt32(long(4294967296))
self.assertRaises(OverflowError, test)
@@ -460,20 +465,20 @@ def test():
def testUInt64Conversion(self):
"""Test uint64 conversion."""
- self.assertTrue(System.UInt64.MaxValue == 18446744073709551615L)
+ self.assertTrue(System.UInt64.MaxValue == long(18446744073709551615))
self.assertTrue(System.UInt64.MinValue == 0)
object = ConversionTest()
self.assertTrue(object.UInt64Field == 0)
- object.UInt64Field = 18446744073709551615L
- self.assertTrue(object.UInt64Field == 18446744073709551615L)
+ object.UInt64Field = long(18446744073709551615)
+ self.assertTrue(object.UInt64Field == long(18446744073709551615))
object.UInt64Field = -0
self.assertTrue(object.UInt64Field == 0)
- object.UInt64Field = System.UInt64(18446744073709551615L)
- self.assertTrue(object.UInt64Field == 18446744073709551615L)
+ object.UInt64Field = System.UInt64(long(18446744073709551615))
+ self.assertTrue(object.UInt64Field == long(18446744073709551615))
object.UInt64Field = System.UInt64(0)
self.assertTrue(object.UInt64Field == 0)
@@ -489,7 +494,7 @@ def test():
self.assertRaises(TypeError, test)
def test():
- ConversionTest().UInt64Field = 18446744073709551616L
+ ConversionTest().UInt64Field = long(18446744073709551616)
self.assertRaises(OverflowError, test)
@@ -499,7 +504,7 @@ def test():
self.assertRaises(OverflowError, test)
def test():
- value = System.UInt64(18446744073709551616L)
+ value = System.UInt64(long(18446744073709551616))
self.assertRaises(OverflowError, test)
@@ -618,7 +623,7 @@ def testDecimalConversion(self):
max_d = Decimal.Parse("79228162514264337593543950335")
min_d = Decimal.Parse("-79228162514264337593543950335")
- self.assertTrue(Decimal.ToInt64(Decimal(10)) == 10L)
+ self.assertTrue(Decimal.ToInt64(Decimal(10)) == long(10))
object = ConversionTest()
self.assertTrue(object.DecimalField == Decimal(0))
@@ -659,25 +664,25 @@ def testStringConversion(self):
object = ConversionTest()
self.assertTrue(object.StringField == "spam")
- self.assertTrue(object.StringField == u"spam")
+ self.assertTrue(object.StringField == six.u("spam"))
object.StringField = "eggs"
self.assertTrue(object.StringField == "eggs")
- self.assertTrue(object.StringField == u"eggs")
+ self.assertTrue(object.StringField == six.u("eggs"))
- object.StringField = u"spam"
+ object.StringField = six.u("spam")
self.assertTrue(object.StringField == "spam")
- self.assertTrue(object.StringField == u"spam")
+ self.assertTrue(object.StringField == six.u("spam"))
- object.StringField = u'\uffff\uffff'
- self.assertTrue(object.StringField == u'\uffff\uffff')
+ object.StringField = six.u('\uffff\uffff')
+ self.assertTrue(object.StringField == six.u('\uffff\uffff'))
object.StringField = System.String("spam")
self.assertTrue(object.StringField == "spam")
- self.assertTrue(object.StringField == u"spam")
+ self.assertTrue(object.StringField == six.u("spam"))
- object.StringField = System.String(u'\uffff\uffff')
- self.assertTrue(object.StringField == u'\uffff\uffff')
+ object.StringField = System.String(six.u('\uffff\uffff'))
+ self.assertTrue(object.StringField == six.u('\uffff\uffff'))
object.StringField = None
self.assertTrue(object.StringField == None)
@@ -829,11 +834,11 @@ def testByteArrayConversion(self):
self.assertTrue(array[0] == 0)
self.assertTrue(array[4] == 4)
- value = "testing"
+ value = six.b("testing")
object.ByteArrayField = value
array = object.ByteArrayField
for i in range(len(value)):
- self.assertTrue(array[i] == ord(value[i]))
+ self.assertTrue(array[i] == six.indexbytes(value, i))
def testSByteArrayConversion(self):
@@ -848,11 +853,11 @@ def testSByteArrayConversion(self):
self.assertTrue(array[0] == 0)
self.assertTrue(array[4] == 4)
- value = "testing"
+ value = six.b("testing")
object.SByteArrayField = value
array = object.SByteArrayField
for i in range(len(value)):
- self.assertTrue(array[i] == ord(value[i]))
+ self.assertTrue(array[i] == six.indexbytes(value, i))
diff --git a/src/tests/test_delegate.py b/src/tests/test_delegate.py
index 21c53ea3f..0d2315925 100644
--- a/src/tests/test_delegate.py
+++ b/src/tests/test_delegate.py
@@ -15,6 +15,12 @@
import sys, os, string, unittest, types
import Python.Test as Test
import System
+import six
+
+if six.PY3:
+ DictProxyType = type(object.__dict__)
+else:
+ DictProxyType = types.DictProxyType
class DelegateTests(unittest.TestCase):
@@ -24,7 +30,7 @@ def testDelegateStandardAttrs(self):
"""Test standard delegate attributes."""
self.assertTrue(PublicDelegate.__name__ == 'PublicDelegate')
self.assertTrue(PublicDelegate.__module__ == 'Python.Test')
- self.assertTrue(type(PublicDelegate.__dict__) == types.DictProxyType)
+ self.assertTrue(type(PublicDelegate.__dict__) == DictProxyType)
self.assertTrue(PublicDelegate.__doc__ == None)
diff --git a/src/tests/test_enum.py b/src/tests/test_enum.py
index 98db3f3c6..26b14c274 100644
--- a/src/tests/test_enum.py
+++ b/src/tests/test_enum.py
@@ -10,6 +10,13 @@
import sys, os, string, unittest, types
from System import DayOfWeek
from Python import Test
+import six
+
+if six.PY3:
+ DictProxyType = type(object.__dict__)
+ long = int
+else:
+ DictProxyType = types.DictProxyType
class EnumTests(unittest.TestCase):
@@ -19,7 +26,7 @@ def testEnumStandardAttrs(self):
"""Test standard enum attributes."""
self.assertTrue(DayOfWeek.__name__ == 'DayOfWeek')
self.assertTrue(DayOfWeek.__module__ == 'System')
- self.assertTrue(type(DayOfWeek.__dict__) == types.DictProxyType)
+ self.assertTrue(type(DayOfWeek.__dict__) == DictProxyType)
self.assertTrue(DayOfWeek.__doc__ == None)
@@ -71,23 +78,23 @@ def testIntEnum(self):
def testUIntEnum(self):
"""Test uint enum."""
- self.assertTrue(Test.UIntEnum.Zero == 0L)
- self.assertTrue(Test.UIntEnum.One == 1L)
- self.assertTrue(Test.UIntEnum.Two == 2L)
+ self.assertTrue(Test.UIntEnum.Zero == long(0))
+ self.assertTrue(Test.UIntEnum.One == long(1))
+ self.assertTrue(Test.UIntEnum.Two == long(2))
def testLongEnum(self):
"""Test long enum."""
- self.assertTrue(Test.LongEnum.Zero == 0L)
- self.assertTrue(Test.LongEnum.One == 1L)
- self.assertTrue(Test.LongEnum.Two == 2L)
+ self.assertTrue(Test.LongEnum.Zero == long(0))
+ self.assertTrue(Test.LongEnum.One == long(1))
+ self.assertTrue(Test.LongEnum.Two == long(2))
def testULongEnum(self):
"""Test ulong enum."""
- self.assertTrue(Test.ULongEnum.Zero == 0L)
- self.assertTrue(Test.ULongEnum.One == 1L)
- self.assertTrue(Test.ULongEnum.Two == 2L)
+ self.assertTrue(Test.ULongEnum.Zero == long(0))
+ self.assertTrue(Test.ULongEnum.One == long(1))
+ self.assertTrue(Test.ULongEnum.Two == long(2))
def testInstantiateEnumFails(self):
diff --git a/src/tests/test_exceptions.py b/src/tests/test_exceptions.py
index de6dd01e5..86a141403 100644
--- a/src/tests/test_exceptions.py
+++ b/src/tests/test_exceptions.py
@@ -9,6 +9,10 @@
import sys, os, string, unittest, types
import System
+import six
+
+if six.PY3:
+ unicode = str
# Note: all of these tests are known to fail because Python currently
# doesn't allow new-style classes to be used as exceptions. I'm leaving
@@ -21,10 +25,11 @@ class ExceptionTests(unittest.TestCase):
def testUnifiedExceptionSemantics(self):
"""Test unified exception semantics."""
from System import Exception, Object
- import exceptions
e = Exception('Something bad happened')
- self.assertTrue(isinstance(e, exceptions.Exception))
+ if not six.PY3:
+ import exceptions
+ self.assertTrue(isinstance(e, exceptions.Exception))
self.assertTrue(isinstance(e, Exception))
@@ -49,7 +54,6 @@ def testExtendedExceptionAttributes(self):
"""Test accessing extended exception attributes."""
from Python.Test import ExceptionTest, ExtendedException
from System import Exception, OverflowException
- import exceptions
e = ExceptionTest.GetExtendedException()
self.assertTrue(isinstance(e, ExtendedException))
@@ -93,7 +97,7 @@ def testRaiseClassExceptionWithValue(self):
from System import NullReferenceException
def test():
- raise NullReferenceException, 'Aiiieee!'
+ raise NullReferenceException('Aiiieee!')
self.assertRaises(NullReferenceException, test)
@@ -185,7 +189,8 @@ def testCatchExceptionFromManagedMethod(self):
try:
ExceptionTest().ThrowException()
- except OverflowException, e:
+ except OverflowException:
+ e = sys.exc_info()[1]
self.assertTrue(isinstance(e, OverflowException))
return
@@ -199,13 +204,15 @@ def testCatchExceptionFromManagedProperty(self):
try:
v = ExceptionTest().ThrowProperty
- except OverflowException, e:
+ except OverflowException:
+ e = sys.exc_info()[1]
self.assertTrue(isinstance(e, OverflowException))
return
try:
ExceptionTest().ThrowProperty = 1
- except OverflowException, e:
+ except OverflowException:
+ e = sys.exc_info()[1]
self.assertTrue(isinstance(e, OverflowException))
return
@@ -227,7 +234,10 @@ def testCatchExceptionManagedClass(self):
def testCatchExceptionPythonClass(self):
"""Test catching the python class of an exception."""
from System import OverflowException
- from exceptions import Exception
+ if six.PY3:
+ from builtins import Exception
+ else:
+ from exceptions import Exception
try:
raise OverflowException('overflow')
@@ -267,7 +277,8 @@ def testCatchExceptionWithAssignment(self):
try:
raise OverflowException('overflow')
- except OverflowException, e:
+ except OverflowException:
+ e = sys.exc_info()[1]
self.assertTrue(isinstance(e, OverflowException))
@@ -303,9 +314,10 @@ def testStrOfException(self):
try:
Convert.ToDateTime('this will fail')
- except FormatException, e:
+ except FormatException:
+ e = sys.exc_info()[1]
msg = unicode(e).encode("utf8") # fix for international installation
- self.assertTrue(msg.find('System.Convert.ToDateTime') > -1, msg)
+ self.assertTrue(msg.find(unicode('System.Convert.ToDateTime').encode("utf8")) > -1, msg)
def testPythonCompatOfManagedExceptions(self):
diff --git a/src/tests/test_field.py b/src/tests/test_field.py
index e266f65d1..1ec9c7744 100644
--- a/src/tests/test_field.py
+++ b/src/tests/test_field.py
@@ -11,6 +11,12 @@
from Python.Test import FieldTest
from Python.Test import ShortEnum
import System
+import six
+
+if six.PY3:
+ IntType = int
+else:
+ IntType = types.IntType
class FieldTests(unittest.TestCase):
@@ -212,15 +218,15 @@ def testFieldDescriptorGetSet(self):
self.assertTrue(object.PublicStaticField == 0)
descriptor = FieldTest.__dict__['PublicStaticField']
- self.assertTrue(type(descriptor) != types.IntType)
+ self.assertTrue(type(descriptor) != IntType)
object.PublicStaticField = 0
descriptor = FieldTest.__dict__['PublicStaticField']
- self.assertTrue(type(descriptor) != types.IntType)
+ self.assertTrue(type(descriptor) != IntType)
FieldTest.PublicStaticField = 0
descriptor = FieldTest.__dict__['PublicStaticField']
- self.assertTrue(type(descriptor) != types.IntType)
+ self.assertTrue(type(descriptor) != IntType)
def testFieldDescriptorWrongType(self):
@@ -286,15 +292,15 @@ def testByteField(self):
def testCharField(self):
"""Test char fields."""
object = FieldTest()
- self.assertTrue(object.CharField == u'A')
+ self.assertTrue(object.CharField == six.u('A'))
self.assertTrue(object.CharField == 'A')
object.CharField = 'B'
- self.assertTrue(object.CharField == u'B')
+ self.assertTrue(object.CharField == six.u('B'))
self.assertTrue(object.CharField == 'B')
- object.CharField = u'C'
- self.assertTrue(object.CharField == u'C')
+ object.CharField = six.u('C')
+ self.assertTrue(object.CharField == six.u('C'))
self.assertTrue(object.CharField == 'C')
diff --git a/src/tests/test_generic.py b/src/tests/test_generic.py
index 256bca29a..d7ae2e26b 100644
--- a/src/tests/test_generic.py
+++ b/src/tests/test_generic.py
@@ -14,6 +14,13 @@
import sys, os, string, unittest, types
import Python.Test as Test
import System
+import six
+
+if six.PY3:
+ long = int
+ unichr = chr
+ unicode = str
+
class GenericTests(unittest.TestCase):
"""Test CLR generics support."""
@@ -42,13 +49,13 @@ def testPythonTypeAliasing(self):
dict = Dictionary[long, long]()
self.assertEquals(dict.Count, 0)
- dict.Add(1L, 1L)
- self.assertTrue(dict[1L] == 1L)
+ dict.Add(long(1), long(1))
+ self.assertTrue(dict[long(1)] == long(1))
dict = Dictionary[System.Int64, System.Int64]()
self.assertEquals(dict.Count, 0)
- dict.Add(1L, 1L)
- self.assertTrue(dict[1L] == 1L)
+ dict.Add(long(1), long(1))
+ self.assertTrue(dict[long(1)] == long(1))
dict = Dictionary[float, float]()
self.assertEquals(dict.Count, 0)
@@ -172,15 +179,17 @@ def testGenericTypeBinding(self):
self._testGenericWrapperByType(bool, True)
self._testGenericWrapperByType(System.Byte, 255)
self._testGenericWrapperByType(System.SByte, 127)
- self._testGenericWrapperByType(System.Char, u'A')
+ self._testGenericWrapperByType(System.Char, six.u('A'))
self._testGenericWrapperByType(System.Int16, 32767)
self._testGenericWrapperByType(System.Int32, 2147483647)
self._testGenericWrapperByType(int, 2147483647)
- self._testGenericWrapperByType(System.Int64, 9223372036854775807L)
- self._testGenericWrapperByType(long, 9223372036854775807L)
+ self._testGenericWrapperByType(System.Int64, long(9223372036854775807))
+ # Python 3 has no explicit long type, use System.Int64 instead
+ if not six.PY3:
+ self._testGenericWrapperByType(long, long(9223372036854775807))
self._testGenericWrapperByType(System.UInt16, 65000)
- self._testGenericWrapperByType(System.UInt32, 4294967295L)
- self._testGenericWrapperByType(System.UInt64, 18446744073709551615L)
+ self._testGenericWrapperByType(System.UInt32, long(4294967295))
+ self._testGenericWrapperByType(System.UInt64, long(18446744073709551615))
self._testGenericWrapperByType(System.Single, 3.402823e38)
self._testGenericWrapperByType(System.Double, 1.7976931348623157e308)
self._testGenericWrapperByType(float, 1.7976931348623157e308)
@@ -309,15 +318,17 @@ def testGenericMethodTypeHandling(self):
self._testGenericMethodByType(bool, True)
self._testGenericMethodByType(System.Byte, 255)
self._testGenericMethodByType(System.SByte, 127)
- self._testGenericMethodByType(System.Char, u'A')
+ self._testGenericMethodByType(System.Char, six.u('A'))
self._testGenericMethodByType(System.Int16, 32767)
self._testGenericMethodByType(System.Int32, 2147483647)
self._testGenericMethodByType(int, 2147483647)
- self._testGenericMethodByType(System.Int64, 9223372036854775807L)
- self._testGenericMethodByType(long, 9223372036854775807L)
+ # Python 3 has no explicit long type, use System.Int64 instead
+ if not six.PY3:
+ self._testGenericMethodByType(System.Int64, long(9223372036854775807))
+ self._testGenericMethodByType(long, long(9223372036854775807))
+ self._testGenericMethodByType(System.UInt32, long(4294967295))
+ self._testGenericMethodByType(System.Int64, long(1844674407370955161))
self._testGenericMethodByType(System.UInt16, 65000)
- self._testGenericMethodByType(System.UInt32, 4294967295L)
- self._testGenericMethodByType(System.Int64, 1844674407370955161L)
self._testGenericMethodByType(System.Single, 3.402823e38)
self._testGenericMethodByType(System.Double, 1.7976931348623157e308)
self._testGenericMethodByType(float, 1.7976931348623157e308)
@@ -439,9 +450,9 @@ def testMethodOverloadSelectionWithGenericTypes(self):
self.assertTrue(value.value == 127)
vtype = GenericWrapper[System.Char]
- input = vtype(u'A')
+ input = vtype(six.u('A'))
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value.value == u'A')
+ self.assertTrue(value.value == six.u('A'))
vtype = GenericWrapper[System.Char]
input = vtype(65535)
@@ -464,14 +475,16 @@ def testMethodOverloadSelectionWithGenericTypes(self):
self.assertTrue(value.value == 2147483647)
vtype = GenericWrapper[System.Int64]
- input = vtype(9223372036854775807L)
+ input = vtype(long(9223372036854775807))
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value.value == 9223372036854775807L)
+ self.assertTrue(value.value == long(9223372036854775807))
- vtype = GenericWrapper[long]
- input = vtype(9223372036854775807L)
- value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value.value == 9223372036854775807L)
+ # Python 3 has no explicit long type, use System.Int64 instead
+ if not six.PY3:
+ vtype = GenericWrapper[long]
+ input = vtype(long(9223372036854775807))
+ value = MethodTest.Overloaded.__overloads__[vtype](input)
+ self.assertTrue(value.value == long(9223372036854775807))
vtype = GenericWrapper[System.UInt16]
input = vtype(65000)
@@ -479,14 +492,14 @@ def testMethodOverloadSelectionWithGenericTypes(self):
self.assertTrue(value.value == 65000)
vtype = GenericWrapper[System.UInt32]
- input = vtype(4294967295L)
+ input = vtype(long(4294967295))
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value.value == 4294967295L)
+ self.assertTrue(value.value == long(4294967295))
vtype = GenericWrapper[System.UInt64]
- input = vtype(18446744073709551615L)
+ input = vtype(long(18446744073709551615))
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value.value == 18446744073709551615L)
+ self.assertTrue(value.value == long(18446744073709551615))
vtype = GenericWrapper[System.Single]
input = vtype(3.402823e38)
@@ -580,9 +593,9 @@ def testOverloadSelectionWithArraysOfGenericTypes(self):
gtype = GenericWrapper[System.Char]
vtype = System.Array[gtype]
- input = vtype([gtype(u'A'), gtype(u'A')])
+ input = vtype([gtype(six.u('A')), gtype(six.u('A'))])
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value[0].value == u'A')
+ self.assertTrue(value[0].value == six.u('A'))
self.assertTrue(value.Length == 2)
gtype = GenericWrapper[System.Char]
@@ -615,19 +628,21 @@ def testOverloadSelectionWithArraysOfGenericTypes(self):
gtype = GenericWrapper[System.Int64]
vtype = System.Array[gtype]
- input = vtype([gtype(9223372036854775807L),
- gtype(9223372036854775807L)])
- value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value[0].value == 9223372036854775807L)
- self.assertTrue(value.Length == 2)
-
- gtype = GenericWrapper[long]
- vtype = System.Array[gtype]
- input = vtype([gtype(9223372036854775807L),
- gtype(9223372036854775807L)])
+ input = vtype([gtype(long(9223372036854775807)),
+ gtype(long(9223372036854775807))])
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value[0].value == 9223372036854775807L)
+ self.assertTrue(value[0].value == long(9223372036854775807))
self.assertTrue(value.Length == 2)
+
+ # Python 3 has no explicit long type, use System.Int64 instead
+ if not six.PY3:
+ gtype = GenericWrapper[long]
+ vtype = System.Array[gtype]
+ input = vtype([gtype(long(9223372036854775807)),
+ gtype(long(9223372036854775807))])
+ value = MethodTest.Overloaded.__overloads__[vtype](input)
+ self.assertTrue(value[0].value == long(9223372036854775807))
+ self.assertTrue(value.Length == 2)
gtype = GenericWrapper[System.UInt16]
vtype = System.Array[gtype]
@@ -638,17 +653,17 @@ def testOverloadSelectionWithArraysOfGenericTypes(self):
gtype = GenericWrapper[System.UInt32]
vtype = System.Array[gtype]
- input = vtype([gtype(4294967295L), gtype(4294967295L)])
+ input = vtype([gtype(long(4294967295)), gtype(long(4294967295))])
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value[0].value == 4294967295L)
+ self.assertTrue(value[0].value == long(4294967295))
self.assertTrue(value.Length == 2)
gtype = GenericWrapper[System.UInt64]
vtype = System.Array[gtype]
- input = vtype([gtype(18446744073709551615L),
- gtype(18446744073709551615L)])
+ input = vtype([gtype(long(18446744073709551615)),
+ gtype(long(18446744073709551615))])
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value[0].value == 18446744073709551615L)
+ self.assertTrue(value[0].value == long(18446744073709551615))
self.assertTrue(value.Length == 2)
gtype = GenericWrapper[System.Single]
diff --git a/src/tests/test_indexer.py b/src/tests/test_indexer.py
index 2b1d4e100..cb572e3a8 100644
--- a/src/tests/test_indexer.py
+++ b/src/tests/test_indexer.py
@@ -9,6 +9,11 @@
import sys, os, string, unittest, types
import Python.Test as Test
+import six
+
+if six.PY3:
+ long = int
+ unichr = chr
class IndexerTests(unittest.TestCase):
@@ -238,8 +243,8 @@ def test():
def testInt64Indexer(self):
"""Test Int64 indexers."""
object = Test.Int64IndexerTest()
- max = 9223372036854775807L
- min = -9223372036854775808L
+ max = long(9223372036854775807)
+ min = long(-9223372036854775808)
self.assertTrue(object[max] == None)
@@ -292,7 +297,7 @@ def test():
def testUInt32Indexer(self):
"""Test UInt32 indexers."""
object = Test.UInt32IndexerTest()
- max = 4294967295L
+ max = long(4294967295)
min = 0
self.assertTrue(object[max] == None)
@@ -319,7 +324,7 @@ def test():
def testUInt64Indexer(self):
"""Test UInt64 indexers."""
object = Test.UInt64IndexerTest()
- max = 18446744073709551615L
+ max = long(18446744073709551615)
min = 0
self.assertTrue(object[max] == None)
@@ -431,19 +436,19 @@ def testStringIndexer(self):
object = Test.StringIndexerTest()
self.assertTrue(object["spam"] == None)
- self.assertTrue(object[u"spam"] == None)
+ self.assertTrue(object[six.u("spam")] == None)
object["spam"] = "spam"
self.assertTrue(object["spam"] == "spam")
- self.assertTrue(object["spam"] == u"spam")
- self.assertTrue(object[u"spam"] == "spam")
- self.assertTrue(object[u"spam"] == u"spam")
+ self.assertTrue(object["spam"] == six.u("spam"))
+ self.assertTrue(object[six.u("spam")] == "spam")
+ self.assertTrue(object[six.u("spam")] == six.u("spam"))
- object[u"eggs"] = u"eggs"
+ object[six.u("eggs")] = six.u("eggs")
self.assertTrue(object["eggs"] == "eggs")
- self.assertTrue(object["eggs"] == u"eggs")
- self.assertTrue(object[u"eggs"] == "eggs")
- self.assertTrue(object[u"eggs"] == u"eggs")
+ self.assertTrue(object["eggs"] == six.u("eggs"))
+ self.assertTrue(object[six.u("eggs")] == "eggs")
+ self.assertTrue(object[six.u("eggs")] == six.u("eggs"))
def test():
object = Test.StringIndexerTest()
@@ -509,8 +514,8 @@ def testObjectIndexer(self):
object[1] = "one"
self.assertTrue(object[1] == "one")
- object[1L] = "long"
- self.assertTrue(object[1L] == "long")
+ object[long(1)] = "long"
+ self.assertTrue(object[long(1)] == "long")
def test():
class eggs:
diff --git a/src/tests/test_interface.py b/src/tests/test_interface.py
index 1e9c0ad96..4412aefb2 100644
--- a/src/tests/test_interface.py
+++ b/src/tests/test_interface.py
@@ -11,6 +11,13 @@
import sys, os, string, unittest, types
import Python.Test as Test
import System
+import six
+
+if six.PY3:
+ DictProxyType = type(object.__dict__)
+else:
+ DictProxyType = types.DictProxyType
+
class InterfaceTests(unittest.TestCase):
"""Test CLR interface support."""
@@ -20,7 +27,7 @@ def testInterfaceStandardAttrs(self):
from Python.Test import IPublicInterface as ip
self.assertTrue(ip.__name__ == 'IPublicInterface')
self.assertTrue(ip.__module__ == 'Python.Test')
- self.assertTrue(type(ip.__dict__) == types.DictProxyType)
+ self.assertTrue(type(ip.__dict__) == DictProxyType)
def testGlobalInterfaceVisibility(self):
diff --git a/src/tests/test_method.py b/src/tests/test_method.py
index 03a23cf84..cdfc1e33b 100644
--- a/src/tests/test_method.py
+++ b/src/tests/test_method.py
@@ -13,6 +13,12 @@
from Python.Test import MethodTest, MethodTestSub
import System
+import six
+
+if six.PY3:
+ long = int
+ unichr = chr
+
class MethodTests(unittest.TestCase):
"""Test CLR method support."""
@@ -235,11 +241,11 @@ def testMethodCallStructConversion(self):
def testSubclassInstanceConversion(self):
"""Test subclass instance conversion in method call."""
- class sub(System.Exception):
+ class TestSubException(System.Exception):
pass
object = MethodTest()
- instance = sub()
+ instance = TestSubException()
result = object.TestSubclassConversion(instance)
self.assertTrue(isinstance(result, System.Exception))
@@ -501,8 +507,8 @@ def testExplicitOverloadSelection(self):
value = MethodTest.Overloaded.__overloads__[System.SByte](127)
self.assertTrue(value == 127)
- value = MethodTest.Overloaded.__overloads__[System.Char](u'A')
- self.assertTrue(value == u'A')
+ value = MethodTest.Overloaded.__overloads__[System.Char](six.u('A'))
+ self.assertTrue(value == six.u('A'))
value = MethodTest.Overloaded.__overloads__[System.Char](65535)
self.assertTrue(value == unichr(65535))
@@ -517,25 +523,27 @@ def testExplicitOverloadSelection(self):
self.assertTrue(value == 2147483647)
value = MethodTest.Overloaded.__overloads__[System.Int64](
- 9223372036854775807L
+ long(9223372036854775807)
)
- self.assertTrue(value == 9223372036854775807L)
+ self.assertTrue(value == long(9223372036854775807))
- value = MethodTest.Overloaded.__overloads__[long](
- 9223372036854775807L
- )
- self.assertTrue(value == 9223372036854775807L)
+ # Python 3 has no explicit long type, use System.Int64 instead
+ if not six.PY3:
+ value = MethodTest.Overloaded.__overloads__[long](
+ long(9223372036854775807)
+ )
+ self.assertTrue(value == long(9223372036854775807))
value = MethodTest.Overloaded.__overloads__[System.UInt16](65000)
self.assertTrue(value == 65000)
- value = MethodTest.Overloaded.__overloads__[System.UInt32](4294967295L)
- self.assertTrue(value == 4294967295L)
+ value = MethodTest.Overloaded.__overloads__[System.UInt32](long(4294967295))
+ self.assertTrue(value == long(4294967295))
value = MethodTest.Overloaded.__overloads__[System.UInt64](
- 18446744073709551615L
+ long(18446744073709551615)
)
- self.assertTrue(value == 18446744073709551615L)
+ self.assertTrue(value == long(18446744073709551615))
value = MethodTest.Overloaded.__overloads__[System.Single](3.402823e38)
self.assertTrue(value == 3.402823e38)
@@ -617,10 +625,10 @@ def testOverloadSelectionWithArrayTypes(self):
self.assertTrue(value[1] == 127)
vtype = Array[System.Char]
- input = vtype([u'A', u'Z'])
+ input = vtype([six.u('A'), six.u('Z')])
value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value[0] == u'A')
- self.assertTrue(value[1] == u'Z')
+ self.assertTrue(value[0] == six.u('A'))
+ self.assertTrue(value[1] == six.u('Z'))
vtype = Array[System.Char]
input = vtype([0, 65535])
@@ -647,16 +655,18 @@ def testOverloadSelectionWithArrayTypes(self):
self.assertTrue(value[1] == 2147483647)
vtype = Array[System.Int64]
- input = vtype([0, 9223372036854775807L])
+ input = vtype([0, long(9223372036854775807)])
value = MethodTest.Overloaded.__overloads__[vtype](input)
self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 9223372036854775807L)
+ self.assertTrue(value[1] == long(9223372036854775807))
- vtype = Array[long]
- input = vtype([0, 9223372036854775807L])
- value = MethodTest.Overloaded.__overloads__[vtype](input)
- self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 9223372036854775807L)
+ # Python 3 has no explicit long type, use System.Int64 instead
+ if not six.PY3:
+ vtype = Array[long]
+ input = vtype([0, long(9223372036854775807)])
+ value = MethodTest.Overloaded.__overloads__[vtype](input)
+ self.assertTrue(value[0] == 0)
+ self.assertTrue(value[1] == long(9223372036854775807))
vtype = Array[System.UInt16]
input = vtype([0, 65000])
@@ -665,16 +675,16 @@ def testOverloadSelectionWithArrayTypes(self):
self.assertTrue(value[1] == 65000)
vtype = Array[System.UInt32]
- input = vtype([0, 4294967295L])
+ input = vtype([0, long(4294967295)])
value = MethodTest.Overloaded.__overloads__[vtype](input)
self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 4294967295L)
+ self.assertTrue(value[1] == long(4294967295))
vtype = Array[System.UInt64]
- input = vtype([0, 18446744073709551615L])
+ input = vtype([0, long(18446744073709551615)])
value = MethodTest.Overloaded.__overloads__[vtype](input)
self.assertTrue(value[0] == 0)
- self.assertTrue(value[1] == 18446744073709551615L)
+ self.assertTrue(value[1] == long(18446744073709551615))
vtype = Array[System.Single]
input = vtype([0.0, 3.402823e38])
diff --git a/src/tests/test_module.py b/src/tests/test_module.py
index 62ea78311..0d340652a 100644
--- a/src/tests/test_module.py
+++ b/src/tests/test_module.py
@@ -13,6 +13,13 @@
# testImplicitAssemblyLoad() passes on deprecation warning; perfect! #
##clr.AddReference('System.Windows.Forms')
import sys, os, string, unittest, types, warnings
+from fnmatch import fnmatch
+import six
+
+if six.PY3:
+ ClassType = type
+else:
+ ClassType = types.ClassType
class ModuleTests(unittest.TestCase):
@@ -22,6 +29,9 @@ def isCLRModule(self, object):
return type(object).__name__ == 'ModuleObject'
def isCLRRootModule(self, object):
+ if six.PY3:
+ # in Python 3 the clr module is a normal python module
+ return object.__name__ == "clr"
return type(object).__name__ == 'CLRModule'
def isCLRClass(self, object):
@@ -62,8 +72,9 @@ def testModuleInterface(self):
import System
self.assertEquals(type(System.__dict__), type({}))
self.assertEquals(System.__name__, 'System')
- self.assertEquals(System.__file__, None)
- self.assertEquals(System.__doc__, None)
+ # the filename can be any module from the System namespace (eg System.Data.dll or System.dll)
+ self.assertTrue(fnmatch(System.__file__, "*System*.dll"))
+ self.assertTrue(System.__doc__.startswith("Namespace containing types from the following assemblies:"))
self.assertTrue(self.isCLRClass(System.String))
self.assertTrue(self.isCLRClass(System.Int32))
@@ -78,9 +89,14 @@ def testSimpleImport(self):
self.assertTrue(type(sys) == types.ModuleType)
self.assertTrue(sys.__name__ == 'sys')
- import httplib
- self.assertTrue(type(httplib) == types.ModuleType)
- self.assertTrue(httplib.__name__ == 'httplib')
+ if six.PY3:
+ import http.client as httplib
+ self.assertTrue(type(httplib) == types.ModuleType)
+ self.assertTrue(httplib.__name__ == 'http.client')
+ else:
+ import httplib
+ self.assertTrue(type(httplib) == types.ModuleType)
+ self.assertTrue(httplib.__name__ == 'httplib')
def testSimpleImportWithAlias(self):
@@ -93,9 +109,14 @@ def testSimpleImportWithAlias(self):
self.assertTrue(type(mySys) == types.ModuleType)
self.assertTrue(mySys.__name__ == 'sys')
- import httplib as myHttplib
- self.assertTrue(type(myHttplib) == types.ModuleType)
- self.assertTrue(myHttplib.__name__ == 'httplib')
+ if six.PY3:
+ import http.client as myHttplib
+ self.assertTrue(type(myHttplib) == types.ModuleType)
+ self.assertTrue(myHttplib.__name__ == 'http.client')
+ else:
+ import httplib as myHttplib
+ self.assertTrue(type(myHttplib) == types.ModuleType)
+ self.assertTrue(myHttplib.__name__ == 'httplib')
def testDottedNameImport(self):
@@ -169,7 +190,7 @@ def testDottedNameImportFrom(self):
self.assertTrue(pulldom.__name__ == 'xml.dom.pulldom')
from xml.dom.pulldom import PullDOM
- self.assertTrue(type(PullDOM) == types.ClassType)
+ self.assertTrue(type(PullDOM) == ClassType)
self.assertTrue(PullDOM.__name__ == 'PullDOM')
@@ -188,7 +209,7 @@ def testDottedNameImportFromWithAlias(self):
self.assertTrue(myPulldom.__name__ == 'xml.dom.pulldom')
from xml.dom.pulldom import PullDOM as myPullDOM
- self.assertTrue(type(myPullDOM) == types.ClassType)
+ self.assertTrue(type(myPullDOM) == ClassType)
self.assertTrue(myPullDOM.__name__ == 'PullDOM')
@@ -233,7 +254,7 @@ def testExplicitAssemblyLoad(self):
self.assertTrue(assembly != None)
import System.Data
- self.assertTrue(sys.modules.has_key('System.Data'))
+ self.assertTrue('System.Data' in sys.modules)
assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam')
self.assertTrue(assembly == None)
@@ -340,10 +361,10 @@ def test_ClrListAssemblies(self):
from clr import ListAssemblies
verbose = list(ListAssemblies(True))
short = list(ListAssemblies(False))
- self.assertTrue(u'mscorlib' in short)
- self.assertTrue(u'System' in short)
- self.assertTrue('Culture=' in verbose[0])
- self.assertTrue('Version=' in verbose[0])
+ self.assertTrue(six.u('mscorlib') in short)
+ self.assertTrue(six.u('System') in short)
+ self.assertTrue(six.u('Culture=') in verbose[0])
+ self.assertTrue(six.u('Version=') in verbose[0])
def test_ClrAddReference(self):
from clr import AddReference
diff --git a/src/tests/test_property.py b/src/tests/test_property.py
index 851ff8af0..4b00040ef 100644
--- a/src/tests/test_property.py
+++ b/src/tests/test_property.py
@@ -9,6 +9,12 @@
import sys, os, string, unittest, types
from Python.Test import PropertyTest
+import six
+
+if six.PY3:
+ IntType = int
+else:
+ IntType = types.IntType
class PropertyTests(unittest.TestCase):
@@ -139,15 +145,15 @@ def testPropertyDescriptorGetSet(self):
self.assertTrue(object.PublicStaticProperty == 0)
descriptor = PropertyTest.__dict__['PublicStaticProperty']
- self.assertTrue(type(descriptor) != types.IntType)
+ self.assertTrue(type(descriptor) != IntType)
object.PublicStaticProperty = 0
descriptor = PropertyTest.__dict__['PublicStaticProperty']
- self.assertTrue(type(descriptor) != types.IntType)
+ self.assertTrue(type(descriptor) != IntType)
PropertyTest.PublicStaticProperty = 0
descriptor = PropertyTest.__dict__['PublicStaticProperty']
- self.assertTrue(type(descriptor) != types.IntType)
+ self.assertTrue(type(descriptor) != IntType)
def testPropertyDescriptorWrongType(self):
diff --git a/src/tests/test_subclass.py b/src/tests/test_subclass.py
new file mode 100644
index 000000000..113397dba
--- /dev/null
+++ b/src/tests/test_subclass.py
@@ -0,0 +1,119 @@
+# ===========================================================================
+# 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.
+# ===========================================================================
+import clr
+clr.AddReference('Python.Test')
+clr.AddReference('System')
+
+import sys, os, string, unittest, types
+from Python.Test import TestFunctions, SubClassTest, IInterfaceTest
+from System.Collections.Generic import List
+
+# class that implements the test interface
+class InterfaceTestClass(IInterfaceTest):
+ __namespace__ = "Python.Test"
+
+ def foo(self):
+ return "InterfaceTestClass"
+
+ def bar(self, x, i):
+ return "/".join([x] * i)
+
+# class that derives from a class deriving from IInterfaceTest
+class DerivedClass(SubClassTest):
+ __namespace__ = "Python.Test"
+
+ def foo(self):
+ return "DerivedClass"
+
+ def base_foo(self):
+ return SubClassTest.foo(self)
+
+ def super_foo(self):
+ return super(DerivedClass, self).foo()
+
+ def bar(self, x, i):
+ return "_".join([x] * i)
+
+ def return_list(self):
+ l = List[str]()
+ l.Add("A")
+ l.Add("B")
+ l.Add("C")
+ return l
+
+class SubClassTests(unittest.TestCase):
+ """Test subclassing managed types"""
+
+ def testBaseClass(self):
+ """Test base class managed type"""
+ object = SubClassTest()
+ self.assertEqual(object.foo(), "foo")
+ self.assertEqual(TestFunctions.test_foo(object), "foo")
+ self.assertEqual(object.bar("bar", 2), "bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar")
+ self.assertEqual(object.not_overriden(), "not_overriden")
+ self.assertEqual(list(object.return_list()), ["a", "b", "c"])
+ self.assertEqual(list(SubClassTest.test_list(object)), ["a", "b", "c"])
+
+ def testInterface(self):
+ """Test python classes can derive from C# interfaces"""
+ object = InterfaceTestClass()
+ self.assertEqual(object.foo(), "InterfaceTestClass")
+ self.assertEqual(TestFunctions.test_foo(object), "InterfaceTestClass")
+ self.assertEqual(object.bar("bar", 2), "bar/bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar/bar")
+
+ x = TestFunctions.pass_through(object)
+ self.assertEqual(id(x), id(object))
+
+ def testDerivedClass(self):
+ """Test python class derived from managed type"""
+ object = DerivedClass()
+ self.assertEqual(object.foo(), "DerivedClass")
+ self.assertEqual(object.base_foo(), "foo")
+ self.assertEqual(object.super_foo(), "foo")
+ self.assertEqual(TestFunctions.test_foo(object), "DerivedClass")
+ self.assertEqual(object.bar("bar", 2), "bar_bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar_bar")
+ self.assertEqual(object.not_overriden(), "not_overriden")
+ self.assertEqual(list(object.return_list()), ["A", "B", "C"])
+ self.assertEqual(list(SubClassTest.test_list(object)), ["A", "B", "C"])
+
+ x = TestFunctions.pass_through(object)
+ self.assertEqual(id(x), id(object))
+
+ def testCreateInstance(self):
+ """Test derived instances can be created from managed code"""
+ object = TestFunctions.create_instance(DerivedClass)
+ self.assertEqual(object.foo(), "DerivedClass")
+ self.assertEqual(TestFunctions.test_foo(object), "DerivedClass")
+ self.assertEqual(object.bar("bar", 2), "bar_bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar_bar")
+ self.assertEqual(object.not_overriden(), "not_overriden")
+
+ x = TestFunctions.pass_through(object)
+ self.assertEqual(id(x), id(object))
+
+ object2 = TestFunctions.create_instance(InterfaceTestClass)
+ self.assertEqual(object2.foo(), "InterfaceTestClass")
+ self.assertEqual(TestFunctions.test_foo(object2), "InterfaceTestClass")
+ self.assertEqual(object2.bar("bar", 2), "bar/bar")
+ self.assertEqual(TestFunctions.test_bar(object2, "bar", 2), "bar/bar")
+
+ y = TestFunctions.pass_through(object2)
+ self.assertEqual(id(y), id(object2))
+
+def test_suite():
+ return unittest.makeSuite(SubClassTests)
+
+def main():
+ unittest.TextTestRunner().run(test_suite())
+
+if __name__ == '__main__':
+ main()
diff --git a/src/tests/test_thread.py b/src/tests/test_thread.py
index 171efa3bb..22d4c9538 100644
--- a/src/tests/test_thread.py
+++ b/src/tests/test_thread.py
@@ -7,13 +7,19 @@
# FOR A PARTICULAR PURPOSE.
# ===========================================================================
-import sys, os, string, unittest, types, thread
+import sys, os, string, unittest, types
from Python.Test import ThreadTest
+import six
+
+if six.PY3:
+ import _thread as thread
+else:
+ import thread
def dprint(msg):
# Debugging helper to trace thread-related tests.
- if 0: print msg
+ if 0: print(msg)
class ThreadTests(unittest.TestCase):
@@ -39,7 +45,7 @@ def testDoubleCallbackToPython(self):
def testPythonThreadCallsToCLR(self):
"""Test calls by Python-spawned threads into managed code."""
# This test is very likely to hang if something is wrong ;)
- import threading, thread, time
+ import threading, time
from System import String
done = []
diff --git a/subclasstest.cs b/subclasstest.cs
new file mode 100644
index 000000000..64cea87c6
--- /dev/null
+++ b/subclasstest.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Python.Test
+{
+ public interface IInterfaceTest
+ {
+ // simple test with no arguments
+ string foo();
+
+ // test passing objects and boxing primitives
+ string bar(string s, int i);
+ }
+
+ public class SubClassTest : IInterfaceTest
+ {
+ public SubClassTest()
+ {
+ }
+
+ // simple test with no arguments
+ public virtual string foo()
+ {
+ return "foo";
+ }
+
+ // test passing objects and boxing primitives
+ public virtual string bar(string s, int i)
+ {
+ return s;
+ }
+
+ // virtual methods that aren't overriden in python still work
+ public virtual string not_overriden()
+ {
+ return "not_overriden";
+ }
+
+ public virtual IList return_list()
+ {
+ return new List { "a", "b", "c" };
+ }
+
+ public static IList test_list(SubClassTest x)
+ {
+ // calls into python if return_list is overriden
+ return x.return_list();
+ }
+ }
+
+ public class TestFunctions
+ {
+ public static string test_foo(IInterfaceTest x)
+ {
+ // calls into python if foo is overriden
+ return x.foo();
+ }
+
+ public static string test_bar(IInterfaceTest x, string s, int i)
+ {
+ // calls into python if bar is overriden
+ return x.bar(s, i);
+ }
+
+ // test instances can be constructed in managed code
+ public static IInterfaceTest create_instance(Type t)
+ {
+ return (IInterfaceTest)t.GetConstructor(new Type[] {}).Invoke(new Object[] {});
+ }
+
+ // test instances pass through managed code unchanged
+ public static IInterfaceTest pass_through(IInterfaceTest s)
+ {
+ return s;
+ }
+ }
+}
diff --git a/test_subclass.py b/test_subclass.py
new file mode 100644
index 000000000..5a8e0fb8d
--- /dev/null
+++ b/test_subclass.py
@@ -0,0 +1,116 @@
+# ===========================================================================
+# 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.
+# ===========================================================================
+import clr
+clr.AddReference('Python.Test')
+clr.AddReference('System')
+
+import sys, os, string, unittest, types
+from Python.Test import TestFunctions, SubClassTest, IInterfaceTest
+from System.Collections.Generic import List
+
+# class that implements the test interface
+class InterfaceTestClass(IInterfaceTest):
+ def foo(self):
+ return "InterfaceTestClass"
+
+ def bar(self, x, i):
+ return "/".join([x] * i)
+
+# class that derives from a class deriving from IInterfaceTest
+class DerivedClass(SubClassTest):
+
+ def foo(self):
+ return "DerivedClass"
+
+ def base_foo(self):
+ return SubClassTest.foo(self)
+
+ def super_foo(self):
+ return super(DerivedClass, self).foo()
+
+ def bar(self, x, i):
+ return "_".join([x] * i)
+
+ def return_list(self):
+ l = List[str]()
+ l.Add("A")
+ l.Add("B")
+ l.Add("C")
+ return l
+
+class SubClassTests(unittest.TestCase):
+ """Test subclassing managed types"""
+
+ def testBaseClass(self):
+ """Test base class managed type"""
+ object = SubClassTest()
+ self.assertEqual(object.foo(), "foo")
+ self.assertEqual(TestFunctions.test_foo(object), "foo")
+ self.assertEqual(object.bar("bar", 2), "bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar")
+ self.assertEqual(object.not_overriden(), "not_overriden")
+ self.assertEqual(list(object.return_list()), ["a", "b", "c"])
+ self.assertEqual(list(SubClassTest.test_list(object)), ["a", "b", "c"])
+
+ def testInterface(self):
+ """Test python classes can derive from C# interfaces"""
+ object = InterfaceTestClass()
+ self.assertEqual(object.foo(), "InterfaceTestClass")
+ self.assertEqual(TestFunctions.test_foo(object), "InterfaceTestClass")
+ self.assertEqual(object.bar("bar", 2), "bar/bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar/bar")
+
+ x = TestFunctions.pass_through(object)
+ self.assertEqual(id(x), id(object))
+
+ def testDerivedClass(self):
+ """Test python class derived from managed type"""
+ object = DerivedClass()
+ self.assertEqual(object.foo(), "DerivedClass")
+ self.assertEqual(object.base_foo(), "foo")
+ self.assertEqual(object.super_foo(), "foo")
+ self.assertEqual(TestFunctions.test_foo(object), "DerivedClass")
+ self.assertEqual(object.bar("bar", 2), "bar_bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar_bar")
+ self.assertEqual(object.not_overriden(), "not_overriden")
+ self.assertEqual(list(object.return_list()), ["A", "B", "C"])
+ self.assertEqual(list(SubClassTest.test_list(object)), ["A", "B", "C"])
+
+ x = TestFunctions.pass_through(object)
+ self.assertEqual(id(x), id(object))
+
+ def testCreateInstance(self):
+ """Test derived instances can be created from managed code"""
+ object = TestFunctions.create_instance(DerivedClass)
+ self.assertEqual(object.foo(), "DerivedClass")
+ self.assertEqual(TestFunctions.test_foo(object), "DerivedClass")
+ self.assertEqual(object.bar("bar", 2), "bar_bar")
+ self.assertEqual(TestFunctions.test_bar(object, "bar", 2), "bar_bar")
+ self.assertEqual(object.not_overriden(), "not_overriden")
+
+ x = TestFunctions.pass_through(object)
+ self.assertEqual(id(x), id(object))
+
+ object2 = TestFunctions.create_instance(InterfaceTestClass)
+ self.assertEqual(object2.foo(), "InterfaceTestClass")
+ self.assertEqual(TestFunctions.test_foo(object2), "InterfaceTestClass")
+ self.assertEqual(object2.bar("bar", 2), "bar/bar")
+ self.assertEqual(TestFunctions.test_bar(object2, "bar", 2), "bar/bar")
+
+ y = TestFunctions.pass_through(object2)
+ self.assertEqual(id(y), id(object2))
+
+def test_suite():
+ return unittest.makeSuite(SubClassTests)
+
+def main():
+ unittest.TextTestRunner().run(test_suite())
+
+if __name__ == '__main__':
+ main()