diff --git a/.travis.yml b/.travis.yml
index 6355ce73d..551befdf9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,18 +1,24 @@
+sudo: required
language: python
python:
- 2.6
- 2.7
+ - 3.2
+ - 3.4
+ - 3.5
before_install:
- - sudo apt-get install software-properties-common
- sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ trusty main universe"
- - sudo apt-get -qq update
- - sudo apt-get -qq install mono-devel mono-gmcs mono-xbuild nunit-console
- - sudo mozroots --import --machine --sync
- - yes | sudo certmgr -ssl -m https://go.microsoft.com
- - yes | sudo certmgr -ssl -m https://nugetgallery.blob.core.windows.net
- - yes | sudo certmgr -ssl -m https://nuget.org
+ - sudo apt-get install software-properties-common
+ - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+ - echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
+ - echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list
+ - sudo apt-get update
+ - sudo DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" install mono-devel mono-complete referenceassemblies-pcl ca-certificates-mono nunit-console
+
install:
+ - pip install six
+ - pip install pycparser
- 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/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..31ba95121
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,40 @@
+# How to contribute
+
+PythonNet is developed and maintained by unpaid community members so well
+written, documented and tested pull requests are encouraged.
+
+## Getting Started
+
+* Make sure you have a [GitHub account](https://github.com/signup/free)
+* Submit a ticket for your issue, assuming one does not already exist.
+ * Clearly describe the issue including steps to reproduce when it is a bug.
+ * Make sure you include what Python version and operating system you are using.
+* Fork the repository on GitHub
+
+## Making Changes
+
+* Create a topic branch from where you want to base your work.
+ * This is usually the develop branch.
+ * Only target release branches if you are certain your fix must be on that
+ branch.
+ * To quickly create a topic branch based on develop; `git checkout -b
+ fix/develop/my_contribution develop`. Please avoid working directly on the
+ `master` branch.
+* Make commits of logical units.
+* Check for unnecessary whitespace with `git diff --check` before committing.
+* Make sure your commit messages are in the proper format.
+* Make sure you have added the necessary tests for your changes.
+* Run _all_ the tests to assure nothing else was accidentally broken.
+
+
+## Submitting Changes
+
+* Push your changes to a topic branch in your fork of the repository.
+* Submit a pull request to the repository in the pythonnet organization.
+* After feedback has been given we expect responses within two weeks. After two
+ weeks we may close the pull request if it isn't showing any activity.
+
+# Additional Resources
+
+* [General GitHub documentation](https://help.github.com/)
+* [GitHub pull request documentation](https://help.github.com/send-pull-requests/)
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..02807b816 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -3,29 +3,33 @@ os: Windows Server 2012
environment:
global:
PYTHONPATH: c:\testdir
+ PYTHONWARNINGS: 'ignore:::pip.pep425tags:'
matrix:
- - pythonurl: http://www.python.org/ftp/python/2.7.6/python-2.7.6.amd64.msi
- - 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
+ # http://www.appveyor.com/docs/installed-software#python
+ - PYTHON: "C:\\Python27"
+ - PYTHON: "C:\\Python27-x64"
+ - PYTHON: "C:\\Python33"
+ - PYTHON: "C:\\Python33-x64"
+ - PYTHON: "C:\\Python34"
+ - PYTHON: "C:\\Python34-x64"
+ - PYTHON: "C:\\Python35"
+ - PYTHON: "C:\\Python35-x64"
install:
- - ps: (new-object net.webclient).DownloadFile($env:pythonurl, 'C:\python.msi')
- - ps: start-process -wait -FilePath msiexec.exe -ArgumentList "/qn /i C:\python.msi TARGETDIR=C:\Python"
- - ps: (new-object net.webclient).DownloadFile('https://raw.github.com/pypa/pip/master/contrib/get-pip.py', 'C:\get-pip.py')
- # appveyor has python 2.7.6 x86 preinstalled, but in the wrong directory, this works around this
- - ps: if ($env:pythonurl -eq "http://www.python.org/ftp/python/2.7.6/python-2.7.6.msi") {mi c:\python27 c:\python}
- - set PATH=C:\Python;%PATH%
- - C:\Python\python.exe c:\get-pip.py
- - C:\Python\Scripts\pip.exe install wheel
+- "%PYTHON%\\python.exe -m pip install --upgrade pip"
+- "%PYTHON%\\python.exe -m pip install wheel"
+- "%PYTHON%\\python.exe -m pip install six"
build_script:
- - C:\python\python.exe setup.py bdist_wheel
+- "%PYTHON%\\python.exe setup.py bdist_wheel"
test_script:
- - ps: C:\python\scripts\pip.exe install ("dist\" + (gci dist)[0].Name)
+ - ps: '& "$env:PYTHON\\Scripts\\pip.exe" install --no-cache-dir --force-reinstall --ignore-installed ("dist\\" + (gci dist)[0].Name)'
- 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
+ - "%PYTHON%\\python.exe src\\tests\\runtests.py"
+
+artifacts:
+ # bdist_wheel puts your built wheel in the dist directory
+ - path: dist\*
diff --git a/demo/helloform.py b/demo/helloform.py
index 5d7a026f7..bdc5c54ed 100644
--- a/demo/helloform.py
+++ b/demo/helloform.py
@@ -9,7 +9,7 @@
import clr
SWF = clr.AddReference("System.Windows.Forms")
-print SWF.Location
+print (SWF.Location)
import System.Windows.Forms as WinForms
from System.Drawing import Size, Point
@@ -49,7 +49,7 @@ def __init__(self):
def button_Click(self, sender, args):
"""Button click event handler"""
- print "Click"
+ print ("Click")
WinForms.MessageBox.Show("Please do not press this button again.")
def run(self):
@@ -58,9 +58,9 @@ def run(self):
def main():
form = HelloApp()
- print "form created"
+ print ("form created")
app = WinForms.Application
- print "app referenced"
+ print ("app referenced")
app.Run(form)
diff --git a/demo/splitter.py b/demo/splitter.py
index f40b67137..5c5da67a8 100644
--- a/demo/splitter.py
+++ b/demo/splitter.py
@@ -7,6 +7,7 @@
# FOR A PARTICULAR PURPOSE.
# ===========================================================================
+import clr
import System.Windows.Forms as WinForms
from System.Drawing import Color, Size, Point
import System
diff --git a/demo/wordpad.py b/demo/wordpad.py
index 36286b811..300c4a1dd 100644
--- a/demo/wordpad.py
+++ b/demo/wordpad.py
@@ -7,7 +7,9 @@
# FOR A PARTICULAR PURPOSE.
# ===========================================================================
+import clr
import System.Windows.Forms as WinForms
+from System.Threading import Thread, ThreadStart, ApartmentState
from System.Drawing import Color, Size, Point
from System.Text import Encoding
from System.IO import File
@@ -204,7 +206,7 @@ def InitializeComponent(self):
self.richTextBox.TabIndex = 0
self.richTextBox.AutoSize = 1
self.richTextBox.ScrollBars = WinForms.RichTextBoxScrollBars.ForcedBoth
- self.richTextBox.Font = System.Drawing.Font("Tahoma", 10)
+ self.richTextBox.Font = System.Drawing.Font("Tahoma", 10.0)
self.richTextBox.AcceptsTab = 1
self.richTextBox.Location = System.Drawing.Point(0, 0)
@@ -314,11 +316,10 @@ def OpenDocument(self):
buff = System.Array.CreateInstance(System.Byte, 1024)
data = []
- read = -1
- while (read != 0):
+ while stream.Position < stream.Length:
buff.Initialize()
- read = stream.Read(buff, 0, 1024)
+ stream.Read(buff, 0, 1024)
temp = Encoding.ASCII.GetString(buff, 0, 1024)
data.append(temp)
@@ -413,18 +414,25 @@ def InitializeComponent(self):
self.ShowInTaskbar = False
self.StartPosition = WinForms.FormStartPosition.CenterScreen
self.Text = "About"
- self.ResumeLayout(0)
+ self.ResumeLayout(False)
def OnClickClose(self, sender, args):
self.Close()
-
-def main():
+def app_thread():
app = Wordpad()
WinForms.Application.Run(app)
app.Dispose()
+
+def main():
+ thread = Thread(ThreadStart(app_thread))
+ thread.SetApartmentState(ApartmentState.STA)
+ thread.Start()
+ thread.Join()
+
+
if __name__ == '__main__':
main()
diff --git a/setup.py b/setup.py
index 7926c663d..f0c50838f 100644
--- a/setup.py
+++ b/setup.py
@@ -4,88 +4,106 @@
"""
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
+from distutils import log
from platform import architecture
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
+ keys_to_check = []
if use_windows_sdk:
- value_name = "InstallationFolder"
- sdk_name = "Windows SDK"
- keys_to_check = [
- r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1A\WinSDK-Win32Tools",
- r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.1\WinSDKWin32Tools",
- r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A\WinSDK-Win32Tools",
- r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0\WinSDKWin32Tools",
- r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0A\WinSDKWin32Tools",
- ]
+ sdks_root = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows"
+ kits_root = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"
+ kits_suffix = "bin"
+ if PLATFORM == "x64":
+ kits_suffix += r"\x64"
+ keys_to_check.extend([
+ ("Windows Kit 10.0", kits_root, "KitsRoot10", kits_suffix),
+ ("Windows Kit 8.1", kits_root, "KitsRoot81", kits_suffix),
+ ("Windows Kit 8.0", kits_root, "KitsRoot", kits_suffix),
+ ("Windows SDK 7.1A", sdks_root + r"\v7.1A\WinSDK-Win32Tools", "InstallationFolder"),
+ ("Windows SDK 7.1", sdks_root + r"\v7.1\WinSDKWin32Tools", "InstallationFolder"),
+ ("Windows SDK 7.0A", sdks_root + r"\v7.0A\WinSDK-Win32Tools", "InstallationFolder"),
+ ("Windows SDK 7.0", sdks_root + r"\v7.0\WinSDKWin32Tools", "InstallationFolder"),
+ ("Windows SDK 6.0A", sdks_root + r"\v6.0A\WinSDKWin32Tools", "InstallationFolder")
+ ])
else:
- value_name = "MSBuildToolsPath"
- sdk_name = "MSBuild"
- keys_to_check = [
- r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\12.0",
- r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0",
- r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\3.5",
- r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\2.0"
- ]
-
+ vs_root = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"
+ keys_to_check.extend([
+ ("MSBuild 14", vs_root + r"\14.0", "MSBuildToolsPath"),
+ ("MSBuild 12", vs_root + r"\12.0", "MSBuildToolsPath"),
+ ("MSBuild 4", vs_root + r"\4.0", "MSBuildToolsPath"),
+ ("MSBuild 3.5", vs_root + r"\3.5", "MSBuildToolsPath"),
+ ("MSBuild 2.0", vs_root + r"\2.0", "MSBuildToolsPath")
+ ])
+
+ # read the possible tools paths from the various registry locations
+ paths_to_check = []
hreg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
try:
hkey = None
- for key in keys_to_check:
+ for key_to_check in keys_to_check:
+ sdk_name, key, value_name = key_to_check[:3]
+ suffix = key_to_check[3] if len(key_to_check) > 3 else None
try:
hkey = _winreg.OpenKey(hreg, key)
- break
+ val, type_ = _winreg.QueryValueEx(hkey, value_name)
+ if type_ != _winreg.REG_SZ:
+ continue
+ if suffix:
+ val = os.path.join(val, suffix)
+ paths_to_check.append((sdk_name, val))
except WindowsError:
pass
-
- if hkey is None:
- raise RuntimeError("%s could not be found" % sdk_name)
-
- try:
- val, type_ = _winreg.QueryValueEx(hkey, value_name)
- if type_ != _winreg.REG_SZ:
- raise RuntimeError("%s could not be found" % sdk_name)
-
- path = os.path.join(val, tool)
- if os.path.exists(path):
- return path
- finally:
- hkey.Close()
+ finally:
+ hkey.Close()
finally:
hreg.Close()
+ # Add Visual C++ for Python as a fallback in case one of the other Windows SDKs isn't installed
+ if use_windows_sdk:
+ localappdata = os.environ["LOCALAPPDATA"]
+ pywinsdk = localappdata + r"\Programs\Common\Microsoft\Visual C++ for Python\9.0\WinSDK\Bin"
+ if PLATFORM == "x64":
+ pywinsdk += r"\x64"
+ paths_to_check.append(("Visual C++ for Python", pywinsdk))
+
+ for sdk_name, path in paths_to_check:
+ path = os.path.join(path, tool)
+ if os.path.exists(path):
+ log.info("Using %s from %s" % (tool, sdk_name))
+ return path
+
raise RuntimeError("%s could not be found" % tool)
-
+
if DEVTOOLS == "MsDev":
_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,21 +126,55 @@ 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")
+
+ # check the interop file exists, and create it if it doesn't
+ interop_file = _get_interop_filename()
+ if not os.path.exists(interop_file):
+ geninterop = os.path.join("tools", "geninterop", "geninterop.py")
+ _check_output([sys.executable, geninterop, interop_file])
+
cmd = [
_xbuild,
"pythonnet.sln",
"/p:Configuration=%s" % _config,
"/p:Platform=%s" % PLATFORM,
"/p:DefineConstants=\"%s\"" % _defines_sep.join(defines),
- "/p:PythonBuildDir=%s" % os.path.abspath(dest_dir),
+ "/p:PythonBuildDir=\"%s\"" % os.path.abspath(dest_dir),
+ "/p:PythonInteropFile=\"%s\"" % os.path.basename(interop_file),
"/verbosity:%s" % VERBOSITY,
]
@@ -138,7 +190,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 +199,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 +218,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 +266,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,9 +281,21 @@ 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
+def _get_interop_filename():
+ """interopXX.cs is auto-generated as part of the build.
+ For common windows platforms pre-generated files are included
+ as most windows users won't have Clang installed, which is
+ required to generate the file.
+ """
+ interop_file = "interop%d%s%s.cs" % (sys.version_info[0], sys.version_info[1], getattr(sys, "abiflags", ""))
+ return os.path.join("src", "runtime", interop_file)
+
+
if __name__ == "__main__":
setupdir = os.path.dirname(__file__)
if setupdir:
@@ -311,15 +315,23 @@ def _check_output(*popenargs, **kwargs):
for filename in fnmatch.filter(filenames, "*" + ext):
sources.append(os.path.join(root, filename))
+ setup_requires = []
+ interop_file = _get_interop_filename()
+ if not os.path.exists(interop_file):
+ setup_requires.append("pycparser")
+
setup(
name="pythonnet",
- version="2.0.0",
+ version="2.1.0",
description=".Net and Mono integration for Python",
url='http://pythonnet.github.io/',
author="Python for .Net developers",
classifiers=[
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3.2',
+ 'Programming Language :: Python :: 3.3',
+ 'Programming Language :: Python :: 3.4',
+ 'Programming Language :: Python :: 3.5',
'Programming Language :: C#',
'License :: OSI Approved :: Zope Public License',
'Development Status :: 5 - Production/Stable',
@@ -336,13 +348,12 @@ 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,
- }
+ },
+ setup_requires=setup_requires
)
diff --git a/src/clrmodule/ClrModule.cs b/src/clrmodule/ClrModule.cs
index 3347d55a9..801acf7db 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 || PYTHON35)
+ [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 || PYTHON35)
+ 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 || PYTHON35)
+ 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..df9d67c9a 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()";
@@ -31,6 +37,7 @@ PyNet_Args* PyNet_Init(int ext) {
pn_args->shutdown_name = "Python.Runtime:Shutdown()";
pn_args->domain = mono_jit_init_version(MONO_DOMAIN, MONO_VERSION);
+ mono_domain_set_config(pn_args->domain, ".", "Python.Runtime.dll.config");
/*
* Load the default Mono configuration file, this is needed
@@ -91,8 +98,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 +130,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 +212,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..7bfaff313 100644
--- a/src/runtime/Python.Runtime.csproj
+++ b/src/runtime/Python.Runtime.csproj
@@ -1,190 +1,212 @@
-
-
-
- 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..a217e84e2 100644
--- a/src/runtime/assemblymanager.cs
+++ b/src/runtime/assemblymanager.cs
@@ -12,6 +12,7 @@
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
@@ -57,10 +58,17 @@ internal static void Initialize() {
domain.AssemblyResolve += rhandler;
Assembly[] items = domain.GetAssemblies();
- for (int i = 0; i < items.Length; i++) {
- Assembly a = items[i];
- assemblies.Add(a);
- ScanAssembly(a);
+ foreach (var a in items)
+ {
+ try
+ {
+ ScanAssembly(a);
+ assemblies.Add(a);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine(string.Format("Error scanning assembly {0}. {1}", a, ex));
+ }
}
}
@@ -208,6 +216,24 @@ public static Assembly LoadAssemblyPath(string name) {
return assembly;
}
+ ///
+ /// Loads an assembly using full path.
+ ///
+ ///
+ ///
+ public static Assembly LoadAssemblyFullPath(string name) {
+ Assembly assembly = null;
+ if (Path.IsPathRooted(name)) {
+ if (!Path.HasExtension(name))
+ name = name + ".dll";
+ if (File.Exists(name)) {
+ try { assembly = Assembly.LoadFrom(name); }
+ catch { }
+ }
+ }
+ return assembly;
+ }
+
//===================================================================
// Returns an assembly that's already been loaded
//===================================================================
@@ -282,7 +308,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,16 +317,14 @@ 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++) {
s = (n == 0) ? names[0] : s + "." + names[n];
if (!namespaces.ContainsKey(s)) {
- namespaces.Add(s,
- new Dictionary()
- );
+ namespaces.Add(s, new Dictionary());
}
}
}
@@ -336,6 +360,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 +391,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..4aba01df0 100644
--- a/src/runtime/classbase.cs
+++ b/src/runtime/classbase.cs
@@ -51,13 +51,68 @@ public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) {
//====================================================================
public virtual IntPtr type_subscript(IntPtr idx) {
- return Exceptions.RaiseTypeError("unsubscriptable object");
+ Type[] types = Runtime.PythonArgsToTypeArray(idx);
+ if (types == null) {
+ return Exceptions.RaiseTypeError("type(s) expected");
+ }
+
+ Type target = GenericUtil.GenericForType(this.type, types.Length);
+
+ if (target != null) {
+ Type t = target.MakeGenericType(types);
+ ManagedType c = (ManagedType)ClassManager.GetClass(t);
+ Runtime.Incref(c.pyHandle);
+ return c.pyHandle;
+ }
+
+ return Exceptions.RaiseTypeError("no type matches params");
}
//====================================================================
// Standard comparison implementation for instances of reflected types.
//====================================================================
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 +128,7 @@ public static int tp_compare(IntPtr ob, IntPtr other) {
}
return -1;
}
+#endif
//====================================================================
@@ -128,7 +184,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 +220,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..baffbd4e3
--- /dev/null
+++ b/src/runtime/classderived.cs
@@ -0,0 +1,865 @@
+// ==========================================================================
+// 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();
+
+ // If the method isn't abstract create a method for calling the original method
+ string baseMethodName = null;
+ if (!method.IsAbstract)
+ {
+ baseMethodName = "_" + baseType.Name + "__" + method.Name;
+ MethodBuilder baseMethodBuilder = 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 baseIl = baseMethodBuilder.GetILGenerator();
+ baseIl.Emit(OpCodes.Ldarg_0);
+ for (int i = 0; i < parameters.Length; ++i)
+ baseIl.Emit(OpCodes.Ldarg, i + 1);
+ baseIl.Emit(OpCodes.Call, method);
+ baseIl.Emit(OpCodes.Ret);
+ }
+
+ // override the original method with a new one that dispatches to python
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name,
+ MethodAttributes.Public |
+ MethodAttributes.ReuseSlot |
+ MethodAttributes.Virtual |
+ MethodAttributes.HideBySig,
+ method.CallingConvention,
+ method.ReturnType,
+ parameterTypes);
+ ILGenerator il = methodBuilder.GetILGenerator();
+ il.DeclareLocal(typeof(Object[]));
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit(OpCodes.Ldstr, method.Name);
+
+ // don't fall back to the base type's method if it's abstract
+ if (null != baseMethodName)
+ il.Emit(OpCodes.Ldstr, baseMethodName);
+ else
+ il.Emit(OpCodes.Ldnull);
+
+ 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 NotImplementedException("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 NotImplementedException("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/classobject.cs b/src/runtime/classobject.cs
index 5e79e8253..03f784ed7 100644
--- a/src/runtime/classobject.cs
+++ b/src/runtime/classobject.cs
@@ -223,7 +223,6 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
// Arg may be a tuple in the case of an indexer with multiple
// parameters. If so, use it directly, else make a new tuple
// with the index arg (method binders expect arg tuples).
-
IntPtr args = idx;
bool free = false;
@@ -234,13 +233,29 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) {
free = true;
}
+ // Get the args passed in.
int i = Runtime.PyTuple_Size(args);
- IntPtr real = Runtime.PyTuple_New(i + 1);
+ IntPtr defaultArgs = cls.indexer.GetDefaultArgs(args);
+ int numOfDefaultArgs = Runtime.PyTuple_Size(defaultArgs);
+ int temp = i + numOfDefaultArgs;
+ IntPtr real = Runtime.PyTuple_New(temp + 1);
for (int n = 0; n < i; n++) {
IntPtr item = Runtime.PyTuple_GetItem(args, n);
Runtime.Incref(item);
Runtime.PyTuple_SetItem(real, n, item);
}
+
+ // Add Default Args if needed
+ for (int n = 0; n < numOfDefaultArgs; n++) {
+ IntPtr item = Runtime.PyTuple_GetItem(defaultArgs, n);
+ Runtime.Incref(item);
+ Runtime.PyTuple_SetItem(real, n + i, item);
+ }
+ // no longer need defaultArgs
+ Runtime.Decref(defaultArgs);
+ i = temp;
+
+ // Add value to argument list
Runtime.Incref(v);
Runtime.PyTuple_SetItem(real, i, v);
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..6bb2b0293 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 {
@@ -28,23 +29,29 @@ private Converter() {}
static NumberFormatInfo nfi;
static Type objectType;
static Type stringType;
+ static Type singleType;
static Type doubleType;
+ static Type decimalType;
+ static Type int16Type;
static Type int32Type;
static Type int64Type;
static Type flagsType;
static Type boolType;
- //static Type typeType;
+ static Type typeType;
static Converter () {
nfi = NumberFormatInfo.InvariantInfo;
objectType = typeof(Object);
stringType = typeof(String);
+ int16Type = typeof(Int16);
int32Type = typeof(Int32);
int64Type = typeof(Int64);
+ singleType = typeof(Single);
doubleType = typeof(Double);
+ decimalType = typeof(Decimal);
flagsType = typeof(FlagsAttribute);
boolType = typeof(Boolean);
- //typeType = typeof(Type);
+ typeType = typeof(Type);
}
@@ -72,6 +79,35 @@ internal static Type GetTypeByAlias(IntPtr op) {
return null;
}
+ internal static IntPtr GetPythonTypeByAlias(Type op)
+ {
+ if (op == stringType) {
+ return Runtime.PyUnicodeType;
+ }
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ else if ((op == int16Type) ||
+ (op == int32Type) ||
+ (op == int64Type)) {
+ return Runtime.PyIntType;
+ }
+#endif
+ else if ((op == int16Type) ||
+ (op == int32Type)) {
+ return Runtime.PyIntType;
+ }
+ else if (op == int64Type) {
+ return Runtime.PyLongType;
+ }
+ else if ((op == doubleType) ||
+ (op == singleType)) {
+ return Runtime.PyFloatType;
+ }
+ else if (op == boolType) {
+ return Runtime.PyBoolType;
+ }
+ return IntPtr.Zero;
+ }
+
//====================================================================
// Return a Python object for the given native object, converting
@@ -79,6 +115,10 @@ internal static Type GetTypeByAlias(IntPtr op) {
// This always returns a new reference. Note that the System.Decimal
// type has no Python equivalent and converts to a managed instance.
//====================================================================
+ internal static IntPtr ToPython(T value)
+ {
+ return ToPython(value, typeof(T));
+ }
internal static IntPtr ToPython(Object value, Type type) {
IntPtr result = IntPtr.Zero;
@@ -91,6 +131,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 +213,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 +365,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 +444,7 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.Int32:
+#if !(PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
// Trickery to support 64-bit platforms.
if (IntPtr.Size == 4) {
op = Runtime.PyNumber_Int(value);
@@ -357,8 +467,13 @@ 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) {
+ Exceptions.Clear();
if (Exceptions.ExceptionMatches(overflow)) {
goto overflow;
}
@@ -381,6 +496,18 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.Byte:
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 +516,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 +536,16 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.SByte:
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 +554,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 +574,16 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
return true;
case TypeCode.Char:
-
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 +592,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) {
@@ -470,10 +618,10 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
goto type_error;
}
ival = Runtime.PyInt_AsLong(op);
+ Runtime.Decref(op);
if (ival > Char.MaxValue || ival < Char.MinValue) {
goto overflow;
}
- Runtime.Decref(op);
result = (char)ival;
return true;
@@ -536,14 +684,16 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
goto type_error;
}
uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op);
- Runtime.Decref(op);
+
if (Exceptions.ErrorOccurred()) {
+ Runtime.Decref(op);
goto overflow;
}
IntPtr check = Runtime.PyLong_FromUnsignedLong(ui);
int err = Runtime.PyObject_Compare(check, op);
Runtime.Decref(check);
+ Runtime.Decref(op);
if (0 != err || Exceptions.ErrorOccurred()) {
goto overflow;
}
@@ -576,7 +726,8 @@ static bool ToPrimitive(IntPtr value, Type obType, out Object result,
}
goto type_error;
}
- double dd = Runtime.PyFloat_AsDouble(value);
+ double dd = Runtime.PyFloat_AsDouble(op);
+ Runtime.Decref(op);
if (dd > Single.MaxValue || dd < Single.MinValue) {
goto overflow;
}
@@ -713,10 +864,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..5a1ab9021 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 || PYTHON35)
+ 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..fe6fdd3ff 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 || PYTHON35)
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 || PYTHON35)
}
///
@@ -136,7 +136,11 @@ private Exceptions() {}
//===================================================================
internal static void Initialize() {
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 || PYTHON35)
public static IntPtr BaseException;
#endif
public static IntPtr Exception;
public static IntPtr StopIteration;
-#if (PYTHON25 || PYTHON26 || PYTHON27)
+#if (PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
public static IntPtr GeneratorExit;
#endif
+#if !(PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
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 || PYTHON35)
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/generictype.cs b/src/runtime/generictype.cs
index 082bc768c..e1ebc055c 100644
--- a/src/runtime/generictype.cs
+++ b/src/runtime/generictype.cs
@@ -44,57 +44,6 @@ public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) {
"object is not callable");
return IntPtr.Zero;
}
-
- //====================================================================
- // Implements subscript syntax for reflected generic types. A closed
- // type is created by binding the generic type via subscript syntax:
- // inst = List[str]()
- //====================================================================
-
- public override IntPtr type_subscript(IntPtr idx) {
- Type[] types = Runtime.PythonArgsToTypeArray(idx);
- if (types == null) {
- return Exceptions.RaiseTypeError("type(s) expected");
- }
- if (!this.type.IsGenericTypeDefinition) {
- return Exceptions.RaiseTypeError(
- "type is not a generic type definition"
- );
- }
-
- // This is a little tricky, because an instance of GenericType
- // may represent either a specific generic type, or act as an
- // alias for one or more generic types with the same base name.
-
- if (this.type.ContainsGenericParameters) {
- Type[] args = this.type.GetGenericArguments();
- Type target = null;
-
- if (args.Length == types.Length) {
- target = this.type;
- }
- else {
- foreach (Type t in
- GenericUtil.GenericsForType(this.type)) {
- if (t.GetGenericArguments().Length == types.Length) {
- target = t;
- break;
- }
- }
- }
-
- if (target != null) {
- Type t = target.MakeGenericType(types);
- ManagedType c = (ManagedType)ClassManager.GetClass(t);
- Runtime.Incref(c.pyHandle);
- return c.pyHandle;
- }
- return Exceptions.RaiseTypeError("no type matches params");
- }
-
- return Exceptions.RaiseTypeError("unsubscriptable object");
- }
-
}
}
diff --git a/src/runtime/genericutil.cs b/src/runtime/genericutil.cs
index c3de0aa56..bb570e9ab 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) {
@@ -78,14 +81,33 @@ public static List GetGenericBaseNames(string ns) {
// xxx
//====================================================================
- public static List GenericsForType(Type t) {
+ public static Type GenericForType(Type t, int paramCount)
+ {
+ return GenericByName(t.Namespace, t.Name, paramCount);
+ }
+
+ public static Type GenericByName(string ns, string name, int paramCount)
+ {
+ foreach (Type t in GenericsByName(ns, name))
+ {
+ if (t.GetGenericArguments().Length == paramCount)
+ return t;
+ }
+ return null;
+ }
+
+ public static List GenericsForType(Type t)
+ {
+ return GenericsByName(t.Namespace, t.Name);
+ }
+
+ public static List GenericsByName(string ns, string basename) {
Dictionary> nsmap = null;
- mapping.TryGetValue(t.Namespace, out nsmap);
+ mapping.TryGetValue(ns, out nsmap);
if (nsmap == null) {
return null;
}
- string basename = t.Name;
int tick = basename.IndexOf("`");
if (tick > -1) {
basename = basename.Substring(0, tick);
@@ -99,7 +121,7 @@ public static List GenericsForType(Type t) {
List result = new List();
foreach (string name in names) {
- string qname = t.Namespace + "." + name;
+ string qname = ns + "." + name;
Type o = AssemblyManager.LookupType(qname);
if (o != null) {
result.Add(o);
diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs
index c736f0645..d8e62025a 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 || PYTHON35)
+ 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 || PYTHON35)
+ 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__");
-
- hook = new MethodWrapper(typeof(ImportHook), "__import__");
- Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
+#endif
+ hook = new MethodWrapper(typeof(ImportHook), "__import__", "TernaryFunc");
+ Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr);
Runtime.Decref(hook.ptr);
root = new CLRModule();
+
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ // 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 || PYTHON35)
+ 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 || PYTHON35)
+ // 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/indexer.cs b/src/runtime/indexer.cs
index 8118dc339..0781a3a0a 100644
--- a/src/runtime/indexer.cs
+++ b/src/runtime/indexer.cs
@@ -62,7 +62,57 @@ internal void SetItem(IntPtr inst, IntPtr args) {
SetterBinder.Invoke(inst, args, IntPtr.Zero);
}
- }
+ internal bool NeedsDefaultArgs(IntPtr args){
+ int pynargs = Runtime.PyTuple_Size(args);
+ var methods = SetterBinder.GetMethods();
+ if(methods.Length == 0)
+ return false;
+
+ MethodBase mi = methods[0];
+ ParameterInfo[] pi = mi.GetParameters();
+ // need to subtract one for the value
+ int clrnargs = pi.Length - 1;
+ if (pynargs == clrnargs || pynargs > clrnargs)
+ return false;
+
+ for (int v = pynargs; v < clrnargs; v++){
+ if (pi[v].DefaultValue == DBNull.Value)
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// This will return default arguments a new instance of a tuple. The size
+ /// of the tuple will indicate the number of default arguments.
+ ///
+ /// This is pointing to the tuple args passed in
+ /// a new instance of the tuple containing the default args
+ internal IntPtr GetDefaultArgs(IntPtr args){
+
+ // if we don't need default args return empty tuple
+ if(!NeedsDefaultArgs(args))
+ return Runtime.PyTuple_New(0);
+ int pynargs = Runtime.PyTuple_Size(args);
+
+ // Get the default arg tuple
+ var methods = SetterBinder.GetMethods();
+ MethodBase mi = methods[0];
+ ParameterInfo[] pi = mi.GetParameters();
+ int clrnargs = pi.Length - 1;
+ IntPtr defaultArgs = Runtime.PyTuple_New(clrnargs - pynargs);
+ for (int i = 0; i < (clrnargs - pynargs); i++) {
+ if (pi[i + pynargs].DefaultValue == DBNull.Value)
+ continue;
+ else{
+ IntPtr arg = Converter.ToPython(pi[i + pynargs].DefaultValue, pi[i + pynargs].ParameterType);
+ Runtime.PyTuple_SetItem(defaultArgs, i, arg);
+ }
+ }
+ return defaultArgs;
+ }
+ }
+
}
diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs
index 9aad4c6e4..a1c541de4 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 || PYTHON35)
+ 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 || PYTHON35)
+ 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 || PYTHON35)
+ 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,206 +122,136 @@ 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 || PYTHON35)
+ [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 {
-
- static TypeOffset() {
- Type type = typeof(TypeOffset);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ [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++) {
+ for (int i = 0; i < fi.Length; i++)
+ {
fi[i].SetValue(null, i * size);
}
}
- public static int magic() {
- return ob_size;
- }
-
-/* The *real* layout of a type object when allocated on the heap */
-//typedef struct _heaptypeobject {
+ /* 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 {
+ // PyObject_VAR_HEAD {
+ // PyObject_HEAD {
public static int ob_refcnt = 0;
public static int ob_type = 0;
- // }
+ // }
public static int ob_size = 0; /* Number of items in _VAR_iable part */
-// }
- public static int tp_name = 0; /* For printing, in format "." */
- public static int tp_basicsize = 0; /* For allocation */
- public static int tp_itemsize = 0;
-
- /* Methods to implement standard operations */
- public static int tp_dealloc = 0;
- public static int tp_print = 0;
- public static int tp_getattr = 0;
- public static int tp_setattr = 0;
- public static int tp_compare = 0;
- public static int tp_repr = 0;
-
- /* Method suites for standard classes */
- public static int tp_as_number = 0;
- public static int tp_as_sequence = 0;
- public static int tp_as_mapping = 0;
-
- /* More standard operations (here for binary compatibility) */
- public static int tp_hash = 0;
- public static int tp_call = 0;
- public static int tp_str = 0;
- public static int tp_getattro = 0;
- public static int tp_setattro = 0;
-
- /* Functions to access object as input/output buffer */
- public static int tp_as_buffer = 0;
-
- /* Flags to define presence of optional/expanded features */
- public static int tp_flags = 0;
-
- public static int tp_doc = 0; /* Documentation string */
-
- /* Assigned meaning in release 2.0 */
- /* call function for all accessible objects */
- public static int tp_traverse = 0;
- /* delete references to contained objects */
- public static int tp_clear = 0;
-
- /* Assigned meaning in release 2.1 */
- /* rich comparisons */
- public static int tp_richcompare = 0;
- /* weak reference enabler */
- public static int tp_weaklistoffset = 0;
-
- /* Added in release 2.2 */
- /* Iterators */
- public static int tp_iter = 0;
- public static int tp_iternext = 0;
- /* Attribute descriptor and subclassing stuff */
- public static int tp_methods = 0;
- public static int tp_members = 0;
- public static int tp_getset = 0;
- public static int tp_base = 0;
- public static int tp_dict = 0;
- public static int tp_descr_get = 0;
- public static int tp_descr_set = 0;
- public static int tp_dictoffset = 0;
- public static int tp_init = 0;
- public static int tp_alloc = 0;
- public static int tp_new = 0;
- public static int tp_free = 0; /* Low-level free-memory routine */
- public static int tp_is_gc = 0; /* For PyObject_IS_GC */
- public static int tp_bases = 0;
- public static int tp_mro = 0; /* method resolution order */
- public static int tp_cache = 0;
- public static int tp_subclasses = 0;
- public static int tp_weaklist = 0;
- public static int tp_del = 0;
-#if (PYTHON26 || PYTHON27)
- /* Type attribute cache version tag. Added in version 2.6 */
- public static int tp_version_tag;
-#endif
- // COUNT_ALLOCS adds some more stuff to PyTypeObject
-#if (Py_COUNT_ALLOCS)
- /* these must be last and never explicitly initialized */
- public static int tp_allocs = 0;
- public static int tp_frees = 0;
- public static int tp_maxalloc = 0;
- public static int tp_prev = 0;
- public static int tp_next = 0;
-#endif
-//} PyTypeObject;
-//typedef struct {
- public static int nb_add = 0;
- public static int nb_subtract = 0;
- public static int nb_multiply = 0;
- public static int nb_divide = 0;
- public static int nb_remainder = 0;
- public static int nb_divmod = 0;
- public static int nb_power = 0;
- public static int nb_negative = 0;
- public static int nb_positive = 0;
- public static int nb_absolute = 0;
- public static int nb_nonzero = 0;
- public static int nb_invert = 0;
- public static int nb_lshift = 0;
- public static int nb_rshift = 0;
- public static int nb_and = 0;
- public static int nb_xor = 0;
- public static int nb_or = 0;
- public static int nb_coerce = 0;
- public static int nb_int = 0;
- public static int nb_long = 0;
- public static int nb_float = 0;
- public static int nb_oct = 0;
- public static int nb_hex = 0;
- /* Added in release 2.0 */
- public static int nb_inplace_add = 0;
- public static int nb_inplace_subtract = 0;
- public static int nb_inplace_multiply = 0;
- public static int nb_inplace_divide = 0;
- public static int nb_inplace_remainder = 0;
- public static int nb_inplace_power = 0;
- public static int nb_inplace_lshift = 0;
- public static int nb_inplace_rshift = 0;
- public static int nb_inplace_and = 0;
- public static int nb_inplace_xor = 0;
- public static int nb_inplace_or = 0;
- /* Added in release 2.2 */
- /* The following require the Py_TPFLAGS_HAVE_CLASS flag */
- public static int nb_floor_divide = 0;
- public static int nb_true_divide = 0;
- public static int nb_inplace_floor_divide = 0;
- public static int nb_inplace_true_divide = 0;
-#if (PYTHON25 || PYTHON26 || PYTHON27)
- /* Added in release 2.5 */
- public static int nb_index = 0;
-#endif
- //} PyNumberMethods;
-//typedef struct {
- public static int mp_length = 0;
- public static int mp_subscript = 0;
- public static int mp_ass_subscript = 0;
-//} PyMappingMethods;
-//typedef struct {
- public static int sq_length = 0;
- public static int sq_concat = 0;
- public static int sq_repeat = 0;
- public static int sq_item = 0;
- public static int sq_slice = 0;
- public static int sq_ass_item = 0;
- public static int sq_ass_slice = 0;
- public static int sq_contains = 0;
- /* Added in release 2.0 */
- public static int sq_inplace_concat = 0;
- public static int sq_inplace_repeat = 0;
-//} PySequenceMethods;
-//typedef struct {
- public static int bf_getreadbuffer = 0;
- public static int bf_getwritebuffer = 0;
- public static int bf_getsegcount = 0;
- public static int bf_getcharbuffer = 0;
-#if (PYTHON26 || PYTHON27)
- // This addition is not actually noted in the 2.6.5 object.h
- public static int bf_getbuffer = 0;
- public static int bf_releasebuffer = 0;
-//} PyBufferProcs;
-#endif
- //PyObject *ht_name, *ht_slots;
- public static int name = 0;
- public static int slots = 0;
- /* here are optional user slots, followed by the members. */
- public static int members = 0;
+ // }
+ 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 +259,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 +270,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 +281,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 || PYTHON35)
public static int HaveIndex = (1 << 17);
#endif
-#if (PYTHON26 || PYTHON27)
+#if (PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
/* Objects support nb_index in PyNumberMethods */
public static int HaveVersionTag = (1 << 18);
public static int ValidVersionTag = (1 << 19);
@@ -341,7 +301,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 +313,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 || PYTHON35)
+ public static int Default = (
+ HaveStacklessExtension |
+ HaveVersionTag);
+#endif
+
}
@@ -410,7 +383,9 @@ static Interop() {
pmap["nb_add"] = p["BinaryFunc"];
pmap["nb_subtract"] = p["BinaryFunc"];
pmap["nb_multiply"] = p["BinaryFunc"];
+#if !(PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
pmap["nb_divide"] = p["BinaryFunc"];
+#endif
pmap["nb_remainder"] = p["BinaryFunc"];
pmap["nb_divmod"] = p["BinaryFunc"];
pmap["nb_power"] = p["TernaryFunc"];
@@ -433,7 +408,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 || PYTHON35)
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 +422,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 || PYTHON35)
pmap["nb_index"] = p["UnaryFunc"];
#endif
@@ -468,16 +445,19 @@ static Interop() {
pmap["bf_getwritebuffer"] = p["IntObjArgFunc"];
pmap["bf_getsegcount"] = p["ObjObjFunc"];
pmap["bf_getcharbuffer"] = p["IntObjArgFunc"];
-
- pmap["__import__"] = p["TernaryFunc"];
}
internal static Type GetPrototype(string name) {
return pmap[name] as Type;
}
- internal static IntPtr GetThunk(MethodInfo method) {
- Type dt = Interop.GetPrototype(method.Name);
+ internal static IntPtr GetThunk(MethodInfo method, string funcType = null) {
+ Type dt;
+ if (funcType != null)
+ dt = typeof(Interop).GetNestedType(funcType) as Type;
+ else
+ dt = GetPrototype(method.Name);
+
if (dt != null) {
IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size);
Delegate d = Delegate.CreateDelegate(dt, method);
@@ -541,5 +521,4 @@ public Thunk(Delegate d) {
fn = d;
}
}
-
}
diff --git a/src/runtime/interop26.cs b/src/runtime/interop26.cs
new file mode 100644
index 000000000..810e0e62f
--- /dev/null
+++ b/src/runtime/interop26.cs
@@ -0,0 +1,153 @@
+
+// Auto-generated by geninterop.py.
+// DOT NOT MODIFIY BY HAND.
+// ==========================================================================
+// This software is subject to the provisions of the Zope Public License,
+// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+// FOR A PARTICULAR PURPOSE.
+// ==========================================================================
+#if (PYTHON26)
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime {
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
+ internal class TypeOffset {
+
+ static TypeOffset() {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++) {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic() {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+ public static int ob_refcnt = 0;
+ public static int ob_type = 0;
+ public static int ob_size = 0;
+ public static int tp_name = 0;
+ public static int tp_basicsize = 0;
+ public static int tp_itemsize = 0;
+ public static int tp_dealloc = 0;
+ public static int tp_print = 0;
+ public static int tp_getattr = 0;
+ public static int tp_setattr = 0;
+ public static int tp_compare = 0;
+ public static int tp_repr = 0;
+ public static int tp_as_number = 0;
+ public static int tp_as_sequence = 0;
+ public static int tp_as_mapping = 0;
+ public static int tp_hash = 0;
+ public static int tp_call = 0;
+ public static int tp_str = 0;
+ public static int tp_getattro = 0;
+ public static int tp_setattro = 0;
+ public static int tp_as_buffer = 0;
+ public static int tp_flags = 0;
+ public static int tp_doc = 0;
+ public static int tp_traverse = 0;
+ public static int tp_clear = 0;
+ public static int tp_richcompare = 0;
+ public static int tp_weaklistoffset = 0;
+ public static int tp_iter = 0;
+ public static int tp_iternext = 0;
+ public static int tp_methods = 0;
+ public static int tp_members = 0;
+ public static int tp_getset = 0;
+ public static int tp_base = 0;
+ public static int tp_dict = 0;
+ public static int tp_descr_get = 0;
+ public static int tp_descr_set = 0;
+ public static int tp_dictoffset = 0;
+ public static int tp_init = 0;
+ public static int tp_alloc = 0;
+ public static int tp_new = 0;
+ public static int tp_free = 0;
+ public static int tp_is_gc = 0;
+ public static int tp_bases = 0;
+ public static int tp_mro = 0;
+ public static int tp_cache = 0;
+ public static int tp_subclasses = 0;
+ public static int tp_weaklist = 0;
+ public static int tp_del = 0;
+ public static int tp_version_tag = 0;
+ public static int nb_add = 0;
+ public static int nb_subtract = 0;
+ public static int nb_multiply = 0;
+ public static int nb_divide = 0;
+ public static int nb_remainder = 0;
+ public static int nb_divmod = 0;
+ public static int nb_power = 0;
+ public static int nb_negative = 0;
+ public static int nb_positive = 0;
+ public static int nb_absolute = 0;
+ public static int nb_nonzero = 0;
+ public static int nb_invert = 0;
+ public static int nb_lshift = 0;
+ public static int nb_rshift = 0;
+ public static int nb_and = 0;
+ public static int nb_xor = 0;
+ public static int nb_or = 0;
+ public static int nb_coerce = 0;
+ public static int nb_int = 0;
+ public static int nb_long = 0;
+ public static int nb_float = 0;
+ public static int nb_oct = 0;
+ public static int nb_hex = 0;
+ public static int nb_inplace_add = 0;
+ public static int nb_inplace_subtract = 0;
+ public static int nb_inplace_multiply = 0;
+ public static int nb_inplace_divide = 0;
+ public static int nb_inplace_remainder = 0;
+ public static int nb_inplace_power = 0;
+ public static int nb_inplace_lshift = 0;
+ public static int nb_inplace_rshift = 0;
+ public static int nb_inplace_and = 0;
+ public static int nb_inplace_xor = 0;
+ public static int nb_inplace_or = 0;
+ public static int nb_floor_divide = 0;
+ public static int nb_true_divide = 0;
+ public static int nb_inplace_floor_divide = 0;
+ public static int nb_inplace_true_divide = 0;
+ public static int nb_index = 0;
+ public static int mp_length = 0;
+ public static int mp_subscript = 0;
+ public static int mp_ass_subscript = 0;
+ public static int sq_length = 0;
+ public static int sq_concat = 0;
+ public static int sq_repeat = 0;
+ public static int sq_item = 0;
+ public static int sq_slice = 0;
+ public static int sq_ass_item = 0;
+ public static int sq_ass_slice = 0;
+ public static int sq_contains = 0;
+ public static int sq_inplace_concat = 0;
+ public static int sq_inplace_repeat = 0;
+ public static int bf_getreadbuffer = 0;
+ public static int bf_getwritebuffer = 0;
+ public static int bf_getsegcount = 0;
+ public static int bf_getcharbuffer = 0;
+ public static int bf_getbuffer = 0;
+ public static int bf_releasebuffer = 0;
+ public static int name = 0;
+ public static int ht_slots = 0;
+
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+}
+#endif
diff --git a/src/runtime/interop27.cs b/src/runtime/interop27.cs
new file mode 100644
index 000000000..de4511806
--- /dev/null
+++ b/src/runtime/interop27.cs
@@ -0,0 +1,153 @@
+
+// Auto-generated by geninterop.py.
+// DOT NOT MODIFIY BY HAND.
+// ==========================================================================
+// This software is subject to the provisions of the Zope Public License,
+// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+// FOR A PARTICULAR PURPOSE.
+// ==========================================================================
+#if (PYTHON27)
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime {
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
+ internal class TypeOffset {
+
+ static TypeOffset() {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++) {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic() {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+ public static int ob_refcnt = 0;
+ public static int ob_type = 0;
+ public static int ob_size = 0;
+ public static int tp_name = 0;
+ public static int tp_basicsize = 0;
+ public static int tp_itemsize = 0;
+ public static int tp_dealloc = 0;
+ public static int tp_print = 0;
+ public static int tp_getattr = 0;
+ public static int tp_setattr = 0;
+ public static int tp_compare = 0;
+ public static int tp_repr = 0;
+ public static int tp_as_number = 0;
+ public static int tp_as_sequence = 0;
+ public static int tp_as_mapping = 0;
+ public static int tp_hash = 0;
+ public static int tp_call = 0;
+ public static int tp_str = 0;
+ public static int tp_getattro = 0;
+ public static int tp_setattro = 0;
+ public static int tp_as_buffer = 0;
+ public static int tp_flags = 0;
+ public static int tp_doc = 0;
+ public static int tp_traverse = 0;
+ public static int tp_clear = 0;
+ public static int tp_richcompare = 0;
+ public static int tp_weaklistoffset = 0;
+ public static int tp_iter = 0;
+ public static int tp_iternext = 0;
+ public static int tp_methods = 0;
+ public static int tp_members = 0;
+ public static int tp_getset = 0;
+ public static int tp_base = 0;
+ public static int tp_dict = 0;
+ public static int tp_descr_get = 0;
+ public static int tp_descr_set = 0;
+ public static int tp_dictoffset = 0;
+ public static int tp_init = 0;
+ public static int tp_alloc = 0;
+ public static int tp_new = 0;
+ public static int tp_free = 0;
+ public static int tp_is_gc = 0;
+ public static int tp_bases = 0;
+ public static int tp_mro = 0;
+ public static int tp_cache = 0;
+ public static int tp_subclasses = 0;
+ public static int tp_weaklist = 0;
+ public static int tp_del = 0;
+ public static int tp_version_tag = 0;
+ public static int nb_add = 0;
+ public static int nb_subtract = 0;
+ public static int nb_multiply = 0;
+ public static int nb_divide = 0;
+ public static int nb_remainder = 0;
+ public static int nb_divmod = 0;
+ public static int nb_power = 0;
+ public static int nb_negative = 0;
+ public static int nb_positive = 0;
+ public static int nb_absolute = 0;
+ public static int nb_nonzero = 0;
+ public static int nb_invert = 0;
+ public static int nb_lshift = 0;
+ public static int nb_rshift = 0;
+ public static int nb_and = 0;
+ public static int nb_xor = 0;
+ public static int nb_or = 0;
+ public static int nb_coerce = 0;
+ public static int nb_int = 0;
+ public static int nb_long = 0;
+ public static int nb_float = 0;
+ public static int nb_oct = 0;
+ public static int nb_hex = 0;
+ public static int nb_inplace_add = 0;
+ public static int nb_inplace_subtract = 0;
+ public static int nb_inplace_multiply = 0;
+ public static int nb_inplace_divide = 0;
+ public static int nb_inplace_remainder = 0;
+ public static int nb_inplace_power = 0;
+ public static int nb_inplace_lshift = 0;
+ public static int nb_inplace_rshift = 0;
+ public static int nb_inplace_and = 0;
+ public static int nb_inplace_xor = 0;
+ public static int nb_inplace_or = 0;
+ public static int nb_floor_divide = 0;
+ public static int nb_true_divide = 0;
+ public static int nb_inplace_floor_divide = 0;
+ public static int nb_inplace_true_divide = 0;
+ public static int nb_index = 0;
+ public static int mp_length = 0;
+ public static int mp_subscript = 0;
+ public static int mp_ass_subscript = 0;
+ public static int sq_length = 0;
+ public static int sq_concat = 0;
+ public static int sq_repeat = 0;
+ public static int sq_item = 0;
+ public static int sq_slice = 0;
+ public static int sq_ass_item = 0;
+ public static int sq_ass_slice = 0;
+ public static int sq_contains = 0;
+ public static int sq_inplace_concat = 0;
+ public static int sq_inplace_repeat = 0;
+ public static int bf_getreadbuffer = 0;
+ public static int bf_getwritebuffer = 0;
+ public static int bf_getsegcount = 0;
+ public static int bf_getcharbuffer = 0;
+ public static int bf_getbuffer = 0;
+ public static int bf_releasebuffer = 0;
+ public static int name = 0;
+ public static int ht_slots = 0;
+
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+}
+#endif
diff --git a/src/runtime/interop32.cs b/src/runtime/interop32.cs
new file mode 100644
index 000000000..711ef6323
--- /dev/null
+++ b/src/runtime/interop32.cs
@@ -0,0 +1,144 @@
+
+// Auto-generated by geninterop.py.
+// DOT NOT MODIFIY BY HAND.
+// ==========================================================================
+// This software is subject to the provisions of the Zope Public License,
+// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+// FOR A PARTICULAR PURPOSE.
+// ==========================================================================
+#if (PYTHON32)
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime {
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
+ internal class TypeOffset {
+
+ static TypeOffset() {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++) {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic() {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+ public static int ob_refcnt = 0;
+ public static int ob_type = 0;
+ public static int ob_size = 0;
+ public static int tp_name = 0;
+ public static int tp_basicsize = 0;
+ public static int tp_itemsize = 0;
+ public static int tp_dealloc = 0;
+ public static int tp_print = 0;
+ public static int tp_getattr = 0;
+ public static int tp_setattr = 0;
+ public static int tp_reserved = 0;
+ public static int tp_repr = 0;
+ public static int tp_as_number = 0;
+ public static int tp_as_sequence = 0;
+ public static int tp_as_mapping = 0;
+ public static int tp_hash = 0;
+ public static int tp_call = 0;
+ public static int tp_str = 0;
+ public static int tp_getattro = 0;
+ public static int tp_setattro = 0;
+ public static int tp_as_buffer = 0;
+ public static int tp_flags = 0;
+ public static int tp_doc = 0;
+ public static int tp_traverse = 0;
+ public static int tp_clear = 0;
+ public static int tp_richcompare = 0;
+ public static int tp_weaklistoffset = 0;
+ public static int tp_iter = 0;
+ public static int tp_iternext = 0;
+ public static int tp_methods = 0;
+ public static int tp_members = 0;
+ public static int tp_getset = 0;
+ public static int tp_base = 0;
+ public static int tp_dict = 0;
+ public static int tp_descr_get = 0;
+ public static int tp_descr_set = 0;
+ public static int tp_dictoffset = 0;
+ public static int tp_init = 0;
+ public static int tp_alloc = 0;
+ public static int tp_new = 0;
+ public static int tp_free = 0;
+ public static int tp_is_gc = 0;
+ public static int tp_bases = 0;
+ public static int tp_mro = 0;
+ public static int tp_cache = 0;
+ public static int tp_subclasses = 0;
+ public static int tp_weaklist = 0;
+ public static int tp_del = 0;
+ public static int tp_version_tag = 0;
+ public static int nb_add = 0;
+ public static int nb_subtract = 0;
+ public static int nb_multiply = 0;
+ public static int nb_remainder = 0;
+ public static int nb_divmod = 0;
+ public static int nb_power = 0;
+ public static int nb_negative = 0;
+ public static int nb_positive = 0;
+ public static int nb_absolute = 0;
+ public static int nb_bool = 0;
+ public static int nb_invert = 0;
+ public static int nb_lshift = 0;
+ public static int nb_rshift = 0;
+ public static int nb_and = 0;
+ public static int nb_xor = 0;
+ public static int nb_or = 0;
+ public static int nb_int = 0;
+ public static int nb_reserved = 0;
+ public static int nb_float = 0;
+ public static int nb_inplace_add = 0;
+ public static int nb_inplace_subtract = 0;
+ public static int nb_inplace_multiply = 0;
+ public static int nb_inplace_remainder = 0;
+ public static int nb_inplace_power = 0;
+ public static int nb_inplace_lshift = 0;
+ public static int nb_inplace_rshift = 0;
+ public static int nb_inplace_and = 0;
+ public static int nb_inplace_xor = 0;
+ public static int nb_inplace_or = 0;
+ public static int nb_floor_divide = 0;
+ public static int nb_true_divide = 0;
+ public static int nb_inplace_floor_divide = 0;
+ public static int nb_inplace_true_divide = 0;
+ public static int nb_index = 0;
+ public static int mp_length = 0;
+ public static int mp_subscript = 0;
+ public static int mp_ass_subscript = 0;
+ public static int sq_length = 0;
+ public static int sq_concat = 0;
+ public static int sq_repeat = 0;
+ public static int sq_item = 0;
+ public static int was_sq_slice = 0;
+ public static int sq_ass_item = 0;
+ public static int was_sq_ass_slice = 0;
+ public static int sq_contains = 0;
+ public static int sq_inplace_concat = 0;
+ public static int sq_inplace_repeat = 0;
+ public static int bf_getbuffer = 0;
+ public static int bf_releasebuffer = 0;
+ public static int name = 0;
+ public static int ht_slots = 0;
+
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+}
+#endif
diff --git a/src/runtime/interop33.cs b/src/runtime/interop33.cs
new file mode 100644
index 000000000..47aaae96c
--- /dev/null
+++ b/src/runtime/interop33.cs
@@ -0,0 +1,145 @@
+
+// Auto-generated by geninterop.py.
+// DOT NOT MODIFIY BY HAND.
+// ==========================================================================
+// This software is subject to the provisions of the Zope Public License,
+// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+// FOR A PARTICULAR PURPOSE.
+// ==========================================================================
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime {
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
+ internal class TypeOffset {
+
+ static TypeOffset() {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++) {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic() {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+ public static int ob_refcnt = 0;
+ public static int ob_type = 0;
+ public static int ob_size = 0;
+ public static int tp_name = 0;
+ public static int tp_basicsize = 0;
+ public static int tp_itemsize = 0;
+ public static int tp_dealloc = 0;
+ public static int tp_print = 0;
+ public static int tp_getattr = 0;
+ public static int tp_setattr = 0;
+ public static int tp_reserved = 0;
+ public static int tp_repr = 0;
+ public static int tp_as_number = 0;
+ public static int tp_as_sequence = 0;
+ public static int tp_as_mapping = 0;
+ public static int tp_hash = 0;
+ public static int tp_call = 0;
+ public static int tp_str = 0;
+ public static int tp_getattro = 0;
+ public static int tp_setattro = 0;
+ public static int tp_as_buffer = 0;
+ public static int tp_flags = 0;
+ public static int tp_doc = 0;
+ public static int tp_traverse = 0;
+ public static int tp_clear = 0;
+ public static int tp_richcompare = 0;
+ public static int tp_weaklistoffset = 0;
+ public static int tp_iter = 0;
+ public static int tp_iternext = 0;
+ public static int tp_methods = 0;
+ public static int tp_members = 0;
+ public static int tp_getset = 0;
+ public static int tp_base = 0;
+ public static int tp_dict = 0;
+ public static int tp_descr_get = 0;
+ public static int tp_descr_set = 0;
+ public static int tp_dictoffset = 0;
+ public static int tp_init = 0;
+ public static int tp_alloc = 0;
+ public static int tp_new = 0;
+ public static int tp_free = 0;
+ public static int tp_is_gc = 0;
+ public static int tp_bases = 0;
+ public static int tp_mro = 0;
+ public static int tp_cache = 0;
+ public static int tp_subclasses = 0;
+ public static int tp_weaklist = 0;
+ public static int tp_del = 0;
+ public static int tp_version_tag = 0;
+ public static int nb_add = 0;
+ public static int nb_subtract = 0;
+ public static int nb_multiply = 0;
+ public static int nb_remainder = 0;
+ public static int nb_divmod = 0;
+ public static int nb_power = 0;
+ public static int nb_negative = 0;
+ public static int nb_positive = 0;
+ public static int nb_absolute = 0;
+ public static int nb_bool = 0;
+ public static int nb_invert = 0;
+ public static int nb_lshift = 0;
+ public static int nb_rshift = 0;
+ public static int nb_and = 0;
+ public static int nb_xor = 0;
+ public static int nb_or = 0;
+ public static int nb_int = 0;
+ public static int nb_reserved = 0;
+ public static int nb_float = 0;
+ public static int nb_inplace_add = 0;
+ public static int nb_inplace_subtract = 0;
+ public static int nb_inplace_multiply = 0;
+ public static int nb_inplace_remainder = 0;
+ public static int nb_inplace_power = 0;
+ public static int nb_inplace_lshift = 0;
+ public static int nb_inplace_rshift = 0;
+ public static int nb_inplace_and = 0;
+ public static int nb_inplace_xor = 0;
+ public static int nb_inplace_or = 0;
+ public static int nb_floor_divide = 0;
+ public static int nb_true_divide = 0;
+ public static int nb_inplace_floor_divide = 0;
+ public static int nb_inplace_true_divide = 0;
+ public static int nb_index = 0;
+ public static int mp_length = 0;
+ public static int mp_subscript = 0;
+ public static int mp_ass_subscript = 0;
+ public static int sq_length = 0;
+ public static int sq_concat = 0;
+ public static int sq_repeat = 0;
+ public static int sq_item = 0;
+ public static int was_sq_slice = 0;
+ public static int sq_ass_item = 0;
+ public static int was_sq_ass_slice = 0;
+ public static int sq_contains = 0;
+ public static int sq_inplace_concat = 0;
+ public static int sq_inplace_repeat = 0;
+ public static int bf_getbuffer = 0;
+ public static int bf_releasebuffer = 0;
+ public static int name = 0;
+ public static int ht_slots = 0;
+ public static int qualname = 0;
+ public static int ht_cached_keys = 0;
+
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+}
diff --git a/src/runtime/interop34.cs b/src/runtime/interop34.cs
new file mode 100644
index 000000000..8b74930c7
--- /dev/null
+++ b/src/runtime/interop34.cs
@@ -0,0 +1,147 @@
+
+// Auto-generated by geninterop.py.
+// DOT NOT MODIFIY BY HAND.
+// ==========================================================================
+// This software is subject to the provisions of the Zope Public License,
+// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+// FOR A PARTICULAR PURPOSE.
+// ==========================================================================
+#if (PYTHON34)
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime {
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
+ internal class TypeOffset {
+
+ static TypeOffset() {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++) {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic() {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+ public static int ob_refcnt = 0;
+ public static int ob_type = 0;
+ public static int ob_size = 0;
+ public static int tp_name = 0;
+ public static int tp_basicsize = 0;
+ public static int tp_itemsize = 0;
+ public static int tp_dealloc = 0;
+ public static int tp_print = 0;
+ public static int tp_getattr = 0;
+ public static int tp_setattr = 0;
+ public static int tp_reserved = 0;
+ public static int tp_repr = 0;
+ public static int tp_as_number = 0;
+ public static int tp_as_sequence = 0;
+ public static int tp_as_mapping = 0;
+ public static int tp_hash = 0;
+ public static int tp_call = 0;
+ public static int tp_str = 0;
+ public static int tp_getattro = 0;
+ public static int tp_setattro = 0;
+ public static int tp_as_buffer = 0;
+ public static int tp_flags = 0;
+ public static int tp_doc = 0;
+ public static int tp_traverse = 0;
+ public static int tp_clear = 0;
+ public static int tp_richcompare = 0;
+ public static int tp_weaklistoffset = 0;
+ public static int tp_iter = 0;
+ public static int tp_iternext = 0;
+ public static int tp_methods = 0;
+ public static int tp_members = 0;
+ public static int tp_getset = 0;
+ public static int tp_base = 0;
+ public static int tp_dict = 0;
+ public static int tp_descr_get = 0;
+ public static int tp_descr_set = 0;
+ public static int tp_dictoffset = 0;
+ public static int tp_init = 0;
+ public static int tp_alloc = 0;
+ public static int tp_new = 0;
+ public static int tp_free = 0;
+ public static int tp_is_gc = 0;
+ public static int tp_bases = 0;
+ public static int tp_mro = 0;
+ public static int tp_cache = 0;
+ public static int tp_subclasses = 0;
+ public static int tp_weaklist = 0;
+ public static int tp_del = 0;
+ public static int tp_version_tag = 0;
+ public static int tp_finalize = 0;
+ public static int nb_add = 0;
+ public static int nb_subtract = 0;
+ public static int nb_multiply = 0;
+ public static int nb_remainder = 0;
+ public static int nb_divmod = 0;
+ public static int nb_power = 0;
+ public static int nb_negative = 0;
+ public static int nb_positive = 0;
+ public static int nb_absolute = 0;
+ public static int nb_bool = 0;
+ public static int nb_invert = 0;
+ public static int nb_lshift = 0;
+ public static int nb_rshift = 0;
+ public static int nb_and = 0;
+ public static int nb_xor = 0;
+ public static int nb_or = 0;
+ public static int nb_int = 0;
+ public static int nb_reserved = 0;
+ public static int nb_float = 0;
+ public static int nb_inplace_add = 0;
+ public static int nb_inplace_subtract = 0;
+ public static int nb_inplace_multiply = 0;
+ public static int nb_inplace_remainder = 0;
+ public static int nb_inplace_power = 0;
+ public static int nb_inplace_lshift = 0;
+ public static int nb_inplace_rshift = 0;
+ public static int nb_inplace_and = 0;
+ public static int nb_inplace_xor = 0;
+ public static int nb_inplace_or = 0;
+ public static int nb_floor_divide = 0;
+ public static int nb_true_divide = 0;
+ public static int nb_inplace_floor_divide = 0;
+ public static int nb_inplace_true_divide = 0;
+ public static int nb_index = 0;
+ public static int mp_length = 0;
+ public static int mp_subscript = 0;
+ public static int mp_ass_subscript = 0;
+ public static int sq_length = 0;
+ public static int sq_concat = 0;
+ public static int sq_repeat = 0;
+ public static int sq_item = 0;
+ public static int was_sq_slice = 0;
+ public static int sq_ass_item = 0;
+ public static int was_sq_ass_slice = 0;
+ public static int sq_contains = 0;
+ public static int sq_inplace_concat = 0;
+ public static int sq_inplace_repeat = 0;
+ public static int bf_getbuffer = 0;
+ public static int bf_releasebuffer = 0;
+ public static int name = 0;
+ public static int ht_slots = 0;
+ public static int qualname = 0;
+ public static int ht_cached_keys = 0;
+
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+}
+#endif
diff --git a/src/runtime/interop35.cs b/src/runtime/interop35.cs
new file mode 100644
index 000000000..e573b9225
--- /dev/null
+++ b/src/runtime/interop35.cs
@@ -0,0 +1,152 @@
+
+// Auto-generated by geninterop.py.
+// DOT NOT MODIFIY BY HAND.
+// ==========================================================================
+// This software is subject to the provisions of the Zope Public License,
+// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+// FOR A PARTICULAR PURPOSE.
+// ==========================================================================
+#if (PYTHON35)
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime {
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
+ internal class TypeOffset {
+
+ static TypeOffset() {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++) {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic() {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+ public static int ob_refcnt = 0;
+ public static int ob_type = 0;
+ public static int ob_size = 0;
+ public static int tp_name = 0;
+ public static int tp_basicsize = 0;
+ public static int tp_itemsize = 0;
+ public static int tp_dealloc = 0;
+ public static int tp_print = 0;
+ public static int tp_getattr = 0;
+ public static int tp_setattr = 0;
+ public static int tp_as_async = 0;
+ public static int tp_repr = 0;
+ public static int tp_as_number = 0;
+ public static int tp_as_sequence = 0;
+ public static int tp_as_mapping = 0;
+ public static int tp_hash = 0;
+ public static int tp_call = 0;
+ public static int tp_str = 0;
+ public static int tp_getattro = 0;
+ public static int tp_setattro = 0;
+ public static int tp_as_buffer = 0;
+ public static int tp_flags = 0;
+ public static int tp_doc = 0;
+ public static int tp_traverse = 0;
+ public static int tp_clear = 0;
+ public static int tp_richcompare = 0;
+ public static int tp_weaklistoffset = 0;
+ public static int tp_iter = 0;
+ public static int tp_iternext = 0;
+ public static int tp_methods = 0;
+ public static int tp_members = 0;
+ public static int tp_getset = 0;
+ public static int tp_base = 0;
+ public static int tp_dict = 0;
+ public static int tp_descr_get = 0;
+ public static int tp_descr_set = 0;
+ public static int tp_dictoffset = 0;
+ public static int tp_init = 0;
+ public static int tp_alloc = 0;
+ public static int tp_new = 0;
+ public static int tp_free = 0;
+ public static int tp_is_gc = 0;
+ public static int tp_bases = 0;
+ public static int tp_mro = 0;
+ public static int tp_cache = 0;
+ public static int tp_subclasses = 0;
+ public static int tp_weaklist = 0;
+ public static int tp_del = 0;
+ public static int tp_version_tag = 0;
+ public static int tp_finalize = 0;
+ public static int am_await = 0;
+ public static int am_aiter = 0;
+ public static int am_anext = 0;
+ public static int nb_add = 0;
+ public static int nb_subtract = 0;
+ public static int nb_multiply = 0;
+ public static int nb_remainder = 0;
+ public static int nb_divmod = 0;
+ public static int nb_power = 0;
+ public static int nb_negative = 0;
+ public static int nb_positive = 0;
+ public static int nb_absolute = 0;
+ public static int nb_bool = 0;
+ public static int nb_invert = 0;
+ public static int nb_lshift = 0;
+ public static int nb_rshift = 0;
+ public static int nb_and = 0;
+ public static int nb_xor = 0;
+ public static int nb_or = 0;
+ public static int nb_int = 0;
+ public static int nb_reserved = 0;
+ public static int nb_float = 0;
+ public static int nb_inplace_add = 0;
+ public static int nb_inplace_subtract = 0;
+ public static int nb_inplace_multiply = 0;
+ public static int nb_inplace_remainder = 0;
+ public static int nb_inplace_power = 0;
+ public static int nb_inplace_lshift = 0;
+ public static int nb_inplace_rshift = 0;
+ public static int nb_inplace_and = 0;
+ public static int nb_inplace_xor = 0;
+ public static int nb_inplace_or = 0;
+ public static int nb_floor_divide = 0;
+ public static int nb_true_divide = 0;
+ public static int nb_inplace_floor_divide = 0;
+ public static int nb_inplace_true_divide = 0;
+ public static int nb_index = 0;
+ public static int nb_matrix_multiply = 0;
+ public static int nb_inplace_matrix_multiply = 0;
+ public static int mp_length = 0;
+ public static int mp_subscript = 0;
+ public static int mp_ass_subscript = 0;
+ public static int sq_length = 0;
+ public static int sq_concat = 0;
+ public static int sq_repeat = 0;
+ public static int sq_item = 0;
+ public static int was_sq_slice = 0;
+ public static int sq_ass_item = 0;
+ public static int was_sq_ass_slice = 0;
+ public static int sq_contains = 0;
+ public static int sq_inplace_concat = 0;
+ public static int sq_inplace_repeat = 0;
+ public static int bf_getbuffer = 0;
+ public static int bf_releasebuffer = 0;
+ public static int name = 0;
+ public static int ht_slots = 0;
+ public static int qualname = 0;
+ public static int ht_cached_keys = 0;
+
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+}
+#endif
diff --git a/src/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..25456a50d 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;
}
@@ -256,10 +260,44 @@ public static void tp_dealloc(IntPtr tp) {
return;
}
+ static IntPtr DoInstanceCheck(IntPtr tp, IntPtr args, bool checkType)
+ {
+ ClassBase cb = GetManagedObject(tp) as ClassBase;
+
+ if (cb == null)
+ return Runtime.PyFalse;
+
+ using (PyList argsObj = new PyList(args))
+ {
+ if (argsObj.Length() != 1)
+ return Exceptions.RaiseTypeError("Invalid parameter count");
+
+ PyObject arg = argsObj[0];
+ PyObject otherType;
+ if (checkType)
+ otherType = arg;
+ else
+ otherType = arg.GetPythonType();
+
+ if (Runtime.PyObject_TYPE(otherType.Handle) != PyCLRMetaType)
+ return Runtime.PyFalse;
+
+ ClassBase otherCb = GetManagedObject(otherType.Handle) as ClassBase;
+ if (otherCb == null)
+ return Runtime.PyFalse;
+
+ return Converter.ToPython(cb.type.IsAssignableFrom(otherCb.type));
+ }
+ }
-
-
+ public static IntPtr __instancecheck__(IntPtr tp, IntPtr args)
+ {
+ return DoInstanceCheck(tp, args, false);
+ }
+
+ public static IntPtr __subclasscheck__(IntPtr tp, IntPtr args)
+ {
+ return DoInstanceCheck(tp, args, true);
+ }
}
-
-
}
diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs
index 80d3968fd..943f9da04 100644
--- a/src/runtime/methodbinder.cs
+++ b/src/runtime/methodbinder.cs
@@ -50,7 +50,10 @@ internal void AddMethod(MethodBase m) {
//====================================================================
internal static MethodInfo MatchSignature(MethodInfo[] mi, Type[] tp) {
- int count = tp.Length;
+ if (tp == null) {
+ return null;
+ }
+ int count = tp.Length;
for (int i = 0; i < mi.Length; i++) {
ParameterInfo[] pi = mi[i].GetParameters();
if (pi.Length != count) {
@@ -73,8 +76,11 @@ internal static MethodInfo MatchSignature(MethodInfo[] mi, Type[] tp) {
// return the MethodInfo that represents the matching closed generic.
//====================================================================
- internal static MethodInfo MatchParameters(MethodInfo[] mi,Type[] tp) {
- int count = tp.Length;
+ internal static MethodInfo MatchParameters(MethodInfo[] mi, Type[] tp) {
+ if (tp == null) {
+ return null;
+ }
+ int count = tp.Length;
for (int i = 0; i < mi.Length; i++) {
if (!mi[i].IsGenericMethodDefinition) {
continue;
@@ -89,51 +95,54 @@ internal static MethodInfo MatchParameters(MethodInfo[] mi,Type[] tp) {
}
- //====================================================================
- // Given a sequence of MethodInfo and two sequences of type parameters,
- // return the MethodInfo that matches the signature and the closed generic.
- //====================================================================
-
- internal static MethodInfo MatchSignatureAndParameters(MethodInfo[] mi, Type[] genericTp, Type[] sigTp)
- {
- int genericCount = genericTp.Length;
- int signatureCount = sigTp.Length;
- for (int i = 0; i < mi.Length; i++)
- {
- if (!mi[i].IsGenericMethodDefinition)
- {
- continue;
- }
- Type[] genericArgs = mi[i].GetGenericArguments();
- if (genericArgs.Length != genericCount)
- {
- continue;
- }
- ParameterInfo[] pi = mi[i].GetParameters();
- if (pi.Length != signatureCount)
- {
- continue;
- }
- for (int n = 0; n < pi.Length; n++)
- {
- if (sigTp[n] != pi[n].ParameterType)
- {
- break;
- }
- if (n == (pi.Length - 1))
- {
- MethodInfo match = mi[i];
- if (match.IsGenericMethodDefinition)
- {
- Type[] typeArgs = match.GetGenericArguments();
- return match.MakeGenericMethod(genericTp);
- }
- return match;
- }
- }
- }
- return null;
- }
+ //====================================================================
+ // Given a sequence of MethodInfo and two sequences of type parameters,
+ // return the MethodInfo that matches the signature and the closed generic.
+ //====================================================================
+
+ internal static MethodInfo MatchSignatureAndParameters(MethodInfo[] mi, Type[] genericTp, Type[] sigTp)
+ {
+ if ((genericTp == null) || (sigTp == null)) {
+ return null;
+ }
+ int genericCount = genericTp.Length;
+ int signatureCount = sigTp.Length;
+ for (int i = 0; i < mi.Length; i++)
+ {
+ if (!mi[i].IsGenericMethodDefinition)
+ {
+ continue;
+ }
+ Type[] genericArgs = mi[i].GetGenericArguments();
+ if (genericArgs.Length != genericCount)
+ {
+ continue;
+ }
+ ParameterInfo[] pi = mi[i].GetParameters();
+ if (pi.Length != signatureCount)
+ {
+ continue;
+ }
+ for (int n = 0; n < pi.Length; n++)
+ {
+ if (sigTp[n] != pi[n].ParameterType)
+ {
+ break;
+ }
+ if (n == (pi.Length - 1))
+ {
+ MethodInfo match = mi[i];
+ if (match.IsGenericMethodDefinition)
+ {
+ Type[] typeArgs = match.GetGenericArguments();
+ return match.MakeGenericMethod(genericTp);
+ }
+ return match;
+ }
+ }
+ }
+ return null;
+ }
//====================================================================
@@ -226,7 +235,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
int pynargs = Runtime.PyTuple_Size(args);
object arg;
bool isGeneric = false;
-
+ ArrayList defaultArgList = null;
if (info != null) {
_methods = (MethodBase[])Array.CreateInstance(
typeof(MethodBase), 1
@@ -236,9 +245,10 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
else {
_methods = GetMethods();
}
-
+ Type clrtype;
for (int i = 0; i < _methods.Length; i++) {
MethodBase mi = _methods[i];
+
if (mi.IsGenericMethod) { isGeneric = true; }
ParameterInfo[] pi = mi.GetParameters();
int clrnargs = pi.Length;
@@ -247,12 +257,20 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
int outs = 0;
if (pynargs == clrnargs) {
- match = true;
+ match = true;
+ } else if(pynargs < clrnargs){
+ match = true;
+ defaultArgList = new ArrayList();
+ for (int v = pynargs; v < clrnargs; v++)
+ {
+ if (pi[v].DefaultValue == DBNull.Value)
+ match = false;
+ else
+ defaultArgList.Add((object)pi[v].DefaultValue);
+ }
} else if ((pynargs > clrnargs) && (clrnargs > 0) &&
- (pi[clrnargs-1].ParameterType.IsArray)) {
- // The last argument of the mananged functions seems to
- // accept multiple arguments as a array. Hopefully it's a
- // spam(params object[] egg) style method
+ Attribute.IsDefined(pi[clrnargs-1], typeof(ParamArrayAttribute))) {
+ // This is a spam(params object[] egg) style method
match = true;
arrayStart = clrnargs - 1;
}
@@ -262,30 +280,95 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
for (int n = 0; n < clrnargs; n++) {
IntPtr op;
- if (arrayStart == n) {
- // map remaining Python arguments to a tuple since
- // the managed function accepts it - hopefully :]
- op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
+ if (n < pynargs) {
+ if (arrayStart == n) {
+ // map remaining Python arguments to a tuple since
+ // the managed function accepts it - hopefully :]
+ op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs);
+ }
+ else {
+ op = Runtime.PyTuple_GetItem(args, n);
+ }
+
+ // this logic below handles cases when multiple overloading methods
+ // are ambiguous, hence comparison between Python and CLR types
+ // is necessary
+ clrtype = null;
+ IntPtr pyoptype;
+ if (_methods.Length > 1) {
+ pyoptype = IntPtr.Zero;
+ pyoptype = Runtime.PyObject_Type(op);
+ Exceptions.Clear();
+ if (pyoptype != IntPtr.Zero) {
+ clrtype = Converter.GetTypeByAlias(pyoptype);
+ }
+ Runtime.Decref(pyoptype);
+ }
+
+
+ if (clrtype != null) {
+ bool typematch = false;
+ if (pi[n].ParameterType != clrtype) {
+ IntPtr pytype = Converter.GetPythonTypeByAlias(pi[n].ParameterType);
+ pyoptype = Runtime.PyObject_Type(op);
+ Exceptions.Clear();
+ if (pyoptype != IntPtr.Zero) {
+ if (pytype != pyoptype) {
+ typematch = false;
+ }
+ else {
+ typematch = true;
+ clrtype = pi[n].ParameterType;
+ }
+ }
+ if (!typematch) {
+ // this takes care of enum values
+ TypeCode argtypecode = Type.GetTypeCode(pi[n].ParameterType);
+ TypeCode paramtypecode = Type.GetTypeCode(clrtype);
+ if (argtypecode == paramtypecode) {
+ typematch = true;
+ clrtype = pi[n].ParameterType;
+ }
+ }
+ Runtime.Decref(pyoptype);
+ if (!typematch) {
+ margs = null;
+ break;
+ }
+ }
+ else {
+ typematch = true;
+ clrtype = pi[n].ParameterType;
+ }
+ }
+ else {
+ clrtype = pi[n].ParameterType;
+ }
+
+ if (pi[n].IsOut || clrtype.IsByRef)
+ {
+ outs++;
+ }
+
+ if (!Converter.ToManaged(op, clrtype, out arg, false))
+ {
+ Exceptions.Clear();
+ margs = null;
+ break;
+ }
+ if (arrayStart == n)
+ {
+ // GetSlice() creates a new reference but GetItem()
+ // returns only a borrow reference.
+ Runtime.Decref(op);
+ }
+ margs[n] = arg;
}
- else {
- op = Runtime.PyTuple_GetItem(args, n);
+ else
+ {
+ if (defaultArgList != null)
+ margs[n] = defaultArgList[n - pynargs];
}
- Type type = pi[n].ParameterType;
- if (pi[n].IsOut || type.IsByRef) {
- outs++;
- }
-
- if (!Converter.ToManaged(op, type, out arg, false)) {
- Exceptions.Clear();
- margs = null;
- break;
- }
- if (arrayStart == n) {
- // GetSlice() creates a new reference but GetItem()
- // returns only a borrow reference.
- Runtime.Decref(op);
- }
- margs[n] = arg;
}
if (margs == null) {
@@ -322,7 +405,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw,
MethodInfo mi = MethodBinder.MatchParameters(methodinfo, types);
return Bind(inst, args, kw, mi, null);
}
- return null;
+ return null;
}
internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) {
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..764c77446 100644
--- a/src/runtime/methodwrapper.cs
+++ b/src/runtime/methodwrapper.cs
@@ -25,37 +25,22 @@ internal class MethodWrapper {
public IntPtr mdef;
public IntPtr ptr;
- public MethodWrapper(Type type, string name) {
+ public MethodWrapper(Type type, string name, string funcType = null) {
// Turn the managed method into a function pointer
- IntPtr fp = Interop.GetThunk(type.GetMethod(name));
-
- // XXX - here we create a Python string object, then take the
- // char * of the internal string to pass to our methoddef
- // structure. Its a hack, and the name is leaked!
-
- IntPtr ps = Runtime.PyString_FromString(name);
- IntPtr sp = Runtime.PyString_AS_STRING(ps);
+ IntPtr fp = Interop.GetThunk(type.GetMethod(name), funcType);
// Allocate and initialize a PyMethodDef structure to represent
// the managed method, then create a PyCFunction.
mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size);
- Marshal.WriteIntPtr(mdef, sp);
- Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), fp);
- Marshal.WriteIntPtr(mdef, (2 * IntPtr.Size), (IntPtr)0x0002);
- Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), IntPtr.Zero);
- ptr = Runtime.PyCFunction_New(mdef, IntPtr.Zero);
+ TypeManager.WriteMethodDef(mdef, name, fp, 0x0003);
+ ptr = Runtime.PyCFunction_NewEx(mdef, IntPtr.Zero, IntPtr.Zero);
}
public IntPtr Call(IntPtr args, IntPtr kw) {
return Runtime.PyCFunction_Call(ptr, args, kw);
}
-
-
}
-
-
-}
-
+}
\ No newline at end of file
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..d5dc2a562 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);
}
}
@@ -394,11 +409,15 @@ public static Assembly AddReference(string name)
{
assembly = AssemblyManager.LoadAssembly(name);
}
+ if (assembly == null) {
+ assembly = AssemblyManager.LoadAssemblyFullPath(name);
+ }
if (assembly == null)
{
string msg = String.Format("Unable to find assembly '{0}'.", name);
throw new System.IO.FileNotFoundException(msg);
}
+
return assembly ;
}
@@ -425,6 +444,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..d17e89a7a 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,9 @@ 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);
+ }
}
@@ -376,8 +385,9 @@ public virtual PyObject GetItem(string key) {
///
public virtual PyObject GetItem(int index) {
- PyInt key = new PyInt(index);
- return GetItem((PyObject)key);
+ using (PyInt key = new PyInt(index)) {
+ return GetItem((PyObject)key);
+ }
}
@@ -410,7 +420,9 @@ 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 +437,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 +472,9 @@ 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 +489,9 @@ 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 +577,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 +642,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 +661,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 +791,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 +911,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..0cb99bffe 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 || PYTHON35)
+ 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 || PYTHON35)
+ return IntPtr.Zero;
+#endif
}
- }
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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..552f004eb 100644
--- a/src/runtime/pythonexception.cs
+++ b/src/runtime/pythonexception.cs
@@ -34,14 +34,29 @@ public PythonException() : base()
Runtime.Incref(_pyTB);
if ((_pyType != IntPtr.Zero) && (_pyValue != IntPtr.Zero))
{
- string type = new PyObject(_pyType).GetAttr("__name__").ToString();
- string message = Runtime.GetManagedString(_pyValue);
+ string type;
+ string message;
+ Runtime.Incref(_pyType);
+ using (PyObject pyType = new PyObject(_pyType))
+ using (PyObject pyTypeName = pyType.GetAttr("__name__"))
+ {
+ type = pyTypeName.ToString();
+ }
+
+ Runtime.Incref(_pyValue);
+ using (PyObject pyValue = new PyObject(_pyValue))
+ {
+ message = pyValue.ToString();
+ }
_message = type + " : " + message;
}
if (_pyTB != IntPtr.Zero)
{
PyObject tb_module = PythonEngine.ImportModule("traceback");
- _tb = tb_module.InvokeMethod("format_tb", new PyObject(_pyTB)).ToString();
+ Runtime.Incref(_pyTB);
+ using (PyObject pyTB = new PyObject(_pyTB)) {
+ _tb = tb_module.InvokeMethod("format_tb", pyTB).ToString();
+ }
}
PythonEngine.ReleaseLock(gs);
}
@@ -53,6 +68,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
@@ -80,6 +107,18 @@ public IntPtr PyValue
get { return _pyValue; }
}
+ ///
+ /// PyTB Property
+ ///
+ ///
+ ///
+ /// Returns the TraceBack as a Python object.
+ ///
+
+ public IntPtr PyTB {
+ get { return _pyTB; }
+ }
+
///
/// Message 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..260d968d8 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -15,10 +15,86 @@
using Mono.Unix;
#endif
+#if (UCS2 && (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35))
+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,114 @@ 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 (PYTHON35)
+ public const string pyversion = "3.5";
+ public const int pyversionnumber = 35;
+#endif
+#if ! (PYTHON23 || PYTHON24 || PYTHON25 || PYTHON26 || PYTHON27 || PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+#error You must define one of PYTHON23 to PYTHON35
+#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
+#if (PYTHON35)
+ internal const string dllBase = "python3.5";
+#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
+#if (PYTHON35)
+ internal const string dllBase = "python35";
+#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 +228,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 || PYTHON35)
+ 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 +264,11 @@ internal static void Initialize() {
PyMethodType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ Runtime.Decref(dict);
+ Runtime.Decref(op);
+#endif
+
op = Runtime.PyString_FromString("string");
PyStringType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
@@ -108,6 +277,12 @@ internal static void Initialize() {
PyUnicodeType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 +307,13 @@ internal static void Initialize() {
PyFloatType = Runtime.PyObject_Type(op);
Runtime.Decref(op);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 +324,29 @@ internal static void Initialize() {
Runtime.Decref(i);
Runtime.Decref(c);
Runtime.Decref(d);
+#endif
Error = new IntPtr(-1);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 || PYTHON35)
wrap_exceptions = false;
#else
IntPtr m = PyImport_ImportModule("exceptions");
@@ -188,6 +383,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 +414,17 @@ internal static void Shutdown() {
internal static IntPtr PyNoneType;
internal static IntPtr PyTypeType;
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ 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 +576,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 +673,28 @@ internal unsafe static extern void
internal unsafe static extern IntPtr
PyGILState_GetThisThreadState();
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ [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 +741,70 @@ internal unsafe static extern IntPtr
PyEval_GetLocals();
+#if PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35
[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 +851,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 +986,42 @@ internal unsafe static extern IntPtr
internal unsafe static extern IntPtr
PyObject_CallObject(IntPtr pointer, IntPtr args);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ [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 +1038,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 +1068,18 @@ internal unsafe static extern IntPtr
internal unsafe static extern IntPtr
PyObject_Str(IntPtr pointer);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ [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 +1091,18 @@ internal unsafe static extern IntPtr
// Python number API
//====================================================================
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
[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 +1129,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 +1140,51 @@ internal static IntPtr PyInt_FromInt64(long value) {
return PyInt_FromLong(v);
}
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ [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 +1260,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 +1482,57 @@ internal static IntPtr PyString_FromString(string value) {
return PyString_FromStringAndSize(value, value.Length);
}
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ [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 || PYTHON35)
+ [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 +1548,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 || PYTHON35)
+ [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 +1640,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 +1651,8 @@ internal unsafe static string GetManagedString(IntPtr op)
{
IntPtr type = PyObject_TYPE(op);
+// Python 3 strings are all unicode
+#if !(PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
if (type == Runtime.PyStringType)
{
return Marshal.PtrToStringAnsi(
@@ -1084,6 +1660,7 @@ internal unsafe static string GetManagedString(IntPtr op)
Runtime.PyString_Size(op)
);
}
+#endif
if (type == Runtime.PyUnicodeType)
{
@@ -1097,6 +1674,52 @@ internal unsafe static string GetManagedString(IntPtr op)
#endif
#if (UCS4)
+#if (PYTHON33 || PYTHON34 || PYTHON35)
+ [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 +1765,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 +1776,8 @@ internal unsafe static string GetManagedString(IntPtr op)
{
IntPtr type = PyObject_TYPE(op);
+// Python 3 strings are all unicode
+#if !(PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
if (type == Runtime.PyStringType)
{
return Marshal.PtrToStringAnsi(
@@ -1158,11 +1785,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 +1844,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 +1992,20 @@ internal unsafe static extern int
// Python iterator API
//====================================================================
+#if !(PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
[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 +2016,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 +2036,13 @@ internal unsafe static extern IntPtr
internal unsafe static extern string
PyModule_GetFilename(IntPtr module);
+#if (PYTHON32 || PYTHON33 || PYTHON34 || PYTHON35)
+ [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..d022625ab 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 || PYTHON35)
+ 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,57 +195,99 @@ 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);
+ // 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");
+ }
- Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_);
- Runtime.Incref(base_);
+ 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();
+ }
- 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);
+ // 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");
+ }
- CopySlot(base_, type, TypeOffset.tp_traverse);
- CopySlot(base_, type, TypeOffset.tp_clear);
- CopySlot(base_, type, TypeOffset.tp_is_gc);
+ try
+ {
+ Type subType = ClassDerivedObject.CreateDerivedType(name,
+ baseClass.type,
+ py_dict,
+ (string)namespaceStr,
+ (string)assembly);
- Runtime.PyType_Ready(type);
+ // create the new ManagedType and python type
+ ClassBase subClass = ClassManager.GetClass(subType);
+ IntPtr py_type = GetTypeHandle(subClass, subType);
+ // 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);
- IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict);
- IntPtr mod = Runtime.PyString_FromString("CLR");
- Runtime.PyDict_SetItemString(tp_dict, "__module__", mod);
+ return py_type;
+ }
+ catch (Exception e)
+ {
+ return Exceptions.RaiseTypeError(e.Message);
+ }
+ }
- // for now, move up hidden handle...
- IntPtr gc = Marshal.ReadIntPtr(base_, TypeOffset.magic());
- Marshal.WriteIntPtr(type, TypeOffset.magic(), gc);
+ internal static IntPtr WriteMethodDef(IntPtr mdef, IntPtr name, IntPtr func, int flags, IntPtr doc)
+ {
+ Marshal.WriteIntPtr(mdef, name);
+ Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), func);
+ Marshal.WriteInt32(mdef, (2 * IntPtr.Size), flags);
+ Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), doc);
+ return mdef + 4 * IntPtr.Size;
+ }
- return type;
+ internal static IntPtr WriteMethodDef(IntPtr mdef, string name, IntPtr func, int flags = 0x0001, string doc = null)
+ {
+ IntPtr namePtr = Marshal.StringToHGlobalAnsi(name);
+ IntPtr docPtr = doc != null ? Marshal.StringToHGlobalAnsi(doc) : IntPtr.Zero;
+
+ return WriteMethodDef(mdef, namePtr, func, flags, docPtr);
}
+ internal static IntPtr WriteMethodDefSentinel(IntPtr mdef)
+ {
+ return WriteMethodDef(mdef, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero);
+ }
internal static IntPtr CreateMetaType(Type impl) {
@@ -273,7 +322,27 @@ internal static IntPtr CreateMetaType(Type impl) {
flags |= TypeFlags.Managed;
flags |= TypeFlags.HeapType;
flags |= TypeFlags.HaveGC;
- Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+ Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags);
+
+ // We need space for 3 PyMethodDef structs, each of them
+ // 4 int-ptrs in size.
+ IntPtr mdef = Runtime.PyMem_Malloc(3 * (4 * IntPtr.Size));
+ IntPtr mdefStart = mdef;
+ mdef = WriteMethodDef(
+ mdef,
+ "__instancecheck__",
+ Interop.GetThunk(typeof(MetaType).GetMethod("__instancecheck__"), "BinaryFunc")
+ );
+
+ mdef = WriteMethodDef(
+ mdef,
+ "__subclasscheck__",
+ Interop.GetThunk(typeof(MetaType).GetMethod("__subclasscheck__"), "BinaryFunc")
+ );
+
+ mdef = WriteMethodDefSentinel(mdef);
+
+ Marshal.WriteIntPtr(type, TypeOffset.tp_methods, mdefStart);
Runtime.PyType_Ready(type);
@@ -338,12 +407,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 || PYTHON35)
+ // 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 || PYTHON35)
+ Marshal.WriteIntPtr(type, TypeOffset.qualname, temp);
+#endif
+
long ptr = type.ToInt64(); // 64-bit safe
temp = new IntPtr(ptr + TypeOffset.nb_add);
@@ -355,8 +436,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 || PYTHON35)
+ 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 +502,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/indexertest.cs b/src/testing/indexertest.cs
index fa4a8c8e2..7caba4e64 100644
--- a/src/testing/indexertest.cs
+++ b/src/testing/indexertest.cs
@@ -347,6 +347,23 @@ public MultiTypeIndexerTest() : base() {}
}
+ public class MultiDefaultKeyIndexerTest : IndexerBase {
+
+ public MultiDefaultKeyIndexerTest() : base() { }
+
+ public string this[int i1, int i2 = 2] {
+ get {
+ string key = i1.ToString() + i2.ToString();
+ return (string)t[key];
+ }
+ set {
+ string key = i1.ToString() + i2.ToString();
+ t[key] = value;
+ }
+ }
+
+ }
+
diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs
index 086aa58d5..28ef8f553 100644
--- a/src/testing/methodtest.cs
+++ b/src/testing/methodtest.cs
@@ -117,6 +117,14 @@ public static bool TestStringRefParams (string s, ref string s1) {
return true;
}
+ public static bool TestNonParamsArrayInLastPlace(int i1, int[] i2) {
+ return false;
+ }
+
+ public static bool TestNonParamsArrayInLastPlace(int i1, int i2, int i3) {
+ return true;
+ }
+
public static bool TestValueOutParams (string s, out int i1) {
i1 = 42;
return true;
@@ -155,6 +163,16 @@ public static void TestVoidSingleRefParam (ref int i) {
i = 42;
}
+ public static int TestSingleDefaultParam(int i = 5) {
+ return i;
+ }
+ public static int TestTwoDefaultParam(int i = 5, int j = 6) {
+ return i + j;
+ }
+ public static int TestOneArgAndTwoDefaultParam(int z, int i = 5, int j = 6) {
+ return i + j + z;
+ }
+
// overload selection test support
diff --git a/src/testing/subclasstest.cs b/src/testing/subclasstest.cs
new file mode 100644
index 000000000..7a68c6dca
--- /dev/null
+++ b/src/testing/subclasstest.cs
@@ -0,0 +1,106 @@
+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);
+
+ // test events on interfaces
+ event TestEventHandler TestEvent;
+
+ void OnTestEvent(int value);
+ }
+
+ public class SubClassTest : IInterfaceTest
+ {
+ public event TestEventHandler TestEvent;
+
+ 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();
+ }
+
+ // raise the test event
+ public virtual void OnTestEvent(int value)
+ {
+ if (null != TestEvent)
+ TestEvent(this, new TestEventArgs(value));
+ }
+ }
+
+ 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;
+ }
+
+ public static int test_event(IInterfaceTest x, int value)
+ {
+ // reuse the event handler from eventtest.cs
+ EventTest et = new EventTest();
+ x.TestEvent += et.GenericHandler;
+
+ // raise the event (should trigger both python and managed handlers)
+ x.OnTestEvent(value);
+
+ x.TestEvent -= et.GenericHandler;
+ return et.value;
+ }
+ }
+}
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..8435424da 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):
@@ -336,12 +348,20 @@ def testExceptionIsInstanceOfSystemObject(self):
# without causing a crash in the CPython interpreter). This test is
# here mainly to remind me to update the caveat in the documentation
# one day when when exceptions can be new-style classes.
+
+ # This behaviour is now over-shadowed by the implementation of
+ # __instancecheck__ (i.e., overloading isinstance), so for all Python
+ # version >= 2.6 we expect isinstance(, Object) to
+ # be true, even though it does not really subclass Object.
from System import OverflowException
from System import Object
o = OverflowException('error')
- self.assertFalse(isinstance(o, Object))
-
+
+ if sys.version_info >= (2, 6):
+ self.assertTrue(isinstance(o, Object))
+ else:
+ self.assertFalse(isinstance(o, Object))
def test_suite():
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..1d7c6ef67 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)
@@ -330,6 +341,45 @@ def testGenericMethodTypeHandling(self):
self._testGenericMethodByType(InterfaceTest, InterfaceTest(), 1)
self._testGenericMethodByType(ISayHello1, InterfaceTest(), 1)
+ def testCorrectOverloadSelection(self):
+ """
+ Test correct overloading selection for common types.
+ """
+ from System.Drawing import Font
+
+ from System import (String, Double, Single,
+ Int16, Int32, Int64)
+ from System import Math
+
+ substr = String("substring")
+ self.assertTrue(substr.Substring(2) == substr.Substring.__overloads__[Int32](
+ Int32(2)))
+ self.assertTrue(substr.Substring(2, 3) == substr.Substring.__overloads__[Int32,Int32](
+ Int32(2), Int32(3)))
+
+ for atype, value1, value2 in zip([Double, Single, Int16, Int32, Int64],
+ [1.0, 1.0, 1, 1, 1],
+ [2.0, 0.5, 2, 0, -1]):
+ self.assertTrue(Math.Abs(atype(value1)) == Math.Abs.__overloads__[atype](atype(value1)))
+ self.assertTrue(Math.Abs(value1) == Math.Abs.__overloads__[atype](atype(value1)))
+ self.assertTrue(
+ Math.Max(atype(value1),
+ atype(value2)) == Math.Max.__overloads__[atype, atype](
+ atype(value1),
+ atype(value2)))
+ if (atype is Int64) and six.PY2:
+ value2 = long(value2)
+ self.assertTrue(
+ Math.Max(atype(value1),
+ value2) == Math.Max.__overloads__[atype, atype](
+ atype(value1),
+ atype(value2)))
+
+ clr.AddReference("System.Runtime.InteropServices")
+ from System.Runtime.InteropServices import GCHandle, GCHandleType
+ from System import Array, Byte
+ CSArray = Array.CreateInstance(Byte, 1000)
+ handler = GCHandle.Alloc(CSArray, GCHandleType.Pinned)
def testGenericMethodOverloadSelection(self):
"""
@@ -439,9 +489,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 +514,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 +531,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 +632,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 +667,21 @@ def testOverloadSelectionWithArraysOfGenericTypes(self):
gtype = GenericWrapper[System.Int64]
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.Length == 2)
-
- gtype = GenericWrapper[long]
- 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[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 +692,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..691ebb871 100644
--- a/src/tests/test_indexer.py
+++ b/src/tests/test_indexer.py
@@ -8,7 +8,14 @@
# ===========================================================================
import sys, os, string, unittest, types
+import clr
+clr.AddReference("Python.Test")
import Python.Test as Test
+import six
+
+if six.PY3:
+ long = int
+ unichr = chr
class IndexerTests(unittest.TestCase):
@@ -238,8 +245,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 +299,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 +326,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 +438,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 +516,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:
@@ -625,6 +632,17 @@ def test():
object[0, 1, spam] = "wrong"
self.assertRaises(TypeError, test)
+
+
+ def testMultiDefaultKeyIndexer(self):
+ """Test indexers that take multiple indices with a default key arguments."""
+ #default argument is 2 in the MultiDefaultKeyIndexerTest object
+ object = Test.MultiDefaultKeyIndexerTest()
+ object[0, 2] = "zero one spam"
+ self.assertTrue(object[0] == "zero one spam")
+
+ object[1] = "one nine spam"
+ self.assertTrue(object[1, 2] == "one nine spam")
def testIndexerWrongKeyType(self):
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..ca5729a43 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))
@@ -298,6 +304,10 @@ def testValueParamsArgs(self):
self.assertTrue(result[1] == 2)
self.assertTrue(result[2] == 3)
+ def testNonParamsArrayInLastPlace(self):
+ """Test overload resolution with of non-"params" array as last parameter."""
+ result = MethodTest.TestNonParamsArrayInLastPlace(1, 2, 3)
+ self.assertTrue(result)
def testStringOutParams(self):
"""Test use of string out-parameters."""
@@ -441,6 +451,27 @@ def test():
# None cannot be converted to a value type
self.assertRaises(TypeError, test)
+
+ def testSingleDefaultParam(self):
+ """Test void method with single ref-parameter."""
+ result = MethodTest.TestSingleDefaultParam()
+ self.assertTrue(result == 5)
+
+ def testOneArgAndTwoDefaultParam(self):
+ """Test void method with single ref-parameter."""
+ result = MethodTest.TestOneArgAndTwoDefaultParam(11)
+ self.assertTrue(result == 22)
+
+ result = MethodTest.TestOneArgAndTwoDefaultParam(15)
+ self.assertTrue(result == 26)
+
+ result = MethodTest.TestOneArgAndTwoDefaultParam(20)
+ self.assertTrue(result == 31)
+
+ def testTwoDefaultParam(self):
+ """Test void method with single ref-parameter."""
+ result = MethodTest.TestTwoDefaultParam()
+ self.assertTrue(result == 11)
def testExplicitSelectionWithOutModifier(self):
@@ -501,8 +532,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 +548,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 +650,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 +680,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 +700,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..f116eb4de
--- /dev/null
+++ b/src/tests/test_subclass.py
@@ -0,0 +1,163 @@
+# ===========================================================================
+# 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, TestEventArgs
+from System.Collections.Generic import List
+from System import NotImplementedException
+
+# 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 that implements IInterfaceTest.TestEvent
+class DerivedEventTest(IInterfaceTest):
+ __namespace__ = "Python.Test"
+
+ def __init__(self):
+ self.event_handlers = []
+
+ # event handling
+ def add_TestEvent(self, handler):
+ self.event_handlers.append(handler)
+
+ def remove_TestEvent(self, handler):
+ self.event_handlers.remove(handler)
+
+ def OnTestEvent(self, value):
+ args = TestEventArgs(value)
+ for handler in self.event_handlers:
+ handler(self, args)
+
+
+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 testEvents(self):
+
+ class EventHandler:
+ def handler(self, x, args):
+ self.value = args.value
+
+ event_handler = EventHandler()
+
+ x = SubClassTest()
+ x.TestEvent += event_handler.handler
+ self.assertEqual(TestFunctions.test_event(x, 1), 1)
+ self.assertEqual(event_handler.value, 1)
+
+ i = InterfaceTestClass()
+ self.assertRaises(NotImplementedException, TestFunctions.test_event, i, 2)
+
+ d = DerivedEventTest()
+ d.add_TestEvent(event_handler.handler)
+ self.assertEqual(TestFunctions.test_event(d, 3), 3)
+ self.assertEqual(event_handler.value, 3)
+ self.assertEqual(len(d.event_handlers), 1)
+
+
+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()
diff --git a/tools/geninterop/fake_libc_include/_ansi.h b/tools/geninterop/fake_libc_include/_ansi.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/_ansi.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/_fake_defines.h b/tools/geninterop/fake_libc_include/_fake_defines.h
new file mode 100644
index 000000000..2479c665e
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/_fake_defines.h
@@ -0,0 +1,46 @@
+#ifndef _FAKE_DEFINES_H
+#define _FAKE_DEFINES_H
+
+#define NULL 0
+#define BUFSIZ 1024
+#define FOPEN_MAX 20
+#define FILENAME_MAX 1024
+
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* set file offset to offset */
+#endif
+#ifndef SEEK_CUR
+#define SEEK_CUR 1 /* set file offset to current plus offset */
+#endif
+#ifndef SEEK_END
+#define SEEK_END 2 /* set file offset to EOF plus offset */
+#endif
+
+#define __LITTLE_ENDIAN 1234
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+#define __BIG_ENDIAN 4321
+#define BIG_ENDIAN __BIG_ENDIAN
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#define BYTE_ORDER __BYTE_ORDER
+
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+#define UCHAR_MAX 255
+#define USHRT_MAX 65535
+#define UINT_MAX 4294967295U
+#define RAND_MAX 32767
+#define INT_MAX 32767
+
+/* C99 stdbool.h defines */
+#define __bool_true_false_are_defined 1
+#define false 0
+#define true 1
+
+/* va_arg macros and type*/
+typedef int va_list;
+#define va_start(_ap, _type) __builtin_va_start((_ap))
+#define va_arg(_ap, _type) __builtin_va_arg((_ap))
+#define va_end(_list)
+
+#endif
diff --git a/tools/geninterop/fake_libc_include/_fake_typedefs.h b/tools/geninterop/fake_libc_include/_fake_typedefs.h
new file mode 100644
index 000000000..14553219e
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/_fake_typedefs.h
@@ -0,0 +1,155 @@
+#ifndef _FAKE_TYPEDEFS_H
+#define _FAKE_TYPEDEFS_H
+
+typedef int size_t;
+typedef int __builtin_va_list;
+typedef int __gnuc_va_list;
+typedef int __int8_t;
+typedef int __uint8_t;
+typedef int __int16_t;
+typedef int __uint16_t;
+typedef int __int_least16_t;
+typedef int __uint_least16_t;
+typedef int __int32_t;
+typedef int __uint32_t;
+typedef int __int64_t;
+typedef int __uint64_t;
+typedef int __int_least32_t;
+typedef int __uint_least32_t;
+typedef int __s8;
+typedef int __u8;
+typedef int __s16;
+typedef int __u16;
+typedef int __s32;
+typedef int __u32;
+typedef int __s64;
+typedef int __u64;
+typedef int _LOCK_T;
+typedef int _LOCK_RECURSIVE_T;
+typedef int _off_t;
+typedef int __dev_t;
+typedef int __uid_t;
+typedef int __gid_t;
+typedef int _off64_t;
+typedef int _fpos_t;
+typedef int _ssize_t;
+typedef int wint_t;
+typedef int _mbstate_t;
+typedef int _flock_t;
+typedef int _iconv_t;
+typedef int __ULong;
+typedef int __FILE;
+typedef int ptrdiff_t;
+typedef int wchar_t;
+typedef int __off_t;
+typedef int __pid_t;
+typedef int __loff_t;
+typedef int u_char;
+typedef int u_short;
+typedef int u_int;
+typedef int u_long;
+typedef int ushort;
+typedef int uint;
+typedef int clock_t;
+typedef int time_t;
+typedef int daddr_t;
+typedef int caddr_t;
+typedef int ino_t;
+typedef int off_t;
+typedef int dev_t;
+typedef int uid_t;
+typedef int gid_t;
+typedef int pid_t;
+typedef int key_t;
+typedef int ssize_t;
+typedef int mode_t;
+typedef int nlink_t;
+typedef int fd_mask;
+typedef int _types_fd_set;
+typedef int clockid_t;
+typedef int timer_t;
+typedef int useconds_t;
+typedef int suseconds_t;
+typedef int FILE;
+typedef int fpos_t;
+typedef int cookie_read_function_t;
+typedef int cookie_write_function_t;
+typedef int cookie_seek_function_t;
+typedef int cookie_close_function_t;
+typedef int cookie_io_functions_t;
+typedef int div_t;
+typedef int ldiv_t;
+typedef int lldiv_t;
+typedef int sigset_t;
+typedef int __sigset_t;
+typedef int _sig_func_ptr;
+typedef int sig_atomic_t;
+typedef int __tzrule_type;
+typedef int __tzinfo_type;
+typedef int mbstate_t;
+typedef int sem_t;
+typedef int pthread_t;
+typedef int pthread_attr_t;
+typedef int pthread_mutex_t;
+typedef int pthread_mutexattr_t;
+typedef int pthread_cond_t;
+typedef int pthread_condattr_t;
+typedef int pthread_key_t;
+typedef int pthread_once_t;
+typedef int pthread_rwlock_t;
+typedef int pthread_rwlockattr_t;
+typedef int pthread_spinlock_t;
+typedef int pthread_barrier_t;
+typedef int pthread_barrierattr_t;
+typedef int jmp_buf;
+typedef int rlim_t;
+typedef int sa_family_t;
+typedef int sigjmp_buf;
+typedef int stack_t;
+typedef int siginfo_t;
+typedef int z_stream;
+
+/* C99 exact-width integer types */
+typedef int int8_t;
+typedef int uint8_t;
+typedef int int16_t;
+typedef int uint16_t;
+typedef int int32_t;
+typedef int uint32_t;
+typedef int int64_t;
+typedef int uint64_t;
+
+/* C99 minimum-width integer types */
+typedef int int_least8_t;
+typedef int uint_least8_t;
+typedef int int_least16_t;
+typedef int uint_least16_t;
+typedef int int_least32_t;
+typedef int uint_least32_t;
+typedef int int_least64_t;
+typedef int uint_least64_t;
+
+/* C99 fastest minimum-width integer types */
+typedef int int_fast8_t;
+typedef int uint_fast8_t;
+typedef int int_fast16_t;
+typedef int uint_fast16_t;
+typedef int int_fast32_t;
+typedef int uint_fast32_t;
+typedef int int_fast64_t;
+typedef int uint_fast64_t;
+
+/* C99 integer types capable of holding object pointers */
+typedef int intptr_t;
+typedef int uintptr_t;
+
+/* C99 greatest-width integer types */
+typedef int intmax_t;
+typedef int uintmax_t;
+
+/* C99 stdbool.h bool type. _Bool is built-in in C99 */
+typedef _Bool bool;
+
+typedef int va_list;
+
+#endif
diff --git a/tools/geninterop/fake_libc_include/_syslist.h b/tools/geninterop/fake_libc_include/_syslist.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/_syslist.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/alloca.h b/tools/geninterop/fake_libc_include/alloca.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/alloca.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/ar.h b/tools/geninterop/fake_libc_include/ar.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/ar.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/argz.h b/tools/geninterop/fake_libc_include/argz.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/argz.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/arpa/inet.h b/tools/geninterop/fake_libc_include/arpa/inet.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/arpa/inet.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/asm-generic/int-ll64.h b/tools/geninterop/fake_libc_include/asm-generic/int-ll64.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/asm-generic/int-ll64.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/assert.h b/tools/geninterop/fake_libc_include/assert.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/assert.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/complex.h b/tools/geninterop/fake_libc_include/complex.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/complex.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/ctype.h b/tools/geninterop/fake_libc_include/ctype.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/ctype.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/dirent.h b/tools/geninterop/fake_libc_include/dirent.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/dirent.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/dlfcn.h b/tools/geninterop/fake_libc_include/dlfcn.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/dlfcn.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/endian.h b/tools/geninterop/fake_libc_include/endian.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/endian.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/envz.h b/tools/geninterop/fake_libc_include/envz.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/envz.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/errno.h b/tools/geninterop/fake_libc_include/errno.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/errno.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/fastmath.h b/tools/geninterop/fake_libc_include/fastmath.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/fastmath.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/fcntl.h b/tools/geninterop/fake_libc_include/fcntl.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/fcntl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/features.h b/tools/geninterop/fake_libc_include/features.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/features.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/fenv.h b/tools/geninterop/fake_libc_include/fenv.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/fenv.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/float.h b/tools/geninterop/fake_libc_include/float.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/float.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/getopt.h b/tools/geninterop/fake_libc_include/getopt.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/getopt.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/grp.h b/tools/geninterop/fake_libc_include/grp.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/grp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/iconv.h b/tools/geninterop/fake_libc_include/iconv.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/iconv.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/ieeefp.h b/tools/geninterop/fake_libc_include/ieeefp.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/ieeefp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/inttypes.h b/tools/geninterop/fake_libc_include/inttypes.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/inttypes.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/io.h b/tools/geninterop/fake_libc_include/io.h
new file mode 100644
index 000000000..e69de29bb
diff --git a/tools/geninterop/fake_libc_include/iso646.h b/tools/geninterop/fake_libc_include/iso646.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/iso646.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/langinfo.h b/tools/geninterop/fake_libc_include/langinfo.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/langinfo.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/libgen.h b/tools/geninterop/fake_libc_include/libgen.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/libgen.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/libintl.h b/tools/geninterop/fake_libc_include/libintl.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/libintl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/limits.h b/tools/geninterop/fake_libc_include/limits.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/limits.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/linux/socket.h b/tools/geninterop/fake_libc_include/linux/socket.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/linux/socket.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/linux/version.h b/tools/geninterop/fake_libc_include/linux/version.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/linux/version.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/locale.h b/tools/geninterop/fake_libc_include/locale.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/locale.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/malloc.h b/tools/geninterop/fake_libc_include/malloc.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/malloc.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/math.h b/tools/geninterop/fake_libc_include/math.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/math.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/netdb.h b/tools/geninterop/fake_libc_include/netdb.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/netdb.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/netinet/in.h b/tools/geninterop/fake_libc_include/netinet/in.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/netinet/in.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/netinet/tcp.h b/tools/geninterop/fake_libc_include/netinet/tcp.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/netinet/tcp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/newlib.h b/tools/geninterop/fake_libc_include/newlib.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/newlib.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/openssl/err.h b/tools/geninterop/fake_libc_include/openssl/err.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/openssl/err.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/openssl/evp.h b/tools/geninterop/fake_libc_include/openssl/evp.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/openssl/evp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/openssl/hmac.h b/tools/geninterop/fake_libc_include/openssl/hmac.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/openssl/hmac.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/openssl/ssl.h b/tools/geninterop/fake_libc_include/openssl/ssl.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/openssl/ssl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/openssl/x509v3.h b/tools/geninterop/fake_libc_include/openssl/x509v3.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/openssl/x509v3.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/paths.h b/tools/geninterop/fake_libc_include/paths.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/paths.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/process.h b/tools/geninterop/fake_libc_include/process.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/process.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/pthread.h b/tools/geninterop/fake_libc_include/pthread.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/pthread.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/pwd.h b/tools/geninterop/fake_libc_include/pwd.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/pwd.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/reent.h b/tools/geninterop/fake_libc_include/reent.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/reent.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/regdef.h b/tools/geninterop/fake_libc_include/regdef.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/regdef.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/regex.h b/tools/geninterop/fake_libc_include/regex.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/regex.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sched.h b/tools/geninterop/fake_libc_include/sched.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sched.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/search.h b/tools/geninterop/fake_libc_include/search.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/search.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/semaphore.h b/tools/geninterop/fake_libc_include/semaphore.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/semaphore.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/setjmp.h b/tools/geninterop/fake_libc_include/setjmp.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/setjmp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/signal.h b/tools/geninterop/fake_libc_include/signal.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/signal.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/stdarg.h b/tools/geninterop/fake_libc_include/stdarg.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/stdarg.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/stdbool.h b/tools/geninterop/fake_libc_include/stdbool.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/stdbool.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/stddef.h b/tools/geninterop/fake_libc_include/stddef.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/stddef.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/stdint.h b/tools/geninterop/fake_libc_include/stdint.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/stdint.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/stdio.h b/tools/geninterop/fake_libc_include/stdio.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/stdio.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/stdlib.h b/tools/geninterop/fake_libc_include/stdlib.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/stdlib.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/string.h b/tools/geninterop/fake_libc_include/string.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/string.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/ioctl.h b/tools/geninterop/fake_libc_include/sys/ioctl.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/ioctl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/mman.h b/tools/geninterop/fake_libc_include/sys/mman.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/mman.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/poll.h b/tools/geninterop/fake_libc_include/sys/poll.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/poll.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/resource.h b/tools/geninterop/fake_libc_include/sys/resource.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/resource.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/select.h b/tools/geninterop/fake_libc_include/sys/select.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/select.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/socket.h b/tools/geninterop/fake_libc_include/sys/socket.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/socket.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/stat.h b/tools/geninterop/fake_libc_include/sys/stat.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/stat.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/sysctl.h b/tools/geninterop/fake_libc_include/sys/sysctl.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/sysctl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/time.h b/tools/geninterop/fake_libc_include/sys/time.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/time.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/types.h b/tools/geninterop/fake_libc_include/sys/types.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/types.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/uio.h b/tools/geninterop/fake_libc_include/sys/uio.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/uio.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/un.h b/tools/geninterop/fake_libc_include/sys/un.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/un.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/utsname.h b/tools/geninterop/fake_libc_include/sys/utsname.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/utsname.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/sys/wait.h b/tools/geninterop/fake_libc_include/sys/wait.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/sys/wait.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/syslog.h b/tools/geninterop/fake_libc_include/syslog.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/syslog.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/tar.h b/tools/geninterop/fake_libc_include/tar.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/tar.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/termios.h b/tools/geninterop/fake_libc_include/termios.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/termios.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/tgmath.h b/tools/geninterop/fake_libc_include/tgmath.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/tgmath.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/time.h b/tools/geninterop/fake_libc_include/time.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/time.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/unctrl.h b/tools/geninterop/fake_libc_include/unctrl.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/unctrl.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/unistd.h b/tools/geninterop/fake_libc_include/unistd.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/unistd.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/utime.h b/tools/geninterop/fake_libc_include/utime.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/utime.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/utmp.h b/tools/geninterop/fake_libc_include/utmp.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/utmp.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/wchar.h b/tools/geninterop/fake_libc_include/wchar.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/wchar.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/wctype.h b/tools/geninterop/fake_libc_include/wctype.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/wctype.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/fake_libc_include/zlib.h b/tools/geninterop/fake_libc_include/zlib.h
new file mode 100644
index 000000000..f952c1d67
--- /dev/null
+++ b/tools/geninterop/fake_libc_include/zlib.h
@@ -0,0 +1,2 @@
+#include "_fake_defines.h"
+#include "_fake_typedefs.h"
diff --git a/tools/geninterop/geninterop.py b/tools/geninterop/geninterop.py
new file mode 100644
index 000000000..2d4e15bc9
--- /dev/null
+++ b/tools/geninterop/geninterop.py
@@ -0,0 +1,292 @@
+"""
+TypeOffset is a C# class that mirrors the in-memory layout of heap
+allocated Python objects.
+
+This script parses the Python C headers and outputs the TypeOffset
+C# class.
+
+Requirements:
+ - pycparser
+ - clang
+"""
+from distutils.sysconfig import get_config_var
+from subprocess import Popen, CalledProcessError, PIPE
+from pycparser import c_parser, c_ast
+import logging
+import sys
+import os
+
+_log = logging.getLogger()
+logging.basicConfig(level=logging.DEBUG)
+
+
+# rename some members from their C name when generating the C#
+_typeoffset_member_renames = {
+ "ht_name": "name",
+ "ht_qualname": "qualname"
+}
+
+
+class AstParser(object):
+ """Walk an AST and determine the members of all structs"""
+
+ def __init__(self):
+ self.__typedefs = {}
+ self.__typedecls = {}
+ self.__structs = {}
+ self.__struct_stack = []
+ self.__struct_members_stack = []
+ self.__ptr_decl_depth = 0
+ self.__struct_members = {}
+
+ def get_struct_members(self, name):
+ """return a list of (name, type) of struct members"""
+ if name in self.__typedefs:
+ node = self.__get_leaf_node(self.__typedefs[name])
+ name = node.name
+ if name not in self.__struct_members:
+ raise Exception("Unknown struct '%s'" % name)
+ return self.__struct_members[name]
+
+ def visit(self, node):
+ if isinstance(node, c_ast.FileAST):
+ self.visit_ast(node)
+ elif isinstance(node, c_ast.Typedef):
+ self.visit_typedef(node)
+ elif isinstance(node, c_ast.TypeDecl):
+ self.visit_typedecl(node)
+ elif isinstance(node, c_ast.Struct):
+ self.visit_struct(node)
+ elif isinstance(node, c_ast.Decl):
+ self.visit_decl(node)
+ elif isinstance(node, c_ast.PtrDecl):
+ self.visit_ptrdecl(node)
+ elif isinstance(node, c_ast.IdentifierType):
+ self.visit_identifier(node)
+
+ def visit_ast(self, ast):
+ for name, node in ast.children():
+ self.visit(node)
+
+ def visit_typedef(self, typedef):
+ self.__typedefs[typedef.name] = typedef.type
+ self.visit(typedef.type)
+
+ def visit_typedecl(self, typedecl):
+ self.visit(typedecl.type)
+
+ def visit_struct(self, struct):
+ self.__structs[self.__get_struct_name(struct)] = struct
+ if struct.decls:
+ # recurse into the struct
+ self.__struct_stack.insert(0, struct)
+ for decl in struct.decls:
+ self.__struct_members_stack.insert(0, decl.name)
+ self.visit(decl)
+ self.__struct_members_stack.pop(0)
+ self.__struct_stack.pop(0)
+ elif self.__ptr_decl_depth:
+ # the struct is empty, but add it as a member to the current struct
+ # as the current member maybe a pointer to it.
+ self.__add_struct_member(struct.name)
+
+ def visit_decl(self, decl):
+ self.visit(decl.type)
+
+ def visit_ptrdecl(self, ptrdecl):
+ self.__ptr_decl_depth += 1
+ self.visit(ptrdecl.type)
+ self.__ptr_decl_depth -= 1
+
+ def visit_identifier(self, identifier):
+ type_name = " ".join(identifier.names)
+ self.__add_struct_member(type_name)
+
+ def __add_struct_member(self, type_name):
+ if not (self.__struct_stack and self.__struct_members_stack):
+ return
+
+ # add member to current struct
+ current_struct = self.__struct_stack[0]
+ member_name = self.__struct_members_stack[0]
+ struct_members = self.__struct_members.setdefault(self.__get_struct_name(current_struct), [])
+
+ # get the node associated with this type
+ node = None
+ if type_name in self.__typedefs:
+ node = self.__get_leaf_node(self.__typedefs[type_name])
+ elif type_name in self.__structs:
+ node = self.__structs[type_name]
+
+ # If it's a struct (and not a pointer to a struct) expand it into the current struct definition
+ if not self.__ptr_decl_depth and isinstance(node, c_ast.Struct):
+ for decl in node.decls or []:
+ self.__struct_members_stack.insert(0, decl.name)
+ self.visit(decl)
+ self.__struct_members_stack.pop(0)
+ else:
+ # otherwise add it as a single member
+ struct_members.append((member_name, type_name))
+
+
+ def __get_leaf_node(self, node):
+ if isinstance(node, c_ast.Typedef):
+ return self.__get_leaf_node(node.type)
+ if isinstance(node, c_ast.TypeDecl):
+ return self.__get_leaf_node(node.type)
+ return node
+
+ def __get_struct_name(self, node):
+ return node.name or "_struct_%d" % id(node)
+
+
+def check_output(*popenargs, **kwargs):
+ """subprocess.check_output from python 2.7.
+ Added here to support building for earlier versions
+ of Python.
+ """
+ process = Popen(stdout=PIPE, *popenargs, **kwargs)
+ output, unused_err = process.communicate()
+ retcode = process.poll()
+ if retcode:
+ cmd = kwargs.get("args")
+ if cmd is None:
+ cmd = popenargs[0]
+ raise CalledProcessError(retcode, cmd)
+ if sys.version_info[0] > 2:
+ return output.decode("ascii")
+ return output
+
+
+def preprocess_python_headers():
+ """Return Python.h pre-processed, ready for parsing.
+ Requires clang.
+ """
+ fake_libc_include = os.path.join(os.path.dirname(__file__), "fake_libc_include")
+ include_dirs = [fake_libc_include]
+
+ include_py = get_config_var("INCLUDEPY")
+ include_dirs.append(include_py)
+
+ defines = [
+ "-D", "__attribute__(x)=",
+ "-D", "__inline__=inline",
+ "-D", "__asm__=;#pragma asm",
+ "-D", "__int64=long long"
+ ]
+
+ if hasattr(sys, "abiflags"):
+ if "d" in sys.abiflags:
+ defines.extend(("-D", "PYTHON_WITH_PYDEBUG"))
+ if "m" in sys.abiflags:
+ defines.extend(("-D", "PYTHON_WITH_PYMALLOC"))
+ if "u" in sys.abiflags:
+ defines.extend(("-D", "PYTHON_WITH_WIDE_UNICODE"))
+
+ python_h = os.path.join(include_py, "Python.h")
+ cmd = ["clang", "-I"] + include_dirs + defines + ["-E", python_h]
+
+ # normalize as the parser doesn't like windows line endings.
+ lines = []
+ for line in check_output(cmd).splitlines():
+ if line.startswith("#"):
+ line = line.replace("\\", "/")
+ lines.append(line)
+ return "\n".join(lines)
+
+
+def gen_interop_code(members):
+ """Generate the TypeOffset C# class"""
+
+ defines = [
+ "PYTHON%d%s" % (sys.version_info[:2])
+ ]
+
+ 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")
+
+ class_definition = """
+// Auto-generated by %s.
+// DOT NOT MODIFIY BY HAND.
+// ==========================================================================
+// This software is subject to the provisions of the Zope Public License,
+// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
+// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+// FOR A PARTICULAR PURPOSE.
+// ==========================================================================
+#if (%s)
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime {
+
+ [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
+ internal class TypeOffset {
+
+ static TypeOffset() {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++) {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic() {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+""" % (os.path.basename(__file__), " && ".join(defines))
+
+ # All the members are sizeof(void*) so we don't need to do any
+ # extra work to determine the size based on the type.
+ for name, tpy in members:
+ name = _typeoffset_member_renames.get(name, name)
+ class_definition += " public static int %s = 0;\n" % name
+
+ class_definition += """
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+}
+#endif
+"""
+ return class_definition
+
+
+def main():
+ # preprocess Python.h and build the AST
+ python_h = preprocess_python_headers()
+ parser = c_parser.CParser()
+ ast = parser.parse(python_h)
+
+ # extract struct members from the AST
+ ast_parser = AstParser()
+ ast_parser.visit(ast)
+
+ # generate the C# code
+ members = ast_parser.get_struct_members("PyHeapTypeObject")
+ interop_cs = gen_interop_code(members)
+
+ if len(sys.argv) > 1:
+ with open(sys.argv[1], "wt") as fh:
+ fh.write(interop_cs)
+ else:
+ print(interop_cs)
+
+
+if __name__ == "__main__":
+ sys.exit(main())
+