diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8f598f0df --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*.suo +*.pdb +[Oo]bj/ +[Bb]in/ +*.dll +*.pyd +*.exe +*.pyc +packages/* +dist +pythonnet.egg-info +*.userprefs diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..6355ce73d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: python +python: + - 2.6 + - 2.7 +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 +install: + - python setup.py build_ext --inplace +script: + - export PYTHONPATH=`pwd` + - ./npython src/tests/runtests.py diff --git a/pythonnet/installer/license.txt b/LICENSE old mode 100755 new mode 100644 similarity index 100% rename from pythonnet/installer/license.txt rename to LICENSE diff --git a/Python.Runtime.dll.config b/Python.Runtime.dll.config new file mode 100644 index 000000000..11b4fb0fe --- /dev/null +++ b/Python.Runtime.dll.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 000000000..8b88ac0e9 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +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. + +[![Build Status](https://travis-ci.org/pythonnet/pythonnet.png?branch=develop)](https://travis-ci.org/pythonnet/pythonnet) + +[![Build status](https://ci.appveyor.com/api/projects/status/65riiu1hvgaxsbwb)](https://ci.appveyor.com/project/davidanthoff/pythonnet) diff --git a/VS_README.txt b/VS_README.txt new file mode 100644 index 000000000..d66cbc379 --- /dev/null +++ b/VS_README.txt @@ -0,0 +1,43 @@ +Visual Studio 2005 +================== + +pythonnet contains a new solution file for Visual Studio 2005: pythonnet.sln +It should make development under Windows much easier since you don't have to +install MSys or Cygwin to run the makefile. + +The solution file should work with the free VS .NET Express Edition. + +Available configurations +------------------------ + +Every configuration copies the dll, pdf and exe files to the root directory +of the project. + + * Release + Builds Python.Runtime, Python.Tests, clr.pyd and python.exe. The console + project starts a Python console + + * Debug + Same as Release but creates a build with debug symbols + + * UnitTest + Builds a Debug build. The console project invokes runtests.py instead of + opening a Python shell. + + * EmbeddingTest + Builds Python.EmbeddingTests and its dependencies. The configuration + requires the NUunit framework. + +Python version +-------------- + +You can switch the destination version by defining either PYTHON24 or PYTHON25 +inside the Python.Runtime project. + + ** Don't forget to force a rebuild after you have altered the setting! ** + +MS VS doesn't take changes to define into account. + +Thanks to Virgil Duprasfor his original VS howto! + +Christian 'Tiran' Heimes diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 000000000..18f9761c0 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,31 @@ +os: Windows Server 2012 + +environment: + global: + PYTHONPATH: c:\testdir + + 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 + +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 + +build_script: + - C:\python\python.exe setup.py bdist_wheel + +test_script: + - ps: C:\python\scripts\pip.exe install ("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 diff --git a/pythonnet/demo/helloform.py b/demo/helloform.py old mode 100755 new mode 100644 similarity index 72% rename from pythonnet/demo/helloform.py rename to demo/helloform.py index 568b52922..5d7a026f7 --- a/pythonnet/demo/helloform.py +++ b/demo/helloform.py @@ -1,16 +1,17 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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.System.Windows.Forms as WinForms -from CLR.System.Drawing import Size, Point +import clr +SWF = clr.AddReference("System.Windows.Forms") +print SWF.Location +import System.Windows.Forms as WinForms +from System.Drawing import Size, Point class HelloApp(WinForms.Form): @@ -26,8 +27,8 @@ def __init__(self): # Create the button self.button = WinForms.Button() - self.button.Location = Point(256, 64) - self.button.Size = Size(120, 40) + self.button.Location = Point(160, 64) + self.button.Size = Size(820, 20) self.button.TabIndex = 2 self.button.Text = "Click Me!" @@ -38,8 +39,8 @@ def __init__(self): self.textbox = WinForms.TextBox() self.textbox.Text = "Hello World" self.textbox.TabIndex = 1 - self.textbox.Size = Size(360, 20) - self.textbox.Location = Point(16, 24) + self.textbox.Size = Size(1260, 40) + self.textbox.Location = Point(160, 24) # Add the controls to the form self.AcceptButton = self.button @@ -48,6 +49,7 @@ def __init__(self): def button_Click(self, sender, args): """Button click event handler""" + print "Click" WinForms.MessageBox.Show("Please do not press this button again.") def run(self): @@ -55,7 +57,11 @@ def run(self): def main(): - HelloApp().run() + form = HelloApp() + print "form created" + app = WinForms.Application + print "app referenced" + app.Run(form) if __name__ == '__main__': diff --git a/pythonnet/demo/splitter.py b/demo/splitter.py old mode 100755 new mode 100644 similarity index 92% rename from pythonnet/demo/splitter.py rename to demo/splitter.py index 46adc9bec..f40b67137 --- a/pythonnet/demo/splitter.py +++ b/demo/splitter.py @@ -1,17 +1,15 @@ -# Copyright (c) 2003 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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.System.Windows.Forms as WinForms -from CLR.System.Drawing import Color, Size, Point -from CLR import System +import System.Windows.Forms as WinForms +from System.Drawing import Color, Size, Point +import System class Splitter(WinForms.Form): diff --git a/pythonnet/demo/wordpad.py b/demo/wordpad.py old mode 100755 new mode 100644 similarity index 97% rename from pythonnet/demo/wordpad.py rename to demo/wordpad.py index c2f1eb616..36286b811 --- a/pythonnet/demo/wordpad.py +++ b/demo/wordpad.py @@ -1,19 +1,17 @@ -# Copyright (c) 2003 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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.System.Windows.Forms as WinForms -from CLR.System.Drawing import Color, Size, Point -from CLR.System.Text import Encoding -from CLR.System.IO import File -from CLR import System +import System.Windows.Forms as WinForms +from System.Drawing import Color, Size, Point +from System.Text import Encoding +from System.IO import File +import System class Wordpad(WinForms.Form): diff --git a/doc/Python.Runtime.dll.config b/doc/Python.Runtime.dll.config new file mode 100644 index 000000000..3cfe2735a --- /dev/null +++ b/doc/Python.Runtime.dll.config @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/doc/TODO.txt b/doc/TODO.txt new file mode 100644 index 000000000..b13cf1024 --- /dev/null +++ b/doc/TODO.txt @@ -0,0 +1,34 @@ +TODO list +========= + +For PythonNet 2.0 +----------------- + + * Implement support for ModulePropertyAttribute. + + * Replace CLRModule.preload code with ModulePropertyAttribute specific code. + + * Deprecate implicit loading of assemblies + + * Debug failing unit tests under Mono and report them if they are caused + by incompatibilities in Mono. + +Future and nice-to-have features +-------------------------------- + + * Add support for Python's debug builds. Debug builds have additional fields + in the struct, extensive self testing and C assert() are enabled. Py_DEBUG + implies Py_TRACE_REFS and Py_REF_DEBUG which enlarge the PyObject and + PyVarObject based structs. The Py_INCREF and Py_DECREF macros have a larger + payload as well. They keep track of the absolute number of references and + do tests when an object is GCed. + I've taken care of most of the incompatibilities but the Py_DEBUG build + is still broken. Somehow tp_mro of wrapper_descriptor isn't a tuple. + + * Support Python 2.6. The most important feature I was able to isolate is the + PyType_FastSubclass macro and related TypeFlags in interops.cs. + + * Let's talk to the Debian and Ubuntu maintainers for Python in order to convince + them to build Python with --enable-shared. Ubuntu's Python is semi static and not + linked against libpython2.x.so. This causes trouble with clr.so. + diff --git a/pythonnet/doc/changes.txt b/doc/changes.txt old mode 100755 new mode 100644 similarity index 76% rename from pythonnet/doc/changes.txt rename to doc/changes.txt index dfb9a347e..7e577d96c --- a/pythonnet/doc/changes.txt +++ b/doc/changes.txt @@ -1,5 +1,108 @@ -PythonNet Changes ------------------ +Python for .NET Changes +----------------------- + + PythonNet 2.0 alpha 2 + --------------------------------------------------------------------------- + + - First work on Python 2.5 compatibility. The destination version can be + set by defining PYTHON24 or PYTHON25. Python 2.6 compatibility is in + work. [tiran] + + - Added VS 2005 solution and project files including a UnitTest + configuration which runs the unit test suite. [tiran] + + - Enhanced unit test suite. All test cases are combined in a single + test suite now. [tiran] + + - Fixed bugs in generics support for all Python versions. [tiran] + + - Fixed exception bugs for Python 2.5+. When compiled for Python 2.5+ all + managed exceptions are based on Python's exceptions.Exception class. + [tiran] + + - Added deprecation warnings for importing from CLR.* and the CLR module. + [tiran] + + - Implemented support for methods with variable arguments + spam(params object[] egg) [tiran] + + - Fixed Mono support by adding a custom marshaler for UCS-4 unicode, + fixing a some ref counter bugs and creating a new makefile.mono. + [tiran] + + - Added a standard python extension to load the clr environment. + The src/monoclr/ directory contains additional sample code like a + Python binary linked against libpython2.x.so and some example code + how to embed Mono and PythonNet in a C application. + [tiran] + + - Added yet another python prompt. This time it's a C application that + embedds both Python and Mono. It may be useful as an example app for + others and I need it to debug a nasty bug. [tiran] + + - Implemented ModuleFunctionAttribute and added ForbidPythonThreadsAttribute. + The latter is required for module functions which invoke Python methods. + [tiran] + + - Added clr.setPreload(), clr.getPreload(), clr.AddReference("assembly name"), + clr.FindAssembly("name") and clr.ListAssemblies(verbose). Automatic + preloading can be enabled with clr.setPreload/True). Preloading is + automatically enabled for interactive Python shells and disabled in all + other cases. [tiran] + + - New Makefile that works for Windows and Mono and autodetects the Python + version and UCS 2/4 setting. [tiran] + + - Added code for Python 2.3. PythonNet can be build for Python 2.3 again + but it is not fully supported. [tiran] + + - Changed the PythonException.Message value so it displays the name of + the exception class ("Exception") instead of its representation + (""). + + - Added Python.Runtime.dll.config + + + PythonNet 2.0 alpha 1 + --------------------------------------------------------------------------- + + - Moved the Python for .NET project to Sourceforge and moved version + control to Subversion. + + - Removed CallConvCdecl attributes and the IL hack that they supported. + .NET 2.x now supports UnmanagedFunctionPointer, which does the right + thing without the hackery required in 1.x. This removes a dependency + on ILASM to build the package and better supports Mono (in theory). + + - Refactored import and assembly management machinery. The old 'CLR.' + syntax for import is deprecated, but still supported until 3.x. The + recommended style now is to use 'from System import xxx', etc. We + also now support 'from X import *' correctly. + + - Implemented a (lowercase) 'clr' module to match IronPython for code + compatibility. Methods of this module should be used to explicitly + load assemblies. Implicit (name-based) assembly loading will still + work until 3.x, but it is deprecated. + + - Implemented support for generic types and generic methods using the + same patterns and syntax as IronPython. See the documentation for + usage details. + + - Many small and large performance improvements, switched to generic + collections for some internals, better algorithms for assembly + scanning, etc. + + - Fixed an unboxing issue in generated delegate implementation code + that affected delegates that return value types. + + + PythonNet 1.0 final + --------------------------------------------------------------------------- + + - Backported the refactored import and assembly management from the 2.x + line, mainly to improve the possibility of code-compatibility with + IronPython. + PythonNet 1.0 release candidate 2 --------------------------------------------------------------------------- diff --git a/doc/mono_config.txt b/doc/mono_config.txt new file mode 100644 index 000000000..2e62ad142 --- /dev/null +++ b/doc/mono_config.txt @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/htdocs/index.html b/htdocs/index.html index 607a71ba9..a1c362770 100755 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -1,9 +1,7 @@ - - -Python for .NET - - - - - - - - - - - - - -
- -

Python for .NET

-

- 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. Using this package - you can script .NET applications or build entire applications in Python, - using .NET services and components written in any language that targets the - CLR (Managed C++, C#, VB, JScript). -

- -

- Note that this package does not implement Python as a first-class - CLR language - it does not produce managed code (IL) from Python code. - Rather, it is an integration of the C Python engine with the .NET runtime. - This approach allows you to use use CLR services and continue to use existing - Python code and C-based extensions while maintaining native execution speeds - for Python code. If you are interested in a pure managed-code implementation - of the Python language, you should check out the - IronPython project, which is in - active development. -

- -

- Python for .NET is currently compatible with Python releases 2.3 and greater. - To subscribe to the - - Python for .NET mailing list - or read the - - online archives - of the list, see the - - mailing list information - page. You can also send questions or comments to me at - brian.lloyd@revolution.com - or use the - - Python for .NET issue tracker to report issues. -

- -

- My blog site is also - (sometimes) a good source for more information on Python for .NET ;) -

- - - - - - - - -
- - + + + + + + + + + +
+

Python for .NET

+

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. Using this package you can script .NET applications or + build entire applications in Python, using .NET services and + components written in any language that targets the CLR (Managed + C++, C#, VB, JScript).

+

Note that this package does not implement Python as a + first-class CLR language - it does not produce managed code (IL) + from Python code. Rather, it is an integration of the C Python + engine with the .NET runtime. This approach allows you to use use + CLR services and continue to use existing Python code and C-based + extensions while maintaining native execution speeds for Python + code. If you are interested in a pure managed-code implementation + of the Python language, you should check out the IronPython + project, which is in active development.

+

Python for .NET is currently compatible with Python releases 2.5 + and greater. To subscribe to the + Python for .NET mailing list or read the + online archives of the list, see the + mailing list information page. You can also send questions + or comments to me at brian.lloyd@revolution.com + or use the + Python for .NET issue tracker to report issues.

+

My blog site is + also (sometimes) a good source for more information on Python for + .NET ;)

+
    +
  • The README provides a detailed + overview of Python for .NET, as well as some basic usage + examples. Many other examples can be found in the demos and unit + tests for the package.
  • +
  • Checkout the PythonNet + code from Subversion..
  • +
  • + Download releases for various versions of Python and CLR. +
  • +
+
+ diff --git a/htdocs/readme.html b/htdocs/readme.html index e5cb09cf5..d7ae26f04 100755 --- a/htdocs/readme.html +++ b/htdocs/readme.html @@ -1,9 +1,7 @@ - - -Python for .NET - - - - - - - - - - - - + + +
- - - -

- 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. Using this package - you can script .NET applications or build entire applications in Python, - using .NET services and components written in any language that targets the - CLR (Managed C++, C#, VB, JScript). -

- -

- Note that this package does not implement Python as a first-class - CLR language - it does not produce managed code (IL) from Python code. - Rather, it is an integration of the C Python engine with the .NET runtime. - This approach allows you to use use CLR services and continue to use existing - Python code and C-based extensions while maintaining native execution speeds - for Python code. If you are interested in a pure managed-code implementation - of the Python language, you should check out the - IronPython project, which is in - active development. -

- -

- Python for .NET is currently compatible with Python releases 2.3 and greater. - Current releases are available at the - - Python for .NET website - . To subscribe to the - - Python for .NET mailing list - or read the - - online archives - of the list, see the - - mailing list information - page. -

- - - -

Installation

- -

- Python for .NET is available as a source release and as a Windows installer - for various versions of Python and the common language runtime from the - - Python for .NET website - . On Windows platforms, you can choose to install .NET-awareness into - an existing Python installation as well as install Python for .NET as a - standalone package. -

- -

- The source release is a self-contained "private" assembly. - Just unzip the package wherever you want it, cd to that directory and run - python.exe to start using it. Note that the source release does not - include a copy of the CPython runtime, so you will need to have installed - Python on your machine before using the source release. -

- -

- Running on Linux/Mono: preliminary testing shows that - PythonNet will run under Mono, though - the Mono runtime is not yet complete so there still may be problems. The - Python for .NET integration layer is 100% managed code, so there should be - no long-term issues under Mono - it should work better and better as the - Mono platform matures. -

- -

- It is not currently possible to *build* PythonNet using only the Mono - tools, due to an issue involving the Mono assembler / disassembler. You - should, however, be able to try the pre-built assembly under Mono (or - compile it yourself with the MS tools and run it under Mono). -

- -

- Note that if you are running under Mono on a *nix system, you will need - to have a compatible version of Python installed. You will also need - to create a symbolic link to the copy of libpython2.x.so (in your existing - Python installation) in the PythonNet directory. This is needed to ensure - that the mono interop dll loader will find it by name. For example: -

- -
-    ln -s /usr/lib/libpython2.4.so ./python24.so
+    
+  
+  
+    
+      
+        
+          
+          
-
-
+

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. Using this package you can script .NET applications or + build entire applications in Python, using .NET services and + components written in any language that targets the CLR (Managed + C++, C#, VB, JScript). +

+

Note that this package does not implement Python as a + first-class CLR language - it does not produce managed code (IL) + from Python code. Rather, it is an integration of the C Python + engine with the .NET runtime. This approach allows you to use use + CLR services and continue to use existing Python code and C-based + extensions while maintaining native execution speeds for Python + code. If you are interested in a pure managed-code implementation + of the Python language, you should check out the IronPython + project, which is in active development. +

+

Python for .NET is currently compatible with Python releases 2.3 + and greater. Current releases are available at the + Python for .NET website . To subscribe to the + Python for .NET mailing list or read the + online archives of the list, see the + mailing list information page.

+ +

Installation

+

Python for .NET is available as a source release and as a + Windows installer for various versions of Python and the common + language runtime from the + Python for .NET website . On Windows platforms, you can + choose to install .NET-awareness into an existing Python + installation as well as install Python for .NET as a standalone + package. +

+ +

The source release is a self-contained "private" assembly. Just + unzip the package wherever you want it, cd to that directory and + run python.exe to start using it. Note that the source release + does not include a copy of the CPython runtime, so you will need + to have installed Python on your machine before using the source + release. +

+

Running on Linux/Mono: preliminary testing + shows that PythonNet will run under Mono, + though the Mono runtime is not yet complete so there still may be + problems. The Python for .NET integration layer is 100% managed + code, so there should be no long-term issues under Mono - it + should work better and better as the Mono platform matures. +

+

Note that if you are running under Mono on a *nix system, you + will need to have a compatible version of Python installed. You + will also need to create a symbolic link to the copy of + libpython2.x.so (in your existing Python installation) in the + PythonNet directory. This is needed to ensure that the mono + interop dll loader will find it by name. For example: +

+
    ln -s /usr/lib/libpython2.4.so ./python24.so
 
- - - - -

Getting Started

- -

- A key goal for this project has been that Python for .NET should "work - just the way you'd expect in Python", except for cases that are .NET - specific (in which case the goal is to work "just the way you'd expect - in C#"). -

- -

- If you already know Python, you can probably finish this readme and then - refer to .NET docs to figure out anything you need to do. Conversely if - you are familiar with C# or another .NET language, you probably just - need to pick up one of the many good Python books or read the Python - tutorial online to get started. -

- -

- A good way to start is to run python.exe and follow along - with the examples in this document. If you get stuck, there are also a - number of demos and unit tests located in the source directory of the - distribution that can be helpful as examples. -

- - - - -

Importing Modules

- -

- Python for .NET allows CLR namespaces to be treated essentially as - Python packages. The top-level package is named CLR, and - acts as the root for accessing all CLR namespaces: -

- -
-    from CLR.System import String
-    import CLR.System as System
-
- -

- Types from any loaded assembly may be imported and used in this manner. - The import hook uses "implicit loading" to support automatic loading - of assemblies whose names correspond to an imported namespace: -

- -
-    # This will implicitly load the System.Windows.Forms assembly
-
-    from CLR.System.Windows.Forms import Form
+            
+            

Getting Started

+

A key goal for this project has been that Python for .NET should + "work just the way you'd expect in Python", except for cases that + are .NET specific (in which case the goal is to work "just the way + you'd expect in C#"). In addition, with the IronPython project + gaining traction, it is my goal that code written for IronPython + run without modification under Python for .NET. +

+

If you already know Python, you can probably finish this readme + and then refer to .NET docs to figure out anything you need to do. + Conversely if you are familiar with C# or another .NET language, + you probably just need to pick up one of the many good Python + books or read the Python tutorial online to get started. +

+

A good way to start is to run python.exe and + follow along with the examples in this document. If you get stuck, + there are also a number of demos and unit tests located in the + source directory of the distribution that can be helpful as + examples. +

+

Note that if you have installed CLR support into your existing + Python installation (rather than using the included python.exe), + you will need to use the line: "'import clr" (lower-case!) to + initially load the clr extension module before trying the + following examples. +

+ +

Importing Modules

+

Python for .NET allows CLR namespaces to be treated essentially + as Python packages.

+

+

+
    from System import String
+    from System.Collections import *
 
+

+ Note that earlier releases of Python for .NET required you to + import modules through a special top-level package named CLR. + This is no longer required if you are starting python from the + managed python.exe from this distribution.
+ CLR has been deprecated in favor of the more + pythonic clr, though the syntax is still supported + for backward compatibility. +
+

+

Types from any loaded assembly may be imported and used in this + manner. To load an assembly, use the "AddReference" function in + the "clr" module: +

+
+    import clr
+    clr.AddReference("System.Windows.Forms")
+    from System.Windows.Forms import Form
 
-

- Python for .NET uses the PYTHONPATH (sys.path) to look for assemblies - to load, in addition to the usual application base and the GAC. To - ensure that you can implicitly import an assembly, put the directory - containing the assembly in sys.path. -

- -

- To load assemblies with names that do not correspond with a namespace, - you can use the standard mechanisms provided by the CLR: -

- -
-    from CLR.System.Reflection import Assembly
-
-    a = Assembly.LoadWithPartialName("SomeAssembly")
-
-    # now we can import namespaces defined in that assembly
-
-    from CLR.SomeNamespace import Something
 
- -

- Note that CLR modules are "lazy". Because a namespace can contain a - potentially very large number of classes, reflected CLR classes are - created on-demand when they are requested of a CLR module. This means - that using the Python dir() function in the interactive - interpreter will not necessarily show all of the classes available from - a given CLR module (it will only show any classes that have been referenced - to that point in time). -

- -

- It also means that from somemodule import * will not work as - expected. It is possible that it could be made to work in the future, - but for now it would impose a big performance hit and a lot of - complexity to support something that is used relatively rarely and - often considered bad form in Python anyway ;) -

- - - - -

Using Classes

- -

- Python for .NET allows you to use any non-private classes, structs, - interfaces, enums or delegates from Python. To create an instance of - a managed class, you use the standard instantiation syntax, passing - a set of arguments that match one of its public constructors: -

- -
-    from CLR.System.Drawing import Point
+            

+ Note that earlier releases of Python for .NET relied on + "implicit loading" to support automatic loading of assemblies + whose names corresponded to an imported namespace. Implicit + loading still works for backward compatibility, but will be + removed in a future release so it is recommended to use the + clr.AddReference method. + +

+

Python for .NET uses the PYTHONPATH (sys.path) to look for + assemblies to load, in addition to the usual application base and + the GAC. To ensure that you can implicitly import an assembly, put + the directory containing the assembly in sys.path. +

+ +

Using Classes

+

Python for .NET allows you to use any non-private classes, + structs, interfaces, enums or delegates from Python. To create an + instance of a managed class, you use the standard instantiation + syntax, passing a set of arguments that match one of its public + constructors: +

+
    from System.Drawing import Point
 
     p = Point(5, 5)
 
- -

- You can also subclass managed classes in Python. See the - helloform.py file in the /demo directory of the - distribution for a simple Windows Forms example that demonstrates - subclassing a managed class. -

- - - - -

Fields And Properties

- -

- You can get and set fields and properties of CLR objects just as if - they were regular attributes: -

- -
-    from CLR.System import Environment
+            

In most cases, Python for .NET can determine the correct + constructor to call automatically based on the arguments. In some + cases, it may be necessary to call a particular overloaded + constructor, which is supported by a special "__overloads__" + attribute, which will soon be deprecated in favor of iPy + compatible "Overloads", on a class: +

+
    from System import String, Char, Int32
+
+    s = String.Overloads[Char, Int32]('A', 10)
+    s = String.__overloads__[Char, Int32]('A', 10)
+
+ +

Using Generics

+

When running under versions of the .NET runtime greater than + 2.0, you can use generic types. A generic type must be bound to + create a concrete type before it can be instantiated. Generic + types support the subscript syntax to create bound types: +

+
    from System.Collections.Generic import Dictionary
+    from System import *
+
+    dict1 = Dictionary[String, String]()
+    dict2 = Dictionary[String, Int32]()
+    dict3 = Dictionary[String, Type]()
+
+

When you pass a list of types using the subscript syntax, you + can also pass a subset of Python types that directly correspond to + .NET types: +

+
    dict1 = Dictionary[str, str]()
+    dict2 = Dictionary[str, int]()
+    dict3 = Dictionary[str, Decimal]()
+
+

This shorthand also works when explicitly selecting generic + methods or specific versions of overloaded methods and + constructors (explained later). +

+

You can also subclass managed classes in Python, though members + of the Python subclass are not visible to .NET code. See the helloform.py + file in the /demo directory of the distribution for + a simple Windows Forms example that demonstrates subclassing a + managed class. +

+ +

Fields And Properties

+

You can get and set fields and properties of CLR objects just as + if they were regular attributes: +

+
    from System import Environment
 
     name = Environment.MachineName
     Environment.ExitCode = 1
 
- - - - -

Using Indexers

- -

- If a managed object implements one or more indexers, you can call - the indexer using standard Python indexing syntax: -

- -
-    from CLR.System.Collections import Hashtable
+            
+            

Using Indexers

+

If a managed object implements one or more indexers, you can + call the indexer using standard Python indexing syntax: +

+
    from System.Collections import Hashtable
 
     table = Hashtable()
     table["key 1"] = "value 1"
 
- -

- Overloaded indexers are supported, using the same notation one - would use in C#: -

- -
-    items[0, 2]
+            

Overloaded indexers are supported, using the same notation one + would use in C#: +

+
    items[0, 2]
 
     items[0, 2, 3]
 
- - - - -

Using Methods

- -

- Methods of CLR objects behave generally like normal Python methods. - Static methods may be called either through the class or through an - instance of the class. All public and protected methods of CLR objects - are accessible to Python: -

- -
-    from CLR.System import Environment
+            
+            

Using Methods

+

Methods of CLR objects behave generally like normal Python + methods. Static methods may be called either through the class or + through an instance of the class. All public and protected methods + of CLR objects are accessible to Python: +

+
    from System import Environment
 
     drives = Environment.GetLogicalDrives()
 
- -

- It is also possible to call managed methods unbound (passing the - instance as the first argument) just as with Python methods. This is - most often used to explicitly call methods of a base class. -

- -

- Note that there is one caveat related to calling unbound methods: it - is possible for a managed class to declare a static method and an - instance method with the same name. Since it is not possible for the - runtime to know the intent when such a method is called unbound, the - static method will always be called. -

- -

- The docstring of CLR a method (__doc__) can be used to view the - signature of the method, including overloads if the CLR method is - overloaded. You can also use the Python help method to inspect - a managed class: -

- -
-    from CLR.System import Environment
+            

It is also possible to call managed methods unbound + (passing the instance as the first argument) just as with Python + methods. This is most often used to explicitly call methods of a + base class. +

+

Note that there is one caveat related to calling unbound + methods: it is possible for a managed class to declare a static + method and an instance method with the same name. Since it is + not possible for the runtime to know the intent when such a + method is called unbound, the static method will always be + called. +

+

The docstring of CLR a method (__doc__) can be used to view the + signature of the method, including overloads if the CLR method is + overloaded. You can also use the Python help method + to inspect a managed class: +

+
    from System import Environment
 
     print Environment.GetFolderPath.__doc__
 
     help(Environment)
 
- - - - -

Delegates And Events

- -

- Delegates defined in managed code can be implemented in Python. A - delegate type can be instantiated and passed a callable Python object - to get a delegate instance. The resulting delegate instance is a true - managed delegate that will invoke the given Python callable when it - is called: -

- -
-    def my_handler(source, args):
+            
+            

Overloaded and Generic Methods

+

While Python for .NET will generally be able to figure out the + right version of an overloaded method to call automatically, there + are cases where it is desirable to select a particular method + overload explicitly. +

+

Methods of CLR objects have an "__overloads__", which will soon + be deprecated in favor of iPy compatible Overloads, attribute that + can be used for this purpose : +

+
    from System import Console
+
+    Console.WriteLine.Overloads[bool](true)
+    Console.WriteLine.Overloads[str]("true")
+    Console.WriteLine.__overloads__[int](42)
+
+

Similarly, generic methods may be bound at runtime using the + subscript syntax directly on the method: +

+
    someobject.SomeGenericMethod[int](10)
+    someobject.SomeGenericMethod[str]("10")
+
+ +

Delegates And Events

+

Delegates defined in managed code can be implemented in Python. + A delegate type can be instantiated and passed a callable Python + object to get a delegate instance. The resulting delegate instance + is a true managed delegate that will invoke the given Python + callable when it is called: +

+
    def my_handler(source, args):
         print 'my_handler called!'
 
     # instantiate a delegate
@@ -454,35 +407,24 @@ 

Delegates And Events

# use it as an event handler AppDomain.CurrentDomain.AssemblyLoad += d
- - -

- Multicast delegates can be implemented by adding more callable objects - to a delegate instance: -

- -
-    d += self.method1
+            

Multicast delegates can be implemented by adding more callable + objects to a delegate instance: +

+
    d += self.method1
     d += self.method2
     d()
 
- -

- Events are treated as first-class objects in Python, and behave in - many ways like methods. Python callbacks can be registered with event - attributes, and an event can be called to fire the event. -

- -

- Note that events support a convenience spelling similar to that used - in C#. You do not need to pass an explicitly instantiated delegate - instance to an event (though you can if you want). Events support the - += and -= operators in a way very similar to - the C# idiom: -

- -
-    def handler(source, args):
+            

Events are treated as first-class objects in Python, and behave + in many ways like methods. Python callbacks can be registered with + event attributes, and an event can be called to fire the event. +

+

Note that events support a convenience spelling similar to that + used in C#. You do not need to pass an explicitly instantiated + delegate instance to an event (though you can if you want). Events + support the += and -= operators in a + way very similar to the C# idiom: +

+
    def handler(source, args):
         print 'my_handler called!'
 
     # register event handler
@@ -494,17 +436,12 @@ 

Delegates And Events

# fire the event result = object.SomeEvent(...)
- - - - -

Exception Handling

- -

- You can raise and catch managed exceptions just the same as you would - pure-Python exceptions: -

-    from CLR.System import NullReferenceException
+            
+            

Exception Handling

+

You can raise and catch managed exceptions just the same as you + would pure-Python exceptions: +

+
    from System import NullReferenceException
 
     try:
         raise NullReferenceException("aiieee!")
@@ -512,19 +449,20 @@ 

Exception Handling

print e.Message print e.Source
-

- - - - -

Using Arrays

- -

- Managed arrays support the standard Python sequence protocols: -

- -
-    items = SomeObject.GetArray()
+            

+ +

Using Arrays

+

The type System.Array supports the subscript + syntax in order to make it easy to create managed arrays from + Python: +

+
    from System import Array
+
+    myarray = Array[int](10)
+
+

Managed arrays support the standard Python sequence protocols: +

+
    items = SomeObject.GetArray()
 
     # Get first item
     v = items[0]
@@ -540,136 +478,99 @@ 

Using Arrays

# Containment test test = v in items
- -

- Multidimensional arrays support indexing using the same notation one - would use in C#: -

- -
-    items[0, 2]
+            

Multidimensional arrays support indexing using the same notation + one would use in C#: +

+
    items[0, 2]
 
     items[0, 2, 3]
 
- - - - -

Using Collections

- -

- Managed arrays and managed objects that implement the IEnumerable - interface can be iterated over using the standard iteration Python -idioms: -

- -
-    domain = System.AppDomain.CurrentDomain
+            
+            

Using Collections

+

Managed arrays and managed objects that implement the + IEnumerable interface can be iterated over using the standard + iteration Python idioms: +

+
    domain = System.AppDomain.CurrentDomain
 
     for item in domain.GetAssemblies():
         name = item.GetName()
 
- - - - -

Using COM Components

- -

- Using Microsoft-provided tools such as aximp.exe and - tlbimp.exe, it is possible to generate managed wrappers - for COM libraries. After generating such a wrapper, you can use the - libraries from Python just like any other managed code. -

-

- Note: currently you need to put the generated wrappers in the GAC, - in the PythonNet assembly directory or on the PYTHONPATH in order - to load them. -

- - - -

Type Conversion

- -

- Type conversion under Python for .NET is fairly straightforward - most - elemental Python types (string, int, long, etc.) convert automatically - to compatible managed equivalents (String, Int32, etc.) and vice-versa. - Note that all strings returned from the CLR are returned as unicode. -

- -

- Types that do not have a logical equivalent in Python are exposed as - instances of managed classes or structs (System.Decimal is an example). -

-

- The .NET architecture makes a distinction between value types - and reference types. Reference types are allocated on the heap, - and value types are allocated either on the stack or in-line within an - object. -

- -

- A process called boxing is used in .NET to allow code to treat - a value type as if it were a reference type. Boxing causes a separate - copy of the value type object to be created on the heap, which then - has reference type semantics. -

- -

- Understanding boxing and the distinction between value types and - reference types can be important when using Python for .NET because - the Python language has no value type semantics or syntax - in - Python "everything is a reference". -

- -

- Here is a simple example that demonstrates an issue. If you are an - experienced C# programmer, you might write the following code: -

- -
-    items = CLR.System.Array.CreateInstance(Point, 3)
+            
+            

Using COM Components

+

Using Microsoft-provided tools such as aximp.exe + and tlbimp.exe, it is possible to generate + managed wrappers for COM libraries. After generating such a + wrapper, you can use the libraries from Python just like any other + managed code. +

+

Note: currently you need to put the generated wrappers in the + GAC, in the PythonNet assembly directory or on the PYTHONPATH in + order to load them. +

+ +

Type Conversion

+

Type conversion under Python for .NET is fairly straightforward + - most elemental Python types (string, int, long, etc.) convert + automatically to compatible managed equivalents (String, Int32, + etc.) and vice-versa. Note that all strings returned from the CLR + are returned as unicode. +

+

Types that do not have a logical equivalent in Python are + exposed as instances of managed classes or structs (System.Decimal + is an example). +

+

The .NET architecture makes a distinction between value + types and reference types. Reference types + are allocated on the heap, and value types are allocated either on + the stack or in-line within an object. +

+

A process called boxing is used in .NET to allow + code to treat a value type as if it were a reference type. Boxing + causes a separate copy of the value type object to be created on + the heap, which then has reference type semantics. +

+

Understanding boxing and the distinction between value types and + reference types can be important when using Python for .NET + because the Python language has no value type semantics or syntax + - in Python "everything is a reference". +

+

Here is a simple example that demonstrates an issue. If you are + an experienced C# programmer, you might write the following code: +

+
    items = System.Array.CreateInstance(Point, 3)
     for i in range(3):
         items[i] = Point(0, 0)
 
     items[0].X = 1 # won't work!!
 
- -

- While the spelling of items[0].X = 1 is the same in C# and - Python, there is an important and subtle semantic difference. In C# (and other - compiled-to-IL languages), the compiler knows that Point is a value - type and can do the Right Thing here, changing the value in place. -

- -

- In Python however, "everything's a reference", and there is really no - spelling or semantic to allow it to do the right thing dynamically. The - specific reason that items[0] itself doesn't change is that - when you say items[0], that getitem operation creates a Python - object that holds a reference to the object at items[0] via a - GCHandle. That causes a ValueType (like Point) to be boxed, so the following - setattr (.X = 1) changes the state of the boxed value, not - the original unboxed value. -

- -

- The rule in Python is essentially: "the result of any attribute or - item access is a boxed value", and that can be important in how you - approach your code. -

- -

- Because there are no value type semantics or syntax in Python, you - may need to modify your approach. To revisit the previous example, - we can ensure that the changes we want to make to an array item - aren't "lost" by resetting an array member after making changes - to it: -

- -
-    items = CLR.System.Array.CreateInstance(Point, 3)
+            

While the spelling of items[0].X = 1 is the same + in C# and Python, there is an important and subtle semantic + difference. In C# (and other compiled-to-IL languages), the + compiler knows that Point is a value type and can do the Right + Thing here, changing the value in place. +

+

In Python however, "everything's a reference", and there is + really no spelling or semantic to allow it to do the right thing + dynamically. The specific reason that items[0] + itself doesn't change is that when you say items[0], + that getitem operation creates a Python object that holds a + reference to the object at items[0] via a GCHandle. + That causes a ValueType (like Point) to be boxed, so the following + setattr (.X = 1) changes the state of the boxed + value, not the original unboxed value. +

+

The rule in Python is essentially: "the result of any attribute + or item access is a boxed value", and that can be important in how + you approach your code. +

+

Because there are no value type semantics or syntax in Python, + you may need to modify your approach. To revisit the previous + example, we can ensure that the changes we want to make to an + array item aren't "lost" by resetting an array member after making + changes to it: +

+
    items = System.Array.CreateInstance(Point, 3)
     for i in range(3):
         items[i] = Point(0, 0)
 
@@ -681,190 +582,91 @@ 

Type Conversion

item.X = 1 items[0] = item
- -

- This is not unlike some of the cases you can find in C# where you have - to know about boxing behavior to avoid similar kinds of lost - update problems (generally because an implicit boxing happened that - was not taken into account in the code). -

- -

- This is the same thing, just the manifestation is a little different - in Python. See the .NET documentation for more details on boxing and - the differences between value types and reference types. -

- - - - -

Using Assemblies

- -

- The Python for .NET runtime uses Assembly.LoadWithPartialName to do - name-based imports, which will usually load the most recent version of - an assembly that it can find. -

- -

- The CLR's ability to load different versions of assemblies side-by-side - is one of the (relatively few) places where the matching of meta-models - between Python and the CLR breaks down (though it is unclear how often - this happens in practice). -

- -

- Because Python import is name-based and unaware of any concept of - versioned modules, the design goal has been for name-based implicit assembly - loading to do something consistent and reasonable (i.e. load most - recent available based on the name). -

- -

- It is possible to load a specific version of an assembly if you - need to using code similar to the following: -

- -
-    from CLR.System.Reflection import Assembly, AssemblyName
-
-    name = AssemblyName(...) # set required version, etc.
-    assembly = Assembly.Load(name)
-
-    # now import namespaces from the loaded assembly
-
- -

- Things get a lot more complicated if you need to load more than one - version of a particular assembly (or more likely, you have a dependency - on some library the does so). In this case, the names you access via - the CLR modules will always come from the first version of the - assembly loaded (which will always win in the internals of the Python - for .NET runtime). -

- -

- You can still use particular versions of objects in this case - you - just have to do more work to get the right versions of objects: -

- -
-    from CLR.System.Reflection import Assembly, AssemblyName
-    from System import Activator
-
-    name = AssemblyName(...) # get the right version
-    assembly = Assembly.Load(name)
-    type = assembly.GetType("QualifiedNameOf.TheTypeINeed")
-    obj = Activator.CreateInstance(type)
-
-

- - - - -

Embedding Python

- -

- Note: because Python code running under Python for .NET - is inherently unverifiable, it runs totally under the radar of the security - infrastructure of the CLR so you should restrict use of the Python assembly - to trusted code. -

- -

- The Python runtime assembly defines a number of public classes that - provide a subset of the functionality provided by the Python C API. -

- -

- These classes include PyObject, PyList, PyDict, etc. The source and - the unit tests are currently the only API documentation.. The rhythym - is very similar to using Python C++ wrapper solutions such as CXX. -

- -

- At a very high level, to embed Python in your application you - will need to: -

- -
    -
  • Reference Python.Runtime.dll in your build environment
  • -
  • Call PythonEngine.Intialize() to initialize Python
  • -
  • Call PythonEngine.ImportModule(name) to import a module
  • -
- - -

- The module you import can either start working with your managed app - environment at the time its imported, or you can explicitly lookup and - call objects in a module you import. -

- -

- For general-purpose information on embedding Python in applications, use - www.python.org or Google to find (C) examples. Because Python for .NET is - so closely integrated with the managed environment, you will generally be - better off importing a module and deferring to Python code as early as - possible rather than writing a lot of managed embedding code. -

- -

- Important Note for embedders: Python is not free-threaded - and uses a global interpreter lock to allow multi-threaded applications to - interact safely with the Python interpreter. Much more information about - this is available in the Python C API documentation on the www.python.org - Website. -

- -

- When embedding Python in a managed application, you have to manage the GIL - in just the same way you would when embedding Python in a C or C++ - application. -

- -

- Before interacting with any of the objects or APIs provided by the - Python.Runtime namespace, calling code must have acquired the Python - global interpreter lock by calling the PythonEngine.AcquireLock - method. The only exception to this rule is the - PythonEngine.Initialize method, which may be called at startup - without having acquired the GIL. -

- -

- When finished using Python APIs, managed code must call a corresponding - PythonEngine.ReleaseLock to release the GIL and allow other - threads to use Python. -

- -

- The AcquireLock and ReleaseLock methods are thin wrappers over the - unmanaged PyGILState_Ensure and PyGILState_Release - functions from the Python API, and the documentation for those APIs applies - to the managed versions. -

- - - - -

License

- -

- Python for .NET is released under the open source Zope Public License (ZPL). - A copy of the ZPL is included in the distribution, or you can find a copy - of the - - ZPL online - . Some distributions of this package include a copy of the C Python - dlls and standard library, which are covered by the - - Python license - . -

- -
- - +

This is not unlike some of the cases you can find in C# where + you have to know about boxing behavior to avoid similar kinds of lost + update problems (generally because an implicit boxing + happened that was not taken into account in the code). +

+

This is the same thing, just the manifestation is a little + different in Python. See the .NET documentation for more details + on boxing and the differences between value types and reference + types. +

+ +

Embedding Python

+

Note: because Python code running under Python + for .NET is inherently unverifiable, it runs totally under the + radar of the security infrastructure of the CLR so you should + restrict use of the Python assembly to trusted code. +

+

The Python runtime assembly defines a number of public classes + that provide a subset of the functionality provided by the Python + C API. +

+

These classes include PyObject, PyList, PyDict, etc. The source + and the unit tests are currently the only API documentation.. The + rhythym is very similar to using Python C++ wrapper solutions such + as CXX. +

+

At a very high level, to embed Python in your application you + will need to: +

+
    +
  • Reference Python.Runtime.dll in your build environment
  • +
  • Call PythonEngine.Intialize() to initialize Python
  • +
  • Call PythonEngine.ImportModule(name) to import a module
  • +
+

The module you import can either start working with your managed + app environment at the time its imported, or you can explicitly + lookup and call objects in a module you import. +

+

For general-purpose information on embedding Python in + applications, use www.python.org or Google to find (C) examples. + Because Python for .NET is so closely integrated with the managed + environment, you will generally be better off importing a module + and deferring to Python code as early as possible rather than + writing a lot of managed embedding code. +

+

Important Note for embedders: Python is not + free-threaded and uses a global interpreter lock to allow + multi-threaded applications to interact safely with the Python + interpreter. Much more information about this is available in the + Python C API documentation on the www.python.org Website. +

+

When embedding Python in a managed application, you have to + manage the GIL in just the same way you would when embedding + Python in a C or C++ application. +

+

Before interacting with any of the objects or APIs provided by + the Python.Runtime namespace, calling code must have acquired the + Python global interpreter lock by calling the PythonEngine.AcquireLock + method. The only exception to this rule is the PythonEngine.Initialize + method, which may be called at startup without having acquired the + GIL. +

+

When finished using Python APIs, managed code must call a + corresponding PythonEngine.ReleaseLock to release + the GIL and allow other threads to use Python. +

+

The AcquireLock and ReleaseLock methods are thin wrappers over + the unmanaged PyGILState_Ensure and PyGILState_Release + functions from the Python API, and the documentation for those + APIs applies to the managed versions. +

+ +

License

+
+

Python for .NET is released under the open + source Zope Public License (ZPL). A copy of the ZPL is included + in the distribution, or you can find a copy of the + ZPL online . Some distributions of this package include a + copy of the C Python dlls and standard library, which are covered + by the Python + license . +

+
+ diff --git a/pythonnet/installer/installer.iss b/installer/installer.iss old mode 100755 new mode 100644 similarity index 100% rename from pythonnet/installer/installer.iss rename to installer/installer.iss diff --git a/pythonnet/installer/left.bmp b/installer/left.bmp old mode 100755 new mode 100644 similarity index 100% rename from pythonnet/installer/left.bmp rename to installer/left.bmp diff --git a/pythonnet/doc/license.txt b/installer/license.txt old mode 100755 new mode 100644 similarity index 99% rename from pythonnet/doc/license.txt rename to installer/license.txt index ec12c9f2a..44e0648b3 --- a/pythonnet/doc/license.txt +++ b/installer/license.txt @@ -57,5 +57,3 @@ This software consists of contributions made by Zope Corporation and many individuals on behalf of Zope Corporation. Specific attributions are listed in the accompanying credits file. - - diff --git a/pythonnet/installer/top.bmp b/installer/top.bmp old mode 100755 new mode 100644 similarity index 100% rename from pythonnet/installer/top.bmp rename to installer/top.bmp diff --git a/monopythonnet.mds b/monopythonnet.mds new file mode 100644 index 000000000..1d3dc000d --- /dev/null +++ b/monopythonnet.mds @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pythonnet.build b/pythonnet.build new file mode 100644 index 000000000..9d0d6584a --- /dev/null +++ b/pythonnet.build @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pythonnet.sln b/pythonnet.sln new file mode 100644 index 000000000..64bf45fa2 --- /dev/null +++ b/pythonnet.sln @@ -0,0 +1,115 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30110.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Runtime", "src\runtime\Python.Runtime.csproj", "{097B4AC0-74E9-4C58-BCF8-C69746EC8271}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Test", "src\testing\Python.Test.csproj", "{6F401A34-273B-450F-9A4C-13550BE0767B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.EmbeddingTest", "src\embed_tests\Python.EmbeddingTest.csproj", "{4165C59D-2822-499F-A6DB-EACA4C331EB5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "src\console\Console.csproj", "{E29DCF0A-5114-4A98-B1DD-71264B6EA349}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "clrmodule", "src\clrmodule\clrmodule.csproj", "{86E834DE-1139-4511-96CC-69636A56E7AC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + DebugMono|x64 = DebugMono|x64 + DebugMono|x86 = DebugMono|x86 + DebugWin|x64 = DebugWin|x64 + DebugWin|x86 = DebugWin|x86 + ReleaseMono|x64 = ReleaseMono|x64 + ReleaseMono|x86 = ReleaseMono|x86 + ReleaseWin|x64 = ReleaseWin|x64 + ReleaseWin|x86 = ReleaseWin|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.Build.0 = DebugMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.Build.0 = DebugMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.Build.0 = DebugWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.Build.0 = DebugWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.Build.0 = DebugMono|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x86.Build.0 = DebugMono|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x64.Build.0 = DebugWin|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugWin|x86.Build.0 = DebugWin|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {6F401A34-273B-450F-9A4C-13550BE0767B}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x64.Build.0 = DebugMono|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugMono|x86.Build.0 = DebugMono|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x64.Build.0 = DebugWin|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.DebugWin|x86.Build.0 = DebugWin|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.ActiveCfg = DebugMono_x86|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x64.Build.0 = DebugMono_x86|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.ActiveCfg = DebugMono_x86|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugMono|x86.Build.0 = DebugMono_x86|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.ActiveCfg = DebugMono_x86|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x64.Build.0 = DebugMono_x86|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.ActiveCfg = DebugMono_x86|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.DebugWin|x86.Build.0 = DebugMono_x86|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.ActiveCfg = Release|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x64.Build.0 = Release|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.ActiveCfg = Release|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseMono|x86.Build.0 = Release|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.ActiveCfg = Release|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x64.Build.0 = Release|x64 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.ActiveCfg = Release|x86 + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.ReleaseWin|x86.Build.0 = Release|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x64.Build.0 = DebugWin|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.DebugWin|x86.Build.0 = DebugWin|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {86E834DE-1139-4511-96CC-69636A56E7AC}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = src\console\Console.csproj + Policies = $0 + $0.VersionControlPolicy = $1 + $1.inheritsSet = Mono + $0.ChangeLogPolicy = $2 + $2.UpdateMode = None + $2.MessageStyle = $3 + $3.LineAlign = 0 + $2.inheritsSet = Mono + EndGlobalSection +EndGlobal diff --git a/pythonnet.snk b/pythonnet.snk new file mode 100644 index 000000000..90e3d6f41 Binary files /dev/null and b/pythonnet.snk differ diff --git a/pythonnet/doc/index.html b/pythonnet/doc/index.html deleted file mode 100755 index 607a71ba9..000000000 --- a/pythonnet/doc/index.html +++ /dev/null @@ -1,210 +0,0 @@ - - - -Python for .NET - - - - - - - - - - - - - -
- -

Python for .NET

-

- 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. Using this package - you can script .NET applications or build entire applications in Python, - using .NET services and components written in any language that targets the - CLR (Managed C++, C#, VB, JScript). -

- -

- Note that this package does not implement Python as a first-class - CLR language - it does not produce managed code (IL) from Python code. - Rather, it is an integration of the C Python engine with the .NET runtime. - This approach allows you to use use CLR services and continue to use existing - Python code and C-based extensions while maintaining native execution speeds - for Python code. If you are interested in a pure managed-code implementation - of the Python language, you should check out the - IronPython project, which is in - active development. -

- -

- Python for .NET is currently compatible with Python releases 2.3 and greater. - To subscribe to the - - Python for .NET mailing list - or read the - - online archives - of the list, see the - - mailing list information - page. You can also send questions or comments to me at - brian.lloyd@revolution.com - or use the - - Python for .NET issue tracker to report issues. -

- -

- My blog site is also - (sometimes) a good source for more information on Python for .NET ;) -

- - - - - - - - -
- - - diff --git a/pythonnet/doc/readme.html b/pythonnet/doc/readme.html deleted file mode 100755 index e5cb09cf5..000000000 --- a/pythonnet/doc/readme.html +++ /dev/null @@ -1,870 +0,0 @@ - - - -Python for .NET - - - - - - - - - - - - - -
- - - -

- 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. Using this package - you can script .NET applications or build entire applications in Python, - using .NET services and components written in any language that targets the - CLR (Managed C++, C#, VB, JScript). -

- -

- Note that this package does not implement Python as a first-class - CLR language - it does not produce managed code (IL) from Python code. - Rather, it is an integration of the C Python engine with the .NET runtime. - This approach allows you to use use CLR services and continue to use existing - Python code and C-based extensions while maintaining native execution speeds - for Python code. If you are interested in a pure managed-code implementation - of the Python language, you should check out the - IronPython project, which is in - active development. -

- -

- Python for .NET is currently compatible with Python releases 2.3 and greater. - Current releases are available at the - - Python for .NET website - . To subscribe to the - - Python for .NET mailing list - or read the - - online archives - of the list, see the - - mailing list information - page. -

- - - -

Installation

- -

- Python for .NET is available as a source release and as a Windows installer - for various versions of Python and the common language runtime from the - - Python for .NET website - . On Windows platforms, you can choose to install .NET-awareness into - an existing Python installation as well as install Python for .NET as a - standalone package. -

- -

- The source release is a self-contained "private" assembly. - Just unzip the package wherever you want it, cd to that directory and run - python.exe to start using it. Note that the source release does not - include a copy of the CPython runtime, so you will need to have installed - Python on your machine before using the source release. -

- -

- Running on Linux/Mono: preliminary testing shows that - PythonNet will run under Mono, though - the Mono runtime is not yet complete so there still may be problems. The - Python for .NET integration layer is 100% managed code, so there should be - no long-term issues under Mono - it should work better and better as the - Mono platform matures. -

- -

- It is not currently possible to *build* PythonNet using only the Mono - tools, due to an issue involving the Mono assembler / disassembler. You - should, however, be able to try the pre-built assembly under Mono (or - compile it yourself with the MS tools and run it under Mono). -

- -

- Note that if you are running under Mono on a *nix system, you will need - to have a compatible version of Python installed. You will also need - to create a symbolic link to the copy of libpython2.x.so (in your existing - Python installation) in the PythonNet directory. This is needed to ensure - that the mono interop dll loader will find it by name. For example: -

- -
-    ln -s /usr/lib/libpython2.4.so ./python24.so
-
- - - - -

Getting Started

- -

- A key goal for this project has been that Python for .NET should "work - just the way you'd expect in Python", except for cases that are .NET - specific (in which case the goal is to work "just the way you'd expect - in C#"). -

- -

- If you already know Python, you can probably finish this readme and then - refer to .NET docs to figure out anything you need to do. Conversely if - you are familiar with C# or another .NET language, you probably just - need to pick up one of the many good Python books or read the Python - tutorial online to get started. -

- -

- A good way to start is to run python.exe and follow along - with the examples in this document. If you get stuck, there are also a - number of demos and unit tests located in the source directory of the - distribution that can be helpful as examples. -

- - - - -

Importing Modules

- -

- Python for .NET allows CLR namespaces to be treated essentially as - Python packages. The top-level package is named CLR, and - acts as the root for accessing all CLR namespaces: -

- -
-    from CLR.System import String
-    import CLR.System as System
-
- -

- Types from any loaded assembly may be imported and used in this manner. - The import hook uses "implicit loading" to support automatic loading - of assemblies whose names correspond to an imported namespace: -

- -
-    # This will implicitly load the System.Windows.Forms assembly
-
-    from CLR.System.Windows.Forms import Form
-
- -

- Python for .NET uses the PYTHONPATH (sys.path) to look for assemblies - to load, in addition to the usual application base and the GAC. To - ensure that you can implicitly import an assembly, put the directory - containing the assembly in sys.path. -

- -

- To load assemblies with names that do not correspond with a namespace, - you can use the standard mechanisms provided by the CLR: -

- -
-    from CLR.System.Reflection import Assembly
-
-    a = Assembly.LoadWithPartialName("SomeAssembly")
-
-    # now we can import namespaces defined in that assembly
-
-    from CLR.SomeNamespace import Something
-
- -

- Note that CLR modules are "lazy". Because a namespace can contain a - potentially very large number of classes, reflected CLR classes are - created on-demand when they are requested of a CLR module. This means - that using the Python dir() function in the interactive - interpreter will not necessarily show all of the classes available from - a given CLR module (it will only show any classes that have been referenced - to that point in time). -

- -

- It also means that from somemodule import * will not work as - expected. It is possible that it could be made to work in the future, - but for now it would impose a big performance hit and a lot of - complexity to support something that is used relatively rarely and - often considered bad form in Python anyway ;) -

- - - - -

Using Classes

- -

- Python for .NET allows you to use any non-private classes, structs, - interfaces, enums or delegates from Python. To create an instance of - a managed class, you use the standard instantiation syntax, passing - a set of arguments that match one of its public constructors: -

- -
-    from CLR.System.Drawing import Point
-
-    p = Point(5, 5)
-
- -

- You can also subclass managed classes in Python. See the - helloform.py file in the /demo directory of the - distribution for a simple Windows Forms example that demonstrates - subclassing a managed class. -

- - - - -

Fields And Properties

- -

- You can get and set fields and properties of CLR objects just as if - they were regular attributes: -

- -
-    from CLR.System import Environment
-
-    name = Environment.MachineName
-    Environment.ExitCode = 1
-
- - - - -

Using Indexers

- -

- If a managed object implements one or more indexers, you can call - the indexer using standard Python indexing syntax: -

- -
-    from CLR.System.Collections import Hashtable
-
-    table = Hashtable()
-    table["key 1"] = "value 1"
-
- -

- Overloaded indexers are supported, using the same notation one - would use in C#: -

- -
-    items[0, 2]
-
-    items[0, 2, 3]
-
- - - - -

Using Methods

- -

- Methods of CLR objects behave generally like normal Python methods. - Static methods may be called either through the class or through an - instance of the class. All public and protected methods of CLR objects - are accessible to Python: -

- -
-    from CLR.System import Environment
-
-    drives = Environment.GetLogicalDrives()
-
- -

- It is also possible to call managed methods unbound (passing the - instance as the first argument) just as with Python methods. This is - most often used to explicitly call methods of a base class. -

- -

- Note that there is one caveat related to calling unbound methods: it - is possible for a managed class to declare a static method and an - instance method with the same name. Since it is not possible for the - runtime to know the intent when such a method is called unbound, the - static method will always be called. -

- -

- The docstring of CLR a method (__doc__) can be used to view the - signature of the method, including overloads if the CLR method is - overloaded. You can also use the Python help method to inspect - a managed class: -

- -
-    from CLR.System import Environment
-
-    print Environment.GetFolderPath.__doc__
-
-    help(Environment)
-
- - - - -

Delegates And Events

- -

- Delegates defined in managed code can be implemented in Python. A - delegate type can be instantiated and passed a callable Python object - to get a delegate instance. The resulting delegate instance is a true - managed delegate that will invoke the given Python callable when it - is called: -

- -
-    def my_handler(source, args):
-        print 'my_handler called!'
-
-    # instantiate a delegate
-    d = AssemblyLoadEventHandler(my_handler)
-
-    # use it as an event handler
-    AppDomain.CurrentDomain.AssemblyLoad += d
-
- - -

- Multicast delegates can be implemented by adding more callable objects - to a delegate instance: -

- -
-    d += self.method1
-    d += self.method2
-    d()
-
- -

- Events are treated as first-class objects in Python, and behave in - many ways like methods. Python callbacks can be registered with event - attributes, and an event can be called to fire the event. -

- -

- Note that events support a convenience spelling similar to that used - in C#. You do not need to pass an explicitly instantiated delegate - instance to an event (though you can if you want). Events support the - += and -= operators in a way very similar to - the C# idiom: -

- -
-    def handler(source, args):
-        print 'my_handler called!'
-
-    # register event handler
-    object.SomeEvent += handler
-
-    # unregister event handler
-    object.SomeEvent -= handler
-
-    # fire the event
-    result = object.SomeEvent(...)
-
- - - - -

Exception Handling

- -

- You can raise and catch managed exceptions just the same as you would - pure-Python exceptions: -

-    from CLR.System import NullReferenceException
-
-    try:
-        raise NullReferenceException("aiieee!")
-    except NullReferenceException, e:
-        print e.Message
-        print e.Source
-
-

- - - - -

Using Arrays

- -

- Managed arrays support the standard Python sequence protocols: -

- -
-    items = SomeObject.GetArray()
-
-    # Get first item
-    v = items[0]
-    items[0] = v
-
-    # Get last item
-    v = items[-1]
-    items[-1] = v
-
-    # Get length
-    l = len(items)
-
-    # Containment test
-    test = v in items
-
- -

- Multidimensional arrays support indexing using the same notation one - would use in C#: -

- -
-    items[0, 2]
-
-    items[0, 2, 3]
-
- - - - -

Using Collections

- -

- Managed arrays and managed objects that implement the IEnumerable - interface can be iterated over using the standard iteration Python -idioms: -

- -
-    domain = System.AppDomain.CurrentDomain
-
-    for item in domain.GetAssemblies():
-        name = item.GetName()
-
- - - - -

Using COM Components

- -

- Using Microsoft-provided tools such as aximp.exe and - tlbimp.exe, it is possible to generate managed wrappers - for COM libraries. After generating such a wrapper, you can use the - libraries from Python just like any other managed code. -

-

- Note: currently you need to put the generated wrappers in the GAC, - in the PythonNet assembly directory or on the PYTHONPATH in order - to load them. -

- - - -

Type Conversion

- -

- Type conversion under Python for .NET is fairly straightforward - most - elemental Python types (string, int, long, etc.) convert automatically - to compatible managed equivalents (String, Int32, etc.) and vice-versa. - Note that all strings returned from the CLR are returned as unicode. -

- -

- Types that do not have a logical equivalent in Python are exposed as - instances of managed classes or structs (System.Decimal is an example). -

-

- The .NET architecture makes a distinction between value types - and reference types. Reference types are allocated on the heap, - and value types are allocated either on the stack or in-line within an - object. -

- -

- A process called boxing is used in .NET to allow code to treat - a value type as if it were a reference type. Boxing causes a separate - copy of the value type object to be created on the heap, which then - has reference type semantics. -

- -

- Understanding boxing and the distinction between value types and - reference types can be important when using Python for .NET because - the Python language has no value type semantics or syntax - in - Python "everything is a reference". -

- -

- Here is a simple example that demonstrates an issue. If you are an - experienced C# programmer, you might write the following code: -

- -
-    items = CLR.System.Array.CreateInstance(Point, 3)
-    for i in range(3):
-        items[i] = Point(0, 0)
-
-    items[0].X = 1 # won't work!!
-
- -

- While the spelling of items[0].X = 1 is the same in C# and - Python, there is an important and subtle semantic difference. In C# (and other - compiled-to-IL languages), the compiler knows that Point is a value - type and can do the Right Thing here, changing the value in place. -

- -

- In Python however, "everything's a reference", and there is really no - spelling or semantic to allow it to do the right thing dynamically. The - specific reason that items[0] itself doesn't change is that - when you say items[0], that getitem operation creates a Python - object that holds a reference to the object at items[0] via a - GCHandle. That causes a ValueType (like Point) to be boxed, so the following - setattr (.X = 1) changes the state of the boxed value, not - the original unboxed value. -

- -

- The rule in Python is essentially: "the result of any attribute or - item access is a boxed value", and that can be important in how you - approach your code. -

- -

- Because there are no value type semantics or syntax in Python, you - may need to modify your approach. To revisit the previous example, - we can ensure that the changes we want to make to an array item - aren't "lost" by resetting an array member after making changes - to it: -

- -
-    items = CLR.System.Array.CreateInstance(Point, 3)
-    for i in range(3):
-        items[i] = Point(0, 0)
-
-    # This _will_ work. We get 'item' as a boxed copy of the Point
-    # object actually stored in the array. After making our changes
-    # we re-set the array item to update the bits in the array.
-
-    item = items[0]
-    item.X = 1
-    items[0] = item
-
- -

- This is not unlike some of the cases you can find in C# where you have - to know about boxing behavior to avoid similar kinds of lost - update problems (generally because an implicit boxing happened that - was not taken into account in the code). -

- -

- This is the same thing, just the manifestation is a little different - in Python. See the .NET documentation for more details on boxing and - the differences between value types and reference types. -

- - - - -

Using Assemblies

- -

- The Python for .NET runtime uses Assembly.LoadWithPartialName to do - name-based imports, which will usually load the most recent version of - an assembly that it can find. -

- -

- The CLR's ability to load different versions of assemblies side-by-side - is one of the (relatively few) places where the matching of meta-models - between Python and the CLR breaks down (though it is unclear how often - this happens in practice). -

- -

- Because Python import is name-based and unaware of any concept of - versioned modules, the design goal has been for name-based implicit assembly - loading to do something consistent and reasonable (i.e. load most - recent available based on the name). -

- -

- It is possible to load a specific version of an assembly if you - need to using code similar to the following: -

- -
-    from CLR.System.Reflection import Assembly, AssemblyName
-
-    name = AssemblyName(...) # set required version, etc.
-    assembly = Assembly.Load(name)
-
-    # now import namespaces from the loaded assembly
-
- -

- Things get a lot more complicated if you need to load more than one - version of a particular assembly (or more likely, you have a dependency - on some library the does so). In this case, the names you access via - the CLR modules will always come from the first version of the - assembly loaded (which will always win in the internals of the Python - for .NET runtime). -

- -

- You can still use particular versions of objects in this case - you - just have to do more work to get the right versions of objects: -

- -
-    from CLR.System.Reflection import Assembly, AssemblyName
-    from System import Activator
-
-    name = AssemblyName(...) # get the right version
-    assembly = Assembly.Load(name)
-    type = assembly.GetType("QualifiedNameOf.TheTypeINeed")
-    obj = Activator.CreateInstance(type)
-
-

- - - - -

Embedding Python

- -

- Note: because Python code running under Python for .NET - is inherently unverifiable, it runs totally under the radar of the security - infrastructure of the CLR so you should restrict use of the Python assembly - to trusted code. -

- -

- The Python runtime assembly defines a number of public classes that - provide a subset of the functionality provided by the Python C API. -

- -

- These classes include PyObject, PyList, PyDict, etc. The source and - the unit tests are currently the only API documentation.. The rhythym - is very similar to using Python C++ wrapper solutions such as CXX. -

- -

- At a very high level, to embed Python in your application you - will need to: -

- -
    -
  • Reference Python.Runtime.dll in your build environment
  • -
  • Call PythonEngine.Intialize() to initialize Python
  • -
  • Call PythonEngine.ImportModule(name) to import a module
  • -
- - -

- The module you import can either start working with your managed app - environment at the time its imported, or you can explicitly lookup and - call objects in a module you import. -

- -

- For general-purpose information on embedding Python in applications, use - www.python.org or Google to find (C) examples. Because Python for .NET is - so closely integrated with the managed environment, you will generally be - better off importing a module and deferring to Python code as early as - possible rather than writing a lot of managed embedding code. -

- -

- Important Note for embedders: Python is not free-threaded - and uses a global interpreter lock to allow multi-threaded applications to - interact safely with the Python interpreter. Much more information about - this is available in the Python C API documentation on the www.python.org - Website. -

- -

- When embedding Python in a managed application, you have to manage the GIL - in just the same way you would when embedding Python in a C or C++ - application. -

- -

- Before interacting with any of the objects or APIs provided by the - Python.Runtime namespace, calling code must have acquired the Python - global interpreter lock by calling the PythonEngine.AcquireLock - method. The only exception to this rule is the - PythonEngine.Initialize method, which may be called at startup - without having acquired the GIL. -

- -

- When finished using Python APIs, managed code must call a corresponding - PythonEngine.ReleaseLock to release the GIL and allow other - threads to use Python. -

- -

- The AcquireLock and ReleaseLock methods are thin wrappers over the - unmanaged PyGILState_Ensure and PyGILState_Release - functions from the Python API, and the documentation for those APIs applies - to the managed versions. -

- - - - -

License

- -

- Python for .NET is released under the open source Zope Public License (ZPL). - A copy of the ZPL is included in the distribution, or you can find a copy - of the - - ZPL online - . Some distributions of this package include a copy of the C Python - dlls and standard library, which are covered by the - - Python license - . -

- -
- - - diff --git a/pythonnet/makefile b/pythonnet/makefile deleted file mode 100755 index 74d4b5930..000000000 --- a/pythonnet/makefile +++ /dev/null @@ -1,99 +0,0 @@ -# Makefile for the PythonRuntime .NET assembly and tests. Thanks to -# Camilo Uribe for contributing Mono support. - -RELEASE=pythonnet-1.0-rc2-py2.4-clr1.1-src -RUNNER= -ILDASM=ildasm -ILASM=ilasm -CSC=csc.exe - -all: python.exe CLR.dll Python.Test.dll - - -python.exe: Python.Runtime.dll - cd src; cd console; \ - $(CSC) /nologo /target:exe /out:../../python.exe \ - /reference:../../Python.Runtime.dll /recurse:*.cs - cd ..; cd ..; - - -Python.Runtime.dll: callconvutil.exe - cd src; cd runtime; \ - $(CSC) /nologo /unsafe /target:library /out:../../Python.Runtime.dll \ - /recurse:*.cs - cd ..; cd ..; - $(ILDASM) /nobar Python.Runtime.dll /out=Python.Runtime.il; - $(RUNNER) ./callconvutil.exe; - $(ILASM) /nologo /quiet /dll \ - /resource=Python.Runtime.res /output=Python.Runtime.dll \ - Python.Runtime.il2; - rm -f Python.Runtime.il; - rm -f Python.Runtime.il2; - rm -f Python.Runtime.res; - rm -f ./callconvutil.exe; - - -CLR.dll: Python.Runtime.dll - $(ILASM) /nologo /dll /quiet /output=CLR.dll \ - ./src/runtime/clrmodule.il; - - -Python.Test.dll: Python.Runtime.dll - cd src; cd testing; \ - $(CSC) /nologo /target:library /out:../../Python.Test.dll \ - /reference:../../Python.Runtime.dll \ - /recurse:*.cs - cd ..; cd ..; - - -callconvutil.exe: - cd src; cd tools; \ - $(CSC) /nologo /target:exe /out:../../callconvutil.exe \ - /recurse:*.cs - cd ..; cd ..; - - -clean: - rm -f python.exe Python*.dll Python*.il Python*.il2 Python*.res - rm -f callconvutil.exe - rm -f CLR.dll - rm -f ./*~ - cd src; cd console; rm -f *~; cd ..; cd ..; - cd src; cd runtime; rm -f *~; cd ..; cd ..; - cd src; cd testing; rm -f *~; cd ..; cd ..; - cd src; cd tests; rm -f *~; rm -f *.pyc; cd ..; cd ..; - cd src; cd tools; rm -f *~; cd ..; cd ..; - cd doc; rm -f *~; cd ..; - cd demo; rm -f *~; cd ..; - - -test: - rm -f ./src/tests/*.pyc - $(RUNNER) ./python.exe ./src/tests/runtests.py - - -dist: clean - mkdir ./$(RELEASE) - cp -R ./makefile ./$(RELEASE)/ - cp -R ./demo ./$(RELEASE)/ - cp -R ./doc ./$(RELEASE)/ - cp -R ./src ./$(RELEASE)/ - make - cp ./python.exe ./$(RELEASE)/ - cp ./*.dll ./$(RELEASE)/ - tar czf $(RELEASE).tgz ./$(RELEASE)/ - mv $(RELEASE).tgz ./release/ - rm -rf ./$(RELEASE)/ - - -dis: - $(ILDASM) Python.Runtime.dll /out=Python.Runtime.il - - -asm: - $(ILASM) /dll /quiet \ - /resource=Python.Runtime.res /output=Python.Runtime.dll \ - Python.Runtime.il - - - diff --git a/pythonnet/makefile.mono b/pythonnet/makefile.mono deleted file mode 100755 index 8eaa51681..000000000 --- a/pythonnet/makefile.mono +++ /dev/null @@ -1,101 +0,0 @@ -# Makefile for the PythonRuntime .NET assembly and tests. Thanks to -# Camilo Uribe for contributing Mono support. - -# WARNING: this makefile cannot currently build the Python runtime -# dll under mono, due to use of attributes that the mono assembler / -# disassembler doesn't yet support. - -RELEASE=pythonnet-1.0-rc1-py2.3-clr1.1-src -RUNNER=mono -ILDASM=monodis -ILASM=ilasm -CSC=mcs - -all: python.exe CLR.dll Python.Test.dll - - -python.exe: Python.Runtime.dll - cd src; cd console; \ - $(CSC) /nologo /target:exe /out:../../python.exe \ - /reference:../../Python.Runtime.dll /recurse:*.cs - cd ..; cd ..; - - -Python.Runtime.dll: callconvutil.exe - cd src; cd runtime; \ - $(CSC) /nologo /unsafe /target:library /out:../../Python.Runtime.dll \ - /recurse:*.cs - cd ..; cd ..; - $(ILDASM) /nobar Python.Runtime.dll /out=Python.Runtime.il; - $(RUNNER) ./callconvutil.exe; - $(ILASM) /nologo /quiet /dll \ - /resource=Python.Runtime.res /output=Python.Runtime.dll \ - Python.Runtime.il2; - rm -f Python.Runtime.il; - rm -f Python.Runtime.il2; - rm -f Python.Runtime.res; - rm -f ./callconvutil.exe; - - -CLR.dll: Python.Runtime.dll - $(ILASM) /nologo /dll /quiet /output=CLR.dll \ - ./src/runtime/clrmodule.il; - - -Python.Test.dll: Python.Runtime.dll - cd src; cd testing; \ - $(CSC) /nologo /target:library /out:../../Python.Test.dll \ - /reference:../../Python.Runtime.dll \ - /recurse:*.cs - cd ..; cd ..; - - -callconvutil.exe: - cd src; cd tools; \ - $(CSC) /nologo /target:exe /out:../../callconvutil.exe \ - /recurse:*.cs - cd ..; cd ..; - - -clean: - rm -f python.exe Python*.dll Python*.il Python*.il2 Python*.res - rm -f callconvutil.exe - rm -f CLR.dll - rm -f ./*~ - cd src; cd console; rm -f *~; cd ..; cd ..; - cd src; cd runtime; rm -f *~; cd ..; cd ..; - cd src; cd testing; rm -f *~; cd ..; cd ..; - cd src; cd tests; rm -f *~; rm -f *.pyc; cd ..; cd ..; - cd src; cd tools; rm -f *~; cd ..; cd ..; - cd doc; rm -f *~; cd ..; - cd demo; rm -f *~; cd ..; - - -test: - rm -f ./src/tests/*.pyc - $(RUNNER) ./python.exe ./src/tests/runtests.py - - -dist: clean - mkdir ./$(RELEASE) - cp -R ./makefile ./$(RELEASE)/ - cp -R ./demo ./$(RELEASE)/ - cp -R ./doc ./$(RELEASE)/ - cp -R ./src ./$(RELEASE)/ - make - cp ./python.exe ./$(RELEASE)/ - cp ./*.dll ./$(RELEASE)/ - tar czf $(RELEASE).tgz ./$(RELEASE)/ - mv $(RELEASE).tgz ./release/ - rm -rf ./$(RELEASE)/ - - -dis: - $(ILDASM) Python.Runtime.dll /out=Python.Runtime.il - - -asm: - $(ILASM) /dll /quiet \ - /resource=Python.Runtime.res /output=Python.Runtime.dll \ - Python.Runtime.il - diff --git a/pythonnet/src/console/pythonconsole.cs b/pythonnet/src/console/pythonconsole.cs deleted file mode 100755 index 672d0f3cd..000000000 --- a/pythonnet/src/console/pythonconsole.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// 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 Python.Runtime; - -namespace Python.Runtime { - -public sealed class PythonConsole { - - private PythonConsole() {} - - [STAThread] - public static int Main(string[] args) { - string [] cmd = Environment.GetCommandLineArgs(); - PythonEngine.Initialize(); - - int i = Runtime.Py_Main(cmd.Length, cmd); - PythonEngine.Shutdown(); - - return i; - } - -} - -} diff --git a/pythonnet/src/runtime/arrayobject.cs b/pythonnet/src/runtime/arrayobject.cs deleted file mode 100755 index e1668e1d2..000000000 --- a/pythonnet/src/runtime/arrayobject.cs +++ /dev/null @@ -1,251 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// Implements a Python type for managed arrays. This type is essentially - /// the same as a ClassObject, except that it provides sequence semantics - /// to support natural array usage (indexing) from Python. - /// - - internal class ArrayObject : ClassBase { - - internal ArrayObject(Type tp) : base(tp) {} - - internal override bool CanSubclass() { - return false; - } - - [CallConvCdecl()] - public static IntPtr tp_new(IntPtr ob, IntPtr args, IntPtr kw) { - string message = "cannot instantiate array wrapper"; - return Exceptions.RaiseTypeError(message); - } - - - //==================================================================== - // Implements __getitem__ for array types. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { - CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); - Array items = obj.inst as Array; - Type itemType = obj.inst.GetType().GetElementType(); - int rank = items.Rank; - int index = 0; - object value; - - // Note that CLR 1.0 only supports int indexes - methods to - // support long indices were introduced in 1.1. We could - // support long indices automatically, but given that long - // indices are not backward compatible and a relative edge - // case, we won't bother for now. - - // Single-dimensional arrays are the most common case and are - // cheaper to deal with than multi-dimensional, so check first. - - if (rank == 1) { - index = (int)Runtime.PyInt_AsLong(idx); - - if (Exceptions.ErrorOccurred()) { - return Exceptions.RaiseTypeError("invalid index value"); - } - - if (index < 0) { - index = items.Length + index; - } - - try { - value = items.GetValue(index); - } - catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); - return IntPtr.Zero; - } - - return Converter.ToPython(items.GetValue(index), itemType); - } - - // Multi-dimensional arrays can be indexed a la: list[1, 2, 3]. - - if (!Runtime.PyTuple_Check(idx)) { - Exceptions.SetError(Exceptions.TypeError, - "invalid index value" - ); - return IntPtr.Zero; - } - - int count = Runtime.PyTuple_Size(idx); - - Array args = Array.CreateInstance(typeof(Int32), count); - - for (int i = 0; i < count; i++) { - IntPtr op = Runtime.PyTuple_GetItem(idx, i); - index = (int)Runtime.PyInt_AsLong(op); - - if (Exceptions.ErrorOccurred()) { - return Exceptions.RaiseTypeError("invalid index value"); - } - - if (index < 0) { - index = items.GetLength(i) + index; - } - - args.SetValue(index, i); - } - - try { - value = items.GetValue((int[]) args); - } - catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); - return IntPtr.Zero; - } - - return Converter.ToPython(value, itemType); - } - - - //==================================================================== - // Implements __setitem__ for array types. - //==================================================================== - - [CallConvCdecl()] - public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { - CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); - Array items = obj.inst as Array; - Type itemType = obj.inst.GetType().GetElementType(); - int rank = items.Rank; - int index = 0; - object value; - - if (items.IsReadOnly) { - Exceptions.RaiseTypeError("array is read-only"); - return -1; - } - - if (!Converter.ToManaged(v, itemType, out value, true)) { - return -1; - } - - if (rank == 1) { - index = (int)Runtime.PyInt_AsLong(idx); - - if (Exceptions.ErrorOccurred()) { - Exceptions.RaiseTypeError("invalid index value"); - return -1; - } - - if (index < 0) { - index = items.Length + index; - } - - try { - items.SetValue(value, index); - } - catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); - return -1; - } - - return 0; - } - - if (!Runtime.PyTuple_Check(idx)) { - Exceptions.RaiseTypeError("invalid index value"); - return -1; - } - - int count = Runtime.PyTuple_Size(idx); - - Array args = Array.CreateInstance(typeof(Int32), count); - - for (int i = 0; i < count; i++) { - IntPtr op = Runtime.PyTuple_GetItem(idx, i); - index = (int)Runtime.PyInt_AsLong(op); - - if (Exceptions.ErrorOccurred()) { - Exceptions.RaiseTypeError("invalid index value"); - return -1; - } - - if (index < 0) { - index = items.GetLength(i) + index; - } - - args.SetValue(index, i); - } - - try { - items.SetValue(value, (int[])args); - } - catch (IndexOutOfRangeException) { - Exceptions.SetError(Exceptions.IndexError, - "array index out of range" - ); - return -1; - } - - return 0; - } - - - //==================================================================== - // Implements __contains__ for array types. - //==================================================================== - - [CallConvCdecl()] - public static int sq_contains(IntPtr ob, IntPtr v) { - CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); - Type itemType = obj.inst.GetType().GetElementType(); - IList items = obj.inst as IList; - object value; - - if (!Converter.ToManaged(v, itemType, out value, false)) { - return 0; - } - - if (items.Contains(value)) { - return 1; - } - - return 0; - } - - - //==================================================================== - // Implements __len__ for array types. - //==================================================================== - - [CallConvCdecl()] - public static int mp_length(IntPtr ob) { - CLRObject self = (CLRObject)ManagedType.GetManagedObject(ob); - Array items = self.inst as Array; - return items.Length; - } - - - } - -} diff --git a/pythonnet/src/runtime/assemblyinfo.cs b/pythonnet/src/runtime/assemblyinfo.cs deleted file mode 100755 index eaa619665..000000000 --- a/pythonnet/src/runtime/assemblyinfo.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Reflection; -using System.Security.Permissions; -using System.Runtime.InteropServices; - -[assembly: System.Reflection.AssemblyProduct("Python for .NET")] -[assembly: System.Reflection.AssemblyVersion("1.0.0.0")] -[assembly: AssemblyTitleAttribute("Python.Runtime")] -[assembly: AssemblyDefaultAliasAttribute("Python.Runtime.dll")] -[assembly: CLSCompliant(true)] -[assembly: ComVisible(false)] - - -[assembly:PermissionSetAttribute(SecurityAction.RequestMinimum, - Name = "FullTrust")] diff --git a/pythonnet/src/runtime/assemblymanager.cs b/pythonnet/src/runtime/assemblymanager.cs deleted file mode 100755 index d7375c406..000000000 --- a/pythonnet/src/runtime/assemblymanager.cs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.IO; -using System.Collections; -using System.Collections.Specialized; -using System.Reflection; -using System.Reflection.Emit; - -namespace Python.Runtime { - - /// - /// The AssemblyManager maintains information about the assemblies and - /// namespaces that have been loaded, and provides a simplified internal - /// interface for finding and obtaining Type objects by qualified names. - /// - - internal class AssemblyManager { - - static StringCollection pypath; - static AssemblyLoadEventHandler lh; - static ResolveEventHandler rh; - static Hashtable namespaces; - static ArrayList assemblies; - static Hashtable probed; - static int last; - - private AssemblyManager() {} - - //=================================================================== - // Initialization performed on startup of the Python runtime. - //=================================================================== - - internal static void Initialize() { - pypath = new StringCollection(); - namespaces = new Hashtable(); - assemblies = new ArrayList(); - probed = new Hashtable(); - - AppDomain domain = AppDomain.CurrentDomain; - - lh = new AssemblyLoadEventHandler(AssemblyLoadHandler); - domain.AssemblyLoad += lh; - - rh = new ResolveEventHandler(ResolveHandler); - domain.AssemblyResolve += rh; - - Assembly[] items = domain.GetAssemblies(); - for (int i = 0; i < items.Length; i++) { - Assembly a = items[i]; - assemblies.Add(a); - ScanAssembly(a); - } - } - - - //=================================================================== - // Cleanup resources upon shutdown of the Python runtime. - //=================================================================== - - internal static void Shutdown() { - AppDomain domain = AppDomain.CurrentDomain; - domain.AssemblyLoad -= lh; - domain.AssemblyResolve -= rh; - } - - - //=================================================================== - // Event handler for assembly load events. At the time the Python - // runtime loads, we scan the app domain to map the assemblies that - // are loaded at the time. We also have to register this event handler - // so that we can know about assemblies that get loaded after the - // Python runtime is initialized. - //=================================================================== - - static void AssemblyLoadHandler(Object ob, AssemblyLoadEventArgs args){ - Assembly assembly = args.LoadedAssembly; - assemblies.Add(assembly); - ScanAssembly(assembly); - } - - - //=================================================================== - // Event handler for assembly resolve events. This is needed because - // we augment the assembly search path with the PYTHONPATH when we - // load an assembly from Python. Because of that, we need to listen - // for failed loads, because they might be dependencies of something - // we loaded from Python which also needs to be found on PYTHONPATH. - //=================================================================== - - static Assembly ResolveHandler(Object ob, ResolveEventArgs args){ - string name = args.Name.ToLower(); - for (int i = 0; i < assemblies.Count; i++) { - Assembly a = (Assembly)assemblies[i]; - string full = a.FullName.ToLower(); - if (full.StartsWith(name)) { - return a; - } - } - Assembly ao = LoadAssemblyPath(args.Name); - return ao; - } - - - //=================================================================== - // We __really__ want to avoid using Python objects or APIs when - // probing for assemblies to load, since our ResolveHandler may be - // called in contexts where we don't have the Python GIL and can't - // even safely try to get it without risking a deadlock ;( - // - // To work around that, we update a managed copy of sys.path (which - // is the main thing we care about) when UpdatePath is called. The - // import hook calls this whenever it knows its about to use the - // assembly manager, which lets us keep up with changes to sys.path - // in a relatively lightweight and low-overhead way. - //=================================================================== - - internal static void UpdatePath() { - IntPtr list = Runtime.PySys_GetObject("path"); - int count = Runtime.PyList_Size(list); - if (count != pypath.Count) { - pypath.Clear(); - probed.Clear(); - for (int i = 0; i < count; i++) { - IntPtr item = Runtime.PyList_GetItem(list, i); - string path = Runtime.GetManagedString(item); - if (path != null) { - pypath.Add(path); - } - } - } - } - - - //=================================================================== - // Given an assembly name, try to find this assembly file using the - // PYTHONPATH. If not found, return null to indicate implicit load - // using standard load semantics (app base directory then GAC, etc.) - //=================================================================== - - static string FindAssembly(string name) { - char sep = Path.DirectorySeparatorChar; - string path; - string temp; - - for (int i = 0; i < pypath.Count; i++) { - string head = pypath[i]; - if (head == null || head.Length == 0) { - path = name; - } - else { - path = head + sep + name; - } - - temp = path + ".dll"; - if (File.Exists(temp)) { - return temp; - } - temp = path + ".exe"; - if (File.Exists(temp)) { - return temp; - } - } - return null; - } - - - //=================================================================== - // Loads an assembly from the application directory or the GAC - // given a simple assembly name. Returns the assembly if loaded. - //=================================================================== - - public static Assembly LoadAssembly(string name) { - Assembly assembly = null; - try { - assembly = Assembly.LoadWithPartialName(name); - } - catch { - } - return assembly; - } - - - //=================================================================== - // Loads an assembly using an augmented search path (the python path). - //=================================================================== - - public static Assembly LoadAssemblyPath(string name) { - string path = FindAssembly(name); - Assembly assembly = null; - if (path != null) { - try { assembly = Assembly.LoadFrom(path); } - catch {} - } - return assembly; - } - - - //=================================================================== - // Given a qualified name of the form A.B.C.D, attempt to load - // an assembly named after each of A.B.C.D, A.B.C, A.B, A. This - // will only actually probe for the assembly once for each unique - // namespace. Returns true if any assemblies were loaded. - //=================================================================== - - public static bool LoadImplicit(string name) { - string[] names = name.Split('.'); - bool loaded = false; - string s = ""; - for (int i = 0; i < names.Length; i++) { - s = (i == 0) ? names[0] : s + "." + names[i]; - if (probed[s] == null) { - if (LoadAssemblyPath(s) != null){ - loaded = true; - } - else if (LoadAssembly(s) != null) { - loaded = true; - } - probed[s] = 1; - } - } - return loaded; - } - - - //=================================================================== - // Scans an assembly for exported namespaces, adding them to the - // mapping of valid namespaces. Note that for a given namespace - // a.b.c.d, each of a, a.b, a.b.c and a.b.c.d are considered to - // be valid namespaces (to better match Python import semantics). - //=================================================================== - - static void ScanAssembly(Assembly assembly) { - - // TODO: this is a workaround for a current Mono bug: calling - // GetTypes on a generated assembly will cause it to fall over. - // For now we'll skip generated assemblies, which usually are - // uninteresting support code anyway. - - if (assembly is AssemblyBuilder) { - return; - } - - Type[] types = assembly.GetTypes(); - for (int i = 0; i < types.Length; i++) { - string type_ns = types[i].Namespace; - if ((type_ns != null) && (!namespaces.ContainsKey(type_ns))) { - string[] names = type_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, String.Empty); - } - } - } - } - } - - - //=================================================================== - // Returns true if the given qualified name matches a namespace - // exported by an assembly loaded in the current app domain. - //=================================================================== - - public static bool IsValidNamespace(string name) { - return namespaces.ContainsKey(name); - } - - - //=================================================================== - // Returns the System.Type object for a given qualified name, - // looking in the currently loaded assemblies for the named - // type. Returns null if the named type cannot be found. - //=================================================================== - - public static Type LookupType(string qualifiedName) { - for (int i = 0; i < assemblies.Count; i++) { - Assembly assembly = (Assembly)assemblies[i]; - Type type = assembly.GetType(qualifiedName); - if (type != null) { - return type; - } - } - return null; - } - - } - - -} diff --git a/pythonnet/src/runtime/classbase.cs b/pythonnet/src/runtime/classbase.cs deleted file mode 100755 index 001b0084b..000000000 --- a/pythonnet/src/runtime/classbase.cs +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; -using System.Security; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// Base class for Python types that reflect managed types / classes. - /// Concrete subclasses include ClassObject and DelegateObject. This - /// class provides common attributes and common machinery for doing - /// class initialization (initialization of the class __dict__). The - /// concrete subclasses provide slot implementations appropriate for - /// each variety of reflected type. - /// - - internal class ClassBase : ManagedType { - - internal bool is_exception; - internal Indexer indexer; - internal Type type; - - internal ClassBase(Type tp) : base() { - is_exception = false; - indexer = null; - type = tp; - } - - internal virtual bool CanSubclass() { - return (!this.type.IsEnum); - } - - - //==================================================================== - // Implements __init__ for reflected classes and value types. - //==================================================================== - - [CallConvCdecl()] - public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) { - return 0; - } - - //==================================================================== - // Standard comparison implementation for instances of reflected types. - //==================================================================== - - [CallConvCdecl()] - public static int tp_compare(IntPtr ob, IntPtr other) { - if (ob == other) { - return 0; - } - - CLRObject co1 = GetManagedObject(ob) as CLRObject; - CLRObject co2 = GetManagedObject(other) as CLRObject; - Object o1 = co1.inst; - Object o2 = co2.inst; - - if (Object.Equals(o1, o2)) { - return 0; - } - return -1; - } - - - //==================================================================== - // Standard iteration support for instances of reflected types. This - // allows natural iteration over objects that either are IEnumerable - // or themselves support IEnumerator directly. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_iter(IntPtr ob) { - CLRObject co = GetManagedObject(ob) as CLRObject; - if (co == null) { - return Exceptions.RaiseTypeError("invalid object"); - } - - IEnumerable e = co.inst as IEnumerable; - IEnumerator o; - - if (e != null) { - o = e.GetEnumerator(); - } - else { - o = co.inst as IEnumerator; - if (o == null) { - string message = "iteration over non-sequence"; - return Exceptions.RaiseTypeError(message); - } - } - - return new Iterator(o).pyHandle; - } - - - //==================================================================== - // Standard __hash__ implementation for instances of reflected types. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_hash(IntPtr ob) { - CLRObject co = GetManagedObject(ob) as CLRObject; - if (co == null) { - return Exceptions.RaiseTypeError("unhashable type"); - } - return new IntPtr(co.inst.GetHashCode()); - } - - - //==================================================================== - // Standard __str__ implementation for instances of reflected types. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_str(IntPtr ob) { - CLRObject co = GetManagedObject(ob) as CLRObject; - if (co == null) { - return Exceptions.RaiseTypeError("invalid object"); - } - return Runtime.PyString_FromString(co.inst.ToString()); - } - - - //==================================================================== - // Default implementations for required Python GC support. - //==================================================================== - - [CallConvCdecl()] - public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) { - return 0; - } - - [CallConvCdecl()] - public static int tp_clear(IntPtr ob) { - return 0; - } - - [CallConvCdecl()] - public static int tp_is_gc(IntPtr type) { - return 1; - } - - //==================================================================== - // Standard dealloc implementation for instances of reflected types. - //==================================================================== - - [CallConvCdecl()] - public static void tp_dealloc(IntPtr ob) { - ManagedType self = GetManagedObject(ob); - IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.ob_dict); - Runtime.Decref(dict); - Runtime.PyObject_GC_UnTrack(self.pyHandle); - Runtime.PyObject_GC_Del(self.pyHandle); - Runtime.Decref(self.tpHandle); - self.gcHandle.Free(); - } - - - } - -} diff --git a/pythonnet/src/runtime/classmanager.cs b/pythonnet/src/runtime/classmanager.cs deleted file mode 100755 index d5695c6aa..000000000 --- a/pythonnet/src/runtime/classmanager.cs +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; -using System.Security; - -namespace Python.Runtime { - - /// - /// The ClassManager is responsible for creating and managing instances - /// that implement the Python type objects that reflect managed classes. - /// - /// Each managed type reflected to Python is represented by an instance - /// of a concrete subclass of ClassBase. Each instance is associated with - /// a generated Python type object, whose slots point to static methods - /// of the managed instance's class. - /// - - internal class ClassManager { - - static Hashtable cache; - static Type dtype; - - private ClassManager() {} - - static ClassManager() { - cache = new Hashtable(); - dtype = typeof(System.Delegate); - } - - //==================================================================== - // Return the ClassBase-derived instance that implements a particular - // reflected managed type, creating it if it doesn't yet exist. - //==================================================================== - - internal static ClassBase GetClass(Type type) { - Object ob = cache[type]; - if (ob == null) { - ClassBase c = CreateClass(type); - cache.Add(type, c); - return c; - } - return (ClassBase) ob; - } - - - //==================================================================== - // Create a new ClassBase-derived instance that implements a reflected - // managed type. The new object will be associated with a generated - // Python type object. - //==================================================================== - - private static ClassBase CreateClass(Type type) { - - // First, we introspect the managed type and build some class - // information, including generating the member descriptors - // that we'll be putting in the Python class __dict__. - - ClassInfo info = GetClassInfo(type); - - // Next, select the appropriate managed implementation class. - // Different kinds of types, such as array types or interface - // types, want to vary certain implementation details to make - // sure that the type semantics are consistent in Python. - - ClassBase impl; - - // Check to see if the given type extends System.Exception. This - // lets us check once (vs. on every lookup) in case we need to - // wrap Exception-derived types in old-style classes - - if (type.IsSubclassOf(dtype)) { - impl = new DelegateObject(type); - } - - else if (type.IsArray) { - impl = new ArrayObject(type); - } - - else if (type.IsInterface) { - impl = new InterfaceObject(type); - } - - else { - impl = new ClassObject(type); - if (type == typeof(Exception) || type.IsSubclassOf(typeof(Exception))) { - impl.is_exception = true; - } - } - - impl.indexer = info.indexer; - - // Now we allocate the Python type object to reflect the given - // managed type, filling the Python type slots with thunks that - // point to the managed methods providing the implementation. - - - IntPtr tp = TypeManager.GetTypeHandle(impl, type); - impl.tpHandle = tp; - - // Finally, initialize the class __dict__ and return the object. - IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict); - - - IDictionaryEnumerator iter = info.members.GetEnumerator(); - while(iter.MoveNext()) { - ManagedType item = (ManagedType)iter.Value; - string name = (string)iter.Key; - Runtime.PyDict_SetItemString(dict, name, item.pyHandle); - } - - // If class has constructors, generate an __doc__ attribute. - - ClassObject co = impl as ClassObject; - if (co != null) { - IntPtr doc = co.GetDocString(); - Runtime.PyDict_SetItemString(dict, "__doc__", doc); - Runtime.Decref(doc); - } - - return impl; - } - - - - - private static ClassInfo GetClassInfo(Type type) { - ClassInfo ci = new ClassInfo(type); - Hashtable methods = new Hashtable(); - ArrayList list; - MethodInfo meth; - ManagedType ob; - String name; - Object item; - Type tp; - int i, n; - - // This is complicated because inheritance in Python is name - // based. We can't just find DeclaredOnly members, because we - // could have a base class A that defines two overloads of a - // method and a class B that defines two more. The name-based - // descriptor Python will find needs to know about inherited - // overloads as well as those declared on the sub class. - - BindingFlags flags = BindingFlags.Static | - BindingFlags.Instance | - BindingFlags.Public | - BindingFlags.NonPublic; - - MemberInfo[] info = type.GetMembers(flags); - Hashtable local = new Hashtable(); - ArrayList items = new ArrayList(); - MemberInfo m; - - // Loop through once to find out which names are declared - for (i = 0; i < info.Length; i++) { - m = info[i]; - if (m.DeclaringType == type) { - local[m.Name] = 1; - } - } - - // Now again to filter w/o losing overloaded member info - for (i = 0; i < info.Length; i++) { - m = info[i]; - if (local[m.Name] != null) { - items.Add(m); - } - } - - if (type.IsInterface) { - // Interface inheritance seems to be a different animal: - // more contractual, less structural. Thus, a Type that - // represents an interface that inherits from another - // interface does not return the inherited interface's - // methods in GetMembers. For example ICollection inherits - // from IEnumerable, but ICollection's GetMemebers does not - // return GetEnumerator. - // - // Not sure if this is the correct way to fix this, but it - // seems to work. Thanks to Bruce Dodson for the fix. - - Type[] inheritedInterfaces = type.GetInterfaces(); - - for (i = 0; i < inheritedInterfaces.Length; ++i) { - Type inheritedType = inheritedInterfaces[i]; - MemberInfo[] imembers = inheritedType.GetMembers(flags); - for (n = 0; n < imembers.Length; n++) { - m = imembers[n]; - if (local[m.Name] == null) { - items.Add(m); - } - } - } - } - - for (i = 0; i < items.Count; i++) { - - MemberInfo mi = (MemberInfo)items[i]; - - switch(mi.MemberType) { - - case MemberTypes.Method: - meth = (MethodInfo) mi; - if (!(meth.IsPublic || meth.IsFamily || - meth.IsFamilyOrAssembly)) - continue; - name = meth.Name; - item = methods[name]; - if (item == null) { - item = methods[name] = new ArrayList(); - } - list = (ArrayList) item; - list.Add(meth); - continue; - - case MemberTypes.Property: - PropertyInfo pi = (PropertyInfo) mi; - - MethodInfo mm = null; - try { - mm = pi.GetGetMethod(true); - if (mm == null) { - mm = pi.GetSetMethod(true); - } - } - catch (SecurityException) { - // GetGetMethod may try to get a method protected by - // StrongNameIdentityPermission - effectively private. - continue; - } - - if (mm == null) { - continue; - } - - if (!(mm.IsPublic || mm.IsFamily || mm.IsFamilyOrAssembly)) - continue; - - // Check for indexer - ParameterInfo[] args = pi.GetIndexParameters(); - if (args.GetLength(0) > 0) { - Indexer idx = ci.indexer; - if (idx == null) { - ci.indexer = new Indexer(); - idx = ci.indexer; - } - idx.AddProperty(pi); - continue; - } - - ob = new PropertyObject(pi); - ci.members[pi.Name] = ob; - continue; - - case MemberTypes.Field: - FieldInfo fi = (FieldInfo) mi; - if (!(fi.IsPublic || fi.IsFamily || fi.IsFamilyOrAssembly)) - continue; - ob = new FieldObject(fi); - ci.members[mi.Name] = ob; - continue; - - case MemberTypes.Event: - EventInfo ei = (EventInfo)mi; - MethodInfo me = ei.GetAddMethod(true); - if (!(me.IsPublic || me.IsFamily || me.IsFamilyOrAssembly)) - continue; - ob = new EventObject(ei); - ci.members[ei.Name] = ob; - continue; - - case MemberTypes.NestedType: - tp = (Type) mi; - if (!(tp.IsNestedPublic || tp.IsNestedFamily || - tp.IsNestedFamORAssem)) - continue; - ob = ClassManager.GetClass(tp); - ci.members[mi.Name] = ob; - continue; - - } - } - - IDictionaryEnumerator iter = methods.GetEnumerator(); - - while(iter.MoveNext()) { - name = (string) iter.Key; - list = (ArrayList) iter.Value; - - MethodInfo[] mlist = (MethodInfo[])list.ToArray( - typeof(MethodInfo) - ); - - ob = new MethodObject(name, mlist); - ci.members[name] = ob; - } - - return ci; - - } - - - } - - - internal class ClassInfo { - - internal ClassInfo(Type t) { - members = new Hashtable(); - indexer = null; - } - - public Hashtable members; - public Indexer indexer; - } - - - -} diff --git a/pythonnet/src/runtime/classobject.cs b/pythonnet/src/runtime/classobject.cs deleted file mode 100755 index 196300dee..000000000 --- a/pythonnet/src/runtime/classobject.cs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2003 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// Managed class that provides the implementation for reflected types. - /// Managed classes and value types are represented in Python by actual - /// Python type objects. Each of those type objects is associated with - /// an instance of ClassObject, which provides its implementation. - /// - - internal class ClassObject : ClassBase { - - ConstructorBinder binder; - - internal ClassObject(Type tp) : base(tp) { - ConstructorInfo[] ctors = type.GetConstructors(); - binder = new ConstructorBinder(); - - for (int i = 0; i < ctors.Length; i++) { - binder.AddMethod(ctors[i]); - } - } - - - //==================================================================== - // Helper to get docstring from reflected constructor info. - //==================================================================== - - internal IntPtr GetDocString() { - MethodBase[] methods = binder.GetMethods(); - string str = ""; - for (int i = 0; i < methods.Length; i++) { - if (str.Length > 0) - str += Environment.NewLine; - str += methods[i].ToString(); - } - return Runtime.PyString_FromString(str); - } - - - //==================================================================== - // Implements __new__ for reflected classes and value types. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - - ClassObject self = GetManagedObject(tp) as ClassObject; - - // Sanity check: this ensures a graceful error if someone does - // something intentially wrong like use the managed metatype for - // a class that is not really derived from a managed class. - - if (self == null) { - return Exceptions.RaiseTypeError("invalid object"); - } - - Type type = self.type; - - // Primitive types do not have constructors, but they look like - // they do from Python. If the ClassObject represents one of the - // convertible primitive types, just convert the arg directly. - - if (type.IsPrimitive || type == typeof(String)) { - if (Runtime.PyTuple_Size(args) != 1) { - Exceptions.SetError(Exceptions.TypeError, - "no constructors match given arguments" - ); - return IntPtr.Zero; - } - - IntPtr op = Runtime.PyTuple_GetItem(args, 0); - Object result; - - if (!Converter.ToManaged(op, type, out result, true)) { - return IntPtr.Zero; - } - - return CLRObject.GetInstHandle(result, tp); - } - - if (type.IsAbstract) { - Exceptions.SetError(Exceptions.TypeError, - "cannot instantiate abstract class" - ); - return IntPtr.Zero; - } - - if (type.IsEnum) { - Exceptions.SetError(Exceptions.TypeError, - "cannot instantiate enumeration" - ); - return IntPtr.Zero; - } - - Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw); - if (obj == null) { - // It is possible for __new__ to be invoked on construction - // of a Python subclass of a managed class, so args may - // reflect more args than are required to instantiate the - // class. So if we cant find a ctor that matches, we'll see - // if there is a default constructor and, if so, assume that - // any extra args are intended for the subclass' __init__. - - IntPtr eargs = Runtime.PyTuple_New(0); - obj = self.binder.InvokeRaw(IntPtr.Zero, eargs, kw); - Runtime.Decref(eargs); - if (obj == null) { - return IntPtr.Zero; - } - } - - return CLRObject.GetInstHandle(obj, tp); - } - - - //==================================================================== - // Implements __getitem__ for reflected classes and value types. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { - ManagedType self = GetManagedObject(ob); - IntPtr tp = Runtime.PyObject_TYPE(ob); - ClassBase cls = (ClassBase)GetManagedObject(tp); - - if (cls.indexer == null || !cls.indexer.CanGet) { - Exceptions.SetError(Exceptions.TypeError, - "unindexable object" - ); - return IntPtr.Zero; - } - - // Arg may be a tuple in the case of an indexer with multiple - // parameters. If so, use it directly, else make a new tuple - // with the index arg (method binders expect arg tuples). - - IntPtr args = idx; - bool free = false; - - if (!Runtime.PyTuple_Check(idx)) { - args = Runtime.PyTuple_New(1); - Runtime.Incref(idx); - Runtime.PyTuple_SetItem(args, 0, idx); - free = true; - } - - IntPtr value = IntPtr.Zero; - - try { - value = cls.indexer.GetItem(ob, args); - } - finally { - if (free) { - Runtime.Decref(args); - } - } - return value; - } - - - //==================================================================== - // Implements __setitem__ for reflected classes and value types. - //==================================================================== - - [CallConvCdecl()] - public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { - ManagedType self = GetManagedObject(ob); - IntPtr tp = Runtime.PyObject_TYPE(ob); - ClassBase cls = (ClassBase)GetManagedObject(tp); - - if (cls.indexer == null || !cls.indexer.CanSet) { - Exceptions.SetError(Exceptions.TypeError, - "object doesn't support item assignment x" - ); - return -1; - } - - // Arg may be a tuple in the case of an indexer with multiple - // parameters. If so, use it directly, else make a new tuple - // with the index arg (method binders expect arg tuples). - - IntPtr args = idx; - bool free = false; - - if (!Runtime.PyTuple_Check(idx)) { - args = Runtime.PyTuple_New(1); - Runtime.Incref(idx); - Runtime.PyTuple_SetItem(args, 0, idx); - free = true; - } - - int i = Runtime.PyTuple_Size(args); - IntPtr real = Runtime.PyTuple_New(i + 1); - for (int n = 0; n < i; n++) { - IntPtr item = Runtime.PyTuple_GetItem(args, n); - Runtime.Incref(item); - Runtime.PyTuple_SetItem(real, n, item); - } - Runtime.Incref(v); - Runtime.PyTuple_SetItem(real, i, v); - - try { - cls.indexer.SetItem(ob, real); - } - finally { - Runtime.Decref(real); - - if (free) { - Runtime.Decref(args); - } - } - - if (Exceptions.ErrorOccurred()) { - return -1; - } - - return 0; - } - - - //==================================================================== - // This is a hack. Generally, no managed class is considered callable - // from Python - with the exception of System.Delegate. It is useful - // to be able to call a System.Delegate instance directly, especially - // when working with multicast delegates. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - ManagedType self = GetManagedObject(ob); - IntPtr tp = Runtime.PyObject_TYPE(ob); - ClassBase cb = (ClassBase)GetManagedObject(tp); - - if (cb.type != typeof(System.Delegate)) { - Exceptions.SetError(Exceptions.TypeError, - "object is not callable"); - return IntPtr.Zero; - } - - CLRObject co = (CLRObject)ManagedType.GetManagedObject(ob); - Delegate d = co.inst as Delegate; - BindingFlags flags = BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.Static; - - MethodInfo method = d.GetType().GetMethod("Invoke", flags); - MethodBinder binder = new MethodBinder(method); - return binder.Invoke(ob, args, kw); - } - - - } - -} diff --git a/pythonnet/src/runtime/clrmodule.il b/pythonnet/src/runtime/clrmodule.il deleted file mode 100755 index 0f148cec6..000000000 --- a/pythonnet/src/runtime/clrmodule.il +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2003 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -//============================================================================ -// This file is a hand-maintained stub - it implements CLR.dll, which can be -// loaded by a standard CPython interpreter as an extension module. When it -// is loaded, it bootstraps the managed runtime integration layer and defers -// to it do initialization and put the CLR module into sys.modules, etc. -//============================================================================ - -.assembly extern mscorlib -{ - .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) - .ver 1:0:5000:0 -} -.assembly extern Python.Runtime -{ - .ver 1:0:0:0 -} -.assembly CLR -{ - // --- The following custom attribute is added automatically, do not uncomment ------- - // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool, - // bool) = ( 01 00 00 01 00 00 ) - .hash algorithm 0x00008004 - .ver 0:0:0:0 -} - -.module CLR.dll -// MVID: {01BEB897-1638-4D9D-B01C-3638714A76B4} -.imagebase 0x00400000 -.subsystem 0x00000003 -.file alignment 512 -.corflags 0x00000002 - -.vtfixup [1] int32 fromunmanaged at VT_01 -.data VT_01 = int32(0) - - -.class public auto ansi beforefieldinit CLRModule - extends [mscorlib]System.Object -{ -} // end of class CLRModule - - - -.class public auto ansi beforefieldinit CLRModule - extends [mscorlib]System.Object -{ - .method public hidebysig static void - modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) - initCLR() cil managed - { - .vtentry 1:1 - .export [1] as initCLR - - // Code size 8 (0x8) - .maxstack 0 - IL_0000: call void [Python.Runtime]Python.Runtime.PythonEngine::InitExt() - IL_0005: br.s IL_0007 - - IL_0007: ret - } // end of method CLRModule::initCLR - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 1 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method CLRModule::.ctor - -} // end of class CLRModule - - diff --git a/pythonnet/src/runtime/clrobject.cs b/pythonnet/src/runtime/clrobject.cs deleted file mode 100755 index 8ed9a4b8e..000000000 --- a/pythonnet/src/runtime/clrobject.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - - internal class CLRObject : ManagedType { - - internal Object inst; - - internal CLRObject(Object ob, IntPtr tp) : base() { - - IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); - - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); - if ((flags & TypeFlags.Subclass) != 0) { - IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.ob_dict); - if (dict == IntPtr.Zero) { - dict = Runtime.PyDict_New(); - Marshal.WriteIntPtr(py, ObjectOffset.ob_dict, dict); - } - } - - GCHandle gc = GCHandle.Alloc(this); - Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc); - this.tpHandle = tp; - this.pyHandle = py; - this.gcHandle = gc; - inst = ob; - - //DebugUtil.DumpInst(py); - - } - - - internal static CLRObject GetInstance(Object ob, IntPtr pyType) { - return new CLRObject(ob, pyType); - } - - - internal static CLRObject GetInstance(Object ob) { - ClassBase cc = ClassManager.GetClass(ob.GetType()); - return GetInstance(ob, cc.tpHandle); - } - - - internal static IntPtr GetInstHandle(Object ob, IntPtr pyType) { - CLRObject co = GetInstance(ob, pyType); - return co.pyHandle; - } - - - internal static IntPtr GetInstHandle(Object ob, Type type) { - ClassBase cc = ClassManager.GetClass(type); - CLRObject co = GetInstance(ob, cc.tpHandle); - return co.pyHandle; - } - - - internal static IntPtr GetInstHandle(Object ob) { - CLRObject co = GetInstance(ob); - return co.pyHandle; - } - - - } - - -} - diff --git a/pythonnet/src/runtime/codegenerator.cs b/pythonnet/src/runtime/codegenerator.cs deleted file mode 100755 index b8458dbe8..000000000 --- a/pythonnet/src/runtime/codegenerator.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Threading; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Collections; -using System.Reflection; -using System.Reflection.Emit; - -namespace Python.Runtime { - - /// - /// Several places in the runtime generate code on the fly to support - /// dynamic functionality. The CodeGenerator class manages the dynamic - /// assembly used for code generation and provides utility methods for - /// certain repetitive tasks. - /// - - internal class CodeGenerator { - - static AssemblyBuilder aBuilder; - static ModuleBuilder mBuilder; - - static CodeGenerator() { - AssemblyName aname = new AssemblyName(); - aname.Name = "__CodeGenerator_Assembly"; - AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run; - - aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); - mBuilder = aBuilder.DefineDynamicModule("__CodeGenerator_Module"); - - } - - //==================================================================== - // DefineType is a shortcut utility to get a new TypeBuilder. - //==================================================================== - - internal static TypeBuilder DefineType(string name) { - TypeAttributes attrs = TypeAttributes.Public; - return mBuilder.DefineType(name, attrs); - } - - //==================================================================== - // DefineType is a shortcut utility to get a new TypeBuilder. - //==================================================================== - - internal static TypeBuilder DefineType(string name, Type basetype) { - TypeAttributes attrs = TypeAttributes.Public; - return mBuilder.DefineType(name, attrs, basetype); - } - - } - - -} diff --git a/pythonnet/src/runtime/constructorbinder.cs b/pythonnet/src/runtime/constructorbinder.cs deleted file mode 100755 index 39f9cb316..000000000 --- a/pythonnet/src/runtime/constructorbinder.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2003 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // A ConstructorBinder encapsulates information about one or more managed - // constructors, and is responsible for selecting the right constructor - // given a set of Python arguments. This is slightly different than the - // standard MethodBinder because of a difference in invoking constructors - // using reflection (which is seems to be a CLR bug). - //======================================================================== - - internal class ConstructorBinder : MethodBinder { - - internal ConstructorBinder () : base() {} - - //==================================================================== - // Constructors get invoked when an instance of a wrapped managed - // class or a subclass of a managed class is created. This differs - // from the MethodBinder implementation in that we return the raw - // result of the constructor rather than wrapping it as a Python - // object - the reason is that only the caller knows the correct - // Python type to use when wrapping the result (may be a subclass). - //==================================================================== - - internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) { - Binding binding = this.Bind(inst, args, kw); - Object result; - - if (binding == null) { - Exceptions.SetError(Exceptions.TypeError, - "no constructor matches given arguments" - ); - return null; - } - - // Object construction is presumed to be non-blocking and fast - // enough that we shouldn't really need to release the GIL. - - ConstructorInfo ci = (ConstructorInfo)binding.info; - try { - result = ci.Invoke(binding.args); - } - catch (Exception e) { - if (e.InnerException != null) { - e = e.InnerException; - } - Exceptions.SetError(e); - return null; - } - - return result; - } - - - } - - -} diff --git a/pythonnet/src/runtime/converter.cs b/pythonnet/src/runtime/converter.cs deleted file mode 100755 index 30cf412c3..000000000 --- a/pythonnet/src/runtime/converter.cs +++ /dev/null @@ -1,668 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Globalization; -using System.Security; - -namespace Python.Runtime { - - //======================================================================== - // Performs data conversions between managed types and Python types. - //======================================================================== - - [SuppressUnmanagedCodeSecurityAttribute()] - - internal class Converter { - - private Converter() {} - - static NumberFormatInfo nfi; - static Type objectType; - static Type stringType; - static Type int32Type; - static Type int64Type; - static Type flagsType; - static Type boolType; - static Type typeType; - - static Converter () { - nfi = NumberFormatInfo.InvariantInfo; - objectType = typeof(Object); - stringType = typeof(String); - int32Type = typeof(Int32); - int64Type = typeof(Int64); - flagsType = typeof(FlagsAttribute); - boolType = typeof(Boolean); - typeType = typeof(Type); - } - - - //==================================================================== - // Return a Python object for the given native object, converting - // basic types (string, int, etc.) into equivalent Python objects. - // This always returns a new reference. Note that the System.Decimal - // type has no Python equivalent and converts to a managed instance. - //==================================================================== - - internal static IntPtr ToPython(Object value, Type type) { - IntPtr result = IntPtr.Zero; - - // Null always converts to None in Python. - - if (value == null) { - result = Runtime.PyNone; - Runtime.Incref(result); - return result; - } - - // hmm - from Python, we almost never care what the declared - // type is. we'd rather have the object bound to the actual - // implementing class. - - type = value.GetType(); - - TypeCode tc = Type.GetTypeCode(type); - - switch(tc) { - - case TypeCode.Object: - result = CLRObject.GetInstHandle(value, type); - - // XXX - hack to make sure we convert new-style class based - // managed exception instances to wrappers ;( - if (Runtime.wrap_exceptions) { - Exception e = value as Exception; - if (e != null) { - return Exceptions.GetExceptionInstanceWrapper(result); - } - } - - return result; - - case TypeCode.String: - return Runtime.PyUnicode_FromString((string)value); - - case TypeCode.Int32: - return Runtime.PyInt_FromInt32((int)value); - - case TypeCode.Boolean: - if ((bool)value) { - Runtime.Incref(Runtime.PyTrue); - return Runtime.PyTrue; - } - Runtime.Incref(Runtime.PyFalse); - return Runtime.PyFalse; - - case TypeCode.Byte: - return Runtime.PyInt_FromInt32((int)((byte)value)); - - case TypeCode.Char: - return Runtime.PyUnicode_FromOrdinal((int)((char)value)); - - case TypeCode.Int16: - return Runtime.PyInt_FromInt32((int)((short)value)); - - case TypeCode.Int64: - return Runtime.PyLong_FromLongLong((long)value); - - case TypeCode.Single: - // return Runtime.PyFloat_FromDouble((double)((float)value)); - string ss = ((float)value).ToString(nfi); - IntPtr ps = Runtime.PyString_FromString(ss); - IntPtr op = Runtime.PyFloat_FromString(ps, IntPtr.Zero); - Runtime.Decref(ps); - return op; - - case TypeCode.Double: - return Runtime.PyFloat_FromDouble((double)value); - - case TypeCode.SByte: - return Runtime.PyInt_FromInt32((int)((sbyte)value)); - - case TypeCode.UInt16: - return Runtime.PyInt_FromInt32((int)((ushort)value)); - - case TypeCode.UInt32: - return Runtime.PyLong_FromUnsignedLong((uint)value); - - case TypeCode.UInt64: - return Runtime.PyLong_FromUnsignedLongLong((ulong)value); - - default: - result = CLRObject.GetInstHandle(value, type); - return result; - } - - } - - - //==================================================================== - // In a few situations, we don't have any advisory type information - // when we want to convert an object to Python. - //==================================================================== - - internal static IntPtr ToPythonImplicit(Object value) { - if (value == null) { - IntPtr result = Runtime.PyNone; - Runtime.Incref(result); - return result; - } - - return ToPython(value, objectType); - } - - - //==================================================================== - // Return a managed object for the given Python object, taking funny - // byref types into account. - //==================================================================== - - internal static bool ToManaged(IntPtr value, Type type, - out object result, bool setError) { - if (type.IsByRef) { - type = type.GetElementType(); - } - return Converter.ToManagedValue(value, type, out result, setError); - } - - - internal static bool ToManagedValue(IntPtr value, Type obType, - out Object result, bool setError) { - - // Common case: if the Python value is a wrapped managed object - // instance, just return the wrapped object. - ManagedType mt = ManagedType.GetManagedObject(value); - result = null; - - // XXX - hack to support objects wrapped in old-style classes - // (such as exception objects). - if (Runtime.wrap_exceptions) { - if (mt == null) { - if (Runtime.PyObject_IsInstance( - value, Exceptions.Exception - ) > 0) { - IntPtr p = Runtime.PyObject_GetAttrString(value, "_inner"); - if (p != IntPtr.Zero) { - // This is safe because we know that the __dict__ of - // value holds a reference to _inner. - value = p; - Runtime.Decref(p); - mt = ManagedType.GetManagedObject(value); - } - } - } - } - - if (mt != null) { - if (mt is CLRObject) { - object tmp = ((CLRObject)mt).inst; - if (obType.IsInstanceOfType(tmp)) { - result = tmp; - return true; - } - string err = "value cannot be converted to {0}"; - err = String.Format(err, obType); - Exceptions.SetError(Exceptions.TypeError, err); - return false; - } - if (mt is ClassBase) { - result = ((ClassBase)mt).type; - return true; - } - // shouldnt happen - return false; - } - - if (value == Runtime.PyNone && !obType.IsValueType) { - result = null; - return true; - } - - if (obType.IsArray) { - return ToArray(value, obType, out result, setError); - } - - if (obType.IsEnum) { - return ToEnum(value, obType, out result, setError); - } - - // Conversion to 'Object' is done based on some reasonable - // default conversions (Python string -> managed string, - // Python int -> Int32 etc.). - - if (obType == objectType) { - if (Runtime.IsStringType(value)) { - return ToPrimitive(value, stringType, out result, - setError); - } - - else if (Runtime.PyBool_Check(value)) { - return ToPrimitive(value, boolType, out result, setError); - } - - else if (Runtime.PyInt_Check(value)) { - return ToPrimitive(value, int32Type, out result, setError); - } - - else if (Runtime.PyLong_Check(value)) { - return ToPrimitive(value, int64Type, out result, setError); - } - - else if (Runtime.PySequence_Check(value)) { - return ToArray(value, typeof(object[]), out result, - setError); - } - - if (setError) { - Exceptions.SetError(Exceptions.TypeError, - "value cannot be converted to Object" - ); - } - - return false; - } - - return ToPrimitive(value, obType, out result, setError); - - } - - //==================================================================== - // Convert a Python value to an instance of a primitive managed type. - //==================================================================== - - static bool ToPrimitive(IntPtr value, Type obType, out Object result, - bool setError) { - - IntPtr overflow = Exceptions.OverflowError; - TypeCode tc = Type.GetTypeCode(obType); - result = null; - IntPtr op; - int ival; - - switch(tc) { - - case TypeCode.String: - string st = Runtime.GetManagedString(value); - if (st == null) { - goto type_error; - } - result = st; - return true; - - case TypeCode.Int32: - // Trickery to support 64-bit platforms. - if (IntPtr.Size == 4) { - op = Runtime.PyNumber_Int(value); - - // As of Python 2.3, large ints magically convert :( - if (Runtime.PyLong_Check(op) ) { - Runtime.Decref(op); - goto overflow; - } - - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - ival = (int)Runtime.PyInt_AsLong(op); - Runtime.Decref(op); - result = ival; - return true; - } - else { - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - long ll = (long)Runtime.PyLong_AsLongLong(op); - Runtime.Decref(op); - if ((ll == -1) && Exceptions.ErrorOccurred()) { - goto overflow; - } - if (ll > Int32.MaxValue || ll < Int32.MinValue) { - goto overflow; - } - result = (int)ll; - return true; - } - - case TypeCode.Boolean: - result = (Runtime.PyObject_IsTrue(value) != 0); - return true; - - case TypeCode.Byte: - if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { - if (Runtime.PyString_Size(value) == 1) { - op = Runtime.PyString_AS_STRING(value); - result = (byte)Marshal.ReadByte(op); - return true; - } - goto type_error; - } - - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - ival = (int) Runtime.PyInt_AsLong(op); - Runtime.Decref(op); - - if (ival > Byte.MaxValue || ival < Byte.MinValue) { - goto overflow; - } - byte b = (byte) ival; - result = b; - return true; - - case TypeCode.SByte: - if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { - if (Runtime.PyString_Size(value) == 1) { - op = Runtime.PyString_AS_STRING(value); - result = (sbyte)Marshal.ReadByte(op); - return true; - } - goto type_error; - } - - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - ival = (int) Runtime.PyInt_AsLong(op); - Runtime.Decref(op); - - if (ival > SByte.MaxValue || ival < SByte.MinValue) { - goto overflow; - } - sbyte sb = (sbyte) ival; - result = sb; - return true; - - case TypeCode.Char: - - if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { - if (Runtime.PyString_Size(value) == 1) { - op = Runtime.PyString_AS_STRING(value); - result = (char)Marshal.ReadByte(op); - return true; - } - goto type_error; - } - - else if (Runtime.PyObject_TypeCheck(value, - Runtime.PyUnicodeType)) { - if (Runtime.PyUnicode_GetSize(value) == 1) { - op = Runtime.PyUnicode_AS_UNICODE(value); - result = (char)Marshal.ReadInt16(op); - return true; - } - goto type_error; - } - - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) { - goto type_error; - } - ival = Runtime.PyInt_AsLong(op); - if (ival > Char.MaxValue || ival < Char.MinValue) { - goto overflow; - } - Runtime.Decref(op); - result = (char)ival; - return true; - - case TypeCode.Int16: - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - ival = (int) Runtime.PyInt_AsLong(op); - Runtime.Decref(op); - if (ival > Int16.MaxValue || ival < Int16.MinValue) { - goto overflow; - } - short s = (short) ival; - result = s; - return true; - - case TypeCode.Int64: - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - long l = (long)Runtime.PyLong_AsLongLong(op); - Runtime.Decref(op); - if ((l == -1) && Exceptions.ErrorOccurred()) { - goto overflow; - } - result = l; - return true; - - case TypeCode.UInt16: - op = Runtime.PyNumber_Int(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - ival = (int) Runtime.PyInt_AsLong(op); - Runtime.Decref(op); - if (ival > UInt16.MaxValue || ival < UInt16.MinValue) { - goto overflow; - } - ushort us = (ushort) ival; - result = us; - return true; - - case TypeCode.UInt32: - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op); - Runtime.Decref(op); - if (Exceptions.ErrorOccurred()) { - goto overflow; - } - result = ui; - return true; - - case TypeCode.UInt64: - op = Runtime.PyNumber_Long(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - ulong ul = (ulong)Runtime.PyLong_AsUnsignedLongLong(op); - Runtime.Decref(op); - if (Exceptions.ErrorOccurred()) { - goto overflow; - } - result = ul; - return true; - - - case TypeCode.Single: - op = Runtime.PyNumber_Float(value); - if (op == IntPtr.Zero) { - if (Exceptions.ExceptionMatches(overflow)) { - goto overflow; - } - goto type_error; - } - double dd = Runtime.PyFloat_AsDouble(value); - if (dd > Single.MaxValue || dd < Single.MinValue) { - goto overflow; - } - result = (float)dd; - return true; - - case TypeCode.Double: - op = Runtime.PyNumber_Float(value); - if (op == IntPtr.Zero) { - goto type_error; - } - double d = Runtime.PyFloat_AsDouble(op); - Runtime.Decref(op); - if (d > Double.MaxValue || d < Double.MinValue) { - goto overflow; - } - result = d; - return true; - - } - - - type_error: - - if (setError) { - string format = "'{0}' value cannot be converted to {1}"; - string tpName = Runtime.PyObject_GetTypeName(value); - string error = String.Format(format, tpName, obType); - Exceptions.SetError(Exceptions.TypeError, error); - } - - return false; - - overflow: - - if (setError) { - string error = "value too large to convert"; - Exceptions.SetError(Exceptions.OverflowError, error); - } - - return false; - - } - - - static void SetConversionError(IntPtr value, Type target) { - IntPtr ob = Runtime.PyObject_Repr(value); - string src = Runtime.GetManagedString(ob); - Runtime.Decref(ob); - string error = String.Format( - "Cannot convert {0} to {1}", src, target - ); - Exceptions.SetError(Exceptions.TypeError, error); - } - - - //==================================================================== - // Convert a Python value to a correctly typed managed array instance. - // The Python value must support the Python sequence protocol and the - // items in the sequence must be convertible to the target array type. - //==================================================================== - - static bool ToArray(IntPtr value, Type obType, out Object result, - bool setError) { - - Type elementType = obType.GetElementType(); - int size = Runtime.PySequence_Size(value); - result = null; - - if (size < 0) { - if (setError) { - SetConversionError(value, obType); - } - return false; - } - - Array items = Array.CreateInstance(elementType, size); - - for (int i = 0; i < size; i++) { - Object obj = null; - IntPtr item = Runtime.PySequence_GetItem(value, i); - if (item == IntPtr.Zero) { - if (setError) { - SetConversionError(value, obType); - return false; - } - } - - if (!Converter.ToManaged(item, elementType, out obj, true)) { - Runtime.Decref(item); - return false; - } - - items.SetValue(obj, i); - Runtime.Decref(item); - } - - result = items; - return true; - } - - - //==================================================================== - // Convert a Python value to a correctly typed managed enum instance. - //==================================================================== - - static bool ToEnum(IntPtr value, Type obType, out Object result, - bool setError) { - - Type etype = Enum.GetUnderlyingType(obType); - result = null; - - if (!ToPrimitive(value, etype, out result, setError)) { - return false; - } - - if (Enum.IsDefined(obType, result)) { - result = Enum.ToObject(obType, result); - return true; - } - - if (obType.GetCustomAttributes(flagsType, true).Length > 0) { - result = Enum.ToObject(obType, result); - return true; - } - - if (setError) { - string error = "invalid enumeration value"; - Exceptions.SetError(Exceptions.ValueError, error); - } - - return false; - - } - - - - } - - -} diff --git a/pythonnet/src/runtime/debughelper.cs b/pythonnet/src/runtime/debughelper.cs deleted file mode 100755 index 5c016a147..000000000 --- a/pythonnet/src/runtime/debughelper.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Diagnostics; -using System.Threading; - -namespace Python.Runtime { - - /// - /// Debugging helper utilities. - /// - - internal class DebugUtil { - - - - public static void Print(string msg, params IntPtr[] args) { - string result = msg; - result += " "; - - for (int i = 0; i < args.Length; i++) { - if (args[i] == IntPtr.Zero) { - Console.WriteLine("null arg to print"); - } - IntPtr ob = Runtime.PyObject_Repr(args[i]); - result += Runtime.GetManagedString(ob); - Runtime.Decref(ob); - result += " "; - } - Console.WriteLine(result); - return; - } - - - internal static void DumpType(IntPtr type) { - IntPtr op = Marshal.ReadIntPtr(type, TypeOffset.tp_name); - string name = Marshal.PtrToStringAnsi(op); - - Console.WriteLine("Dump type: {0}", name); - - op = Marshal.ReadIntPtr(type, TypeOffset.ob_type); - DebugUtil.Print(" type: ", op); - - op = Marshal.ReadIntPtr(type, TypeOffset.tp_base); - DebugUtil.Print(" base: ", op); - - op = Marshal.ReadIntPtr(type, TypeOffset.tp_bases); - DebugUtil.Print(" bases: ", op); - - //op = Marshal.ReadIntPtr(type, TypeOffset.tp_mro); - //DebugUtil.Print(" mro: ", op); - - - FieldInfo[] slots = typeof(TypeOffset).GetFields(); - int size = IntPtr.Size; - - for (int i = 0; i < slots.Length; i++) { - int offset = i * size; - name = slots[i].Name; - op = Marshal.ReadIntPtr(type, offset); - Console.WriteLine(" {0}: {1}", name, op); - } - - Console.WriteLine(""); - Console.WriteLine(""); - - op = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - if (op == IntPtr.Zero) { - Console.WriteLine(" dict: null"); - } - else { - DebugUtil.Print(" dict: ", op); - } - - } - - - internal static void DumpInst(IntPtr ob) { - IntPtr tp = Runtime.PyObject_TYPE(ob); - int sz = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_basicsize); - - for (int i = 0; i < sz; i += IntPtr.Size) { - IntPtr pp = new IntPtr(ob.ToInt64() + i); - IntPtr v = Marshal.ReadIntPtr(pp); - Console.WriteLine("offset {0}: {1}", i, v); - } - - Console.WriteLine(""); - Console.WriteLine(""); - } - - - internal static void debug(string msg) { - StackTrace st = new StackTrace(1, true); - StackFrame sf = st.GetFrame(0); - MethodBase mb = sf.GetMethod(); - Type mt = mb.DeclaringType; - string caller = mt.Name + "." + sf.GetMethod().Name; - Thread t = Thread.CurrentThread; - string tid = t.GetHashCode().ToString(); - Console.WriteLine("thread {0} : {1}", tid, caller); - Console.WriteLine(" {0}", msg); - return; - } - - - } - - -} - diff --git a/pythonnet/src/runtime/delegatemanager.cs b/pythonnet/src/runtime/delegatemanager.cs deleted file mode 100755 index 870c41bdd..000000000 --- a/pythonnet/src/runtime/delegatemanager.cs +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Threading; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; -using System.Collections; -using System.Reflection; -using System.Reflection.Emit; - -namespace Python.Runtime { - - /// - /// The DelegateManager class manages the creation of true managed - /// delegate instances that dispatch calls to Python methods. - /// - - internal class DelegateManager { - - static Hashtable cache; - static Type basetype; - static Type listtype; - static Type voidtype; - static Type typetype; - static Type ptrtype; - - static DelegateManager() { - basetype = typeof(Dispatcher); - listtype = typeof(ArrayList); - voidtype = typeof(void); - typetype = typeof(Type); - ptrtype = typeof(IntPtr); - cache = new Hashtable(); - } - - //==================================================================== - // Given a true delegate instance, return the PyObject handle of the - // Python object implementing the delegate (or IntPtr.Zero if the - // delegate is not implemented in Python code. - //==================================================================== - - public static IntPtr GetPythonHandle(Delegate d) { - if ((d != null) && (d.Target is Dispatcher)) { - Dispatcher disp = d.Target as Dispatcher; - return disp.target; - } - return IntPtr.Zero; - } - - //==================================================================== - // GetDispatcher is responsible for creating a class that provides - // an appropriate managed callback method for a given delegate type. - //==================================================================== - - private static Type GetDispatcher(Type dtype) { - - // If a dispatcher type for the given delegate type has already - // been generated, get it from the cache. The cache maps delegate - // types to generated dispatcher types. A possible optimization - // for the future would be to generate dispatcher types based on - // unique signatures rather than delegate types, since multiple - // delegate types with the same sig could use the same dispatcher. - - Object item = cache[dtype]; - if (item != null) { - return (Type)item; - } - - string name = "__" + dtype.FullName + "Dispatcher"; - name = name.Replace('.', '_'); - name = name.Replace('+', '_'); - TypeBuilder tb = CodeGenerator.DefineType(name, basetype); - - // Generate a constructor for the generated type that calls the - // appropriate constructor of the Dispatcher base type. - - MethodAttributes ma = MethodAttributes.Public | - MethodAttributes.HideBySig | - MethodAttributes.SpecialName | - MethodAttributes.RTSpecialName; - CallingConventions cc = CallingConventions.Standard; - Type[] args = {ptrtype, typetype}; - ConstructorBuilder cb = tb.DefineConstructor(ma, cc, args); - ConstructorInfo ci = basetype.GetConstructor(args); - ILGenerator il = cb.GetILGenerator(); - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - il.Emit(OpCodes.Ldarg_2); - il.Emit(OpCodes.Call, ci); - il.Emit(OpCodes.Ret); - - // Method generation: we generate a method named "Invoke" on the - // dispatcher type, whose signature matches the delegate type for - // which it is generated. The method body simply packages the - // arguments and hands them to the Dispatch() method, which deals - // with converting the arguments, calling the Python method and - // converting the result of the call. - - MethodInfo method = dtype.GetMethod("Invoke"); - ParameterInfo[] pi = method.GetParameters(); - - Type[] signature = new Type[pi.Length]; - for (int i = 0; i < pi.Length; i++) { - signature[i] = pi[i].ParameterType; - } - - MethodBuilder mb = tb.DefineMethod( - "Invoke", - MethodAttributes.Public, - method.ReturnType, - signature - ); - - ConstructorInfo ctor = listtype.GetConstructor(Type.EmptyTypes); - MethodInfo dispatch = basetype.GetMethod("Dispatch"); - MethodInfo add = listtype.GetMethod("Add"); - - il = mb.GetILGenerator(); - il.DeclareLocal(listtype); - il.Emit(OpCodes.Newobj, ctor); - il.Emit(OpCodes.Stloc_0); - - for (int c = 0; c < signature.Length; c++) { - Type t = signature[c]; - il.Emit(OpCodes.Ldloc_0); - il.Emit(OpCodes.Ldarg_S, (byte)(c + 1)); - - if (t.IsValueType) { - il.Emit(OpCodes.Box, t); - } - - il.Emit(OpCodes.Callvirt, add); - il.Emit(OpCodes.Pop); - } - - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldloc_0); - il.Emit(OpCodes.Call, dispatch); - - if (method.ReturnType == voidtype) { - il.Emit(OpCodes.Pop); - } - - il.Emit(OpCodes.Ret); - - Type disp = tb.CreateType(); - cache[dtype] = disp; - return disp; - } - - //==================================================================== - // Given a delegate type and a callable Python object, GetDelegate - // returns an instance of the delegate type. The delegate instance - // returned will dispatch calls to the given Python object. - //==================================================================== - - internal static Delegate GetDelegate(Type dtype, IntPtr callable) { - Type dispatcher = GetDispatcher(dtype); - object[] args = {callable, dtype}; - object o = Activator.CreateInstance(dispatcher, args); - return Delegate.CreateDelegate(dtype, o, "Invoke"); - } - - - - } - - - /* When a delegate instance is created that has a Python implementation, - the delegate manager generates a custom subclass of Dispatcher and - instantiates it, passing the IntPtr of the Python callable. - - The "real" delegate is created using CreateDelegate, passing the - instance of the generated type and the name of the (generated) - implementing method (Invoke). - - The true delegate instance holds the only reference to the dispatcher - instance, which ensures that when the delegate dies, the finalizer - of the referenced instance will be able to decref the Python - callable. - - A possible alternate strategy would be to create custom subclasses - of the required delegate type, storing the IntPtr in it directly. - This would be slightly cleaner, but I'm not sure if delegates are - too "special" for this to work. It would be more work, so for now - the 80/20 rule applies :) - - */ - - public class Dispatcher { - - public IntPtr target; - public Type dtype; - - public Dispatcher(IntPtr target, Type dtype) { - Runtime.Incref(target); - this.target = target; - this.dtype = dtype; - } - - ~Dispatcher() { - // Note: the managed GC thread can run and try to free one of - // these *after* the Python runtime has been finalized! - if (Runtime.Py_IsInitialized() > 0) { - IntPtr gs = PythonEngine.AcquireLock(); - Runtime.Decref(target); - PythonEngine.ReleaseLock(gs); - } - } - - public object Dispatch(ArrayList args) { - IntPtr gs = PythonEngine.AcquireLock(); - object ob = null; - - try { - ob = TrueDispatch(args); - } - catch (Exception e) { - PythonEngine.ReleaseLock(gs); - throw e; - } - - PythonEngine.ReleaseLock(gs); - return ob; - } - - public object TrueDispatch(ArrayList args) { - MethodInfo method = dtype.GetMethod("Invoke"); - ParameterInfo[] pi = method.GetParameters(); - IntPtr pyargs = Runtime.PyTuple_New(pi.Length); - Type rtype = method.ReturnType; - - for (int i = 0; i < pi.Length; i++) { - // Here we own the reference to the Python value, and we - // give the ownership to the arg tuple. - IntPtr arg = Converter.ToPython(args[i], pi[i].ParameterType); - int r = Runtime.PyTuple_SetItem(pyargs, i, arg); - } - - IntPtr op = Runtime.PyObject_Call(target, pyargs, IntPtr.Zero); - Runtime.Decref(pyargs); - - if (op == IntPtr.Zero) { - PythonException e = new PythonException(); - throw e; - } - - if (rtype == typeof(void)) { - return null; - } - - Object result = null; - if (!Converter.ToManaged(op, rtype, out result, false)) { - string s = "could not convert Python result to " + - rtype.ToString(); - Runtime.Decref(op); - throw new ConversionException(s); - } - - Runtime.Decref(op); - return result; - } - - - } - - - public class ConversionException : System.Exception { - - public ConversionException() : base() {} - - public ConversionException(string msg) : base(msg) {} - - } - - -} diff --git a/pythonnet/src/runtime/delegateobject.cs b/pythonnet/src/runtime/delegateobject.cs deleted file mode 100755 index 50c4620a9..000000000 --- a/pythonnet/src/runtime/delegateobject.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) 2003 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Reflection; - -namespace Python.Runtime { - - /// - /// Managed class that provides the implementation for reflected delegate - /// types. Delegates are represented in Python by generated type objects. - /// Each of those type objects is associated an instance of this class, - /// which provides its implementation. - /// - - internal class DelegateObject : ClassBase { - - MethodBinder binder; - - internal DelegateObject(Type tp) : base(tp) { - binder = new MethodBinder(tp.GetMethod("Invoke")); - } - - - //==================================================================== - // Given a PyObject pointer to an instance of a delegate type, return - // the true managed delegate the Python object represents (or null). - //==================================================================== - - private static Delegate GetTrueDelegate(IntPtr op) { - CLRObject o = GetManagedObject(op) as CLRObject; - if (o != null) { - Delegate d = o.inst as Delegate; - return d; - } - return null; - } - - - internal override bool CanSubclass() { - return false; - } - - - //==================================================================== - // DelegateObject __new__ implementation. The result of this is a new - // PyObject whose type is DelegateObject and whose ob_data is a handle - // to an actual delegate instance. The method wrapped by the actual - // delegate instance belongs to an object generated to relay the call - // to the Python callable passed in. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - DelegateObject self = (DelegateObject)GetManagedObject(tp); - - if (Runtime.PyTuple_Size(args) != 1) { - string message = "class takes exactly one argument"; - return Exceptions.RaiseTypeError(message); - } - - IntPtr method = Runtime.PyTuple_GetItem(args, 0); - - if (Runtime.PyCallable_Check(method) != 1) { - return Exceptions.RaiseTypeError("argument must be callable"); - } - - Delegate d = DelegateManager.GetDelegate(self.type, method); - return CLRObject.GetInstHandle(d, self.pyHandle); - } - - - - //==================================================================== - // Implements __call__ for reflected delegate types. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - // todo: add fast type check! - IntPtr pytype = Runtime.PyObject_TYPE(ob); - DelegateObject self = (DelegateObject)GetManagedObject(pytype); - CLRObject o = GetManagedObject(ob) as CLRObject; - - if (o == null) { - return Exceptions.RaiseTypeError("invalid argument"); - } - - Delegate d = o.inst as Delegate; - - if (d == null) { - return Exceptions.RaiseTypeError("invalid argument"); - } - - return self.binder.Invoke(ob, args, kw); - } - - - //==================================================================== - // Implements __cmp__ for reflected delegate types. - //==================================================================== - - [CallConvCdecl()] - public static new int tp_compare(IntPtr ob, IntPtr other) { - Delegate d1 = GetTrueDelegate(ob); - Delegate d2 = GetTrueDelegate(other); - if (d1 == d2) { - return 0; - } - return -1; - } - - - } - - -} diff --git a/pythonnet/src/runtime/eventbinding.cs b/pythonnet/src/runtime/eventbinding.cs deleted file mode 100755 index 98a386470..000000000 --- a/pythonnet/src/runtime/eventbinding.cs +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - //======================================================================== - // Implements a Python event binding type, similar to a method binding. - //======================================================================== - - internal class EventBinding : ExtensionType { - - EventObject e; - IntPtr target; - - public EventBinding(EventObject e, IntPtr target) : base() { - Runtime.Incref(target); - this.target = target; - this.e = e; - } - - - //==================================================================== - // EventBinding += operator implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr nb_inplace_add(IntPtr ob, IntPtr arg) { - EventBinding self = (EventBinding)GetManagedObject(ob); - - if (Runtime.PyCallable_Check(arg) < 1) { - Exceptions.SetError(Exceptions.TypeError, - "event handlers must be callable" - ); - return IntPtr.Zero; - } - - if(!self.e.AddEventHandler(self.target, arg)) { - return IntPtr.Zero; - } - - Runtime.Incref(self.pyHandle); - return self.pyHandle; - } - - - //==================================================================== - // EventBinding -= operator implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr nb_inplace_subtract(IntPtr ob, IntPtr arg) { - EventBinding self = (EventBinding)GetManagedObject(ob); - - if (Runtime.PyCallable_Check(arg) < 1) { - Exceptions.SetError(Exceptions.TypeError, - "invalid event handler" - ); - return IntPtr.Zero; - } - - if (!self.e.RemoveEventHandler(self.target, arg)) { - return IntPtr.Zero; - } - - Runtime.Incref(self.pyHandle); - return self.pyHandle; - } - - - //==================================================================== - // EventBinding __hash__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_hash(IntPtr ob) { - EventBinding self = (EventBinding)GetManagedObject(ob); - long x = 0; - long y = 0; - - if (self.target != IntPtr.Zero) { - x = Runtime.PyObject_Hash(self.target).ToInt64(); - if (x == -1) { - return new IntPtr(-1); - } - } - - y = Runtime.PyObject_Hash(self.e.pyHandle).ToInt64(); - if (y == -1) { - return new IntPtr(-1); - } - - x ^= y; - - if (x == -1) { - x = -1; - } - - return new IntPtr(x); - } - - - //==================================================================== - // EventBinding __repr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_repr(IntPtr ob) { - EventBinding self = (EventBinding)GetManagedObject(ob); - string type = (self.target == IntPtr.Zero) ? "unbound" : "bound"; - string s = String.Format("<{0} event '{1}'>", type, self.e.name); - return Runtime.PyString_FromString(s); - } - - - //==================================================================== - // EventBinding dealloc implementation. - //==================================================================== - - [CallConvCdecl()] - public static new void tp_dealloc(IntPtr ob) { - EventBinding self = (EventBinding)GetManagedObject(ob); - Runtime.Decref(self.target); - ExtensionType.FinalizeObject(self); - } - - } - - -} diff --git a/pythonnet/src/runtime/eventobject.cs b/pythonnet/src/runtime/eventobject.cs deleted file mode 100755 index 44c4a8374..000000000 --- a/pythonnet/src/runtime/eventobject.cs +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // Implements a Python descriptor type that provides access to CLR events. - //======================================================================== - - internal class EventObject : ExtensionType { - - internal string name; - internal EventBinding unbound; - internal EventInfo info; - internal Hashtable reg; - - public EventObject(EventInfo info) : base() { - this.name = info.Name; - this.info = info; - } - - - //==================================================================== - // Register a new Python object event handler with the event. - //==================================================================== - - internal bool AddEventHandler(IntPtr target, IntPtr handler) { - Object obj = null; - if (target != IntPtr.Zero) { - CLRObject co = (CLRObject)ManagedType.GetManagedObject(target); - obj = co.inst; - } - - // Create a true delegate instance of the appropriate type to - // wrap the Python handler. Note that wrapper delegate creation - // always succeeds, though calling the wrapper may fail. - - Type type = this.info.EventHandlerType; - Delegate d = DelegateManager.GetDelegate(type, handler); - - // Now register the handler in a mapping from instance to pairs - // of (handler hash, delegate) so we can lookup to remove later. - // All this is done lazily to avoid overhead until an event is - // actually subscribed to by a Python event handler. - - if (reg == null) { - reg = new Hashtable(); - } - object key = (obj != null) ? obj : this.info.ReflectedType; - ArrayList list = reg[key] as ArrayList; - if (list == null) { - list = new ArrayList(); - reg[key] = list; - } - list.Add(new Handler(Runtime.PyObject_Hash(handler), d)); - - // Note that AddEventHandler helper only works for public events, - // so we have to get the underlying add method explicitly. - - object[] args = { d }; - MethodInfo mi = this.info.GetAddMethod(true); - mi.Invoke(obj, BindingFlags.Default, null, args, null); - - return true; - } - - - //==================================================================== - // Remove the given Python object event handler. - //==================================================================== - - internal bool RemoveEventHandler(IntPtr target, IntPtr handler) { - Object obj = null; - if (target != IntPtr.Zero) { - CLRObject co = (CLRObject)ManagedType.GetManagedObject(target); - obj = co.inst; - } - - IntPtr hash = Runtime.PyObject_Hash(handler); - if (Exceptions.ErrorOccurred() || (reg == null)) { - Exceptions.SetError(Exceptions.ValueError, - "unknown event handler" - ); - return false; - } - - object key = (obj != null) ? obj : this.info.ReflectedType; - ArrayList list = reg[key] as ArrayList; - - if (list == null) { - Exceptions.SetError(Exceptions.ValueError, - "unknown event handler" - ); - return false; - } - - object[] args = { null }; - MethodInfo mi = this.info.GetRemoveMethod(true); - - for (int i = 0; i < list.Count; i++) { - Handler item = (Handler)list[i]; - if (item.hash != hash) { - continue; - } - args[0] = item.del; - try { - mi.Invoke(obj, BindingFlags.Default, null, args, null); - } - catch { - continue; - } - list.RemoveAt(i); - return true; - } - - Exceptions.SetError(Exceptions.ValueError, - "unknown event handler" - ); - return false; - } - - - //==================================================================== - // Descriptor __get__ implementation. A getattr on an event returns - // a "bound" event that keeps a reference to the object instance. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - EventObject self = GetManagedObject(ds) as EventObject; - EventBinding binding; - - if (self == null) { - return Exceptions.RaiseTypeError("invalid argument"); - } - - // If the event is accessed through its type (rather than via - // an instance) we return an 'unbound' EventBinding that will - // be cached for future accesses through the type. - - if (ob == IntPtr.Zero) { - if (self.unbound == null) { - self.unbound = new EventBinding(self, IntPtr.Zero); - } - binding = self.unbound; - Runtime.Incref(binding.pyHandle); - return binding.pyHandle; - } - - if (Runtime.PyObject_IsInstance(ob, tp) < 1) { - return Exceptions.RaiseTypeError("invalid argument"); - } - - binding = new EventBinding(self, ob); - return binding.pyHandle; - } - - - //==================================================================== - // Descriptor __set__ implementation. This actually never allows you - // to set anything; it exists solely to support the '+=' spelling of - // event handler registration. The reason is that given code like: - // 'ob.SomeEvent += method', Python will attempt to set the attribute - // SomeEvent on ob to the result of the '+=' operation. - //==================================================================== - - [CallConvCdecl()] - public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - EventBinding e = GetManagedObject(val) as EventBinding; - - if (e != null) { - return 0; - } - - string message = "cannot set event attributes"; - Exceptions.RaiseTypeError(message); - return -1; - } - - - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_repr(IntPtr ob) { - EventObject self = (EventObject)GetManagedObject(ob); - string s = String.Format("", self.name); - return Runtime.PyString_FromString(s); - } - - - //==================================================================== - // Descriptor dealloc implementation. - //==================================================================== - - [CallConvCdecl()] - public static new void tp_dealloc(IntPtr ob) { - EventObject self = (EventObject)GetManagedObject(ob); - if (self.unbound != null) { - Runtime.Decref(self.unbound.pyHandle); - } - ExtensionType.FinalizeObject(self); - } - - - } - - - - internal class Handler { - - public IntPtr hash; - public Delegate del; - - public Handler(IntPtr hash, Delegate d) { - this.hash = hash; - this.del = d; - } - - } - - -} diff --git a/pythonnet/src/runtime/exceptions.cs b/pythonnet/src/runtime/exceptions.cs deleted file mode 100755 index 1bae03228..000000000 --- a/pythonnet/src/runtime/exceptions.cs +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Reflection; -using System.Collections; -using System.Runtime.InteropServices; - - -namespace Python.Runtime { - - /// - /// Encapsulates the Python exception APIs. - /// - - public class Exceptions { - - private Exceptions() {} - - //=================================================================== - // Initialization performed on startup of the Python runtime. - //=================================================================== - - internal static void Initialize() { - IntPtr module = Runtime.PyImport_ImportModule("exceptions"); - Type type = typeof(Exceptions); - foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | - BindingFlags.Static)) { - IntPtr op = Runtime.PyObject_GetAttrString(module, fi.Name); - if (op != IntPtr.Zero) { - fi.SetValue(type, op); - } - } - Runtime.Decref(module); - Runtime.PyErr_Clear(); - if (Runtime.wrap_exceptions) { - SetupExceptionHack(); - } - } - - - //=================================================================== - // Cleanup resources upon shutdown of the Python runtime. - //=================================================================== - - internal static void Shutdown() { - Type type = typeof(Exceptions); - foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | - BindingFlags.Static)) { - IntPtr op = (IntPtr)fi.GetValue(type); - Runtime.Decref(op); - } - } - - - // Versions of CPython up to 2.4 do not allow exceptions to be - // new-style classes. To get around that restriction and provide - // a consistent user experience for programmers, we wrap managed - // exceptions in an old-style class that (through some dont-try- - // this-at-home hackery) delegates to the managed exception and - // obeys the conventions of both Python and managed exceptions. - - static IntPtr ns_exc; // new-style class for System.Exception - static IntPtr os_exc; // old-style class for System.Exception - static Hashtable cache; - - internal static void SetupExceptionHack() { - ns_exc = ClassManager.GetClass(typeof(Exception)).pyHandle; - cache = new Hashtable(); - - string code = - "import exceptions\n" + - "class Exception(exceptions.Exception):\n" + - " _class = None\n" + - " _inner = None\n" + - "\n" + - " def __init__(self, *args, **kw):\n" + - " inst = self.__class__._class(*args, **kw)\n" + - " self.__dict__['_inner'] = inst\n" + - " exceptions.Exception.__init__(self, *args, **kw)\n" + - "\n" + - " def __getattr__(self, name, _marker=[]):\n" + - " inner = self.__dict__['_inner']\n" + - " v = getattr(inner, name, _marker)\n" + - " if v is not _marker:\n" + - " return v\n" + - " v = self.__dict__.get(name, _marker)\n" + - " if v is not _marker:\n" + - " return v\n" + - " raise AttributeError(name)\n" + - "\n" + - " def __setattr__(self, name, value):\n" + - " inner = self.__dict__['_inner']\n" + - " setattr(inner, name, value)\n" + - "\n" + - " def __str__(self):\n" + - " inner = self.__dict__.get('_inner')\n" + - " msg = getattr(inner, 'Message', '')\n" + - " st = getattr(inner, 'StackTrace', '')\n" + - " st = st and '\\n' + st or ''\n" + - " return msg + st\n" + - "\n"; - - IntPtr dict = Runtime.PyDict_New(); - - IntPtr builtins = Runtime.PyEval_GetBuiltins(); - Runtime.PyDict_SetItemString(dict, "__builtins__", builtins); - - IntPtr namestr = Runtime.PyString_FromString("CLR.System"); - Runtime.PyDict_SetItemString(dict, "__name__", namestr); - Runtime.Decref(namestr); - - Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone); - Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone); - - IntPtr flag = Runtime.Py_file_input; - IntPtr done = Runtime.PyRun_String(code, flag, dict, dict); - - os_exc = Runtime.PyDict_GetItemString(dict, "Exception"); - Runtime.PyObject_SetAttrString(os_exc, "_class", ns_exc); - Runtime.PyErr_Clear(); - } - - - internal static IntPtr GenerateExceptionClass(IntPtr real) { - if (real == ns_exc) { - return os_exc; - } - - IntPtr nbases = Runtime.PyObject_GetAttrString(real, "__bases__"); - if (Runtime.PyTuple_Size(nbases) != 1) { - throw new SystemException("Invalid __bases__"); - } - IntPtr nsbase = Runtime.PyTuple_GetItem(nbases, 0); - Runtime.Decref(nbases); - - IntPtr osbase = GetExceptionClassWrapper(nsbase); - IntPtr baselist = Runtime.PyTuple_New(1); - Runtime.Incref(osbase); - Runtime.PyTuple_SetItem(baselist, 0, osbase); - IntPtr name = Runtime.PyObject_GetAttrString(real, "__name__"); - - IntPtr dict = Runtime.PyDict_New(); - IntPtr mod = Runtime.PyObject_GetAttrString(real, "__module__"); - Runtime.PyDict_SetItemString(dict, "__module__", mod); - Runtime.Decref(mod); - - IntPtr subc = Runtime.PyClass_New(baselist, dict, name); - Runtime.Decref(baselist); - Runtime.Decref(dict); - Runtime.Decref(name); - - Runtime.PyObject_SetAttrString(subc, "_class", real); - return subc; - } - - internal static IntPtr GetExceptionClassWrapper(IntPtr real) { - // Given the pointer to a new-style class representing a managed - // exception, return an appropriate old-style class wrapper that - // maintains all of the expectations and delegates to the wrapped - // class. - object ob = cache[real]; - if (ob == null) { - IntPtr op = GenerateExceptionClass(real); - cache[real] = op; - return op; - } - return (IntPtr)ob; - } - - internal static IntPtr GetExceptionInstanceWrapper(IntPtr real) { - // Given the pointer to a new-style class instance representing a - // managed exception, return an appropriate old-style class - // wrapper instance that delegates to the wrapped instance. - IntPtr tp = Runtime.PyObject_TYPE(real); - if (Runtime.PyObject_TYPE(tp) == Runtime.PyInstanceType) { - return real; - } - // Get / generate a class wrapper, instantiate it and set its - // _inner attribute to the real new-style exception instance. - IntPtr ct = GetExceptionClassWrapper(tp); - IntPtr op = Runtime.PyInstance_NewRaw(ct, IntPtr.Zero); - IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__"); - Runtime.PyDict_SetItemString(d, "_inner", real); - Runtime.Decref(d); - return op; - } - - - - /// - /// GetException Method - /// - /// - /// - /// Retrieve Python exception information as a PythonException - /// instance. The properties of the PythonException may be used - /// to access the exception type, value and traceback info. - /// - - public static PythonException GetException() { - // TODO: implement this. - return null; - } - - /// - /// ExceptionMatches Method - /// - /// - /// - /// Returns true if the current Python exception matches the given - /// Python object. This is a wrapper for PyErr_ExceptionMatches. - /// - - public static bool ExceptionMatches(IntPtr ob) { - return Runtime.PyErr_ExceptionMatches(ob) != 0; - } - - /// - /// ExceptionMatches Method - /// - /// - /// - /// Returns true if the given Python exception matches the given - /// Python object. This is a wrapper for PyErr_GivenExceptionMatches. - /// - - public static bool ExceptionMatches(IntPtr exc, IntPtr ob) { - int i = Runtime.PyErr_GivenExceptionMatches(exc, ob); - return (i != 0); - } - - /// - /// SetError Method - /// - /// - /// - /// Sets the current Python exception given a native string. - /// This is a wrapper for the Python PyErr_SetString call. - /// - - public static void SetError(IntPtr ob, string value) { - Runtime.PyErr_SetString(ob, value); - } - - /// - /// SetError Method - /// - /// - /// - /// Sets the current Python exception given a Python object. - /// This is a wrapper for the Python PyErr_SetObject call. - /// - - public static void SetError(IntPtr ob, IntPtr value) { - Runtime.PyErr_SetObject(ob, value); - } - - /// - /// SetError Method - /// - /// - /// - /// Sets the current Python exception given a CLR exception - /// object. The CLR exception instance is wrapped as a Python - /// object, allowing it to be handled naturally from Python. - /// - - public static void SetError(Exception e) { - - // Because delegates allow arbitrary nestings of Python calling - // managed calling Python calling... etc. it is possible that we - // might get a managed exception raised that is a wrapper for a - // Python exception. In that case we'd rather have the real thing. - - PythonException pe = e as PythonException; - if (pe != null) { - Runtime.PyErr_SetObject(pe.Type, pe.Value); - return; - } - - IntPtr op = CLRObject.GetInstHandle(e); - - // XXX - hack to raise a compatible old-style exception ;( - if (Runtime.wrap_exceptions) { - op = GetExceptionInstanceWrapper(op); - } - IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__"); - Runtime.PyErr_SetObject(etype, op); - Runtime.Decref(etype); - } - - /// - /// ErrorOccurred Method - /// - /// - /// - /// Returns true if an exception occurred in the Python runtime. - /// This is a wrapper for the Python PyErr_Occurred call. - /// - - public static bool ErrorOccurred() { - return Runtime.PyErr_Occurred() != 0; - } - - /// - /// Clear Method - /// - /// - /// - /// Clear any exception that has been set in the Python runtime. - /// - - public static void Clear() { - Runtime.PyErr_Clear(); - } - - - - //==================================================================== - // Internal helper methods for common error handling scenarios. - //==================================================================== - - internal static IntPtr RaiseTypeError(string message) { - Exceptions.SetError(Exceptions.TypeError, message); - return IntPtr.Zero; - } - - - public static IntPtr ArithmeticError; - public static IntPtr AssertionError; - public static IntPtr AttributeError; - public static IntPtr DeprecationWarning; - public static IntPtr EOFError; - public static IntPtr EnvironmentError; - public static IntPtr Exception; - public static IntPtr FloatingPointError; - public static IntPtr IOError; - public static IntPtr ImportError; - public static IntPtr IndentationError; - public static IntPtr IndexError; - public static IntPtr KeyError; - public static IntPtr KeyboardInterrupt; - public static IntPtr LookupError; - public static IntPtr MemoryError; - public static IntPtr NameError; - public static IntPtr NotImplementedError; - public static IntPtr OSError; - public static IntPtr OverflowError; - public static IntPtr OverflowWarning; - public static IntPtr ReferenceError; - public static IntPtr RuntimeError; - public static IntPtr RuntimeWarning; - public static IntPtr StandardError; - public static IntPtr StopIteration; - public static IntPtr SyntaxError; - public static IntPtr SyntaxWarning; - public static IntPtr SystemError; - public static IntPtr SystemExit; - public static IntPtr TabError; - public static IntPtr TypeError; - public static IntPtr UnboundLocalError; - public static IntPtr UnicodeError; - public static IntPtr UserWarning; - public static IntPtr ValueError; - public static IntPtr Warning; - public static IntPtr WindowsError; - public static IntPtr ZeroDivisionError; - - } - - -} diff --git a/pythonnet/src/runtime/extensiontype.cs b/pythonnet/src/runtime/extensiontype.cs deleted file mode 100755 index 8ece4123a..000000000 --- a/pythonnet/src/runtime/extensiontype.cs +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - /// - /// Base class for extensions whose instances *share* a single Python - /// type object, such as the types that represent CLR methods, fields, - /// etc. Instances implemented by this class do not support subtyping. - /// - - internal abstract class ExtensionType : ManagedType { - - public ExtensionType() : base() { - - // Create a new PyObject whose type is a generated type that is - // implemented by the particuar concrete ExtensionType subclass. - // The Python instance object is related to an instance of a - // particular concrete subclass with a hidden CLR gchandle. - - IntPtr tp = TypeManager.GetTypeHandle(this.GetType()); - -// int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt); -// if (rc > 1050) { -// DebugUtil.Print("tp is: ", tp); -// DebugUtil.DumpType(tp); -// } - - IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); - - GCHandle gc = GCHandle.Alloc(this); - Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc); - - // We have to support gc because the type machinery makes it very - // hard not to - but we really don't have a need for it in most - // concrete extension types, so untrack the object to save calls - // from Python into the managed runtime that are pure overhead. - - Runtime.PyObject_GC_UnTrack(py); - - this.tpHandle = tp; - this.pyHandle = py; - this.gcHandle = gc; - } - - - //==================================================================== - // Common finalization code to support custom tp_deallocs. - //==================================================================== - - public static void FinalizeObject(ManagedType self) { - Runtime.PyObject_GC_Del(self.pyHandle); - Runtime.Decref(self.tpHandle); - self.gcHandle.Free(); - } - - - //==================================================================== - // Type __setattr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static int tp_setattro(IntPtr ob, IntPtr key, IntPtr val) { - string message = "type does not support setting attributes"; - if (val == IntPtr.Zero) { - message = "readonly attribute"; - } - Exceptions.SetError(Exceptions.TypeError, message); - return -1; - } - - - //==================================================================== - // Default __set__ implementation - this prevents descriptor instances - // being silently replaced in a type __dict__ by default __setattr__. - //==================================================================== - - [CallConvCdecl()] - public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - string message = "attribute is read-only"; - Exceptions.SetError(Exceptions.AttributeError, message); - return -1; - } - - - //==================================================================== - // Required Python GC support. - //==================================================================== - - [CallConvCdecl()] - public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) { - return 0; - } - - - [CallConvCdecl()] - public static int tp_clear(IntPtr ob) { - return 0; - } - - - [CallConvCdecl()] - public static int tp_is_gc(IntPtr type) { - return 1; - } - - - //==================================================================== - // Default dealloc implementation. - //==================================================================== - - [CallConvCdecl()] - public static void tp_dealloc(IntPtr ob) { - // Clean up a Python instance of this extension type. This - // frees the allocated Python object and decrefs the type. - ManagedType self = GetManagedObject(ob); - FinalizeObject(self); - } - - - } - - -} diff --git a/pythonnet/src/runtime/fieldobject.cs b/pythonnet/src/runtime/fieldobject.cs deleted file mode 100755 index 39589717a..000000000 --- a/pythonnet/src/runtime/fieldobject.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // Implements a Python descriptor type that provides access to CLR fields. - //======================================================================== - - internal class FieldObject : ExtensionType { - - FieldInfo info; - - public FieldObject(FieldInfo info) : base() { - this.info = info; - } - - //==================================================================== - // Descriptor __get__ implementation. This method returns the - // value of the field on the given object. The returned value - // is converted to an appropriately typed Python object. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - FieldObject self = (FieldObject)GetManagedObject(ds); - Object result; - - if (self == null) { - return IntPtr.Zero; - } - - FieldInfo info = self.info; - - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { - if (!info.IsStatic) { - Exceptions.SetError(Exceptions.TypeError, - "instance attribute must be accessed " + - "through a class instance" - ); - return IntPtr.Zero; - } - try { - result = info.GetValue(null); - return Converter.ToPython(result, info.FieldType); - } - catch(Exception e) { - Exceptions.SetError(Exceptions.TypeError, e.Message); - return IntPtr.Zero; - } - } - - try { - CLRObject co = (CLRObject)GetManagedObject(ob); - result = info.GetValue(co.inst); - return Converter.ToPython(result, info.FieldType); - } - catch(Exception e) { - Exceptions.SetError(Exceptions.TypeError, e.Message); - return IntPtr.Zero; - } - } - - //==================================================================== - // Descriptor __set__ implementation. This method sets the value of - // a field based on the given Python value. The Python value must be - // convertible to the type of the field. - //==================================================================== - - [CallConvCdecl()] - public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - FieldObject self = (FieldObject)GetManagedObject(ds); - Object newval; - - if (self == null) { - return -1; - } - - if (val == IntPtr.Zero) { - Exceptions.SetError(Exceptions.TypeError, - "cannot delete field" - ); - return -1; - } - - FieldInfo info = self.info; - - if (info.IsLiteral || info.IsInitOnly) { - Exceptions.SetError(Exceptions.TypeError, - "field is read-only" - ); - return -1; - } - - bool is_static = info.IsStatic; - - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { - if (!is_static) { - Exceptions.SetError(Exceptions.TypeError, - "instance attribute must be set " + - "through a class instance" - ); - return -1; - } - } - - if (!Converter.ToManaged(val, info.FieldType, out newval, - true)) { - return -1; - } - - try { - if (!is_static) { - CLRObject co = (CLRObject)GetManagedObject(ob); - info.SetValue(co.inst, newval); - } - else { - info.SetValue(null, newval); - } - return 0; - } - catch(Exception e) { - Exceptions.SetError(Exceptions.TypeError, e.Message); - return -1; - } - } - - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_repr(IntPtr ob) { - FieldObject self = (FieldObject)GetManagedObject(ob); - string s = String.Format("", self.info.Name); - return Runtime.PyString_FromStringAndSize(s, s.Length); - } - - } - - -} diff --git a/pythonnet/src/runtime/importhook.cs b/pythonnet/src/runtime/importhook.cs deleted file mode 100755 index b01a381f5..000000000 --- a/pythonnet/src/runtime/importhook.cs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; - -namespace Python.Runtime { - - //======================================================================== - // Implements the "import hook" used to integrate Python with the CLR. - //======================================================================== - - internal class ImportHook { - - static IntPtr py_import; - static ModuleObject root; - static MethodWrapper hook; - - //=================================================================== - // Initialization performed on startup of the Python runtime. - //=================================================================== - - internal static void Initialize() { - - // Initialize the Python <--> CLR module hook. We replace the - // built-in Python __import__ with our own. This isn't ideal, - // but it provides the most "Pythonic" way of dealing with CLR - // modules (Python doesn't provide a way to emulate packages). - - IntPtr dict = Runtime.PyImport_GetModuleDict(); - IntPtr mod = Runtime.PyDict_GetItemString(dict, "__builtin__"); - py_import = Runtime.PyObject_GetAttrString(mod, "__import__"); - - - hook = new MethodWrapper(typeof(ImportHook), "__import__"); - - Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr); - - Runtime.Decref(hook.ptr); - - root = new ModuleObject(""); - - Runtime.PyDict_SetItemString(dict, "CLR", root.pyHandle); - } - - - //=================================================================== - // Cleanup resources upon shutdown of the Python runtime. - //=================================================================== - - internal static void Shutdown() { - Runtime.Decref(root.pyHandle); - Runtime.Decref(py_import); - } - - - //=================================================================== - // The actual import hook that ties Python to the managed world. - //=================================================================== - - [CallConvCdecl()] - public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { - - // Replacement for the builtin __import__. The original import - // hook is saved as this.importFunc. This version handles CLR - // import and defers to the normal builtin for everything else. - - int num_args = Runtime.PyTuple_Size(args); - - if (num_args < 1) { - Exceptions.SetError( - Exceptions.TypeError, - "__import__() takes at least 1 argument (0 given)" - ); - return IntPtr.Zero; - } - - // borrowed reference - IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0); - - if ((py_mod_name == IntPtr.Zero) || - (!Runtime.IsStringType(py_mod_name))) { - Exceptions.SetError(Exceptions.TypeError, "string expected"); - return IntPtr.Zero; - } - - // If not a CLR module, defer to the standard Python import. - // Could use Python here to avoid a string conversion. - - string mod_name = Runtime.GetManagedString(py_mod_name); - - if (!(mod_name.StartsWith("CLR.") || mod_name == "CLR")) { - return Runtime.PyObject_Call(py_import, args, kw); - } - - // Check whether the import is of the form 'from x import y'. - // This determines whether we return the head or tail module. - - bool from_list = false; - if (num_args >= 4) { - IntPtr fromList = Runtime.PyTuple_GetItem(args, 3); - if ((fromList != IntPtr.Zero) && - (Runtime.PyObject_IsTrue(fromList) == 1)) { - from_list = true; - } - } - - // See if sys.modules for this interpreter already has the - // requested module. If so, just return the exising module. - - IntPtr sys_modules = Runtime.PyImport_GetModuleDict(); - IntPtr module = Runtime.PyDict_GetItem(sys_modules, py_mod_name); - - if (module != IntPtr.Zero) { - if (from_list) { - Runtime.Incref(module); - return module; - } - Runtime.Incref(root.pyHandle); - return root.pyHandle; - } - - // Now we know we are looking for a CLR module and are likely - // going to have to ask the AssemblyManager. The assembly mgr - // tries really hard not to use Python objects or APIs, because - // parts of it can run recursively and on strange threads, etc. - // - // It does need an opportunity from time to time to check to - // see if sys.path has changed, in a context that is safe. Here - // we know we have the GIL, so we'll let it update if needed. - - AssemblyManager.UpdatePath(); - - // Special case handling: if the qualified module name would - // cause an implicit assembly load, we need to do that first - // to make sure that each of the steps in the qualified name - // is recognized as a valid namespace. Otherwise the import - // process can encounter unknown namespaces before it gets to - // load the assembly that would make them valid. - - if (mod_name.StartsWith("CLR.")) { - string real_name = mod_name.Substring(4); - AssemblyManager.LoadImplicit(real_name); - } - - // Traverse the qualified module name to get the requested - // module and place references in sys.modules as we go. - - string[] names = mod_name.Split('.'); - ModuleObject tail = root; - - for (int i = 0; i < names.Length; i++) { - string name = names[i]; - if (name == "CLR") { - tail = root; - } - else { - ManagedType mt = tail.GetAttribute(name); - if (!(mt is ModuleObject)) { - string error = String.Format("No module named {0}", - name - ); - Exceptions.SetError(Exceptions.ImportError, error); - return IntPtr.Zero; - } - tail = (ModuleObject) mt; - } - - Runtime.PyDict_SetItemString( - sys_modules, tail.ModuleName, tail.pyHandle - ); - } - - ModuleObject mod = from_list ? tail : root; - Runtime.Incref(mod.pyHandle); - return mod.pyHandle; - } - - } - - -} diff --git a/pythonnet/src/runtime/indexer.cs b/pythonnet/src/runtime/indexer.cs deleted file mode 100755 index 938949ce9..000000000 --- a/pythonnet/src/runtime/indexer.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; -using System.Security.Permissions; - -namespace Python.Runtime { - - //======================================================================== - // Bundles the information required to support an indexer property. - //======================================================================== - - internal class Indexer { - - public MethodBinder GetterBinder; - public MethodBinder SetterBinder; - - public Indexer() { - GetterBinder = new MethodBinder(); - SetterBinder = new MethodBinder(); - } - - - public bool CanGet { - get { - return GetterBinder.Count > 0; - } - } - - public bool CanSet { - get { - return SetterBinder.Count > 0; - } - } - - - public void AddProperty(PropertyInfo pi) { - MethodInfo getter = pi.GetGetMethod(true); - MethodInfo setter = pi.GetSetMethod(true); - if (getter != null) { - GetterBinder.AddMethod(getter); - } - if (setter != null) { - SetterBinder.AddMethod(setter); - } - } - - internal IntPtr GetItem(IntPtr inst, IntPtr args) { - return GetterBinder.Invoke(inst, args, IntPtr.Zero); - } - - - internal void SetItem(IntPtr inst, IntPtr args) { - SetterBinder.Invoke(inst, args, IntPtr.Zero); - } - - } - - -} diff --git a/pythonnet/src/runtime/interfaceobject.cs b/pythonnet/src/runtime/interfaceobject.cs deleted file mode 100755 index 9b6b18595..000000000 --- a/pythonnet/src/runtime/interfaceobject.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2003 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// Provides the implementation for reflected interface types. Managed - /// interfaces are represented in Python by actual Python type objects. - /// Each of those type objects is associated with an instance of this - /// class, which provides the implementation for the Python type. - /// - - internal class InterfaceObject : ClassBase { - - internal ConstructorInfo ctor; - - internal InterfaceObject(Type tp) : base(tp) { - CoClassAttribute coclass = (CoClassAttribute) - Attribute.GetCustomAttribute(tp, cc_attr); - if (coclass != null) { - ctor = coclass.CoClass.GetConstructor(Type.EmptyTypes); - } - } - - static Type cc_attr; - - static InterfaceObject() { - cc_attr = typeof(CoClassAttribute); - } - - //==================================================================== - // Implements __new__ for reflected interface types. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - InterfaceObject self = (InterfaceObject)GetManagedObject(tp); - int nargs = Runtime.PyTuple_Size(args); - Type type = self.type; - Object obj; - - if (nargs == 1) { - IntPtr inst = Runtime.PyTuple_GetItem(args, 0); - CLRObject co = GetManagedObject(inst) as CLRObject; - - if ((co == null) || (!type.IsInstanceOfType(co.inst))) { - string msg = "object does not implement " + type.Name; - Exceptions.SetError(Exceptions.TypeError, msg); - return IntPtr.Zero; - } - - obj = co.inst; - } - - else if ((nargs == 0) && (self.ctor != null)) { - obj = self.ctor.Invoke(null); - - if (obj == null || !type.IsInstanceOfType(obj)) { - Exceptions.SetError(Exceptions.TypeError, - "CoClass default constructor failed" - ); - return IntPtr.Zero; - } - } - - else { - Exceptions.SetError(Exceptions.TypeError, - "interface takes exactly one argument" - ); - return IntPtr.Zero; - } - - return CLRObject.GetInstHandle(obj, self.pyHandle); - } - - - } - - -} diff --git a/pythonnet/src/runtime/interop.cs b/pythonnet/src/runtime/interop.cs deleted file mode 100755 index f20e9bbc0..000000000 --- a/pythonnet/src/runtime/interop.cs +++ /dev/null @@ -1,408 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Collections.Specialized; -using System.Runtime.InteropServices; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================= - // This file defines objects to support binary interop with the Python - // runtime. Generally, the definitions here need to be kept up to date - // when moving to new Python versions. - //======================================================================= - - [Serializable()] - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] - internal class CallConvCdeclAttribute : Attribute { - public CallConvCdeclAttribute() {} - } - - - [Serializable()] - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] - internal class PythonMethodAttribute : Attribute { - public PythonMethodAttribute() {} - } - - - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] - internal class ObjectOffset { - - static ObjectOffset() { - int size = IntPtr.Size; - ob_refcnt = 0; - ob_type = 1 * size; - ob_dict = 2 * size; - ob_data = 3 * size; - } - - public static int magic() { - return ob_data; - } - - public static int Size() { - return 4 * IntPtr.Size; - } - - public static int ob_refcnt; - public static int ob_type; - public static int ob_dict; - public static int ob_data; - } - - - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] - internal class TypeOffset { - - static TypeOffset() { - Type type = typeof(TypeOffset); - FieldInfo[] fi = type.GetFields(); - int size = IntPtr.Size; - for (int i = 0; i < fi.Length; i++) { - fi[i].SetValue(null, i * size); - } - } - - public static int magic() { - return ob_size; - } - - 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 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 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 name = 0; - public static int slots = 0; - public static int members = 0; - - } - - - internal class TypeFlags { - public static int HaveGetCharBuffer = (1 << 0); - public static int HaveSequenceIn = (1 << 1); - public static int GC = 0; - public static int HaveInPlaceOps = (1 << 3); - public static int CheckTypes = (1 << 4); - public static int HaveRichCompare = (1 << 5); - public static int HaveWeakRefs = (1 << 6); - public static int HaveIter = (1 << 7); - public static int HaveClass = (1 << 8); - public static int HeapType = (1 << 9); - public static int BaseType = (1 << 10); - public static int Ready = (1 << 12); - public static int Readying = (1 << 13); - public static int HaveGC = (1 << 14); - public static int Managed = (1 << 29); - public static int Subclass = (1 << 30); - public static int Default = (1 << 0) | - (1 << 1) | - (1 << 3) | - (1 << 5) | - (1 << 6) | - (1 << 7) | - (1 << 8) | 0; - } - - - // This class defines the function prototypes (delegates) used for low - // level integration with the CPython runtime. It also provides name - // based lookup of the correct prototype for a particular Python type - // slot and utilities for generating method thunks for managed methods. - - internal class Interop { - - static ArrayList keepAlive; - static Hashtable pmap; - static IntPtr temp; - - static Interop() { - - // Here we build a mapping of PyTypeObject slot names to the - // appropriate prototype (delegate) type to use for the slot. - - Type[] items = typeof(Interop).GetNestedTypes(); - Hashtable p = new Hashtable(); - - for (int i = 0; i < items.Length; i++) { - Type item = items[i]; - p[item.Name] = item; - } - - keepAlive = new ArrayList(); - temp = Marshal.AllocHGlobal(IntPtr.Size); - pmap = new Hashtable(); - - pmap["tp_dealloc"] = p["DestructorFunc"]; - pmap["tp_print"] = p["PrintFunc"]; - pmap["tp_getattr"] = p["BinaryFunc"]; - pmap["tp_setattr"] = p["ObjObjArgFunc"]; - pmap["tp_compare"] = p["ObjObjFunc"]; - pmap["tp_repr"] = p["UnaryFunc"]; - pmap["tp_hash"] = p["UnaryFunc"]; - pmap["tp_call"] = p["TernaryFunc"]; - pmap["tp_str"] = p["UnaryFunc"]; - pmap["tp_getattro"] = p["BinaryFunc"]; - pmap["tp_setattro"] = p["ObjObjArgFunc"]; - pmap["tp_traverse"] = p["ObjObjArgFunc"]; - pmap["tp_clear"] = p["InquiryFunc"]; - pmap["tp_richcompare"] = p["RichCmpFunc"]; - pmap["tp_iter"] = p["UnaryFunc"]; - pmap["tp_iternext"] = p["UnaryFunc"]; - pmap["tp_descr_get"] = p["TernaryFunc"]; - pmap["tp_descr_set"] = p["ObjObjArgFunc"]; - pmap["tp_init"] = p["ObjObjArgFunc"]; - pmap["tp_alloc"] = p["IntArgFunc"]; - pmap["tp_new"] = p["TernaryFunc"]; - pmap["tp_free"] = p["DestructorFunc"]; - pmap["tp_is_gc"] = p["InquiryFunc"]; - - pmap["nb_add"] = p["BinaryFunc"]; - pmap["nb_subtract"] = p["BinaryFunc"]; - pmap["nb_multiply"] = p["BinaryFunc"]; - pmap["nb_divide"] = p["BinaryFunc"]; - pmap["nb_remainder"] = p["BinaryFunc"]; - pmap["nb_divmod"] = p["BinaryFunc"]; - pmap["nb_power"] = p["TernaryFunc"]; - pmap["nb_negative"] = p["UnaryFunc"]; - pmap["nb_positive"] = p["UnaryFunc"]; - pmap["nb_absolute"] = p["UnaryFunc"]; - pmap["nb_nonzero"] = p["InquiryFunc"]; - pmap["nb_invert"] = p["UnaryFunc"]; - pmap["nb_lshift"] = p["BinaryFunc"]; - pmap["nb_rshift"] = p["BinaryFunc"]; - pmap["nb_and"] = p["BinaryFunc"]; - pmap["nb_xor"] = p["BinaryFunc"]; - pmap["nb_or"] = p["BinaryFunc"]; - pmap["nb_coerce"] = p["ObjObjFunc"]; - pmap["nb_int"] = p["UnaryFunc"]; - pmap["nb_long"] = p["UnaryFunc"]; - pmap["nb_float"] = p["UnaryFunc"]; - pmap["nb_oct"] = p["UnaryFunc"]; - pmap["nb_hex"] = p["UnaryFunc"]; - pmap["nb_inplace_add"] = p["BinaryFunc"]; - pmap["nb_inplace_subtract"] = p["BinaryFunc"]; - pmap["nb_inplace_multiply"] = p["BinaryFunc"]; - pmap["nb_inplace_divide"] = p["BinaryFunc"]; - pmap["nb_inplace_remainder"] = p["BinaryFunc"]; - pmap["nb_inplace_power"] = p["TernaryFunc"]; - pmap["nb_inplace_lshift"] = p["BinaryFunc"]; - pmap["nb_inplace_rshift"] = p["BinaryFunc"]; - pmap["nb_inplace_and"] = p["BinaryFunc"]; - pmap["nb_inplace_xor"] = p["BinaryFunc"]; - pmap["nb_inplace_or"] = p["BinaryFunc"]; - pmap["nb_floor_divide"] = p["BinaryFunc"]; - pmap["nb_true_divide"] = p["BinaryFunc"]; - pmap["nb_inplace_floor_divide"] = p["BinaryFunc"]; - pmap["nb_inplace_true_divide"] = p["BinaryFunc"]; - - pmap["sq_length"] = p["InquiryFunc"]; - pmap["sq_concat"] = p["BinaryFunc"]; - pmap["sq_repeat"] = p["IntArgFunc"]; - pmap["sq_item"] = p["IntArgFunc"]; - pmap["sq_slice"] = p["IntIntArgFunc"]; - pmap["sq_ass_item"] = p["IntObjArgFunc"]; - pmap["sq_ass_slice"] = p["IntIntObjArgFunc"]; - pmap["sq_contains"] = p["ObjObjFunc"]; - pmap["sq_inplace_concat"] = p["BinaryFunc"]; - pmap["sq_inplace_repeat"] = p["IntArgFunc"]; - - pmap["mp_length"] = p["InquiryFunc"]; - pmap["mp_subscript"] = p["BinaryFunc"]; - pmap["mp_ass_subscript"] = p["ObjObjArgFunc"]; - - pmap["bf_getreadbuffer"] = p["IntObjArgFunc"]; - pmap["bf_getwritebuffer"] = p["IntObjArgFunc"]; - pmap["bf_getsegcount"] = p["ObjObjFunc"]; - pmap["bf_getcharbuffer"] = p["IntObjArgFunc"]; - - pmap["__import__"] = p["TernaryFunc"]; - } - - internal static Type GetPrototype(string name) { - return pmap[name] as Type; - } - - internal static IntPtr GetThunk(MethodInfo method) { - Type dt = Interop.GetPrototype(method.Name); - if (dt != null) { - IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size); - Delegate d = Delegate.CreateDelegate(dt, method); - Thunk cb = new Thunk(d); - Marshal.StructureToPtr(cb, tmp, false); - IntPtr fp = Marshal.ReadIntPtr(tmp, 0); - Marshal.FreeHGlobal(tmp); - keepAlive.Add(d); - return fp; - } - return IntPtr.Zero; - } - - [CallConvCdecl()] - public delegate IntPtr UnaryFunc(IntPtr ob); - - [CallConvCdecl()] - public delegate IntPtr BinaryFunc(IntPtr ob, IntPtr arg); - - [CallConvCdecl()] - public delegate IntPtr TernaryFunc(IntPtr ob, IntPtr a1, IntPtr a2); - - [CallConvCdecl()] - public delegate int InquiryFunc(IntPtr ob); - - [CallConvCdecl()] - public delegate IntPtr IntArgFunc(IntPtr ob, int arg); - - [CallConvCdecl()] - public delegate IntPtr IntIntArgFunc(IntPtr ob, int a1, int a2); - - [CallConvCdecl()] - public delegate int IntObjArgFunc(IntPtr ob, int a1, IntPtr a2); - - [CallConvCdecl()] - public delegate int IntIntObjArgFunc(IntPtr o, int a, int b, IntPtr c); - - [CallConvCdecl()] - public delegate int ObjObjArgFunc(IntPtr o, IntPtr a, IntPtr b); - - [CallConvCdecl()] - public delegate int ObjObjFunc(IntPtr ob, IntPtr arg); - - [CallConvCdecl()] - public delegate void DestructorFunc(IntPtr ob); - - [CallConvCdecl()] - public delegate int PrintFunc(IntPtr ob, IntPtr a, int b); - - [CallConvCdecl()] - public delegate IntPtr RichCmpFunc(IntPtr ob, IntPtr a, int b); - - } - - - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] - internal struct Thunk { - public Delegate fn; - - public Thunk(Delegate d) { - fn = d; - } - } - -} diff --git a/pythonnet/src/runtime/ipythonconvertable.cs b/pythonnet/src/runtime/ipythonconvertable.cs deleted file mode 100755 index 746744b4f..000000000 --- a/pythonnet/src/runtime/ipythonconvertable.cs +++ /dev/null @@ -1,71 +0,0 @@ -// =========================================================================== -// -// Copyright (c) 2005 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// 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. -// -// =========================================================================== - -using System; - -namespace Python.Runtime { - - //======================================================================== - // Internal interface for objects that are convertable to a Python object - // representation. The outputs of this interface are generally expected to - // be platform-compatible pointers meaningful to the CPython runtime. - //======================================================================== - - internal interface IPythonConvertable { - - //===================================================================== - // Given an arbitrary managed object, return a valid PyObject pointer - // or null if the given object cannot be converted to a Python object. - //===================================================================== - - IntPtr GetPythonObjectPtr(object o); - - //===================================================================== - // Given an arbitrary managed object, return a valid PyType_Object - // pointer representing the Python version of the type of that object, - // or null if the object has no meaningful Python type. - //===================================================================== - - IntPtr GetPythonTypePtr(object o); - - //===================================================================== - // Given an arbitrary managed type object, return a valid PyType_Object - // pointer representing the Python version of that type, or null if the - // given type cannot be converted to a meaningful Python type. - //===================================================================== - - IntPtr GetPythonTypePtr(Type t); - - - //===================================================================== - // Given an arbitrary python object, return the managed object that - // the python object wraps, or null if the python object does not wrap - // a valid managed object. - //===================================================================== - - object GetManagedObject(IntPtr op); - - //===================================================================== - // Given an arbitrary python object, return a valid managed Type object - // representing the type of the python wrapper object, or null if the - // python object does not wrap a managed type. - //===================================================================== - - Type GetManagedType(IntPtr op); - - - } - -} diff --git a/pythonnet/src/runtime/iterator.cs b/pythonnet/src/runtime/iterator.cs deleted file mode 100755 index 8fdfa5805..000000000 --- a/pythonnet/src/runtime/iterator.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // Implements a generic Python iterator for IEnumerable objects and - // managed array objects. This supports 'for i in object:' in Python. - //======================================================================== - - internal class Iterator : ExtensionType { - - IEnumerator iter; - - public Iterator(IEnumerator e) : base() { - this.iter = e; - } - - - //==================================================================== - // Implements support for the Python iteration protocol. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_iternext(IntPtr ob) { - Iterator self = GetManagedObject(ob) as Iterator; - if (!self.iter.MoveNext()) { - Exceptions.SetError(Exceptions.StopIteration, Runtime.PyNone); - return IntPtr.Zero; - } - object item = self.iter.Current; - return Converter.ToPythonImplicit(item); - } - - - [CallConvCdecl()] - public static IntPtr tp_iter(IntPtr ob) { - Runtime.Incref(ob); - return ob; - } - - } - - -} diff --git a/pythonnet/src/runtime/managedtype.cs b/pythonnet/src/runtime/managedtype.cs deleted file mode 100755 index 8724b0f37..000000000 --- a/pythonnet/src/runtime/managedtype.cs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // Common base class for all objects that are implemented in managed - // code. It defines the common fields that associate CLR and Python - // objects and common utilities to convert between those identities. - //======================================================================== - - internal abstract class ManagedType { - - internal GCHandle gcHandle; // Native handle - internal IntPtr pyHandle; // PyObject * - internal IntPtr tpHandle; // PyType * - - - //==================================================================== - // Given a Python object, return the associated managed object or null. - //==================================================================== - - internal static ManagedType GetManagedObject(IntPtr ob) { - if (ob != IntPtr.Zero) { - IntPtr tp = Runtime.PyObject_TYPE(ob); - if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) { - tp = ob; - } - - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); - if ((flags & TypeFlags.Managed) != 0) { - IntPtr op = (tp == ob) ? - Marshal.ReadIntPtr(tp, TypeOffset.magic()) : - Marshal.ReadIntPtr(ob, ObjectOffset.magic()); - GCHandle gc = (GCHandle)op; - return (ManagedType)gc.Target; - } - } - return null; - } - - - internal static ManagedType GetManagedObjectErr(IntPtr ob) { - ManagedType result = GetManagedObject(ob); - if (result == null) { - Exceptions.SetError(Exceptions.TypeError, - "invalid argument, expected CLR type" - ); - } - return result; - } - - - internal static bool IsManagedType(IntPtr ob) { - if (ob != IntPtr.Zero) { - IntPtr tp = Runtime.PyObject_TYPE(ob); - if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) { - tp = ob; - } - - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); - if ((flags & TypeFlags.Managed) != 0) { - return true; - } - } - return false; - } - - - } - - -} - diff --git a/pythonnet/src/runtime/metatype.cs b/pythonnet/src/runtime/metatype.cs deleted file mode 100755 index b7d6ca971..000000000 --- a/pythonnet/src/runtime/metatype.cs +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // The managed metatype. This object implements the type of all reflected - // types. It also provides support for single-inheritance from reflected - // managed types. - //======================================================================== - - internal class MetaType : ManagedType { - - static IntPtr PyCLRMetaType; - - - //==================================================================== - // Metatype initialization. This bootstraps the CLR metatype to life. - //==================================================================== - - public static IntPtr Initialize() { - PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType)); - return PyCLRMetaType; - } - - - //==================================================================== - // Metatype __new__ implementation. This is called to create a new - // class / type when a reflected class is subclassed. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { - int len = Runtime.PyTuple_Size(args); - if (len < 3) { - return Exceptions.RaiseTypeError("invalid argument list"); - } - - IntPtr name = Runtime.PyTuple_GetItem(args, 0); - IntPtr bases = Runtime.PyTuple_GetItem(args, 1); - IntPtr dict = Runtime.PyTuple_GetItem(args, 2); - - // We do not support multiple inheritance, so the bases argument - // should be a 1-item tuple containing the type we are subtyping. - // That type must itself have a managed implementation. We check - // that by making sure its metatype is the CLR metatype. - - if (Runtime.PyTuple_Size(bases) != 1) { - return Exceptions.RaiseTypeError( - "cannot use multiple inheritance with managed classes" - ); - - } - - IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0); - IntPtr mt = Runtime.PyObject_TYPE(base_type); - - if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType))) { - return Exceptions.RaiseTypeError("invalid metatype"); - } - - // Ensure that the reflected type is appropriate for subclassing, - // disallowing subclassing of delegates, enums and array types. - - ClassBase cb = GetManagedObject(base_type) as ClassBase; - if (cb != null) { - if (! cb.CanSubclass() ) { - return Exceptions.RaiseTypeError( - "delegates, enums and array types cannot be subclassed" - ); - } - } - - IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__"); - if (slots != IntPtr.Zero) { - return Exceptions.RaiseTypeError( - "subclasses of managed classes do not support __slots__" - ); - } - - // hack for now... fix for 1.0 - //return TypeManager.CreateSubType(args); - - - // right way - - IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType, - TypeOffset.tp_new); - IntPtr type = NativeCall.Call_3(func, tp, args, kw); - if (type == IntPtr.Zero) { - return IntPtr.Zero; - } - - int flags = TypeFlags.Default; - flags |= TypeFlags.Managed; - flags |= TypeFlags.HeapType; - flags |= TypeFlags.BaseType; - flags |= TypeFlags.Subclass; - flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); - - TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc); - - // Hmm - the standard subtype_traverse, clear look at ob_size to - // do things, so to allow gc to work correctly we need to move - // our hidden handle out of ob_size. Then, in theory we can - // comment this out and still not crash. - TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse); - TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear); - - - // for now, move up hidden handle... - IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic()); - Marshal.WriteIntPtr(type, TypeOffset.magic(), gc); - - //DebugUtil.DumpType(base_type); - //DebugUtil.DumpType(type); - - return type; - } - - - [CallConvCdecl()] - public static IntPtr tp_alloc(IntPtr mt, int n) { - IntPtr type = Runtime.PyType_GenericAlloc(mt, n); - return type; - } - - - [CallConvCdecl()] - public static void tp_free(IntPtr tp) { - Runtime.PyObject_GC_Del(tp); - } - - - //==================================================================== - // Metatype __call__ implementation. This is needed to ensure correct - // initialization (__init__ support), because the tp_call we inherit - // from PyType_Type won't call __init__ for metatypes it doesnt know. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) { - IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new); - if (func == IntPtr.Zero) { - return Exceptions.RaiseTypeError("invalid object"); - } - - IntPtr obj = NativeCall.Call_3(func, tp, args, kw); - if (obj == IntPtr.Zero) { - return IntPtr.Zero; - } - - IntPtr py__init__ = Runtime.PyString_FromString("__init__"); - IntPtr type = Runtime.PyObject_TYPE(obj); - IntPtr init = Runtime._PyType_Lookup(type, py__init__); - Runtime.Decref(py__init__); - Runtime.PyErr_Clear(); - - if (init != IntPtr.Zero) { - IntPtr bound = Runtime.GetBoundArgTuple(obj, args); - if (bound == IntPtr.Zero) { - Runtime.Decref(obj); - return IntPtr.Zero; - } - - IntPtr result = Runtime.PyObject_Call(init, bound, kw); - Runtime.Decref(bound); - - if (result == IntPtr.Zero) { - Runtime.Decref(obj); - return IntPtr.Zero; - } - - Runtime.Decref(result); - } - - return obj; - } - - - //==================================================================== - // Type __setattr__ implementation for reflected types. Note that this - // is slightly different than the standard setattr implementation for - // the normal Python metatype (PyTypeType). We need to look first in - // the type object of a reflected type for a descriptor in order to - // support the right setattr behavior for static fields and properties. - //==================================================================== - - [CallConvCdecl()] - public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) { - IntPtr descr = Runtime._PyType_Lookup(tp, name); - - if (descr != IntPtr.Zero) { - IntPtr dt = Runtime.PyObject_TYPE(descr); - IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set); - if (fp != IntPtr.Zero) { - return NativeCall.Impl.Int_Call_3(fp, descr, name, value); - } - Exceptions.SetError(Exceptions.AttributeError, - "attribute is read-only"); - return -1; - } - - if (Runtime.PyObject_GenericSetAttr(tp, name, value) < 0) { - return -1; - } - - return 0; - } - - - //==================================================================== - // Dealloc implementation. This is called when a Python type generated - // by this metatype is no longer referenced from the Python runtime. - //==================================================================== - - [CallConvCdecl()] - public static void tp_dealloc(IntPtr tp) { - // Fix this when we dont cheat on the handle for subclasses! - - int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); - if ((flags & TypeFlags.Subclass) == 0) { - IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic()); - ((GCHandle)gc).Free(); - } - - IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type); - Runtime.Decref(op); - - // Delegate the rest of finalization the Python metatype. Note - // that the PyType_Type implementation of tp_dealloc will call - // tp_free on the type of the type being deallocated - in this - // case our CLR metatype. That is why we implement tp_free. - - op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc); - NativeCall.Void_Call_1(op, tp); - - return; - } - - - - - } - - -} diff --git a/pythonnet/src/runtime/methodbinder.cs b/pythonnet/src/runtime/methodbinder.cs deleted file mode 100755 index 0711298f6..000000000 --- a/pythonnet/src/runtime/methodbinder.cs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) 2003 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // A MethodBinder encapsulates information about a (possibly overloaded) - // managed method, and is responsible for selecting the right method given - // a set of Python arguments. This is also used as a base class for the - // ConstructorBinder, a minor variation used to invoke constructors. - //======================================================================== - - internal class MethodBinder { - - public ArrayList list; - public MethodBase[] methods; - public bool init = false; - - internal MethodBinder () { - this.list = new ArrayList(); - } - - internal MethodBinder(MethodInfo mi) : base () { - this.list = new ArrayList(); - this.list.Add(mi); - } - - public int Count { - get { return this.list.Count; } - } - - internal void AddMethod(MethodBase m) { - this.list.Add(m); - } - - - //==================================================================== - // Return the array of MethodInfo for this method. The result array - // is arranged in order of precendence (done lazily to avoid doing it - // at all for methods that are never called). - //==================================================================== - - internal MethodBase[] GetMethods() { - if (!init) { - // I'm sure this could be made more efficient. - list.Sort(new MethodSorter()); - methods = (MethodBase[])list.ToArray(typeof(MethodBase)); - init = true; - } - return methods; - } - - - //==================================================================== - // Precedence algorithm largely lifted from jython - the concerns are - // generally the same so we'll start w/this and tweak as necessary. - //==================================================================== - - internal static int GetPrecedence(MethodBase mi) { - ParameterInfo[] pi = mi.GetParameters(); - int val = mi.IsStatic ? 3000 : 0; - int num = pi.Length; - - for (int i = 0; i < num; i++) { - val += ArgPrecedence(pi[i].ParameterType); - } - - return val; - } - - - //==================================================================== - // Return a precedence value for a particular Type object. - //==================================================================== - - internal static int ArgPrecedence(Type t) { - Type objectType = typeof(Object); - if (t == objectType) return 3000; - - TypeCode tc = Type.GetTypeCode(t); - if (tc == TypeCode.Object) return 1; - if (tc == TypeCode.UInt64) return 10; - if (tc == TypeCode.UInt32) return 11; - if (tc == TypeCode.UInt16) return 12; - if (tc == TypeCode.Int64) return 13; - if (tc == TypeCode.Int32) return 14; - if (tc == TypeCode.Int16) return 15; - if (tc == TypeCode.Char) return 16; - if (tc == TypeCode.SByte) return 17; - if (tc == TypeCode.Byte) return 18; - if (tc == TypeCode.Single) return 20; - if (tc == TypeCode.Double) return 21; - if (tc == TypeCode.String) return 30; - if (tc == TypeCode.Boolean) return 40; - - if (t.IsArray) { - Type e = t.GetElementType(); - if (e == objectType) - return 2500; - return 100 + ArgPrecedence(e); - } - - return 2000; - } - - - - //==================================================================== - // Bind the given Python instance and arguments to a particular method - // overload and return a structure that contains the converted Python - // instance, converted arguments and the correct method to call. - //==================================================================== - - internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw) { - // loop to find match, return invoker w/ or /wo error - int nargs = Runtime.PyTuple_Size(args); - object arg; - - MethodBase[] _methods = GetMethods(); - - for (int i = 0; i < _methods.Length; i++) { - MethodBase mi = _methods[i]; - ParameterInfo[] pi = mi.GetParameters(); - int count = pi.Length; - int outs = 0; - - if ( nargs == count ) { - Object[] margs = new Object[count]; - - for (int n = 0; n < count; n++) { - IntPtr op = Runtime.PyTuple_GetItem(args, n); - Type type = pi[n].ParameterType; - if (pi[n].IsOut || type.IsByRef) { - outs++; - } - - if (!Converter.ToManaged(op, type, out arg, false)) { - Exceptions.Clear(); - margs = null; - break; - } - margs[n] = arg; - } - - if (margs == null) { - continue; - } - - Object target = null; - if ((!mi.IsStatic) && (inst != IntPtr.Zero)) { - CLRObject co = (CLRObject)ManagedType.GetManagedObject( - inst - ); - target = co.inst; - } - - return new Binding(mi, target, margs, outs); - } - - } - return null; - } - - - internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) { - Binding binding = this.Bind(inst, args, kw); - Object result; - - if (binding == null) { - Exceptions.SetError(Exceptions.TypeError, - "no method matches given arguments" - ); - return IntPtr.Zero; - } - - IntPtr ts = PythonEngine.BeginAllowThreads(); - try { - result = binding.info.Invoke(binding.inst, - BindingFlags.Default, - null, - binding.args, - null); - } - catch (Exception e) { - if (e.InnerException != null) { - e = e.InnerException; - } - PythonEngine.EndAllowThreads(ts); - Exceptions.SetError(e); - return IntPtr.Zero; - } - - PythonEngine.EndAllowThreads(ts); - - // If there are out parameters, we return a tuple containing - // the result followed by the out parameters. If there is only - // one out parameter and the return type of the method is void, - // we return the out parameter as the result to Python (for - // code compatibility with ironpython). - - MethodInfo mi = (MethodInfo)binding.info; - - if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) { - - } - - if (binding.outs > 0) { - ParameterInfo[] pi = mi.GetParameters(); - int c = pi.Length; - int n = 0; - - IntPtr t = Runtime.PyTuple_New(binding.outs + 1); - IntPtr v = Converter.ToPython(result, mi.ReturnType); - Runtime.PyTuple_SetItem(t, n, v); - n++; - - for (int i=0; i < c; i++) { - Type pt = pi[i].ParameterType; - if (pi[i].IsOut || pt.IsByRef) { - v = Converter.ToPython(binding.args[i], pt); - Runtime.PyTuple_SetItem(t, n, v); - n++; - } - } - - if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) { - v = Runtime.PyTuple_GetItem(t, 1); - Runtime.Incref(v); - Runtime.Decref(t); - return v; - } - - return t; - } - - return Converter.ToPython(result, mi.ReturnType); - } - - } - - - - //======================================================================== - // Utility class to sort method info by parameter type precedence. - //======================================================================== - - internal class MethodSorter : IComparer { - - int IComparer.Compare(Object m1, Object m2) { - int p1 = MethodBinder.GetPrecedence((MethodBase)m1); - int p2 = MethodBinder.GetPrecedence((MethodBase)m2); - if (p1 < p2) return -1; - if (p1 > p2) return 1; - return 0; - } - - } - - - //======================================================================== - // A Binding is a utility instance that bundles together a MethodInfo - // representing a method to call, a (possibly null) target instance for - // the call, and the arguments for the call (all as managed values). - //======================================================================== - - internal class Binding { - - public MethodBase info; - public Object[] args; - public Object inst; - public int outs; - - internal Binding(MethodBase info, Object inst, Object[] args, - int outs) { - this.info = info; - this.inst = inst; - this.args = args; - this.outs = outs; - } - - } - -} diff --git a/pythonnet/src/runtime/methodbinding.cs b/pythonnet/src/runtime/methodbinding.cs deleted file mode 100755 index c32785199..000000000 --- a/pythonnet/src/runtime/methodbinding.cs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - //======================================================================== - // Implements a Python binding type for CLR methods. These work much like - // standard Python method bindings, but the same type is used to bind - // both static and instance methods. - //======================================================================== - - internal class MethodBinding : ExtensionType { - - MethodObject m; - IntPtr target; - - public MethodBinding(MethodObject m, IntPtr target) : base() { - Runtime.Incref(target); - this.target = target; - this.m = m; - } - - - //==================================================================== - // MethodBinding __getattribute__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); - - if (!Runtime.PyString_Check(key)) { - Exceptions.SetError(Exceptions.TypeError, "string expected"); - return IntPtr.Zero; - } - - string name = Runtime.GetManagedString(key); - if (name == "__doc__") { - IntPtr doc = self.m.GetDocString(); - Runtime.Incref(doc); - return doc; - } - - return Runtime.PyObject_GenericGetAttr(ob, key); - } - - - //==================================================================== - // MethodBinding __call__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); - - // This supports calling a method 'unbound', passing the instance - // as the first argument. Note that this is not supported if any - // of the overloads are static since we can't know if the intent - // was to call the static method or the unbound instance method. - - if ((self.target == IntPtr.Zero) && (!self.m.IsStatic())) { - if (Runtime.PyTuple_Size(args) < 1) { - Exceptions.SetError(Exceptions.TypeError, - "not enough arguments" - ); - return IntPtr.Zero; - } - int len = Runtime.PyTuple_Size(args); - 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); - Runtime.Decref(inst); - return r; - } - - return self.m.Invoke(self.target, args, kw); - } - - - //==================================================================== - // MethodBinding __hash__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_hash(IntPtr ob) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); - long x = 0; - long y = 0; - - if (self.target != IntPtr.Zero) { - x = Runtime.PyObject_Hash(self.target).ToInt64(); - if (x == -1) { - return new IntPtr(-1); - } - } - - y = Runtime.PyObject_Hash(self.m.pyHandle).ToInt64(); - if (y == -1) { - return new IntPtr(-1); - } - - x ^= y; - - if (x == -1) { - x = -1; - } - - return new IntPtr(x); - } - - - //==================================================================== - // MethodBinding __repr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_repr(IntPtr ob) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); - string type = (self.target == IntPtr.Zero) ? "unbound" : "bound"; - string s = String.Format("<{0} method '{1}'>", type, self.m.name); - return Runtime.PyString_FromStringAndSize(s, s.Length); - } - - //==================================================================== - // MethodBinding dealloc implementation. - //==================================================================== - - [CallConvCdecl()] - public static new void tp_dealloc(IntPtr ob) { - MethodBinding self = (MethodBinding)GetManagedObject(ob); - Runtime.Decref(self.target); - ExtensionType.FinalizeObject(self); - } - - } - - -} diff --git a/pythonnet/src/runtime/methodobject.cs b/pythonnet/src/runtime/methodobject.cs deleted file mode 100755 index 9d0972d04..000000000 --- a/pythonnet/src/runtime/methodobject.cs +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // Implements a Python type that provides access to CLR object methods. - //======================================================================== - - internal class MethodObject : ExtensionType { - - internal MethodInfo[] info; - internal string name; - internal MethodBinding unbound; - internal MethodBinder binder; - internal IntPtr doc; - - public MethodObject(string name, MethodInfo[] info) : base() { - this.name = name; - this.info = info; - binder = new MethodBinder(); - for (int i = 0; i < info.Length; i++) { - binder.AddMethod((MethodInfo)info[i]); - } - } - - - public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw) { - return binder.Invoke(target, args, kw); - } - - - //==================================================================== - // Helper to get docstrings from reflected method / param info. - //==================================================================== - - internal IntPtr GetDocString() { - if (doc != IntPtr.Zero) { - return doc; - } - MethodBase[] methods = binder.GetMethods(); - string str = ""; - for (int i = 0; i < methods.Length; i++) { - if (str.Length > 0) - str += Environment.NewLine; - str += methods[i].ToString(); - } - doc = Runtime.PyString_FromString(str); - return doc; - } - - - //==================================================================== - // This is a little tricky: a class can actually have a static method - // and instance methods all with the same name. That makes it tough - // to support calling a method 'unbound' (passing the instance as the - // first argument), because in this case we can't know whether to call - // the instance method unbound or call the static method. - // - // The rule we is that if there are both instance and static methods - // with the same name, then we always call the static method. So this - // method returns true if any of the methods that are represented by - // the descriptor are static methods (called by MethodBinding). - //==================================================================== - - internal bool IsStatic() { - MethodBase[] methods = binder.GetMethods(); - for (int i = 0; i < methods.Length; i++) { - if (methods[i].IsStatic) - return true; - } - return false; - } - - - //==================================================================== - // Descriptor __getattribute__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - MethodObject self = (MethodObject)GetManagedObject(ob); - - if (!Runtime.PyString_Check(key)) { - return Exceptions.RaiseTypeError("string expected"); - } - - string name = Runtime.GetManagedString(key); - if (name == "__doc__") { - IntPtr doc = self.GetDocString(); - Runtime.Incref(doc); - return doc; - } - - return Runtime.PyObject_GenericGetAttr(ob, key); - } - - - //==================================================================== - // Descriptor __get__ implementation. Accessing a CLR method returns - // a "bound" method similar to a Python bound method. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - MethodObject self = (MethodObject)GetManagedObject(ds); - MethodBinding binding; - - // If the method is accessed through its type (rather than via - // an instance) we return an 'unbound' MethodBinding that will - // cached for future accesses through the type. - - if (ob == IntPtr.Zero) { - if (self.unbound == null) { - self.unbound = new MethodBinding(self, IntPtr.Zero); - } - binding = self.unbound; - Runtime.Incref(binding.pyHandle);; - return binding.pyHandle; - } - - if (Runtime.PyObject_IsInstance(ob, tp) < 1) { - return Exceptions.RaiseTypeError("invalid argument"); - } - - binding = new MethodBinding(self, ob); - return binding.pyHandle; - } - - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_repr(IntPtr ob) { - MethodObject self = (MethodObject)GetManagedObject(ob); - string s = String.Format("", self.name); - return Runtime.PyString_FromStringAndSize(s, s.Length); - } - - //==================================================================== - // Descriptor dealloc implementation. - //==================================================================== - - [CallConvCdecl()] - public static new void tp_dealloc(IntPtr ob) { - MethodObject self = (MethodObject)GetManagedObject(ob); - Runtime.Decref(self.doc); - if (self.unbound != null) { - Runtime.Decref(self.unbound.pyHandle); - } - ExtensionType.FinalizeObject(self); - } - - - } - - -} diff --git a/pythonnet/src/runtime/methodwrapper.cs b/pythonnet/src/runtime/methodwrapper.cs deleted file mode 100755 index 0d866aab9..000000000 --- a/pythonnet/src/runtime/methodwrapper.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// A MethodWrapper wraps a static method of a managed type, - /// making it callable by Python as a PyCFunction object. This is - /// currently used mainly to implement special cases like the CLR - /// import hook. - /// - - internal class MethodWrapper { - - public IntPtr mdef; - public IntPtr ptr; - - public MethodWrapper(Type type, string name) { - - // Turn the managed method into a function pointer - - IntPtr fp = Interop.GetThunk(type.GetMethod(name)); - - // XXX - here we create a Python string object, then take the - // char * of the internal string to pass to our methoddef - // structure. Its a hack, and the name is leaked! - - IntPtr ps = Runtime.PyString_FromString(name); - IntPtr sp = Runtime.PyString_AS_STRING(ps); - - // Allocate and initialize a PyMethodDef structure to represent - // the managed method, then create a PyCFunction. - - mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size); - Marshal.WriteIntPtr(mdef, sp); - Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), fp); - Marshal.WriteIntPtr(mdef, (2 * IntPtr.Size), (IntPtr)0x0002); - Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), IntPtr.Zero); - ptr = Runtime.PyCFunction_New(mdef, IntPtr.Zero); - } - - public IntPtr Call(IntPtr args, IntPtr kw) { - return Runtime.PyCFunction_Call(ptr, args, kw); - } - - - } - - -} - diff --git a/pythonnet/src/runtime/moduleobject.cs b/pythonnet/src/runtime/moduleobject.cs deleted file mode 100755 index f9741ff62..000000000 --- a/pythonnet/src/runtime/moduleobject.cs +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; -using System.Collections.Specialized; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - // TODO: decide whether to support __all__ and / or whether to impl - // a 'preload' method to force names to be pre-loaded. - - //======================================================================== - // Implements a Python type that provides access to CLR namespaces. The - // type behaves like a Python module, and can contain other sub-modules. - //======================================================================== - - internal class ModuleObject : ExtensionType { - - string moduleName; - string _namespace; - Hashtable cache; - static bool hacked; - IntPtr dict; - - public ModuleObject(string name) : base() { - moduleName = (name == String.Empty) ? "CLR" : "CLR." + name; - cache = new Hashtable(); - _namespace = name; - - dict = Runtime.PyDict_New(); - IntPtr pyname = Runtime.PyString_FromString(moduleName); - Runtime.PyDict_SetItemString(dict, "__name__", pyname); - Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone); - Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone); - Runtime.Decref(pyname); - - Marshal.WriteIntPtr(this.pyHandle, ObjectOffset.ob_dict, dict); - - // This hackery is required in order to allow a plain Python to - // import the managed runtime via the CLR bootstrapper module. - // The standard Python machinery in control at the time of the - // import requires the module to pass PyModule_Check. :( - - if (!hacked) { - IntPtr type = this.tpHandle; - IntPtr mro = Marshal.ReadIntPtr(type, TypeOffset.tp_mro); - IntPtr ext = Runtime.ExtendTuple(mro, Runtime.PyModuleType); - Marshal.WriteIntPtr(type, TypeOffset.tp_mro, ext); - Runtime.Decref(mro); - hacked = true; - } - - } - - public string ModuleName { - get { - return moduleName; - } - } - - - //=================================================================== - // Returns a ClassBase object representing a type that appears in - // this module's namespace or a ModuleObject representing a child - // namespace (or null if the name is not found). This method does - // not increment the Python refcount of the returned object. - //=================================================================== - - public ManagedType GetAttribute(string name) { - Object ob = this.cache[name]; - if (ob != null) { - return (ManagedType) ob; - } - - string qname = (_namespace == String.Empty) ? name : - _namespace + "." + name; - - ModuleObject m; - ClassBase c; - - // If the fully-qualified name of the requested attribute is - // a namespace exported by a currently loaded assembly, return - // a new ModuleObject representing that namespace. - - if (AssemblyManager.IsValidNamespace(qname)) { - m = new ModuleObject(qname); - StoreAttribute(name, m); - return (ManagedType) m; - } - - // Look for a type in the current namespace. Note that this - // includes types, delegates, enums, interfaces and structs. - // Only public namespace members are exposed to Python. - - Type type = AssemblyManager.LookupType(qname); - if (type != null) { - if (!type.IsPublic) { - return null; - } - c = ClassManager.GetClass(type); - StoreAttribute(name, c); - return (ManagedType) c; - } - - // This is a little repetitive, but it ensures that the right - // thing happens with implicit assembly loading at a reasonable - // cost. Ask the AssemblyManager to do implicit loading for each - // of the steps in the qualified name, then try it again. - - if (AssemblyManager.LoadImplicit(qname)) { - if (AssemblyManager.IsValidNamespace(qname)) { - m = new ModuleObject(qname); - StoreAttribute(name, m); - return (ManagedType) m; - } - - type = AssemblyManager.LookupType(qname); - if (type != null) { - if (!type.IsPublic) { - return null; - } - c = ClassManager.GetClass(type); - StoreAttribute(name, c); - return (ManagedType) c; - } - } - - return null; - } - - - //=================================================================== - // Stores an attribute in the instance dict for future lookups. - //=================================================================== - - private void StoreAttribute(string name, ManagedType ob) { - Runtime.PyDict_SetItemString(dict, name, ob.pyHandle); - cache[name] = ob; - } - - - [PythonMethod] - public static IntPtr _preload(IntPtr ob, IntPtr args, IntPtr kw) { - ModuleObject self = (ModuleObject)GetManagedObject(ob); - - string module_ns = self._namespace; - AppDomain domain = AppDomain.CurrentDomain; - Assembly[] assemblies = domain.GetAssemblies(); - for (int i = 0; i < assemblies.Length; i++) { - Assembly assembly = assemblies[i]; - Type[] types = assembly.GetTypes(); - for (int n = 0; n < types.Length; n++) { - Type type = types[n]; - - string ns = type.Namespace; - if ((ns != null) && (ns == module_ns)) { - if (type.IsPublic) { - ClassBase c = ClassManager.GetClass(type); - self.StoreAttribute(type.Name, c); - } - } - } - } - Runtime.Incref(Runtime.PyNone); - return Runtime.PyNone; - } - - - //==================================================================== - // ModuleObject __getattribute__ implementation. Module attributes - // are always either classes or sub-modules representing subordinate - // namespaces. CLR modules implement a lazy pattern - the sub-modules - // and classes are created when accessed and cached for future use. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { - ModuleObject self = (ModuleObject)GetManagedObject(ob); - - if (!Runtime.PyString_Check(key)) { - Exceptions.SetError(Exceptions.TypeError, "string expected"); - return IntPtr.Zero; - } - - IntPtr op = Runtime.PyDict_GetItem(self.dict, key); - if (op != IntPtr.Zero) { - Runtime.Incref(op); - return op; - } - - string name = Runtime.GetManagedString(key); - if (name == "__dict__") { - Runtime.Incref(self.dict); - return self.dict; - } - - ManagedType attr = self.GetAttribute(name); - - if (attr == null) { - Exceptions.SetError(Exceptions.AttributeError, name); - return IntPtr.Zero; - } - - // XXX - hack required to recognize exception types. These types - // may need to be wrapped in old-style class wrappers in versions - // of Python where new-style classes cannot be used as exceptions. - - if (Runtime.wrap_exceptions) { - if (attr is ClassBase) { - ClassBase c = attr as ClassBase; - if (c.is_exception) { - IntPtr p = attr.pyHandle; - IntPtr r = Exceptions.GetExceptionClassWrapper(p); - Runtime.PyDict_SetItemString(self.dict, name, r); - Runtime.Incref(r); - return r; - } - } - } - - Runtime.Incref(attr.pyHandle); - return attr.pyHandle; - } - - //==================================================================== - // ModuleObject __repr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_repr(IntPtr ob) { - ModuleObject self = (ModuleObject)GetManagedObject(ob); - string s = String.Format("", self.moduleName); - return Runtime.PyString_FromString(s); - } - - } - - -} diff --git a/pythonnet/src/runtime/nativecall.cs b/pythonnet/src/runtime/nativecall.cs deleted file mode 100755 index 2d120b0ec..000000000 --- a/pythonnet/src/runtime/nativecall.cs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Threading; -using System.Runtime.InteropServices; -using System.Collections; -using System.Reflection; -using System.Reflection.Emit; - -namespace Python.Runtime { - - /// - /// Provides support for calling native code indirectly through - /// function pointers. Most of the important parts of the Python - /// C API can just be wrapped with p/invoke, but there are some - /// situations (specifically, calling functions through Python - /// type structures) where we need to call functions indirectly. - /// - /// This class uses Reflection.Emit to generate IJW thunks that - /// support indirect calls to native code using various common - /// call signatures. This is mainly a workaround for the fact - /// that you can't spell an indirect call in C# (but can in IL). - /// - /// Another approach that would work is for this to be turned - /// into a separate utility program that could be run during the - /// build process to generate the thunks as a separate assembly - /// that could then be referenced by the main Python runtime. - /// - - internal class NativeCall { - - static AssemblyBuilder aBuilder; - static ModuleBuilder mBuilder; - - public static INativeCall Impl; - - static NativeCall() { - - // The static constructor is responsible for generating the - // assembly and the methods that implement the IJW thunks. - // - // To do this, we actually use reflection on the INativeCall - // interface (defined below) and generate the required thunk - // code based on the method signatures. - - AssemblyName aname = new AssemblyName(); - aname.Name = "e__NativeCall_Assembly"; - AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run; - - aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); - mBuilder = aBuilder.DefineDynamicModule("e__NativeCall_Module"); - - TypeAttributes ta = TypeAttributes.Public; - TypeBuilder tBuilder = mBuilder.DefineType("e__NativeCall", ta); - - Type iType = typeof(INativeCall); - tBuilder.AddInterfaceImplementation(iType); - - // Use reflection to loop over the INativeCall interface methods, - // calling GenerateThunk to create a managed thunk for each one. - - foreach (MethodInfo method in iType.GetMethods()) { - GenerateThunk(tBuilder, method); - } - - Type theType = tBuilder.CreateType(); - - Impl = (INativeCall)Activator.CreateInstance(theType); - - } - - private static void GenerateThunk(TypeBuilder tb, MethodInfo method) { - - ParameterInfo[] pi = method.GetParameters(); - int count = pi.Length; - int argc = count - 1; - - Type[] args = new Type[count]; - for (int i = 0; i < count; i++) { - args[i] = pi[i].ParameterType; - } - - MethodBuilder mb = tb.DefineMethod( - method.Name, - MethodAttributes.Public | - MethodAttributes.Virtual, - method.ReturnType, - args - ); - - // Build the method signature for the actual native function. - // This is essentially the signature of the wrapper method - // minus the first argument (the passed in function pointer). - - Type[] nargs = new Type[argc]; - for (int i = 1; i < count; i++) { - nargs[(i - 1)] = args[i]; - } - - // IL generation: the (implicit) first argument of the method - // is the 'this' pointer and the second is the function pointer. - // This code pushes the real args onto the stack, followed by - // the function pointer, then the calli opcode to make the call. - - ILGenerator il = mb.GetILGenerator(); - - for (int i = 0; i < argc; i++) { - il.Emit(OpCodes.Ldarg_S, (i + 2)); - } - - il.Emit(OpCodes.Ldarg_1); - - il.EmitCalli(OpCodes.Calli, - CallingConvention.Cdecl, - method.ReturnType, - nargs - ); - - il.Emit(OpCodes.Ret); - - tb.DefineMethodOverride(mb, method); - return; - } - - - public static void Void_Call_1(IntPtr fp, IntPtr a1) { - Impl.Void_Call_1(fp, a1); - } - - public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2, - IntPtr a3) { - return Impl.Call_3(fp, a1, a2, a3); - } - - public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2, - IntPtr a3) { - return Impl.Int_Call_3(fp, a1, a2, a3); - } - - } - - - /// - /// Defines native call signatures to be generated by NativeCall. - /// - - public interface INativeCall { - - void Void_Call_0(IntPtr funcPtr); - - void Void_Call_1(IntPtr funcPtr, IntPtr arg1); - - int Int_Call_3(IntPtr funcPtr, IntPtr t, IntPtr n, IntPtr v); - - IntPtr Call_3(IntPtr funcPtr, IntPtr a1, IntPtr a2, IntPtr a3); - - } - -} diff --git a/pythonnet/src/runtime/propertyobject.cs b/pythonnet/src/runtime/propertyobject.cs deleted file mode 100755 index 496ae14ad..000000000 --- a/pythonnet/src/runtime/propertyobject.cs +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; -using System.Security.Permissions; - -namespace Python.Runtime { - - //======================================================================== - // Implements a Python descriptor type that manages CLR properties. - //======================================================================== - - internal class PropertyObject : ExtensionType { - - PropertyInfo info; - MethodInfo getter; - MethodInfo setter; - - [StrongNameIdentityPermissionAttribute(SecurityAction.Assert)] - public PropertyObject(PropertyInfo md) : base() { - getter = md.GetGetMethod(true); - setter = md.GetSetMethod(true); - info = md; - } - - - //==================================================================== - // Descriptor __get__ implementation. This method returns the - // value of the property on the given object. The returned value - // is converted to an appropriately typed Python object. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { - PropertyObject self = (PropertyObject)GetManagedObject(ds); - MethodInfo getter = self.getter; - IntPtr ts = IntPtr.Zero; - Object result; - - - if (getter == null) { - return Exceptions.RaiseTypeError("property cannot be read"); - } - - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { - if (!(getter.IsStatic)) { - Exceptions.SetError(Exceptions.TypeError, - "instance property must be accessed through " + - "a class instance" - ); - return IntPtr.Zero; - } - - try { - result = self.info.GetValue(null, null); - return Converter.ToPython(result, self.info.PropertyType); - } - catch(Exception e) { - return Exceptions.RaiseTypeError(e.Message); - } - } - - CLRObject co = GetManagedObject(ob) as CLRObject; - if (co == null) { - return Exceptions.RaiseTypeError("invalid target"); - } - - try { - result = self.info.GetValue(co.inst, null); - return Converter.ToPython(result, self.info.PropertyType); - } - catch(Exception e) { - if (e.InnerException != null) { - e = e.InnerException; - } - Exceptions.SetError(e); - return IntPtr.Zero; - } - } - - - //==================================================================== - // Descriptor __set__ implementation. This method sets the value of - // a property based on the given Python value. The Python value must - // be convertible to the type of the property. - //==================================================================== - - [CallConvCdecl()] - public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { - PropertyObject self = (PropertyObject)GetManagedObject(ds); - MethodInfo setter = self.setter; - IntPtr ts = IntPtr.Zero; - Object newval; - - if (val == IntPtr.Zero) { - Exceptions.RaiseTypeError("cannot delete property"); - return -1; - } - - if (setter == null) { - Exceptions.RaiseTypeError("property is read-only"); - return -1; - } - - - if (!Converter.ToManaged(val, self.info.PropertyType, out newval, - true)) { - return -1; - } - - bool is_static = setter.IsStatic; - - if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { - if (!(is_static)) { - Exceptions.RaiseTypeError( - "instance property must be set on an instance" - ); - return -1; - } - } - - try { - if (!is_static) { - CLRObject co = GetManagedObject(ob) as CLRObject; - if (co == null) { - Exceptions.RaiseTypeError("invalid target"); - return -1; - } - self.info.SetValue(co.inst, newval, null); - } - else { - self.info.SetValue(null, newval, null); - } - return 0; - } - catch(Exception e) { - if (e.InnerException != null) { - e = e.InnerException; - } - Exceptions.SetError(e); - return -1; - } - - } - - - //==================================================================== - // Descriptor __repr__ implementation. - //==================================================================== - - [CallConvCdecl()] - public static IntPtr tp_repr(IntPtr ob) { - PropertyObject self = (PropertyObject)GetManagedObject(ob); - string s = String.Format("", self.info.Name); - return Runtime.PyString_FromStringAndSize(s, s.Length); - } - - } - - -} diff --git a/pythonnet/src/runtime/pydict.cs b/pythonnet/src/runtime/pydict.cs deleted file mode 100755 index 8556313b9..000000000 --- a/pythonnet/src/runtime/pydict.cs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// Represents a Python dictionary object. See the documentation at - /// http://www.python.org/doc/current/api/dictObjects.html for details. - /// - - public class PyDict : PyObject { - - /// - /// PyDict Constructor - /// - /// - /// - /// Creates a new PyDict from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - - public PyDict(IntPtr ptr) : base(ptr) {} - - - /// - /// PyDict Constructor - /// - /// - /// - /// Creates a new Python dictionary object. - /// - - public PyDict() : base() { - obj = Runtime.PyDict_New(); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyDict Constructor - /// - /// - /// - /// Copy constructor - obtain a PyDict from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python dictionary object. - /// - - public PyDict(PyObject o) : base() { - if (!IsDictType(o)) { - throw new ArgumentException("object is not a dict"); - } - Runtime.Incref(o.obj); - obj = o.obj; - } - - - /// - /// IsDictType Method - /// - /// - /// - /// Returns true if the given object is a Python dictionary. - /// - - public static bool IsDictType(PyObject value) { - return Runtime.PyDict_Check(value.obj); - } - - - /// - /// HasKey Method - /// - /// - /// - /// Returns true if the object key appears in the dictionary. - /// - - public bool HasKey(PyObject key) { - return (Runtime.PyMapping_HasKey(obj, key.obj) != 0); - } - - - /// - /// HasKey Method - /// - /// - /// - /// Returns true if the string key appears in the dictionary. - /// - - public bool HasKey(string key) { - return HasKey(new PyString(key)); - } - - - /// - /// Keys Method - /// - /// - /// - /// Returns a sequence containing the keys of the dictionary. - /// - - public PyObject Keys() { - IntPtr items = Runtime.PyDict_Keys(obj); - if (items == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(items); - } - - - /// - /// Values Method - /// - /// - /// - /// Returns a sequence containing the values of the dictionary. - /// - - public PyObject Values() { - IntPtr items = Runtime.PyDict_Values(obj); - if (items == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(items); - } - - - /// - /// Items Method - /// - /// - /// - /// Returns a sequence containing the items of the dictionary. - /// - - public PyObject Items() { - IntPtr items = Runtime.PyDict_Items(obj); - if (items == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(items); - } - - - /// - /// Copy Method - /// - /// - /// - /// Returns a copy of the dictionary. - /// - - public PyDict Copy() { - IntPtr op = Runtime.PyDict_Copy(obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyDict(op); - } - - - /// - /// Update Method - /// - /// - /// - /// Update the dictionary from another dictionary. - /// - - public void Update(PyObject other) { - int result = Runtime.PyDict_Update(obj, other.obj); - if (result < 0) { - throw new PythonException(); - } - } - - - /// - /// Clear Method - /// - /// - /// - /// Clears the dictionary. - /// - - public void Clear() { - Runtime.PyDict_Clear(obj); - } - - - } - -} diff --git a/pythonnet/src/runtime/pyfloat.cs b/pythonnet/src/runtime/pyfloat.cs deleted file mode 100755 index 317fda4f9..000000000 --- a/pythonnet/src/runtime/pyfloat.cs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// Represents a Python float object. See the documentation at - /// http://www.python.org/doc/current/api/floatObjects.html - /// - - public class PyFloat : PyNumber { - - /// - /// PyFloat Constructor - /// - /// - /// - /// Creates a new PyFloat from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - - public PyFloat(IntPtr ptr) : base(ptr) {} - - - /// - /// PyFloat Constructor - /// - /// - /// - /// Copy constructor - obtain a PyFloat from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python float object. - /// - - public PyFloat(PyObject o) : base() { - if (!IsFloatType(o)) { - throw new ArgumentException("object is not a float"); - } - Runtime.Incref(o.obj); - obj = o.obj; - } - - - /// - /// PyFloat Constructor - /// - /// - /// - /// Creates a new Python float from a double value. - /// - - public PyFloat(double value) : base() { - obj = Runtime.PyFloat_FromDouble(value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyFloat Constructor - /// - /// - /// - /// Creates a new Python float from a string value. - /// - - public PyFloat(string value) : base() { - PyString s = new PyString(value); - obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// IsFloatType Method - /// - /// - /// - /// Returns true if the given object is a Python float. - /// - - public static bool IsFloatType(PyObject value) { - return Runtime.PyFloat_Check(value.obj); - } - - - /// - /// AsFloat Method - /// - /// - /// - /// - /// Convert a Python object to a Python float if possible, raising - /// a PythonException if the conversion is not possible. This is - /// equivalent to the Python expression "float(object)". - /// - - public static PyFloat AsFloat(PyObject value) { - IntPtr op = Runtime.PyNumber_Float(value.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyFloat(op); - } - - - } - -} diff --git a/pythonnet/src/runtime/pyint.cs b/pythonnet/src/runtime/pyint.cs deleted file mode 100755 index c07d63fd5..000000000 --- a/pythonnet/src/runtime/pyint.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; - -namespace Python.Runtime { - - /// - /// Represents a Python integer object. See the documentation at - /// http://www.python.org/doc/current/api/intObjects.html for details. - /// - - public class PyInt : PyNumber { - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new PyInt from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - - public PyInt(IntPtr ptr) : base(ptr) {} - - - /// - /// PyInt Constructor - /// - /// - /// - /// Copy constructor - obtain a PyInt from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python int object. - /// - - public PyInt(PyObject o) : base() { - if (!IsIntType(o)) { - throw new ArgumentException("object is not an int"); - } - Runtime.Incref(o.obj); - obj = o.obj; - } - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from an int32 value. - /// - - public PyInt(int value) : base() { - obj = Runtime.PyInt_FromInt32(value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from a uint32 value. - /// - - [CLSCompliant(false)] - public PyInt(uint value) : base(IntPtr.Zero) { - obj = Runtime.PyInt_FromInt64((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from an int64 value. - /// - - public PyInt(long value) : base(IntPtr.Zero) { - obj = Runtime.PyInt_FromInt64(value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from a uint64 value. - /// - - [CLSCompliant(false)] - public PyInt(ulong value) : base(IntPtr.Zero) { - obj = Runtime.PyInt_FromInt64((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from an int16 value. - /// - - public PyInt(short value) : this((int)value) {} - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from a uint16 value. - /// - - [CLSCompliant(false)] - public PyInt(ushort value) : this((int)value) {} - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from a byte value. - /// - - public PyInt(byte value) : this((int)value) {} - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from an sbyte value. - /// - - [CLSCompliant(false)] - public PyInt(sbyte value) : this((int)value) {} - - - /// - /// PyInt Constructor - /// - /// - /// - /// Creates a new Python int from a string value. - /// - - public PyInt(string value) : base() { - obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// IsIntType Method - /// - /// - /// - /// Returns true if the given object is a Python int. - /// - - public static bool IsIntType(PyObject value) { - return Runtime.PyInt_Check(value.obj); - } - - - /// - /// AsInt Method - /// - /// - /// - /// - /// Convert a Python object to a Python int if possible, raising - /// a PythonException if the conversion is not possible. This is - /// equivalent to the Python expression "int(object)". - /// - - public static PyInt AsInt(PyObject value) { - IntPtr op = Runtime.PyNumber_Int(value.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyInt(op); - } - - - /// - /// ToInt16 Method - /// - /// - /// - /// Return the value of the Python int object as an int16. - /// - - public short ToInt16() { - return System.Convert.ToInt16(this.ToInt32()); - } - - - /// - /// ToInt32 Method - /// - /// - /// - /// Return the value of the Python int object as an int32. - /// - - public int ToInt32() { - return Runtime.PyInt_AsLong(obj); - } - - - /// - /// ToInt64 Method - /// - /// - /// - /// Return the value of the Python int object as an int64. - /// - - public long ToInt64() { - return System.Convert.ToInt64(this.ToInt32()); - } - - - - } - -} diff --git a/pythonnet/src/runtime/pylist.cs b/pythonnet/src/runtime/pylist.cs deleted file mode 100755 index d7ac1e1ca..000000000 --- a/pythonnet/src/runtime/pylist.cs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - /// - /// Represents a standard Python list object. See the documentation at - /// http://www.python.org/doc/current/api/listObjects.html for details. - /// - - public class PyList : PySequence { - - /// - /// PyList Constructor - /// - /// - /// - /// Creates a new PyList from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - - public PyList(IntPtr ptr) : base(ptr) {} - - - /// - /// PyList Constructor - /// - /// - /// - /// Copy constructor - obtain a PyList from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python list object. - /// - - public PyList(PyObject o) : base() { - if (!IsListType(o)) { - throw new ArgumentException("object is not a list"); - } - Runtime.Incref(o.obj); - obj = o.obj; - } - - - /// - /// PyList Constructor - /// - /// - /// - /// Creates a new empty Python list object. - /// - - public PyList() : base() { - obj = Runtime.PyList_New(0); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyList Constructor - /// - /// - /// - /// Creates a new Python list object from an array of PyObjects. - /// - - public PyList(PyObject[] items) : base() { - int count = items.Length; - obj = Runtime.PyList_New(count); - for (int i = 0; i < count; i++) { - IntPtr ptr = items[i].obj; - Runtime.Incref(ptr); - int r = Runtime.PyList_SetItem(obj, i, ptr); - if (r < 0) { - throw new PythonException(); - } - } - } - - - /// - /// IsListType Method - /// - /// - /// - /// Returns true if the given object is a Python list. - /// - - public static bool IsListType(PyObject value) { - return Runtime.PyList_Check(value.obj); - } - - - /// - /// AsList Method - /// - /// - /// - /// Converts a Python object to a Python list if possible, raising - /// a PythonException if the conversion is not possible. This is - /// equivalent to the Python expression "list(object)". - /// - - public static PyList AsList(PyObject value) { - IntPtr op = Runtime.PySequence_List(value.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyList(op); - } - - - /// - /// Append Method - /// - /// - /// - /// Append an item to the list object. - /// - - public void Append(PyObject item) { - int r = Runtime.PyList_Append(obj, item.obj); - if (r < 0) { - throw new PythonException(); - } - } - - /// - /// Insert Method - /// - /// - /// - /// Insert an item in the list object at the given index. - /// - - public void Insert(int index, PyObject item) { - int r = Runtime.PyList_Insert(obj, index, item.obj); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// Reverse Method - /// - /// - /// - /// Reverse the order of the list object in place. - /// - - public void Reverse() { - int r = Runtime.PyList_Reverse(obj); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// Sort Method - /// - /// - /// - /// Sort the list in place. - /// - - public void Sort() { - int r = Runtime.PyList_Sort(obj); - if (r < 0) { - throw new PythonException(); - } - } - - - } - - -} diff --git a/pythonnet/src/runtime/pylong.cs b/pythonnet/src/runtime/pylong.cs deleted file mode 100755 index 681134c3d..000000000 --- a/pythonnet/src/runtime/pylong.cs +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - /// - /// Represents a Python long int object. See the documentation at - /// http://www.python.org/doc/current/api/longObjects.html - /// - - public class PyLong : PyNumber { - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - - public PyLong(IntPtr ptr) : base(ptr) {} - - - /// - /// PyLong Constructor - /// - /// - /// - /// Copy constructor - obtain a PyLong from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python long object. - /// - - public PyLong(PyObject o) : base() { - if (!IsLongType(o)) { - throw new ArgumentException("object is not a long"); - } - Runtime.Incref(o.obj); - obj = o.obj; - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from an int32 value. - /// - - public PyLong(int value) : base() { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from a uint32 value. - /// - - [CLSCompliant(false)] - public PyLong(uint value) : base() { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from an int64 value. - /// - - public PyLong(long value) : base() { - obj = Runtime.PyLong_FromLong(value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from a uint64 value. - /// - - [CLSCompliant(false)] - public PyLong(ulong value) : base() { - obj = Runtime.PyLong_FromUnsignedLongLong(value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from an int16 value. - /// - - public PyLong(short value) : base() { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from an uint16 value. - /// - - [CLSCompliant(false)] - public PyLong(ushort value) : base() { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from a byte value. - /// - - public PyLong(byte value) : base() { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from an sbyte value. - /// - - [CLSCompliant(false)] - public PyLong(sbyte value) : base() { - obj = Runtime.PyLong_FromLong((long)value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from an double value. - /// - - public PyLong(double value) : base() { - obj = Runtime.PyLong_FromDouble(value); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyLong Constructor - /// - /// - /// - /// Creates a new PyLong from a string value. - /// - - public PyLong(string value) : base() { - obj = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// IsLongType Method - /// - /// - /// - /// Returns true if the given object is a Python long. - /// - - public static bool IsLongType(PyObject value) { - return Runtime.PyLong_Check(value.obj); - } - - - /// - /// AsLong Method - /// - /// - /// - /// - /// Convert a Python object to a Python long if possible, raising - /// a PythonException if the conversion is not possible. This is - /// equivalent to the Python expression "long(object)". - /// - - public static PyLong AsLong(PyObject value) { - IntPtr op = Runtime.PyNumber_Long(value.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyLong(op); - } - - - } - -} diff --git a/pythonnet/src/runtime/pyobject.cs b/pythonnet/src/runtime/pyobject.cs deleted file mode 100755 index a18790cb8..000000000 --- a/pythonnet/src/runtime/pyobject.cs +++ /dev/null @@ -1,873 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - /// - /// Represents a generic Python object. The methods of this class are - /// generally equivalent to the Python "abstract object API". See - /// http://www.python.org/doc/current/api/object.html for details. - /// - - public class PyObject : IDisposable { - - protected internal IntPtr obj = IntPtr.Zero; - private bool disposed = false; - - /// - /// PyObject Constructor - /// - /// - /// - /// Creates a new PyObject from an IntPtr object reference. Note that - /// the PyObject instance assumes ownership of the object reference - /// and the reference will be DECREFed when the PyObject is garbage - /// collected or explicitly disposed. - /// - - public PyObject(IntPtr ptr) { - obj = ptr; - } - - // Protected default constructor to allow subclasses to manage - // initialization in different ways as appropriate. - - protected PyObject() {} - - // Ensure that encapsulated Python object is decref'ed appropriately - // when the managed wrapper is garbage-collected. - - ~PyObject() { - Dispose(); - } - - - /// - /// Handle Property - /// - /// - /// - /// Gets the native handle of the underlying Python object. This - /// value is generally for internal use by the PythonNet runtime. - /// - - public IntPtr Handle { - get { return obj; } - } - - - /// - /// FromManagedObject Method - /// - /// - /// - /// Given an arbitrary managed object, return a Python instance that - /// reflects the managed object. - /// - - public static PyObject FromManagedObject(object ob) { - // Special case: if ob is null, we return None. - if (ob == null) { - Runtime.Incref(Runtime.PyNone); - return new PyObject(Runtime.PyNone); - } - IntPtr op = CLRObject.GetInstHandle(ob); - return new PyObject(op); - } - - - /// - /// AsManagedObject Method - /// - /// - /// - /// Return a managed object of the given type, based on the - /// value of the Python object. - /// - - public object AsManagedObject(Type t) { - Object result; - if (!Converter.ToManaged(this.Handle, t, out result, false)) { - throw new InvalidCastException( - "cannot convert object to target type" - ); - } - return result; - } - - - /// - /// Dispose Method - /// - /// - /// - /// The Dispose method provides a way to explicitly release the - /// Python object represented by a PyObject instance. It is a good - /// idea to call Dispose on PyObjects that wrap resources that are - /// limited or need strict lifetime control. Otherwise, references - /// to Python objects will not be released until a managed garbage - /// collection occurs. - /// - - public void Dispose() { - if (!disposed) { - if (Runtime.Py_IsInitialized() > 0) { - IntPtr gs = PythonEngine.AcquireLock(); - Runtime.Decref(obj); - obj = IntPtr.Zero; - PythonEngine.ReleaseLock(gs); - } - GC.SuppressFinalize(this); - disposed = true; - } - } - - - /// - /// GetPythonType Method - /// - /// - /// - /// Returns the Python type of the object. This method is equivalent - /// to the Python expression: type(object). - /// - - public PyObject GetPythonType() { - IntPtr tp = Runtime.PyObject_Type(obj); - return new PyObject(tp); - } - - - /// - /// TypeCheck Method - /// - /// - /// - /// Returns true if the object o is of type typeOrClass or a subtype - /// of typeOrClass. - /// - - public bool TypeCheck(PyObject typeOrClass) { - return Runtime.PyObject_TypeCheck(obj, typeOrClass.obj); - } - - - /// - /// HasAttr Method - /// - /// - /// - /// Returns true if the object has an attribute with the given name. - /// - - public bool HasAttr(string name) { - return (Runtime.PyObject_HasAttrString(obj, name) != 0); - } - - - /// - /// HasAttr Method - /// - /// - /// - /// Returns true if the object has an attribute with the given name, - /// where name is a PyObject wrapping a string or unicode object. - /// - - public bool HasAttr(PyObject name) { - return (Runtime.PyObject_HasAttr(obj, name.obj) != 0); - } - - - /// - /// GetAttr Method - /// - /// - /// - /// Returns the named attribute of the Python object, or raises a - /// PythonException if the attribute access fails. - /// - - public PyObject GetAttr(string name) { - IntPtr op = Runtime.PyObject_GetAttrString(obj, name); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(op); - } - - - /// - /// GetAttr Method - /// - /// - /// - /// Returns the named attribute of the Python object, or the given - /// default object if the attribute access fails. - /// - - public PyObject GetAttr(string name, PyObject _default) { - IntPtr op = Runtime.PyObject_GetAttrString(obj, name); - if (op == IntPtr.Zero) { - Runtime.PyErr_Clear(); - return _default; - } - return new PyObject(op); - } - - - /// - /// GetAttr Method - /// - /// - /// - /// Returns the named attribute of the Python object or raises a - /// PythonException if the attribute access fails. The name argument - /// is a PyObject wrapping a Python string or unicode object. - /// - - public PyObject GetAttr(PyObject name) { - IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(op); - } - - - /// - /// GetAttr Method - /// - /// - /// - /// Returns the named attribute of the Python object, or the given - /// default object if the attribute access fails. The name argument - /// is a PyObject wrapping a Python string or unicode object. - /// - - public PyObject GetAttr(PyObject name, PyObject _default) { - IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); - if (op == IntPtr.Zero) { - Runtime.PyErr_Clear(); - return _default; - } - return new PyObject(op); - } - - - /// - /// SetAttr Method - /// - /// - /// - /// Set an attribute of the object with the given name and value. This - /// method throws a PythonException if the attribute set fails. - /// - - public void SetAttr(string name, PyObject value) { - int r = Runtime.PyObject_SetAttrString(obj, name, value.obj); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// SetAttr Method - /// - /// - /// - /// Set an attribute of the object with the given name and value, - /// where the name is a Python string or unicode object. This method - /// throws a PythonException if the attribute set fails. - /// - - public void SetAttr(PyObject name, PyObject value) { - int r = Runtime.PyObject_SetAttr(obj, name.obj, value.obj); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// DelAttr Method - /// - /// - /// - /// Delete the named attribute of the Python object. This method - /// throws a PythonException if the attribute set fails. - /// - - public void DelAttr(string name) { - int r = Runtime.PyObject_SetAttrString(obj, name, IntPtr.Zero); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// DelAttr Method - /// - /// - /// - /// Delete the named attribute of the Python object, where name is a - /// PyObject wrapping a Python string or unicode object. This method - /// throws a PythonException if the attribute set fails. - /// - - public void DelAttr(PyObject name) { - int r = Runtime.PyObject_SetAttr(obj, name.obj, IntPtr.Zero); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// GetItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// return the item at the given object index. This method raises a - /// PythonException if the indexing operation fails. - /// - - public virtual PyObject GetItem(PyObject key) { - IntPtr op = Runtime.PyObject_GetItem(obj, key.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(op); - } - - - /// - /// GetItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// return the item at the given string index. This method raises a - /// PythonException if the indexing operation fails. - /// - - public virtual PyObject GetItem(string key) { - return GetItem(new PyString(key)); - } - - - /// - /// GetItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// return the item at the given numeric index. This method raises a - /// PythonException if the indexing operation fails. - /// - - public virtual PyObject GetItem(int index) { - PyInt key = new PyInt(index); - return GetItem((PyObject)key); - } - - - /// - /// SetItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// set the item at the given object index to the given value. This - /// method raises a PythonException if the set operation fails. - /// - - public virtual void SetItem(PyObject key, PyObject value) { - int r = Runtime.PyObject_SetItem(obj, key.obj, value.obj); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// SetItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// set the item at the given string index to the given value. This - /// method raises a PythonException if the set operation fails. - /// - - public virtual void SetItem(string key, PyObject value) { - SetItem(new PyString(key), value); - } - - - /// - /// SetItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// set the item at the given numeric index to the given value. This - /// method raises a PythonException if the set operation fails. - /// - - public virtual void SetItem(int index, PyObject value) { - SetItem(new PyInt(index), value); - } - - - /// - /// DelItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// delete the item at the given object index. This method raises a - /// PythonException if the delete operation fails. - /// - - public virtual void DelItem(PyObject key) { - int r = Runtime.PyObject_DelItem(obj, key.obj); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// DelItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// delete the item at the given string index. This method raises a - /// PythonException if the delete operation fails. - /// - - public virtual void DelItem(string key) { - DelItem(new PyString(key)); - } - - - /// - /// DelItem Method - /// - /// - /// - /// For objects that support the Python sequence or mapping protocols, - /// delete the item at the given numeric index. This method raises a - /// PythonException if the delete operation fails. - /// - - public virtual void DelItem(int index) { - DelItem(new PyInt(index)); - } - - - /// - /// Length Method - /// - /// - /// - /// Returns the length for objects that support the Python sequence - /// protocol, or 0 if the object does not support the protocol. - /// - - public virtual int Length() { - int s = Runtime.PyObject_Size(obj); - if (s < 0) { - Runtime.PyErr_Clear(); - return 0; - } - return s; - } - - - /// - /// String Indexer - /// - /// - /// - /// Provides a shorthand for the string versions of the GetItem and - /// SetItem methods. - /// - - public virtual PyObject this[string key] { - get { return GetItem(key); } - set { SetItem(key, value); } - } - - - /// - /// PyObject Indexer - /// - /// - /// - /// Provides a shorthand for the object versions of the GetItem and - /// SetItem methods. - /// - - public virtual PyObject this[PyObject key] { - get { return GetItem(key); } - set { SetItem(key, value); } - } - - - /// - /// Numeric Indexer - /// - /// - /// - /// Provides a shorthand for the numeric versions of the GetItem and - /// SetItem methods. - /// - - public virtual PyObject this[int index] { - get { return GetItem(index); } - set { SetItem(index, value); } - } - - - /// - /// GetIterator Method - /// - /// - /// - /// Return a new (Python) iterator for the object. This is equivalent - /// to the Python expression "iter(object)". A PythonException will be - /// raised if the object cannot be iterated. - /// - - public PyObject GetIterator() { - IntPtr r = Runtime.PyObject_GetIter(obj); - if (r == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(r); - } - - - /// - /// Invoke Method - /// - /// - /// - /// Invoke the callable object with the given arguments, passed as a - /// PyObject[]. A PythonException is raised if the invokation fails. - /// - - public PyObject Invoke(params PyObject[] args) { - PyTuple t = new PyTuple(args); - IntPtr r = Runtime.PyObject_Call(obj, t.obj, IntPtr.Zero); - t.Dispose(); - if (r == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(r); - } - - - /// - /// Invoke Method - /// - /// - /// - /// Invoke the callable object with the given arguments, passed as a - /// Python tuple. A PythonException is raised if the invokation fails. - /// - - public PyObject Invoke(PyTuple args) { - IntPtr r = Runtime.PyObject_Call(obj, args.obj, IntPtr.Zero); - if (r == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(r); - } - - - /// - /// Invoke Method - /// - /// - /// - /// Invoke the callable object with the given positional and keyword - /// arguments. A PythonException is raised if the invokation fails. - /// - - public PyObject Invoke(PyObject[] args, PyDict kw) { - PyTuple t = new PyTuple(args); - IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw.obj); - t.Dispose(); - if (r == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(r); - } - - - /// - /// Invoke Method - /// - /// - /// - /// Invoke the callable object with the given positional and keyword - /// arguments. A PythonException is raised if the invokation fails. - /// - - public PyObject Invoke(PyTuple args, PyDict kw) { - IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw.obj); - if (r == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(r); - } - - - /// - /// InvokeMethod Method - /// - /// - /// - /// Invoke the named method of the object with the given arguments. - /// A PythonException is raised if the invokation is unsuccessful. - /// - - public PyObject InvokeMethod(string name, params PyObject[] args) { - PyObject method = GetAttr(name); - PyObject result = method.Invoke(args); - method.Dispose(); - return result; - } - - - /// - /// InvokeMethod Method - /// - /// - /// - /// Invoke the named method of the object with the given arguments. - /// A PythonException is raised if the invokation is unsuccessful. - /// - - public PyObject InvokeMethod(string name, PyTuple args) { - PyObject method = GetAttr(name); - PyObject result = method.Invoke(args); - method.Dispose(); - return result; - } - - - /// - /// InvokeMethod Method - /// - /// - /// - /// Invoke the named method of the object with the given arguments - /// and keyword arguments. Keyword args are passed as a PyDict object. - /// A PythonException is raised if the invokation is unsuccessful. - /// - - public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) { - PyObject method = GetAttr(name); - PyObject result = method.Invoke(args, kw); - method.Dispose(); - return result; - } - - - /// - /// InvokeMethod Method - /// - /// - /// - /// Invoke the named method of the object with the given arguments - /// and keyword arguments. Keyword args are passed as a PyDict object. - /// A PythonException is raised if the invokation is unsuccessful. - /// - - public PyObject InvokeMethod(string name, PyTuple args, PyDict kw) { - PyObject method = GetAttr(name); - PyObject result = method.Invoke(args, kw); - method.Dispose(); - return result; - } - - - /// - /// IsInstance Method - /// - /// - /// - /// Return true if the object is an instance of the given Python type - /// or class. This method always succeeds. - /// - - public bool IsInstance(PyObject typeOrClass) { - int r = Runtime.PyObject_IsInstance(obj, typeOrClass.obj); - if (r < 0) { - Runtime.PyErr_Clear(); - return false; - } - return (r != 0); - } - - - /// - /// IsSubclass Method - /// - /// - /// - /// Return true if the object is identical to or derived from the - /// given Python type or class. This method always succeeds. - /// - - public bool IsSubclass(PyObject typeOrClass) { - int r = Runtime.PyObject_IsSubclass(obj, typeOrClass.obj); - if (r < 0) { - Runtime.PyErr_Clear(); - return false; - } - return (r != 0); - } - - - /// - /// IsCallable Method - /// - /// - /// - /// Returns true if the object is a callable object. This method - /// always succeeds. - /// - - public bool IsCallable() { - return (Runtime.PyCallable_Check(obj) != 0); - } - - - /// - /// IsTrue Method - /// - /// - /// - /// Return true if the object is true according to Python semantics. - /// This method always succeeds. - /// - - public bool IsTrue() { - return (Runtime.PyObject_IsTrue(obj) != 0); - } - - - /// - /// Dir Method - /// - /// - /// - /// Return a list of the names of the attributes of the object. This - /// is equivalent to the Python expression "dir(object)". - /// - - public PyList Dir() { - IntPtr r = Runtime.PyObject_Dir(obj); - if (r == IntPtr.Zero) { - throw new PythonException(); - } - return new PyList(r); - } - - - /// - /// Repr Method - /// - /// - /// - /// Return a string representation of the object. This method is - /// the managed equivalent of the Python expression "repr(object)". - /// - - public string Repr() { - IntPtr strval = Runtime.PyObject_Repr(obj); - string result = Runtime.GetManagedString(strval); - Runtime.Decref(strval); - return result; - } - - - /// - /// ToString Method - /// - /// - /// - /// Return the string representation of the object. This method is - /// the managed equivalent of the Python expression "str(object)". - /// - - public override string ToString() { - IntPtr strval = Runtime.PyObject_Str(obj); - string result = Runtime.GetManagedString(strval); - Runtime.Decref(strval); - return result; - } - - - /// - /// Equals Method - /// - /// - /// - /// Return true if this object is equal to the given object. This - /// method is based on Python equality semantics. - /// - - public override bool Equals(object o) { - if (!(o is PyObject)) { - return false; - } - if (obj == ((PyObject) o).obj) { - return true; - } - int r = Runtime.PyObject_Compare(obj, ((PyObject) o).obj); - if (Exceptions.ErrorOccurred()) { - throw new PythonException(); - } - return (r == 0); - } - - - /// - /// GetHashCode Method - /// - /// - /// - /// Return a hashcode based on the Python object. This returns the - /// hash as computed by Python, equivalent to the Python expression - /// "hash(obj)". - /// - - public override int GetHashCode() { - return Runtime.PyObject_Hash(obj).ToInt32(); - } - - - } - - -} diff --git a/pythonnet/src/runtime/pysequence.cs b/pythonnet/src/runtime/pysequence.cs deleted file mode 100755 index 6382b7ead..000000000 --- a/pythonnet/src/runtime/pysequence.cs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - /// - /// Represents a generic Python sequence. The methods of this class are - /// equivalent to the Python "abstract sequence API". See - /// http://www.python.org/doc/current/api/sequence.html for details. - /// - - public class PySequence : PyObject { - - protected PySequence(IntPtr ptr) : base(ptr) {} - - protected PySequence() : base() {} - - - /// - /// IsSequenceType Method - /// - /// - /// - /// Returns true if the given object implements the sequence protocol. - /// - - public static bool IsSequenceType(PyObject value) { - return Runtime.PySequence_Check(value.obj); - } - - - /// - /// GetSlice Method - /// - /// - /// - /// Return the slice of the sequence with the given indices. - /// - - public PyObject GetSlice(int i1, int i2) { - IntPtr op = Runtime.PySequence_GetSlice(obj, i1, i2); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(op); - } - - - /// - /// SetSlice Method - /// - /// - /// - /// Sets the slice of the sequence with the given indices. - /// - - public void SetSlice(int i1, int i2, PyObject v) { - int r = Runtime.PySequence_SetSlice(obj, i1, i2, v.obj); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// DelSlice Method - /// - /// - /// - /// Deletes the slice of the sequence with the given indices. - /// - - public void DelSlice(int i1, int i2) { - int r = Runtime.PySequence_DelSlice(obj, i1, i2); - if (r < 0) { - throw new PythonException(); - } - } - - - /// - /// Index Method - /// - /// - /// - /// Return the index of the given item in the sequence, or -1 if - /// the item does not appear in the sequence. - /// - - public int Index(PyObject item) { - int r = Runtime.PySequence_Index(obj, item.obj); - if (r < 0) { - Runtime.PyErr_Clear(); - return -1; - } - return r; - } - - - /// - /// Contains Method - /// - /// - /// - /// Return true if the sequence contains the given item. This method - /// throws a PythonException if an error occurs during the check. - /// - - public bool Contains(PyObject item) { - int r = Runtime.PySequence_Contains(obj, item.obj); - if (r < 0) { - throw new PythonException(); - } - return (r != 0); - } - - - /// - /// Concat Method - /// - /// - /// - /// Return the concatenation of the sequence object with the passed in - /// sequence object. - /// - - public PyObject Concat(PyObject other) { - IntPtr op = Runtime.PySequence_Concat(obj, other.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(op); - } - - - /// - /// Repeat Method - /// - /// - /// - /// Return the sequence object repeated N times. This is equivalent - /// to the Python expression "object * count". - /// - - public PyObject Repeat(int count) { - IntPtr op = Runtime.PySequence_Repeat(obj, count); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(op); - } - - - - } - -} diff --git a/pythonnet/src/runtime/pystring.cs b/pythonnet/src/runtime/pystring.cs deleted file mode 100755 index f15a2aa36..000000000 --- a/pythonnet/src/runtime/pystring.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - /// - /// Represents a Python (ansi) string object. See the documentation at - /// http://www.python.org/doc/current/api/stringObjects.html for details. - /// - - public class PyString : PySequence { - - /// - /// PyString Constructor - /// - /// - /// - /// Creates a new PyString from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - - public PyString(IntPtr ptr) : base(ptr) {} - - - /// - /// PyString Constructor - /// - /// - /// - /// Copy constructor - obtain a PyString from a generic PyObject. - /// An ArgumentException will be thrown if the given object is not - /// a Python string object. - /// - - public PyString(PyObject o) : base() { - if (!IsStringType(o)) { - throw new ArgumentException("object is not a string"); - } - Runtime.Incref(o.obj); - obj = o.obj; - } - - - /// - /// PyString Constructor - /// - /// - /// - /// Creates a Python string from a managed string. - /// - - public PyString(string s) : base() { - obj = Runtime.PyString_FromStringAndSize(s, s.Length); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// IsStringType Method - /// - /// - /// - /// Returns true if the given object is a Python string. - /// - - public static bool IsStringType(PyObject value) { - return Runtime.PyString_Check(value.obj); - } - - } - - -} diff --git a/pythonnet/src/runtime/pythonengine.cs b/pythonnet/src/runtime/pythonengine.cs deleted file mode 100755 index 128406f1d..000000000 --- a/pythonnet/src/runtime/pythonengine.cs +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Threading; - -namespace Python.Runtime { - - /// - /// This class provides the public interface of the Python runtime. - /// - - public class PythonEngine { - - private static bool initialized; - - #region Properties - - public static bool IsInitialized { - get { - return initialized; - } - } - - public static string ProgramName { - get { - string result = Runtime.Py_GetProgramName(); - if (result == null) { - return ""; - } - return result; - } - set { - Runtime.Py_SetProgramName(value); - } - } - - public static string PythonHome { - get { - string result = Runtime.Py_GetPythonHome(); - if (result == null) { - return ""; - } - return result; - } - set { - Runtime.Py_SetPythonHome(value); - } - } - - public static string Version { - get { - return Runtime.Py_GetVersion(); - } - } - - public static string BuildInfo { - get { - return Runtime.Py_GetBuildInfo(); - } - } - - public static string Platform { - get { - return Runtime.Py_GetPlatform(); - } - } - - public static string Copyright { - get { - return Runtime.Py_GetCopyright(); - } - } - - public static int RunSimpleString(string code) { - return Runtime.PyRun_SimpleString(code); - } - - #endregion - - - /// - /// Initialize Method - /// - /// - /// - /// Initialize the Python runtime. It is safe to call this method - /// more than once, though initialization will only happen on the - /// first call. It is *not* necessary to hold the Python global - /// interpreter lock (GIL) to call this method. - /// - - public static void Initialize() { - if (!initialized) { - Runtime.Initialize(); - initialized = true; - Exceptions.Clear(); - } - } - - - //==================================================================== - // A helper to perform initialization from the context of an active - // CPython interpreter process - this bootstraps the managed runtime - // when it is imported by the CLR extension module. - //==================================================================== - - public static void InitExt() { - Initialize(); - - // Trickery - when the import hook is installed into an already - // running Python, the standard import machinery is still in - // control for the duration of the import that caused bootstrap. - // - // That is problematic because the std machinery tries to get - // sub-names directly from the module __dict__ rather than going - // through our module object's getattr hook. This workaround is - // evil ;) We essentially climb up the stack looking for the - // import that caused the bootstrap to happen, then re-execute - // the import explicitly after our hook has been installed. By - // doing this, the original outer import should work correctly. - // - // Note that this is only needed during the execution of the - // first import that installs the CLR import hook. This hack - // still doesn't work if you use the interactive interpreter, - // since there is no line info to get the import line ;( - - string code = - - "import traceback\n" + - "for item in traceback.extract_stack():\n" + - " line = item[3]\n" + - " if line is not None:\n" + - " if line.startswith('import CLR') or \\\n" + - " line.startswith('from CLR'):\n" + - " exec line\n" + - " break\n"; - - PyObject r = PythonEngine.RunString(code); - if (r != null) { - r.Dispose(); - } - } - - - /// - /// Shutdown Method - /// - /// - /// - /// Shutdown and release resources held by the Python runtime. The - /// Python runtime can no longer be used in the current process - /// after calling the Shutdown method. - /// - - public static void Shutdown() { - if (initialized) { - Runtime.Shutdown(); - initialized = false; - } - } - - - /// - /// AcquireLock Method - /// - /// - /// - /// Acquire the Python global interpreter lock (GIL). Managed code - /// *must* call this method before using any objects or calling any - /// methods on objects in the Python.Runtime namespace. The only - /// exception is PythonEngine.Initialize, which may be called without - /// first calling AcquireLock. - /// - /// Each call to AcquireLock must be matched by a corresponding call - /// to ReleaseLock, passing the token obtained from AcquireLock. - /// - /// For more information, see the "Extending and Embedding" section - /// of the Python documentation on www.python.org. - /// - - public static IntPtr AcquireLock() { - return Runtime.PyGILState_Ensure(); - } - - - /// - /// ReleaseLock Method - /// - /// - /// - /// Release the Python global interpreter lock using a token obtained - /// from a previous call to AcquireLock. - /// - /// For more information, see the "Extending and Embedding" section - /// of the Python documentation on www.python.org. - /// - - public static void ReleaseLock(IntPtr gs) { - Runtime.PyGILState_Release(gs); - } - - - /// - /// BeginAllowThreads Method - /// - /// - /// - /// Release the Python global interpreter lock to allow other threads - /// to run. This is equivalent to the Py_BEGIN_ALLOW_THREADS macro - /// provided by the C Python API. - /// - /// For more information, see the "Extending and Embedding" section - /// of the Python documentation on www.python.org. - /// - - public static IntPtr BeginAllowThreads() { - return Runtime.PyEval_SaveThread(); - } - - - /// - /// EndAllowThreads Method - /// - /// - /// - /// Re-aquire the Python global interpreter lock for the current - /// thread. This is equivalent to the Py_END_ALLOW_THREADS macro - /// provided by the C Python API. - /// - /// For more information, see the "Extending and Embedding" section - /// of the Python documentation on www.python.org. - /// - - public static void EndAllowThreads(IntPtr ts) { - Runtime.PyEval_RestoreThread(ts); - } - - - - /// - /// ImportModule Method - /// - /// - /// - /// Given a fully-qualified module or package name, import the - /// module and return the resulting module object as a PyObject - /// or null if an exception is raised. - /// - - public static PyObject ImportModule(string name) { - IntPtr op = Runtime.PyImport_ImportModule(name); - if (op == IntPtr.Zero) { - return null; - } - return new PyObject(op); - } - - - /// - /// ReloadModule Method - /// - /// - /// - /// Given a PyObject representing a previously loaded module, reload - /// the module. - /// - - public static PyObject ReloadModule(PyObject module) { - IntPtr op = Runtime.PyImport_ReloadModule(module.Handle); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(op); - } - - - /// - /// ModuleFromString Method - /// - /// - /// - /// Given a string module name and a string containing Python code, - /// execute the code in and return a module of the given name. - /// - - public static PyObject ModuleFromString(string name, string code) { - IntPtr c = Runtime.Py_CompileString(code, "none", (IntPtr)257); - if (c == IntPtr.Zero) { - throw new PythonException(); - } - IntPtr m = Runtime.PyImport_ExecCodeModule(name, c); - if (m == IntPtr.Zero) { - throw new PythonException(); - } - return new PyObject(m); - } - - - /// - /// RunString Method - /// - /// - /// - /// Run a string containing Python code. Returns the result of - /// executing the code string as a PyObject instance, or null if - /// an exception was raised. - /// - - public static PyObject RunString(string code) { - IntPtr globals = Runtime.PyEval_GetGlobals(); - IntPtr locals = Runtime.PyDict_New(); - - IntPtr builtins = Runtime.PyEval_GetBuiltins(); - Runtime.PyDict_SetItemString(locals, "__builtins__", builtins); - - IntPtr flag = (IntPtr)257; /* Py_file_input */ - IntPtr result = Runtime.PyRun_String(code, flag, globals, locals); - Runtime.Decref(locals); - if (result == IntPtr.Zero) { - return null; - } - return new PyObject(result); - } - - - - } - - -} diff --git a/pythonnet/src/runtime/pythonexception.cs b/pythonnet/src/runtime/pythonexception.cs deleted file mode 100755 index 788a7346d..000000000 --- a/pythonnet/src/runtime/pythonexception.cs +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - /// - /// Provides a managed interface to exceptions thrown by the Python - /// runtime. - /// - - public class PythonException : System.Exception { - - private IntPtr excType = IntPtr.Zero; - private IntPtr excValue = IntPtr.Zero; - private IntPtr excTb = IntPtr.Zero; - private bool disposed = false; - - public PythonException() : base() { - Runtime.PyErr_Fetch(ref excType, ref excValue, ref excTb); - Runtime.Incref(excType); - Runtime.Incref(excValue); - Runtime.Incref(excTb); - - } - - // Ensure that encapsulated Python objects are decref'ed appropriately - // when the managed exception wrapper is garbage-collected. - - ~PythonException() { - Dispose(); - } - - - /// - /// Type Property - /// - /// - /// - /// Returns the exception type as a Python object. - /// - - public IntPtr Type { - get { - return excType; - } - } - - /// - /// Value Property - /// - /// - /// - /// Returns the exception value as a Python object. - /// - - public IntPtr Value { - get { - return excValue; - } - } - - /// - /// Traceback Property - /// - /// - /// - /// Returns the exception traceback as a Python object. - /// - - public IntPtr Traceback { - get { - return excTb; - } - } - - - /// - /// Dispose Method - /// - /// - /// - /// The Dispose method provides a way to explicitly release the - /// Python objects represented by a PythonException. - /// - - public void Dispose() { - if (!disposed) { - if (Runtime.Py_IsInitialized() > 0) { - IntPtr gs = PythonEngine.AcquireLock(); - Runtime.Decref(excType); - Runtime.Decref(excValue); - Runtime.Decref(excTb); - PythonEngine.ReleaseLock(gs); - } - GC.SuppressFinalize(this); - disposed = true; - } - } - - /// - /// Matches Method - /// - /// - /// - /// Returns true if the Python exception type represented by the - /// PythonException instance matches the given exception type. - /// - - public static bool Matches(IntPtr ob) { - return Runtime.PyErr_ExceptionMatches(ob) != 0; - } - - } - - -} diff --git a/pythonnet/src/runtime/pytuple.cs b/pythonnet/src/runtime/pytuple.cs deleted file mode 100755 index 2aa702443..000000000 --- a/pythonnet/src/runtime/pytuple.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Runtime { - - /// - /// Represents a Python tuple object. See the documentation at - /// http://www.python.org/doc/current/api/tupleObjects.html for details. - /// - - public class PyTuple : PySequence { - - /// - /// PyTuple Constructor - /// - /// - /// - /// Creates a new PyTuple from an existing object reference. Note - /// that the instance assumes ownership of the object reference. - /// The object reference is not checked for type-correctness. - /// - - public PyTuple(IntPtr ptr) : base(ptr) {} - - - /// - /// PyTuple Constructor - /// - /// - /// - /// Copy constructor - obtain a PyTuple from a generic PyObject. An - /// ArgumentException will be thrown if the given object is not a - /// Python tuple object. - /// - - public PyTuple(PyObject o) : base() { - if (!IsTupleType(o)) { - throw new ArgumentException("object is not a tuple"); - } - Runtime.Incref(o.obj); - obj = o.obj; - } - - - /// - /// PyTuple Constructor - /// - /// - /// - /// Creates a new empty PyTuple. - /// - - public PyTuple() : base() { - obj = Runtime.PyTuple_New(0); - if (obj == IntPtr.Zero) { - throw new PythonException(); - } - } - - - /// - /// PyTuple Constructor - /// - /// - /// - /// Creates a new PyTuple from an array of PyObject instances. - /// - - public PyTuple(PyObject[] items) : base() { - int count = items.Length; - obj = Runtime.PyTuple_New(count); - for (int i = 0; i < count; i++) { - IntPtr ptr = items[i].obj; - Runtime.Incref(ptr); - int r = Runtime.PyTuple_SetItem(obj, i, ptr); - if (r < 0) { - throw new PythonException(); - } - } - } - - - /// - /// IsTupleType Method - /// - /// - /// - /// Returns true if the given object is a Python tuple. - /// - - public static bool IsTupleType(PyObject value) { - return Runtime.PyTuple_Check(value.obj); - } - - - /// - /// AsTuple Method - /// - /// - /// - /// Convert a Python object to a Python tuple if possible, raising - /// a PythonException if the conversion is not possible. This is - /// equivalent to the Python expression "tuple(object)". - /// - - public static PyTuple AsTuple(PyObject value) { - IntPtr op = Runtime.PySequence_Tuple(value.obj); - if (op == IntPtr.Zero) { - throw new PythonException(); - } - return new PyTuple(op); - } - - - } - - -} diff --git a/pythonnet/src/runtime/runtime.cs b/pythonnet/src/runtime/runtime.cs deleted file mode 100755 index 29b085d21..000000000 --- a/pythonnet/src/runtime/runtime.cs +++ /dev/null @@ -1,1359 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; -using System.Security; - -namespace Python.Runtime { - - [SuppressUnmanagedCodeSecurityAttribute()] - - public class Runtime { - - /// - /// Encapsulates the low-level Python C API. Note that it is - /// the responsibility of the caller to have acquired the GIL - /// before calling any of these methods. - /// - - internal const string dll = "python24"; - internal static bool wrap_exceptions; - internal static bool is32bit; - - internal static void Initialize() { - - is32bit = IntPtr.Size == 4; - - Runtime.Py_Initialize(); - Runtime.PyEval_InitThreads(); - - IntPtr dict = Runtime.PyImport_GetModuleDict(); - IntPtr op = Runtime.PyDict_GetItemString(dict, "__builtin__"); - - PyBaseObjectType = Runtime.PyObject_GetAttrString(op, "object"); - - PyModuleType = Runtime.PyObject_Type(op); - PyNone = Runtime.PyObject_GetAttrString(op, "None"); - PyTrue = Runtime.PyObject_GetAttrString(op, "True"); - PyFalse = Runtime.PyObject_GetAttrString(op, "False"); - - PyBoolType = Runtime.PyObject_Type(PyTrue); - PyNoneType = Runtime.PyObject_Type(PyNone); - PyTypeType = Runtime.PyObject_Type(PyNoneType); - - op = Runtime.PyObject_GetAttrString(dict, "keys"); - PyMethodType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyString_FromString("string"); - PyStringType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyUnicode_FromString("unicode"); - PyUnicodeType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyTuple_New(0); - PyTupleType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyList_New(0); - PyListType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyDict_New(); - PyDictType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyInt_FromInt32(0); - PyIntType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyLong_FromLong(0); - PyLongType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - op = Runtime.PyFloat_FromDouble(0); - PyFloatType = Runtime.PyObject_Type(op); - Runtime.Decref(op); - - 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); - - IntPtr i = Runtime.PyInstance_New(c, IntPtr.Zero, IntPtr.Zero); - PyInstanceType = Runtime.PyObject_Type(i); - - Runtime.Decref(s); - Runtime.Decref(i); - Runtime.Decref(c); - Runtime.Decref(d); - - Error = new IntPtr(-1); - - // 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). - - IntPtr m = PyImport_ImportModule("exceptions"); - op = Runtime.PyObject_GetAttrString(m, "Exception"); - if (Runtime.PyObject_TYPE(op) == PyClassType) { - wrap_exceptions = true; - } - Runtime.Decref(op); - Runtime.Decref(m); - - //wrap_exceptions = false; - - // Initialize modules that depend on the runtime class. - AssemblyManager.Initialize(); - PyCLRMetaType = MetaType.Initialize(); - Exceptions.Initialize(); - ImportHook.Initialize(); - } - - internal static void Shutdown() { - AssemblyManager.Shutdown(); - Exceptions.Shutdown(); - ImportHook.Shutdown(); - Py_Finalize(); - } - - internal static IntPtr Py_file_input = (IntPtr)257; - - internal static IntPtr PyBaseObjectType; - internal static IntPtr PyModuleType; - internal static IntPtr PyClassType; - internal static IntPtr PyInstanceType; - internal static IntPtr PyCLRMetaType; - internal static IntPtr PyMethodType; - - internal static IntPtr PyUnicodeType; - internal static IntPtr PyStringType; - internal static IntPtr PyTupleType; - internal static IntPtr PyListType; - internal static IntPtr PyDictType; - internal static IntPtr PyIntType; - internal static IntPtr PyLongType; - internal static IntPtr PyFloatType; - internal static IntPtr PyBoolType; - internal static IntPtr PyNoneType; - internal static IntPtr PyTypeType; - - internal static IntPtr PyTrue; - internal static IntPtr PyFalse; - internal static IntPtr PyNone; - internal static IntPtr Error; - - - - internal static IntPtr GetBoundArgTuple(IntPtr obj, IntPtr args) { - if (Runtime.PyObject_TYPE(args) != Runtime.PyTupleType) { - Exceptions.SetError(Exceptions.TypeError, "tuple expected"); - return IntPtr.Zero; - } - int size = Runtime.PyTuple_Size(args); - IntPtr items = Runtime.PyTuple_New(size + 1); - Runtime.PyTuple_SetItem(items, 0, obj); - Runtime.Incref(obj); - - for (int i = 0; i < size; i++) { - IntPtr item = Runtime.PyTuple_GetItem(args, i); - Runtime.Incref(item); - Runtime.PyTuple_SetItem(items, i + 1, item); - } - - return items; - } - - - internal static IntPtr ExtendTuple(IntPtr t, params IntPtr[] args) { - int size = Runtime.PyTuple_Size(t); - int add = args.Length; - int total = size + add; - IntPtr item; - - IntPtr items = Runtime.PyTuple_New(size + add); - for (int i = 0; i < size; i++) { - item = Runtime.PyTuple_GetItem(t, i); - Runtime.Incref(item); - Runtime.PyTuple_SetItem(items, i, item); - } - - for (int n = 0; n < add; n++) { - item = args[n]; - Runtime.Incref(item); - Runtime.PyTuple_SetItem(items, size + n, item); - } - - return items; - } - - - //=================================================================== - // Managed exports of the Python C API. Where appropriate, we do - // some optimization to avoid managed <--> unmanaged transitions - // (mostly for heavily used methods). - //=================================================================== - - internal unsafe static void Incref(IntPtr op) { - void *p = (void *)op; - if ((void *)0 != p) { - if (is32bit) { (*(int *)p)++; } - else { (*(long *)p)++; } - } - } - - internal unsafe static void Decref(IntPtr op) { - void *p = (void *)op; - if ((void *)0 != p) { - if (is32bit) { --(*(int *)p); } - else { --(*(long *)p); } - if ((*(int *)p) == 0) { - void *t = is32bit ? (void *)(*((uint *)p + 1)) : - (void *)(*((ulong *)p + 1)); - void *f = is32bit ? (void *)(*((uint *)t + 6)) : - (void *)(*((ulong *)t + 6)); - if ((void *)0 == f) { - return; - } - NativeCall.Impl.Void_Call_1(new IntPtr(f), op); - return; - } - } - } - - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - Py_Initialize(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - Py_IsInitialized(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - Py_Finalize(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - Py_NewInterpreter(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - Py_EndInterpreter(IntPtr threadState); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThreadState_New(IntPtr istate); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThreadState_Get(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThread_get_key_value(IntPtr key); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyThread_get_thread_ident(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyThread_set_key_value(IntPtr key, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyThreadState_Swap(IntPtr key); - - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyGILState_Ensure(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyGILState_Release(IntPtr gs); - - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyGILState_GetThisThreadState(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - public unsafe static extern int - Py_Main(int argc, string[] argv); - - [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 void - PyEval_AcquireLock(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyEval_ReleaseLock(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyEval_AcquireThread(IntPtr tstate); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyEval_ReleaseThread(IntPtr tstate); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_SaveThread(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyEval_RestoreThread(IntPtr tstate); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_GetBuiltins(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_GetGlobals(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyEval_GetLocals(); - - - [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_GetVersion(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern string - Py_GetPlatform(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern string - Py_GetCopyright(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern string - Py_GetCompiler(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern string - Py_GetBuildInfo(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyRun_SimpleString(string code); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - Py_CompileString(string code, string file, IntPtr tok); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - 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 - PyCFunction_NewEx(IntPtr ml, IntPtr self, IntPtr mod); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyCFunction_Call(IntPtr func, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyClass_New(IntPtr bases, IntPtr dict, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyInstance_New(IntPtr cls, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyInstance_NewRaw(IntPtr cls, IntPtr dict); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMethod_New(IntPtr func, IntPtr self, IntPtr cls); - - - //==================================================================== - // Python abstract object API - //==================================================================== - - // A macro-like method to get the type of a Python object. This is - // designed to be lean and mean in IL & avoid managed <-> unmanaged - // transitions. Note that this does not incref the type object. - - internal unsafe static IntPtr - PyObject_TYPE(IntPtr op) { - void *p = (void *)op; - if ((void *)0 == p) { - return IntPtr.Zero; - } - if (is32bit) { - return new IntPtr((void *)(*((uint *)p + 1))); - } - else { - return new IntPtr((void *)(*((ulong *)p + 1))); - } - } - - // Managed version of the standard Python C API PyObject_Type call. - // This version avoids a managed <-> unmanaged transition. This one - // does incref the returned type object. - - internal unsafe static IntPtr - PyObject_Type(IntPtr op) { - IntPtr tp = PyObject_TYPE(op); - Runtime.Incref(tp); - return tp; - } - - internal static string PyObject_GetTypeName(IntPtr op) { - IntPtr pyType = Marshal.ReadIntPtr(op, IntPtr.Size); - IntPtr ppName = Marshal.ReadIntPtr(pyType, (3 * IntPtr.Size)); - return Marshal.PtrToStringAnsi(ppName); - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_HasAttrString(IntPtr pointer, string name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetAttrString(IntPtr pointer, string name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_SetAttrString(IntPtr pointer, string name, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_HasAttr(IntPtr pointer, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetAttr(IntPtr pointer, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_SetAttr(IntPtr pointer, IntPtr name, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetItem(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_SetItem(IntPtr pointer, IntPtr key, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_DelItem(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GetIter(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_CallObject(IntPtr pointer, IntPtr args); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_Compare(IntPtr value1, IntPtr value2); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_IsInstance(IntPtr ob, IntPtr type); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_IsSubclass(IntPtr ob, IntPtr type); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyCallable_Check(IntPtr pointer); - - [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_Size(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Hash(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Repr(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Str(IntPtr pointer); - - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_Dir(IntPtr pointer); - - - //==================================================================== - // Python number API - //==================================================================== - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Int(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Long(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyNumber_Float(IntPtr ob); - - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern bool - PyNumber_Check(IntPtr ob); - - - internal static bool PyInt_Check(IntPtr ob) { - return PyObject_TypeCheck(ob, Runtime.PyIntType); - } - - 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) { - IntPtr v = new IntPtr(value); - return PyInt_FromLong(v); - } - - internal static IntPtr PyInt_FromInt64(long value) { - IntPtr v = new IntPtr(value); - return PyInt_FromLong(v); - } - - - [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(); - - - internal static bool PyLong_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyLongType; - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromLong(long value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromUnsignedLong(uint value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromDouble(double value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromLongLong(long value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromUnsignedLongLong(ulong value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyLong_FromString(string value, IntPtr end, int radix); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyLong_AsLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern uint - PyLong_AsUnsignedLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern long - PyLong_AsLongLong(IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern ulong - PyLong_AsUnsignedLongLong(IntPtr value); - - - internal static bool PyFloat_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyFloatType; - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyFloat_FromDouble(double value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyFloat_FromString(IntPtr value, IntPtr junk); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern double - PyFloat_AsDouble(IntPtr ob); - - - //==================================================================== - // Python sequence API - //==================================================================== - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern bool - PySequence_Check(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_GetItem(IntPtr pointer, int index); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_SetItem(IntPtr pointer, int index, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_DelItem(IntPtr pointer, int index); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_GetSlice(IntPtr pointer, int i1, int i2); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_SetSlice(IntPtr pointer, int i1, int i2, IntPtr v); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_DelSlice(IntPtr pointer, int i1, int i2); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_Size(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_Contains(IntPtr pointer, IntPtr item); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_Concat(IntPtr pointer, IntPtr other); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_Repeat(IntPtr pointer, int count); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_Index(IntPtr pointer, IntPtr item); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySequence_Count(IntPtr pointer, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_Tuple(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PySequence_List(IntPtr pointer); - - - //==================================================================== - // Python string API - //==================================================================== - - internal static bool IsStringType(IntPtr op) { - IntPtr t = PyObject_TYPE(op); - return (t == PyStringType) || (t == PyUnicodeType); - } - - internal static bool PyString_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyStringType; - } - - internal static IntPtr PyString_FromString(string value) { - return PyString_FromStringAndSize(value, value.Length); - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyString_FromStringAndSize(string value, int size); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyString_AsString", - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyString_AS_STRING(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyString_Size(IntPtr pointer); - - - internal static bool PyUnicode_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyUnicodeType; - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_FromObject", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromObject(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_FromEncodedObject", - 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="PyUnicodeUCS2_FromUnicode", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromUnicode(string s, int size); - - internal static IntPtr PyUnicode_FromString(string s) { - return PyUnicode_FromUnicode(s, (s.Length)); - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_GetSize", - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyUnicode_GetSize(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_AsUnicode", - ExactSpelling=true)] - internal unsafe static extern char * - PyUnicode_AsUnicode(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_AsUnicode", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_AS_UNICODE(IntPtr op); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - EntryPoint="PyUnicodeUCS2_FromOrdinal", - ExactSpelling=true, CharSet=CharSet.Unicode)] - internal unsafe static extern IntPtr - PyUnicode_FromOrdinal(int c); - - internal unsafe static string GetManagedString(IntPtr op) { - IntPtr type = PyObject_TYPE(op); - - if (type == Runtime.PyStringType) { - return Marshal.PtrToStringAnsi( - PyString_AS_STRING(op), - Runtime.PyString_Size(op) - ); - } - - if (type == Runtime.PyUnicodeType) { - char *p = Runtime.PyUnicode_AsUnicode(op); - int size = Runtime.PyUnicode_GetSize(op); - return new String(p, 0, size); - } - - return null; - } - - - //==================================================================== - // Python dictionary API - //==================================================================== - - internal static bool PyDict_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyDictType; - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_New(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDictProxy_New(IntPtr dict); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_GetItem(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_GetItemString(IntPtr pointer, string key); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyDict_SetItem(IntPtr pointer, IntPtr key, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyDict_SetItemString(IntPtr pointer, string key, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - 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 - PyMapping_HasKey(IntPtr pointer, IntPtr key); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Keys(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Values(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Items(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyDict_Copy(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyDict_Update(IntPtr pointer, IntPtr other); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyDict_Clear(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyDict_Size(IntPtr pointer); - - - //==================================================================== - // Python list API - //==================================================================== - - internal static bool PyList_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyListType; - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_New(int size); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_AsTuple(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_GetItem(IntPtr pointer, int index); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyList_SetItem(IntPtr pointer, int index, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyList_Insert(IntPtr pointer, int index, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyList_Append(IntPtr pointer, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyList_Reverse(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyList_Sort(IntPtr pointer); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyList_GetSlice(IntPtr pointer, int start, int end); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyList_SetSlice(IntPtr pointer, int start, int end, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyList_Size(IntPtr pointer); - - - //==================================================================== - // Python tuple API - //==================================================================== - - internal static bool PyTuple_Check(IntPtr ob) { - return PyObject_TYPE(ob) == Runtime.PyTupleType; - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyTuple_New(int size); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyTuple_GetItem(IntPtr pointer, int index); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyTuple_SetItem(IntPtr pointer, int index, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyTuple_GetSlice(IntPtr pointer, int start, int end); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyTuple_Size(IntPtr pointer); - - - //==================================================================== - // Python module API - //==================================================================== - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern string - PyModule_GetName(IntPtr module); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyModule_GetDict(IntPtr module); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern string - PyModule_GetFilename(IntPtr module); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_Import(IntPtr name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_ImportModule(string name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_ReloadModule(IntPtr module); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_AddModule(string name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyImport_GetModuleDict(); - - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PySys_SetArgv(int argc, IntPtr argv); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PySys_GetObject(string name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PySys_SetObject(string name, IntPtr ob); - - - //==================================================================== - // Python type object API - //==================================================================== - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern bool - PyType_IsSubtype(IntPtr t1, IntPtr t2); - - internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) { - IntPtr t = PyObject_TYPE(ob); - return (t == tp) || PyType_IsSubtype(t, tp); - } - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyType_GenericAlloc(IntPtr type, int n); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyType_Ready(IntPtr type); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - _PyType_Lookup(IntPtr type, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GenericGetAttr(IntPtr obj, IntPtr name); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyObject_GenericSetAttr(IntPtr obj, IntPtr name, IntPtr value); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - _PyObject_GetDictPtr(IntPtr obj); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyObject_GC_New(IntPtr tp); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyObject_GC_Del(IntPtr tp); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyObject_GC_Track(IntPtr tp); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyObject_GC_UnTrack(IntPtr tp); - - - //==================================================================== - // Python memory API - //==================================================================== - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMem_Malloc(int size); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMem_Realloc(IntPtr ptr, int size); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyMem_Free(IntPtr ptr); - - - //==================================================================== - // Python exception API - //==================================================================== - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_SetString(IntPtr ob, string message); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_SetObject(IntPtr ob, IntPtr message); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyErr_SetFromErrno(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_SetNone(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyErr_ExceptionMatches(IntPtr exception); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_NormalizeException(IntPtr ob, IntPtr val, IntPtr tb); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern int - PyErr_Occurred(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_Fetch(ref IntPtr ob, ref IntPtr val, ref IntPtr tb); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_Restore(IntPtr ob, IntPtr val, IntPtr tb); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_Clear(); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern void - PyErr_Print(); - - - //==================================================================== - // Miscellaneous - //==================================================================== - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMethod_Self(IntPtr ob); - - [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, - ExactSpelling=true, CharSet=CharSet.Ansi)] - internal unsafe static extern IntPtr - PyMethod_Function(IntPtr ob); - - } - - -} diff --git a/pythonnet/src/runtime/typemanager.cs b/pythonnet/src/runtime/typemanager.cs deleted file mode 100755 index 87ca5658a..000000000 --- a/pythonnet/src/runtime/typemanager.cs +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Runtime.InteropServices; -using System.Reflection.Emit; -using System.Collections; -using System.Reflection; -using System.Threading; - -namespace Python.Runtime { - - //======================================================================= - // The TypeManager class is responsible for building binary-compatible - // Python type objects that are implemented in managed code. - //======================================================================= - - internal class TypeManager { - - static BindingFlags tbFlags; - static Hashtable cache; - static int obSize; - - static TypeManager() { - tbFlags = BindingFlags.Public | BindingFlags.Static; - obSize = 4 * IntPtr.Size; - cache = new Hashtable(); - } - - - //==================================================================== - // Given a managed Type derived from ExtensionType, get the handle to - // a Python type object that delegates its implementation to the Type - // object. These Python type instances are used to implement internal - // descriptor and utility types like ModuleObject, PropertyObject, etc. - //==================================================================== - - internal static IntPtr GetTypeHandle(Type type) { - - // Note that these types are cached with a refcount of 1, so they - // effectively exist until the CPython runtime is finalized. We - - Object ob = cache[type]; - if (ob != null) { - return (IntPtr) ob; - } - IntPtr tp = CreateType(type); - cache[type] = tp; - return tp; - } - - - //==================================================================== - // Get the handle of a Python type that reflects the given CLR type. - // The given ManagedType instance is a managed object that implements - // the appropriate semantics in Python for the reflected managed type. - //==================================================================== - - internal static IntPtr GetTypeHandle(ManagedType obj, Type clrType) { - Object ob = cache[clrType]; - if (ob != null) { - return (IntPtr) ob; - } - IntPtr tp = CreateType(obj, clrType); - cache[clrType] = tp; - return tp; - } - - - //==================================================================== - // The following CreateType implementations do the necessary work to - // create Python types to represent managed extension types, reflected - // types, subclasses of reflected types and the managed metatype. The - // dance is slightly different for each kind of type due to different - // behavior needed and the desire to have the existing Python runtime - // do as much of the allocation and initialization work as possible. - //==================================================================== - - internal static IntPtr CreateType(Type impl) { - - IntPtr type = AllocateTypeObject(impl.Name); - - // Set tp_basicsize to the size of our managed instance objects. - Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); - - IntPtr offset = (IntPtr)ObjectOffset.ob_dict; - Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); - - InitializeSlots(type, impl); - - int flags = TypeFlags.Default | TypeFlags.Managed | - TypeFlags.HeapType | TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); - - Runtime.PyType_Ready(type); - - IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - IntPtr mod = Runtime.PyString_FromString("CLR"); - Runtime.PyDict_SetItemString(dict, "__module__", mod); - - InitMethods(type, impl); - - return type; - } - - - internal static IntPtr CreateType(ManagedType impl, Type clrType) { - // Cleanup the type name to get rid of funny nested type names. - string name = "CLR." + clrType.FullName; - int i = name.LastIndexOf('+'); - if (i > -1) { - name = name.Substring(i + 1); - } - i = name.LastIndexOf('.'); - if (i > -1) { - name = name.Substring(i + 1); - } - - IntPtr base_ = IntPtr.Zero; - if (clrType.BaseType != null) { - ClassBase bc = ClassManager.GetClass(clrType.BaseType); - base_ = bc.pyHandle; - } - - IntPtr type = AllocateTypeObject(name); - - Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType); - Runtime.Incref(Runtime.PyCLRMetaType); - - Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); - Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); - - IntPtr offset = (IntPtr)ObjectOffset.ob_dict; - Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); - - InitializeSlots(type, impl.GetType()); - - if (base_ != IntPtr.Zero) { - Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); - Runtime.Incref(base_); - } - - int flags = TypeFlags.Default; - flags |= TypeFlags.Managed; - flags |= TypeFlags.HeapType; - flags |= TypeFlags.BaseType; - flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); - - // Leverage followup initialization from the Python runtime. Note - // that the type of the new type must PyType_Type at the time we - // call this, else PyType_Ready will skip some slot initialization. - - Runtime.PyType_Ready(type); - - IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - string mn = "CLR." + clrType.Namespace; - IntPtr mod = Runtime.PyString_FromString(mn); - Runtime.PyDict_SetItemString(dict, "__module__", mod); - - // Hide the gchandle of the implementation in a magic type slot. - GCHandle gc = GCHandle.Alloc(impl); - Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc); - - // Set the handle attributes on the implementing instance. - impl.tpHandle = Runtime.PyCLRMetaType; - impl.gcHandle = gc; - impl.pyHandle = type; - - //DebugUtil.DumpType(type); - - return type; - } - - internal static IntPtr CreateSubType(IntPtr args) { - - IntPtr py_name = Runtime.PyTuple_GetItem(args, 0); - IntPtr bases = Runtime.PyTuple_GetItem(args, 1); - IntPtr dict = Runtime.PyTuple_GetItem(args, 2); - IntPtr base_ = Runtime.PyTuple_GetItem(bases, 0); - - string name = Runtime.GetManagedString(py_name); - IntPtr type = AllocateTypeObject(name); - - Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType); - Runtime.Incref(Runtime.PyCLRMetaType); - - Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); - Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); - - IntPtr offset = (IntPtr)ObjectOffset.ob_dict; - Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); - - IntPtr dc = Runtime.PyDict_Copy(dict); - Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc); - - Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); - Runtime.Incref(base_); - - int flags = TypeFlags.Default; - flags |= TypeFlags.Managed; - flags |= TypeFlags.HeapType; - flags |= TypeFlags.BaseType; - flags |= TypeFlags.Subclass; - flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); - - CopySlot(base_, type, TypeOffset.tp_traverse); - CopySlot(base_, type, TypeOffset.tp_clear); - CopySlot(base_, type, TypeOffset.tp_is_gc); - - Runtime.PyType_Ready(type); - - - IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - IntPtr mod = Runtime.PyString_FromString("CLR"); - Runtime.PyDict_SetItemString(tp_dict, "__module__", mod); - - // for now, move up hidden handle... - IntPtr gc = Marshal.ReadIntPtr(base_, TypeOffset.magic()); - Marshal.WriteIntPtr(type, TypeOffset.magic(), gc); - - return type; - } - - - internal static IntPtr CreateMetaType(Type impl) { - - // The managed metatype is functionally little different than the - // standard Python metatype (PyType_Type). It overrides certain of - // the standard type slots, and has to subclass PyType_Type for - // certain functions in the C runtime to work correctly with it. - - IntPtr type = AllocateTypeObject("CLR Metatype"); - IntPtr py_type = Runtime.PyTypeType; - - Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type); - Runtime.Incref(py_type); - - // Copy gc and other type slots from the base Python metatype. - - CopySlot(py_type, type, TypeOffset.tp_basicsize); - CopySlot(py_type, type, TypeOffset.tp_itemsize); - - CopySlot(py_type, type, TypeOffset.tp_dictoffset); - CopySlot(py_type, type, TypeOffset.tp_weaklistoffset); - - CopySlot(py_type, type, TypeOffset.tp_traverse); - CopySlot(py_type, type, TypeOffset.tp_clear); - CopySlot(py_type, type, TypeOffset.tp_is_gc); - - // Override type slots with those of the managed implementation. - - InitializeSlots(type, impl); - - int flags = TypeFlags.Default; - flags |= TypeFlags.Managed; - flags |= TypeFlags.HeapType; - flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); - - Runtime.PyType_Ready(type); - - IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - IntPtr mod = Runtime.PyString_FromString("CLR"); - Runtime.PyDict_SetItemString(dict, "__module__", mod); - - //DebugUtil.DumpType(type); - - return type; - } - - - internal static IntPtr BasicSubType(string name, IntPtr base_, - Type impl) { - - // Utility to create a subtype of a std Python type, but with - // a managed type able to override implementation - - IntPtr type = AllocateTypeObject(name); - //Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); - //Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); - - //IntPtr offset = (IntPtr)ObjectOffset.ob_dict; - //Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); - - //IntPtr dc = Runtime.PyDict_Copy(dict); - //Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc); - - Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); - Runtime.Incref(base_); - - int flags = TypeFlags.Default; - flags |= TypeFlags.Managed; - flags |= TypeFlags.HeapType; - flags |= TypeFlags.HaveGC; - Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); - - CopySlot(base_, type, TypeOffset.tp_traverse); - CopySlot(base_, type, TypeOffset.tp_clear); - CopySlot(base_, type, TypeOffset.tp_is_gc); - - InitializeSlots(type, impl); - - Runtime.PyType_Ready(type); - - IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); - IntPtr mod = Runtime.PyString_FromString("CLR"); - Runtime.PyDict_SetItemString(tp_dict, "__module__", mod); - - return type; - } - - - //==================================================================== - // Utility method to allocate a type object & do basic initialization. - //==================================================================== - - internal static IntPtr AllocateTypeObject(string name) { - IntPtr type = Runtime.PyType_GenericAlloc(Runtime.PyTypeType, 0); - - // Cheat a little: we'll set tp_name to the internal char * of - // the Python version of the type name - otherwise we'd have to - // allocate the tp_name and would have no way to free it. - - IntPtr temp = Runtime.PyString_FromString(name); - IntPtr raw = Runtime.PyString_AS_STRING(temp); - Marshal.WriteIntPtr(type, TypeOffset.tp_name, raw); - Marshal.WriteIntPtr(type, TypeOffset.name, temp); - - long ptr = type.ToInt64(); // 64-bit safe - - temp = new IntPtr(ptr + TypeOffset.nb_add); - Marshal.WriteIntPtr(type, TypeOffset.tp_as_number, temp); - - temp = new IntPtr(ptr + TypeOffset.sq_length); - Marshal.WriteIntPtr(type, TypeOffset.tp_as_sequence, temp); - - temp = new IntPtr(ptr + TypeOffset.mp_length); - Marshal.WriteIntPtr(type, TypeOffset.tp_as_mapping, temp); - - temp = new IntPtr(ptr + TypeOffset.bf_getreadbuffer); - Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp); - - return type; - } - - - //==================================================================== - // Given a newly allocated Python type object and a managed Type that - // provides the implementation for the type, connect the type slots of - // the Python object to the managed methods of the implementing Type. - //==================================================================== - - internal static void InitializeSlots(IntPtr type, Type impl) { - Hashtable seen = new Hashtable(8); - Type offsetType = typeof(TypeOffset); - - while (impl != null) { - MethodInfo[] methods = impl.GetMethods(tbFlags); - for (int i = 0; i < methods.Length; i++) { - MethodInfo method = methods[i]; - string name = method.Name; - if (! (name.StartsWith("tp_") || - name.StartsWith("nb_") || - name.StartsWith("sq_") || - name.StartsWith("mp_") || - name.StartsWith("bf_") - ) ) { - continue; - } - - if (seen[name] != null) { - continue; - } - - FieldInfo fi = offsetType.GetField(name); - int offset = (int)fi.GetValue(offsetType); - - IntPtr slot = Interop.GetThunk(method); - Marshal.WriteIntPtr(type, offset, slot); - - seen[name] = 1; - } - - impl = impl.BaseType; - } - - } - - - //==================================================================== - // Given a newly allocated Python type object and a managed Type that - // implements it, initialize any methods defined by the Type that need - // to appear in the Python type __dict__ (based on custom attribute). - //==================================================================== - - private static void InitMethods(IntPtr pytype, Type type) { - IntPtr dict = Marshal.ReadIntPtr(pytype, TypeOffset.tp_dict); - Type marker = typeof(PythonMethodAttribute); - - BindingFlags flags = BindingFlags.Public | BindingFlags.Static; - - while (type != null) { - MethodInfo[] methods = type.GetMethods(flags); - for (int i = 0; i < methods.Length; i++) { - MethodInfo method = methods[i]; - object[] attrs = method.GetCustomAttributes(marker, false); - if (attrs.Length > 0) { - string method_name = method.Name; - MethodInfo[] mi = new MethodInfo[1]; - mi[0] = method; - MethodObject m = new TypeMethod(method_name, mi); - Runtime.PyDict_SetItemString(dict, method_name, - m.pyHandle); - } - } - type = type.BaseType; - } - } - - - //==================================================================== - // Utility method to copy slots from a given type to another type. - //==================================================================== - - internal static void CopySlot(IntPtr from, IntPtr to, int offset) { - IntPtr fp = Marshal.ReadIntPtr(from, offset); - Marshal.WriteIntPtr(to, offset, fp); - } - - - } - - -} diff --git a/pythonnet/src/runtime/typemethod.cs b/pythonnet/src/runtime/typemethod.cs deleted file mode 100755 index 84c8e9e0d..000000000 --- a/pythonnet/src/runtime/typemethod.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; -using System.Reflection; - -namespace Python.Runtime { - - //======================================================================== - // Implements a Python type that provides access to CLR object methods. - //======================================================================== - - internal class TypeMethod : MethodObject { - - public TypeMethod(string name, MethodInfo[] info) : - base(name, info) {} - - public override IntPtr Invoke(IntPtr ob, IntPtr args, IntPtr kw) { - MethodInfo mi = this.info[0]; - Object[] arglist = new Object[3]; - arglist[0] = ob; - arglist[1] = args; - arglist[2] = kw; - - try { - Object inst = null; - if (ob != IntPtr.Zero) { - inst = GetManagedObject(ob); - } - return (IntPtr)mi.Invoke(inst, BindingFlags.Default, null, arglist, - null); - } - catch (Exception e) { - Exceptions.SetError(e); - return IntPtr.Zero; - } - } - - - - } - - -} diff --git a/pythonnet/src/testing/arraytest.cs b/pythonnet/src/testing/arraytest.cs deleted file mode 100755 index 045701f4d..000000000 --- a/pythonnet/src/testing/arraytest.cs +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; - -namespace Python.Test { - - //======================================================================== - // Supports units tests for indexer access. - //======================================================================== - - public class PublicArrayTest { - - public int[] items; - - public PublicArrayTest() { - items = new int[5] {0, 1, 2, 3, 4}; - } - - } - - - public class ProtectedArrayTest { - - protected int[] items; - - public ProtectedArrayTest() { - items = new int[5] {0, 1, 2, 3, 4}; - } - - } - - - public class InternalArrayTest { - - internal int[] items; - - public InternalArrayTest() { - items = new int[5] {0, 1, 2, 3, 4}; - } - - } - - - public class PrivateArrayTest { - - private int[] items; - - public PrivateArrayTest() { - items = new int[5] {0, 1, 2, 3, 4}; - } - - } - - - public class BooleanArrayTest { - - public bool[] items; - - public BooleanArrayTest() { - items = new bool[5] {true, false, true, false, true}; - } - - } - - - public class ByteArrayTest { - - public byte[] items; - - public ByteArrayTest() { - items = new byte[5] {0, 1, 2, 3, 4}; - } - - } - - - public class SByteArrayTest { - - public sbyte[] items; - - public SByteArrayTest() { - items = new sbyte[5] {0, 1, 2, 3, 4}; - } - - } - - - public class CharArrayTest { - - public char[] items; - - public CharArrayTest() { - items = new char[5] {'a', 'b', 'c', 'd', 'e'}; - } - - } - - - public class Int16ArrayTest { - - public short[] items; - - public Int16ArrayTest() { - items = new short[5] {0, 1, 2, 3, 4}; - } - - } - - - public class Int32ArrayTest { - - public int[] items; - - public Int32ArrayTest() { - items = new int[5] {0, 1, 2, 3, 4}; - } - - } - - - public class Int64ArrayTest { - - public long[] items; - - public Int64ArrayTest() { - items = new long[5] {0, 1, 2, 3, 4}; - } - - } - - - public class UInt16ArrayTest { - - public ushort[] items; - - public UInt16ArrayTest() { - items = new ushort[5] {0, 1, 2, 3, 4}; - } - - } - - - public class UInt32ArrayTest { - - public uint[] items; - - public UInt32ArrayTest() { - items = new uint[5] {0, 1, 2, 3, 4}; - } - - } - - - public class UInt64ArrayTest { - - public ulong[] items; - - public UInt64ArrayTest() { - items = new ulong[5] {0, 1, 2, 3, 4}; - } - - } - - - public class SingleArrayTest { - - public float[] items; - - public SingleArrayTest() { - items = new float[5] {0.0F, 1.0F, 2.0F, 3.0F, 4.0F}; - } - - } - - - public class DoubleArrayTest { - - public double[] items; - - public DoubleArrayTest() { - items = new double[5] {0.0, 1.0, 2.0, 3.0, 4.0}; - } - - } - - - public class DecimalArrayTest { - - public decimal[] items; - - public DecimalArrayTest() { - items = new decimal[5] {0, 1, 2, 3, 4}; - } - - } - - - public class StringArrayTest { - - public string[] items; - - public StringArrayTest() { - items = new string[5] {"0", "1", "2", "3", "4"}; - } - - } - - public class EnumArrayTest { - - public ShortEnum[] items; - - public EnumArrayTest() { - items = new ShortEnum[5] - { ShortEnum.Zero, - ShortEnum.One, - ShortEnum.Two, - ShortEnum.Three, - ShortEnum.Four}; - } - - } - - - public class NullArrayTest { - - public object[] items; - public object[] empty; - - public NullArrayTest() { - items = new object[5] {null, null, null, null, null}; - empty = new object[0] {}; - } - - } - - - public class ObjectArrayTest { - - public object[] items; - - public ObjectArrayTest() { - items = new object[5]; - items[0] = new Spam("0"); - items[1] = new Spam("1"); - items[2] = new Spam("2"); - items[3] = new Spam("3"); - items[4] = new Spam("4"); - } - - } - - - public class InterfaceArrayTest { - - public ISpam[] items; - - public InterfaceArrayTest() { - items = new ISpam[5]; - items[0] = new Spam("0"); - items[1] = new Spam("1"); - items[2] = new Spam("2"); - items[3] = new Spam("3"); - items[4] = new Spam("4"); - } - - } - - - public class TypedArrayTest { - - public Spam[] items; - - public TypedArrayTest() { - items = new Spam[5]; - items[0] = new Spam("0"); - items[1] = new Spam("1"); - items[2] = new Spam("2"); - items[3] = new Spam("3"); - items[4] = new Spam("4"); - } - - } - - - public class MultiDimensionalArrayTest { - - public int[,] items; - - public MultiDimensionalArrayTest() { - items = new int[5, 5] { - {0, 1, 2, 3, 4}, - {5, 6, 7, 8, 9}, - {10, 11, 12, 13, 14}, - {15, 16, 17, 18, 19}, - {20, 21, 22, 23, 24} - }; - - } - - } - - - public class ArrayConversionTest { - - public static Spam[] EchoRange(Spam[] items) { - return items; - } - - public static Spam[,] EchoRangeMD(Spam[,] items) { - return items; - } - - public static Spam[][] EchoRangeAA(Spam[][] items) { - return items; - } - - } - - - - -} - diff --git a/pythonnet/src/testing/classtest.cs b/pythonnet/src/testing/classtest.cs deleted file mode 100755 index d053f2d65..000000000 --- a/pythonnet/src/testing/classtest.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// 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.Windows.Forms; - -namespace Python.Test { - - //======================================================================== - // Supports CLR class unit tests. - //======================================================================== - - public class ClassTest { - - public static ArrayList GetArrayList() { - ArrayList list = new ArrayList(); - for (int i = 0; i < 10; i++) { - list.Add(i); - } - return list; - } - - public static Hashtable GetHashtable() { - Hashtable dict = new Hashtable(); - dict.Add("one", 1); - dict.Add("two", 2); - dict.Add("three", 3); - dict.Add("four", 4); - dict.Add("five", 5); - return dict; - } - - public static IEnumerator GetEnumerator() { - string temp = "test string"; - return temp.GetEnumerator(); - } - - - } - - - public class ClassCtorTest1 { - public string value; - - public ClassCtorTest1() { - value = "default"; - } - - } - - public class ClassCtorTest2 { - public string value; - - public ClassCtorTest2(string v) { - value = v; - } - - } - - internal class InternalClass { - - - } - - -} diff --git a/pythonnet/src/testing/conversiontest.cs b/pythonnet/src/testing/conversiontest.cs deleted file mode 100755 index 4158ebd6c..000000000 --- a/pythonnet/src/testing/conversiontest.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - - -namespace Python.Test { - - //======================================================================== - // Supports units tests for field access. - //======================================================================== - - public class ConversionTest { - - public ConversionTest() { - EnumField = ShortEnum.Zero; - SpamField = new Spam("spam"); - StringField = "spam"; - } - - public bool BooleanField = false; - public byte ByteField = 0; - public sbyte SByteField = 0; - public char CharField = 'A'; - public short Int16Field = 0; - public int Int32Field = 0; - public long Int64Field = 0; - public ushort UInt16Field = 0; - public uint UInt32Field = 0; - public ulong UInt64Field = 0; - public float SingleField = 0.0F; - public double DoubleField = 0.0; - public decimal DecimalField = 0; - public string StringField; - public ShortEnum EnumField; - public object ObjectField = null; - public ISpam SpamField; - - public byte[] ByteArrayField; - public sbyte[] SByteArrayField; - - } - - - public interface ISpam { - string GetValue(); - } - - public class Spam : ISpam { - string value; - - public Spam(string value) { - this.value = value; - } - - public string GetValue() { - return value; - - } - } - -} diff --git a/pythonnet/src/testing/delegatetest.cs b/pythonnet/src/testing/delegatetest.cs deleted file mode 100755 index 60c85a2fe..000000000 --- a/pythonnet/src/testing/delegatetest.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Test { - - //======================================================================== - // Supports CLR class unit tests. - //======================================================================== - - public delegate void PublicDelegate(); - internal delegate void InternalDelegate(); - - public delegate DelegateTest ObjectDelegate(); - public delegate string StringDelegate(); - - - public class DelegateTest { - - public delegate void PublicDelegate(); - protected delegate void ProtectedDelegate(); - internal delegate void InternalDelegate(); - private delegate void PrivateDelegate(); - - public StringDelegate stringDelegate; - public ObjectDelegate objectDelegate; - - public DelegateTest() { - - } - - public string SayHello() { - return "hello"; - } - - public static string StaticSayHello() { - return "hello"; - } - - public string CallStringDelegate(StringDelegate d) { - return d(); - } - - public DelegateTest CallObjectDelegate(ObjectDelegate d) { - return d(); - } - - } - - -} diff --git a/pythonnet/src/testing/eventtest.cs b/pythonnet/src/testing/eventtest.cs deleted file mode 100755 index 96872d3ab..000000000 --- a/pythonnet/src/testing/eventtest.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// 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.Windows.Forms; - -namespace Python.Test { - - //======================================================================== - // Supports CLR event unit tests. - //======================================================================== - - public delegate void TestEventHandler(object sender, TestEventArgs e); - - - public class EventTest { - - - public void WinFormTest() { - EventTest e = new EventTest(); - EventHandler h = new EventHandler(e.ClickHandler); - - Form f = new Form(); - f.Click += h; - //f.Click(null, new EventArgs()); - f.Click -= h; - } - - public void ClickHandler(object sender, EventArgs e) { - Console.WriteLine("click"); - } - - - public static event TestEventHandler PublicStaticEvent; - - protected static event TestEventHandler ProtectedStaticEvent; - - internal static event TestEventHandler InternalStaticEvent; - - private static event TestEventHandler PrivateStaticEvent; - - public event TestEventHandler PublicEvent; - - protected event TestEventHandler ProtectedEvent; - - internal event TestEventHandler InternalEvent; - - private event TestEventHandler PrivateEvent; - - - public static int s_value; - public int value; - - public EventTest () { - this.value = 0; - } - - static EventTest () { - s_value = 0; - } - - - public void OnPublicEvent(TestEventArgs e) { - if (PublicEvent != null) { - PublicEvent(this, e); - } - } - - - public void OnProtectedEvent(TestEventArgs e) { - if (ProtectedEvent != null) { - ProtectedEvent(this, e); - } - } - - - public static void OnPublicStaticEvent(TestEventArgs e) { - if (PublicStaticEvent != null) { - PublicStaticEvent(null, e); - } - } - - - protected static void OnProtectedStaticEvent(TestEventArgs e) { - if (ProtectedStaticEvent != null) { - ProtectedStaticEvent(null, e); - } - } - - - public void GenericHandler(object sender, TestEventArgs e) { - this.value = e.value; - } - - public static void StaticHandler(object sender, TestEventArgs e) { - s_value = e.value; - } - - public static void ShutUpCompiler() { - // Quiet compiler warnings. - EventTest e = new EventTest(); - TestEventHandler f = new TestEventHandler(e.GenericHandler); - ProtectedStaticEvent += f; - InternalStaticEvent += f; - PrivateStaticEvent += f; - e.ProtectedEvent += f; - e.InternalEvent += f; - e.PrivateEvent += f; - } - - } - - - public class TestEventArgs : EventArgs { - public int value; - - public TestEventArgs(int v) { - this.value = v; - } - - } - - -} diff --git a/pythonnet/src/testing/exceptiontest.cs b/pythonnet/src/testing/exceptiontest.cs deleted file mode 100755 index d2ddd3572..000000000 --- a/pythonnet/src/testing/exceptiontest.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - - -namespace Python.Test { - - //======================================================================== - // Supports CLR Exception unit tests. - //======================================================================== - - public class ExceptionTest { - - public int ThrowProperty { - get { - throw new OverflowException("error"); - } - set { - throw new OverflowException("error"); - } - } - - public static Exception GetBaseException() { - return new Exception("error"); - } - - public static OverflowException GetExplicitException() { - return new OverflowException("error"); - } - - public static Exception GetWidenedException() { - return new OverflowException("error"); - } - - public static ExtendedException GetExtendedException() { - return new ExtendedException("error"); - } - - - public static bool SetBaseException(Exception e) { - return typeof(Exception).IsInstanceOfType(e); - } - - public static bool SetExplicitException(OverflowException e) { - return typeof(OverflowException).IsInstanceOfType(e); - } - - public static bool SetWidenedException(Exception e) { - return typeof(Exception).IsInstanceOfType(e); - } - - public static bool ThrowException() { - throw new OverflowException("error"); - } - } - - - public class ExtendedException : OverflowException { - - public ExtendedException() : base() {} - public ExtendedException(string m) : base(m) {} - - public string extra = "extra"; - - public string ExtraProperty { - get { - return extra; - } - set { - extra = value; - } - } - - public string GetExtraInfo() { - return extra; - } - - - } - - - -} - - - - diff --git a/pythonnet/src/testing/fieldtest.cs b/pythonnet/src/testing/fieldtest.cs deleted file mode 100755 index e41737060..000000000 --- a/pythonnet/src/testing/fieldtest.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - - -namespace Python.Test { - - //======================================================================== - // Supports units tests for field access. - //======================================================================== - - public class FieldTest { - - public FieldTest() { - EnumField = ShortEnum.Zero; - SpamField = new Spam("spam"); - StringField = "spam"; - } - - public void Shutup() { - int i = PrivateStaticField; - int j = PrivateField; - } - - public static readonly int ReadOnlyStaticField = 0; - protected static int ProtectedStaticField = 0; - internal static int InternalStaticField = 0; - private static int PrivateStaticField = 0; - public static int PublicStaticField = 0; - - public const int ConstField = 0; - public readonly int ReadOnlyField = 0; - internal int InternalField = 0; - protected int ProtectedField = 0; - private int PrivateField = 0; - public int PublicField = 0; - - public bool BooleanField = false; - public byte ByteField = 0; - public sbyte SByteField = 0; - public char CharField = 'A'; - public short Int16Field = 0; - public int Int32Field = 0; - public long Int64Field = 0; - public ushort UInt16Field = 0; - public uint UInt32Field = 0; - public ulong UInt64Field = 0; - public float SingleField = 0.0F; - public double DoubleField = 0.0; - public decimal DecimalField = 0; - public string StringField; - public ShortEnum EnumField; - public object ObjectField; - public ISpam SpamField; - - } - - -} diff --git a/pythonnet/src/testing/indexertest.cs b/pythonnet/src/testing/indexertest.cs deleted file mode 100755 index 79a5d1128..000000000 --- a/pythonnet/src/testing/indexertest.cs +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; -using System.Collections; - -namespace Python.Test { - - //======================================================================== - // Supports units tests for indexer access. - //======================================================================== - - public class IndexerBase { - - protected Hashtable t; - - protected IndexerBase() { - t = new Hashtable(); - } - - protected string GetValue(object index) { - if (index == null) { - return null; - } - object value = t[index]; - if (value != null) { - return (string)value; - } - return null; - } - - } - - - public class PublicIndexerTest : IndexerBase { - - public PublicIndexerTest() : base () {} - - public string this [int index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class ProtectedIndexerTest : IndexerBase { - - public ProtectedIndexerTest() : base () {} - - protected string this [int index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class InternalIndexerTest : IndexerBase { - - public InternalIndexerTest() : base () {} - - internal string this [int index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class PrivateIndexerTest : IndexerBase { - - public PrivateIndexerTest() : base () {} - - private string this [int index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class BooleanIndexerTest : IndexerBase { - - public BooleanIndexerTest() : base() {} - - public string this [bool index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class ByteIndexerTest : IndexerBase { - - public ByteIndexerTest() : base() {} - - public string this [byte index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class SByteIndexerTest : IndexerBase { - - public SByteIndexerTest() : base() {} - - public string this [sbyte index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class CharIndexerTest : IndexerBase { - - public CharIndexerTest() : base() {} - - public string this [char index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class Int16IndexerTest : IndexerBase { - - public Int16IndexerTest() : base() {} - - public string this [short index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class Int32IndexerTest : IndexerBase { - - public Int32IndexerTest() : base() {} - - public string this [int index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class Int64IndexerTest : IndexerBase { - - public Int64IndexerTest() : base() {} - - public string this [long index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class UInt16IndexerTest : IndexerBase { - - public UInt16IndexerTest() : base() {} - - public string this [ushort index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class UInt32IndexerTest : IndexerBase { - - public UInt32IndexerTest() : base() {} - - public string this [uint index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class UInt64IndexerTest : IndexerBase { - - public UInt64IndexerTest() : base() {} - - public string this [ulong index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class SingleIndexerTest : IndexerBase { - - public SingleIndexerTest() : base() {} - - public string this [float index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class DoubleIndexerTest : IndexerBase { - - public DoubleIndexerTest() : base() {} - - public string this [double index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class DecimalIndexerTest : IndexerBase { - - public DecimalIndexerTest() : base() {} - - public string this [decimal index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class StringIndexerTest : IndexerBase { - - public StringIndexerTest() : base() {} - - public string this [string index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class EnumIndexerTest : IndexerBase { - - public EnumIndexerTest() : base() {} - - public string this [ShortEnum index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class ObjectIndexerTest : IndexerBase { - - public ObjectIndexerTest() : base() {} - - public string this [object index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class InterfaceIndexerTest : IndexerBase { - - public InterfaceIndexerTest() : base() {} - - public string this [ISpam index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class TypedIndexerTest : IndexerBase { - - public TypedIndexerTest() : base() {} - - public string this [Spam index] { - get { return GetValue(index); } - set { t[index] = value; } - } - - } - - - public class MultiArgIndexerTest : IndexerBase { - - public MultiArgIndexerTest() : base() {} - - public string this [int index1, int index2] { - get { - string key = index1.ToString() + index2.ToString(); - object value = t[key]; - if (value != null) { - return (string)value; - } - return null; - } - set { - string key = index1.ToString() + index2.ToString(); - t[key] = value; - } - } - - } - - - public class MultiTypeIndexerTest : IndexerBase { - - public MultiTypeIndexerTest() : base() {} - - public string this [int i1, string i2, ISpam i3] { - get { - string key = i1.ToString() + i2.ToString() + - i3.GetHashCode().ToString(); - object value = t[key]; - if (value != null) { - return (string)value; - } - return null; - } - set { - string key = i1.ToString() + i2.ToString() + - i3.GetHashCode().ToString(); - t[key] = value; - } - } - - } - - - - - -} diff --git a/pythonnet/src/testing/methodtest.cs b/pythonnet/src/testing/methodtest.cs deleted file mode 100755 index 39a442300..000000000 --- a/pythonnet/src/testing/methodtest.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// 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.Windows.Forms; - -namespace Python.Test { - - //======================================================================== - // Supports units tests for method access. - //======================================================================== - - public class MethodTest { - - public MethodTest() {} - - public string PublicMethod() { - return "public"; - } - - public static string PublicStaticMethod() { - return "public static"; - } - - protected string ProtectedMethod() { - return "protected"; - } - - protected static string ProtectedStaticMethod() { - return "protected static"; - } - - internal string InternalMethod() { - return "internal"; - } - - internal static string InternalStaticMethod() { - return "internal static"; - } - - private string PrivateMethod() { - return "private"; - } - - private static string PrivateStaticMethod() { - return "private static"; - } - - - //=================================================================== - // Methods to support specific argument conversion unit tests - //=================================================================== - - public TypeCode TestEnumConversion(TypeCode v) { - return v; - } - - public FileAccess TestFlagsConversion(FileAccess v) { - return v; - } - - public Guid TestStructConversion(Guid v) { - return v; - } - - public Control TestSubclassConversion(Control v) { - return v; - } - - public Type[] TestNullArrayConversion(Type [] v) { - return v; - } - - - public static bool TestStringOutParams (string s, out string s1) { - s1 = "output string"; - return true; - } - - public static bool TestStringRefParams (string s, ref string s1) { - s1 = "output string"; - return true; - } - - public static bool TestValueOutParams (string s, out int i1) { - i1 = 42; - return true; - } - - public static bool TestValueRefParams (string s, ref int i1) { - i1 = 42; - return true; - } - - public static bool TestObjectOutParams (object o, out object o1) { - o1 = new System.Exception("test"); - return true; - } - - public static bool TestObjectRefParams (object o, ref object o1) { - o1 = new System.Exception("test"); - return true; - } - - public static bool TestStructOutParams (object o, out Guid o1) { - o1 = Guid.NewGuid(); - return true; - } - - public static bool TestStructRefParams (object o, ref Guid o1) { - o1 = Guid.NewGuid(); - return true; - } - - public static void TestVoidSingleOutParam (out int i) { - i = 42; - } - - public static void TestVoidSingleRefParam (ref int i) { - i = 42; - } - - } - - - public class MethodTestSub : MethodTest { - - public MethodTestSub() : base() {} - - public string PublicMethod(string echo) { - return echo; - } - - } - - -} diff --git a/pythonnet/src/testing/propertytest.cs b/pythonnet/src/testing/propertytest.cs deleted file mode 100755 index 1e9454482..000000000 --- a/pythonnet/src/testing/propertytest.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// This software is subject to the provisions of the Zope Public License, -// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. -// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -// FOR A PARTICULAR PURPOSE. - -using System; - -namespace Python.Test { - - //======================================================================== - // Supports units tests for property access. - //======================================================================== - - public class PropertyTest { - - public PropertyTest() {} - - int _public_property = 0; - public int PublicProperty { - get { return _public_property; } - set { _public_property = value; } - } - - static int _public_static_property = 0; - public static int PublicStaticProperty { - get { return _public_static_property; } - set { _public_static_property = value; } - } - - int _protected_property = 0; - protected int ProtectedProperty { - get { return _protected_property; } - set { _protected_property = value; } - } - - static int _protected_static_property = 0; - protected static int ProtectedStaticProperty { - get { return _protected_static_property; } - set { _protected_static_property = value; } - } - - int _internal_property = 0; - internal int InternalProperty { - get { return _internal_property; } - set { _internal_property = value; } - } - - static int _internal_static_property = 0; - internal static int InternalStaticProperty { - get { return _internal_static_property; } - set { _internal_static_property = value; } - } - - int _private_property = 0; - private int PrivateProperty { - get { return _private_property; } - set { _private_property = value; } - } - - static int _private_static_property = 0; - private static int PrivateStaticProperty { - get { return _private_static_property; } - set { _private_static_property = value; } - } - - ShortEnum _enum_property = ShortEnum.Zero; - - public ShortEnum EnumProperty { - get { return _enum_property; } - set { _enum_property = value; } - } - - } - -} diff --git a/pythonnet/src/testing/threadtest.cs b/pythonnet/src/testing/threadtest.cs deleted file mode 100755 index 832b41021..000000000 --- a/pythonnet/src/testing/threadtest.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2005 Zope Corporation and Contributors. -// -// All Rights Reserved. -// -// 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 Python.Runtime; - -namespace Python.Test { - - //======================================================================== - // Supports CLR threading / reentrancy unit tests. - //======================================================================== - - public class ThreadTest { - - private static PyObject module; - - private static string testmod = - "import CLR\n" + - "from CLR.Python.Test import ThreadTest\n" + - "\n" + - "def echostring(value):\n" + - " return value\n" + - "\n" + - "def echostring2(value):\n" + - " return ThreadTest.CallEchoString(value)\n" + - "\n"; - - - // This method calls back into the CPython runtime - tests - // call this from Python to check that we don't hang on - // nested transitions from managed to Python code and back. - - public static string CallEchoString(string arg) { - IntPtr gs = PythonEngine.AcquireLock(); - if (module == null) { - module = PythonEngine.ModuleFromString("tt", testmod); - } - PyObject func = module.GetAttr("echostring"); - PyString parg = new PyString(arg); - PyObject temp = func.Invoke(parg); - string result = (string)temp.AsManagedObject(typeof(String)); - func.Dispose(); - parg.Dispose(); - temp.Dispose(); - PythonEngine.ReleaseLock(gs); - return result; - } - - public static string CallEchoString2(string arg) { - IntPtr gs = PythonEngine.AcquireLock(); - if (module == null) { - module = PythonEngine.ModuleFromString("tt", testmod); - } - - PyObject func = module.GetAttr("echostring2"); - PyString parg = new PyString(arg); - PyObject temp = func.Invoke(parg); - string result = (string)temp.AsManagedObject(typeof(String)); - func.Dispose(); - parg.Dispose(); - temp.Dispose(); - PythonEngine.ReleaseLock(gs); - return result; - } - - - } - - -} diff --git a/pythonnet/src/tests/runtests.py b/pythonnet/src/tests/runtests.py deleted file mode 100755 index df9739527..000000000 --- a/pythonnet/src/tests/runtests.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Run all of the unit tests for this package.""" - -import time - -test_modules = ( - 'test_exceptions', - 'test_module', - 'test_conversion', - 'test_class', - 'test_interface', - 'test_enum', - 'test_field', - 'test_property', - 'test_indexer', - 'test_event', - 'test_method', - 'test_delegate', - 'test_array', - 'test_thread', -) - - -def main(): - - start = time.clock() - - for name in test_modules: - module = __import__(name) - module.main() - - stop = time.clock() - took = str(stop - start) - print 'Total Time: %s' % took - -if __name__ == '__main__': - main() - - diff --git a/pythonnet/src/tests/test_enum.py b/pythonnet/src/tests/test_enum.py deleted file mode 100755 index 9d5578eb7..000000000 --- a/pythonnet/src/tests/test_enum.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# -# 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 sys, os, string, unittest, types -from CLR.System import DayOfWeek -from CLR.Python import Test - - -class EnumTests(unittest.TestCase): - """Test CLR enum support.""" - - def testEnumStandardAttrs(self): - """Test standard enum attributes.""" - self.failUnless(DayOfWeek.__name__ == 'DayOfWeek') - self.failUnless(DayOfWeek.__module__ == 'CLR.System') - self.failUnless(type(DayOfWeek.__dict__) == types.DictProxyType) - self.failUnless(DayOfWeek.__doc__ == '') - - - def testEnumGetMember(self): - """Test access to enum members.""" - self.failUnless(DayOfWeek.Sunday == 0) - self.failUnless(DayOfWeek.Monday == 1) - self.failUnless(DayOfWeek.Tuesday == 2) - self.failUnless(DayOfWeek.Wednesday == 3) - self.failUnless(DayOfWeek.Thursday == 4) - self.failUnless(DayOfWeek.Friday == 5) - self.failUnless(DayOfWeek.Saturday == 6) - - - def testByteEnum(self): - """Test byte enum.""" - self.failUnless(Test.ByteEnum.Zero == 0) - self.failUnless(Test.ByteEnum.One == 1) - self.failUnless(Test.ByteEnum.Two == 2) - - - def testSByteEnum(self): - """Test sbyte enum.""" - self.failUnless(Test.SByteEnum.Zero == 0) - self.failUnless(Test.SByteEnum.One == 1) - self.failUnless(Test.SByteEnum.Two == 2) - - - def testShortEnum(self): - """Test short enum.""" - self.failUnless(Test.ShortEnum.Zero == 0) - self.failUnless(Test.ShortEnum.One == 1) - self.failUnless(Test.ShortEnum.Two == 2) - - - def testUShortEnum(self): - """Test ushort enum.""" - self.failUnless(Test.UShortEnum.Zero == 0) - self.failUnless(Test.UShortEnum.One == 1) - self.failUnless(Test.UShortEnum.Two == 2) - - - def testIntEnum(self): - """Test int enum.""" - self.failUnless(Test.IntEnum.Zero == 0) - self.failUnless(Test.IntEnum.One == 1) - self.failUnless(Test.IntEnum.Two == 2) - - - def testUIntEnum(self): - """Test uint enum.""" - self.failUnless(Test.UIntEnum.Zero == 0L) - self.failUnless(Test.UIntEnum.One == 1L) - self.failUnless(Test.UIntEnum.Two == 2L) - - - def testLongEnum(self): - """Test long enum.""" - self.failUnless(Test.LongEnum.Zero == 0L) - self.failUnless(Test.LongEnum.One == 1L) - self.failUnless(Test.LongEnum.Two == 2L) - - - def testULongEnum(self): - """Test ulong enum.""" - self.failUnless(Test.ULongEnum.Zero == 0L) - self.failUnless(Test.ULongEnum.One == 1L) - self.failUnless(Test.ULongEnum.Two == 2L) - - - def testInstantiateEnumFails(self): - """Test that instantiation of an enum class fails.""" - def test(): - ob = DayOfWeek() - - self.failUnlessRaises(TypeError, test) - - - def testSubclassEnumFails(self): - """Test that subclassing of an enumeration fails.""" - def test(): - class Boom(DayOfWeek): - pass - - self.failUnlessRaises(TypeError, test) - - - def testEnumSetMemberFails(self): - """Test that setattr operations on enumerations fail.""" - def test(): - DayOfWeek.Sunday = 13 - - self.failUnlessRaises(TypeError, test) - - def test(): - del DayOfWeek.Sunday - - self.failUnlessRaises(TypeError, test) - - - def testEnumWithFlagsAttrConversion(self): - """Test enumeration conversion with FlagsAttribute set.""" - from CLR.System.Windows.Forms import Label - - # This works because the AnchorStyles enum has FlagsAttribute. - label = Label() - label.Anchor = 99 - - # This should fail because our test enum doesn't have it. - def test(): - Test.FieldTest().EnumField = 99 - - self.failUnlessRaises(ValueError, test) - - - def testEnumConversion(self): - """Test enumeration conversion.""" - object = Test.FieldTest() - self.failUnless(object.EnumField == 0) - - object.EnumField = Test.ShortEnum.One - self.failUnless(object.EnumField == 1) - - def test(): - Test.FieldTest().EnumField = 20 - - self.failUnlessRaises(ValueError, test) - - def test(): - Test.FieldTest().EnumField = 100000 - - self.failUnlessRaises(OverflowError, test) - - def test(): - Test.FieldTest().EnumField = "str" - - self.failUnlessRaises(TypeError, test) - - - -def test_suite(): - return unittest.makeSuite(EnumTests) - -def main(): - unittest.TextTestRunner().run(test_suite()) - -if __name__ == '__main__': - testcase.setup() - main() - diff --git a/pythonnet/src/tests/test_interface.py b/pythonnet/src/tests/test_interface.py deleted file mode 100755 index 1617ee34e..000000000 --- a/pythonnet/src/tests/test_interface.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# -# 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. - -from CLR.Python.Test import InterfaceTest -import sys, os, string, unittest, types -import CLR.System as System -import CLR.Python.Test as Test - - -class InterfaceTests(unittest.TestCase): - """Test CLR interface support.""" - - def testInterfaceStandardAttrs(self): - """Test standard class attributes.""" - from CLR.Python.Test import IPublicInterface as ip - self.failUnless(ip.__name__ == 'IPublicInterface') - self.failUnless(ip.__module__ == 'CLR.Python.Test') - self.failUnless(type(ip.__dict__) == types.DictProxyType) - - - def testGlobalInterfaceVisibility(self): - """Test visibility of module-level interfaces.""" - from CLR.Python.Test import IPublicInterface - self.failUnless(IPublicInterface.__name__ == 'IPublicInterface') - - def test(): - from CLR.Python.Test import IInternalInterface - - self.failUnlessRaises(ImportError, test) - - def test(): - i = Test.IInternalInterface - - self.failUnlessRaises(AttributeError, test) - - - def testNestedInterfaceVisibility(self): - """Test visibility of nested interfaces.""" - ob = InterfaceTest.IPublic - self.failUnless(ob.__name__ == 'IPublic') - - ob = InterfaceTest.IProtected - self.failUnless(ob.__name__ == 'IProtected') - - def test(): - ob = InterfaceTest.IInternal - - self.failUnlessRaises(AttributeError, test) - - def test(): - ob = InterfaceTest.IPrivate - - self.failUnlessRaises(AttributeError, test) - - - def testExplicitCastToInterface(self): - """Test explicit cast to an interface.""" - ob = InterfaceTest() - self.failUnless(type(ob).__name__ == 'InterfaceTest') - self.failUnless(hasattr(ob, 'HelloProperty')) - - i1 = Test.ISayHello1(ob) - self.failUnless(type(i1).__name__ == 'ISayHello1') - self.failUnless(hasattr(i1, 'SayHello')) - self.failUnless(i1.SayHello() == 'hello 1') - self.failIf(hasattr(i1, 'HelloProperty')) - - i2 = Test.ISayHello2(ob) - self.failUnless(type(i2).__name__ == 'ISayHello2') - self.failUnless(i2.SayHello() == 'hello 2') - self.failUnless(hasattr(i2, 'SayHello')) - self.failIf(hasattr(i2, 'HelloProperty')) - - - -def test_suite(): - return unittest.makeSuite(InterfaceTests) - -def main(): - unittest.TextTestRunner().run(test_suite()) - -if __name__ == '__main__': - testcase.setup() - main() - diff --git a/pythonnet/src/tests/test_method.py b/pythonnet/src/tests/test_method.py deleted file mode 100755 index 10916a683..000000000 --- a/pythonnet/src/tests/test_method.py +++ /dev/null @@ -1,410 +0,0 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# -# 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 sys, os, string, unittest, types -from CLR.Python.Test import MethodTest -from CLR.Python.Test import MethodTestSub - - -class MethodTests(unittest.TestCase): - """Test CLR method support.""" - - def testInstanceMethodDescriptor(self): - """Test instance method descriptor behavior.""" - def test(): - MethodTest().PublicMethod = 0 - - self.failUnlessRaises(AttributeError, test) - - def test(): - MethodTest.PublicMethod = 0 - - self.failUnlessRaises(AttributeError, test) - - def test(): - del MethodTest().PublicMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - del MethodTest.PublicMethod - - self.failUnlessRaises(AttributeError, test) - - - def testStaticMethodDescriptor(self): - """Test static method descriptor behavior.""" - def test(): - MethodTest().PublicStaticMethod = 0 - - self.failUnlessRaises(AttributeError, test) - - def test(): - MethodTest.PublicStaticMethod = 0 - - self.failUnlessRaises(AttributeError, test) - - def test(): - del MethodTest().PublicStaticMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - del MethodTest.PublicStaticMethod - - self.failUnlessRaises(AttributeError, test) - - - def testPublicInstanceMethod(self): - """Test public instance method visibility.""" - object = MethodTest(); - self.failUnless(object.PublicMethod() == "public") - - - def testPublicStaticMethod(self): - """Test public static method visibility.""" - object = MethodTest(); - self.failUnless(MethodTest.PublicStaticMethod() == "public static") - self.failUnless(object.PublicStaticMethod() == "public static") - - - def testProtectedInstanceMethod(self): - """Test protected instance method visibility.""" - object = MethodTest(); - self.failUnless(object.ProtectedMethod() == "protected") - - - def testProtectedStaticMethod(self): - """Test protected static method visibility.""" - object = MethodTest(); - result = "protected static" - self.failUnless(MethodTest.ProtectedStaticMethod() == result) - self.failUnless(object.ProtectedStaticMethod() == result) - - - def testInternalMethod(self): - """Test internal method visibility.""" - def test(): - f = MethodTest().InternalMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - f = MethodTest.InternalMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - f = MethodTest().InternalStaticMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - f = MethodTest.InternalStaticMethod - - self.failUnlessRaises(AttributeError, test) - - - def testPrivateMethod(self): - """Test private method visibility.""" - def test(): - f = MethodTest().PrivateMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - f = MethodTest.PrivateMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - f = MethodTest().PrivateStaticMethod - - self.failUnlessRaises(AttributeError, test) - - def test(): - f = MethodTest.PrivateStaticMethod - - self.failUnlessRaises(AttributeError, test) - - - def testUnboundManagedMethodCall(self): - """Test calling unbound managed methods.""" - - object = MethodTest() - self.failUnless(MethodTest.PublicMethod(object) == "public") - - object = MethodTestSub(); - self.failUnless(MethodTest.PublicMethod(object) == "public") - self.failUnless(MethodTestSub.PublicMethod(object) == "public") - - self.failUnless(MethodTestSub.PublicMethod(object, "echo") == "echo") - - - def testOverloadedMethodInheritance(self): - """Test that overloads are inherited properly.""" - - object = MethodTest() - self.failUnless(object.PublicMethod() == "public") - - def test(): - object = MethodTest() - object.PublicMethod("echo") - - self.failUnlessRaises(TypeError, test) - - - object = MethodTestSub(); - self.failUnless(object.PublicMethod() == "public") - - self.failUnless(object.PublicMethod("echo") == "echo") - - - def testMethodDescriptorAbuse(self): - """Test method descriptor abuse.""" - desc = MethodTest.__dict__['PublicMethod'] - - def test(): - desc.__get__(0, 0) - - self.failUnlessRaises(TypeError, test) - - def test(): - desc.__set__(0, 0) - - self.failUnlessRaises(AttributeError, test) - - - def testMethodDocstrings(self): - """Test standard method docstring generation""" - method = MethodTest.GetType - value = 'System.Type GetType()' - self.failUnless(method.__doc__ == value) - - - #====================================================================== - # Tests of specific argument and result conversion scenarios - #====================================================================== - - def testMethodCallEnumConversion(self): - """Test enum conversion in method call.""" - from CLR.System import TypeCode - - object = MethodTest() - r = object.TestEnumConversion(TypeCode.Int32) - self.failUnless(r == TypeCode.Int32) - - - def testMethodCallFlagsConversion(self): - """Test flags conversion in method call.""" - from CLR.System.IO import FileAccess - - object = MethodTest() - flags = FileAccess.Read | FileAccess.Write - r = object.TestFlagsConversion(flags) - self.failUnless(r == flags) - - - def testMethodCallStructConversion(self): - """Test struct conversion in method call.""" - from CLR.System import Guid - - object = MethodTest() - guid = Guid.NewGuid() - temp = guid.ToString() - r = object.TestStructConversion(guid) - self.failUnless(r.ToString() == temp) - - - def testSubclassInstanceConversion(self): - """Test subclass instance conversion in method call.""" - from CLR.System.Windows.Forms import Form, Control - - class sub(Form): - pass - - object = MethodTest() - form = sub() - result = object.TestSubclassConversion(form) - self.failUnless(isinstance(result, Control)) - - - def testNullArrayConversion(self): - """Test null array conversion in method call.""" - from CLR.System import Type - - object = MethodTest() - r = object.TestNullArrayConversion(None) - self.failUnless(r == None) - - - def testStringOutParams(self): - """Test use of string out-parameters.""" - result = MethodTest.TestStringOutParams("hi", "there") - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(result[1] == "output string") - - result = MethodTest.TestStringOutParams("hi", None) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(result[1] == "output string") - - - def testStringRefParams(self): - """Test use of string byref parameters.""" - result = MethodTest.TestStringRefParams("hi", "there") - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(result[1] == "output string") - - result = MethodTest.TestStringRefParams("hi", None) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(result[1] == "output string") - - - def testValueOutParams(self): - """Test use of value type out-parameters.""" - result = MethodTest.TestValueOutParams("hi", 1) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(result[1] == 42) - - def test(): - MethodTest.TestValueOutParams("hi", None) - - # None cannot be converted to a value type like int, long, etc. - self.failUnlessRaises(TypeError, test) - - - def testValueRefParams(self): - """Test use of value type byref parameters.""" - result = MethodTest.TestValueRefParams("hi", 1) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(result[1] == 42) - - def test(): - MethodTest.TestValueRefParams("hi", None) - - # None cannot be converted to a value type like int, long, etc. - self.failUnlessRaises(TypeError, test) - - - def testObjectOutParams(self): - """Test use of object out-parameters.""" - import CLR - result = MethodTest.TestObjectOutParams("hi", MethodTest()) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(isinstance(result[1], CLR.System.Exception)) - - result = MethodTest.TestObjectOutParams("hi", None) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(isinstance(result[1], CLR.System.Exception)) - - - def testObjectRefParams(self): - """Test use of object byref parameters.""" - import CLR - result = MethodTest.TestObjectRefParams("hi", MethodTest()) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(isinstance(result[1], CLR.System.Exception)) - - result = MethodTest.TestObjectRefParams("hi", None) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(isinstance(result[1], CLR.System.Exception)) - - - def testStructOutParams(self): - """Test use of struct out-parameters.""" - import CLR - result = MethodTest.TestStructOutParams("hi",CLR.System.Guid.NewGuid()) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(isinstance(result[1], CLR.System.Guid)) - - def test(): - MethodTest.TestValueRefParams("hi", None) - - # None cannot be converted to a value type like a struct - self.failUnlessRaises(TypeError, test) - - - def testStructRefParams(self): - """Test use of struct byref parameters.""" - import CLR - result = MethodTest.TestStructRefParams("hi",CLR.System.Guid.NewGuid()) - self.failUnless(type(result) == type(())) - self.failUnless(len(result) == 2) - self.failUnless(result[0] == True) - self.failUnless(isinstance(result[1], CLR.System.Guid)) - - def test(): - MethodTest.TestValueRefParams("hi", None) - - # None cannot be converted to a value type like a struct - self.failUnlessRaises(TypeError, test) - - - def testVoidSingleOutParam(self): - """Test void method with single out-parameter.""" - import CLR - result = MethodTest.TestVoidSingleOutParam(9) - self.failUnless(result == 42) - - def test(): - MethodTest.TestVoidSingleOutParam(None) - - # None cannot be converted to a value type - self.failUnlessRaises(TypeError, test) - - - def testVoidSingleRefParam(self): - """Test void method with single ref-parameter.""" - import CLR - result = MethodTest.TestVoidSingleRefParam(9) - self.failUnless(result == 42) - - def test(): - MethodTest.TestVoidSingleRefParam(None) - - # None cannot be converted to a value type - self.failUnlessRaises(TypeError, test) - - - - -def test_suite(): - return unittest.makeSuite(MethodTests) - -def main(): - unittest.TextTestRunner().run(test_suite()) - -if __name__ == '__main__': - testcase.setup() - main() - diff --git a/pythonnet/src/tests/test_module.py b/pythonnet/src/tests/test_module.py deleted file mode 100755 index e3e850c3a..000000000 --- a/pythonnet/src/tests/test_module.py +++ /dev/null @@ -1,311 +0,0 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# -# 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 sys, os, string, unittest, types - - -class ModuleTests(unittest.TestCase): - """Test CLR modules and the CLR import hook.""" - - def isCLRModule(self, object): - return type(object).__name__ == 'ModuleObject' - - - def isCLRClass(self, object): - return type(object).__name__ == 'CLR Metatype' # for now - - def testAAAImportHookWorks(self): - """Test that the import hook works correctly both using the - included runtime and an external runtime. This must be - the first test run in the unit tests!""" - - from CLR.System import String - - - def testModuleInterface(self): - """Test the interface exposed by CLR module objects.""" - import CLR.System as System - - self.assertEquals(type(System.__dict__), type({})) - self.assertEquals(System.__name__, 'CLR.System') - self.assertEquals(System.__file__, None) - self.assertEquals(System.__doc__, None) - self.failUnless(self.isCLRClass(System.String)) - self.failUnless(self.isCLRClass(System.Int32)) - - - def testSimpleImport(self): - """Test simple import.""" - import CLR - self.failUnless(self.isCLRModule(CLR)) - self.failUnless(CLR.__name__ == 'CLR') - - import sys - self.failUnless(type(sys) == types.ModuleType) - self.failUnless(sys.__name__ == 'sys') - - import httplib - self.failUnless(type(httplib) == types.ModuleType) - self.failUnless(httplib.__name__ == 'httplib') - - - def testSimpleImportWithAlias(self): - """Test simple import with aliasing.""" - import CLR as myCLR - self.failUnless(self.isCLRModule(myCLR)) - self.failUnless(myCLR.__name__ == 'CLR') - - import sys as mySys - self.failUnless(type(mySys) == types.ModuleType) - self.failUnless(mySys.__name__ == 'sys') - - import httplib as myHttplib - self.failUnless(type(myHttplib) == types.ModuleType) - self.failUnless(myHttplib.__name__ == 'httplib') - - - def testDottedNameImport(self): - """Test dotted-name import.""" - import CLR.System - self.failUnless(self.isCLRModule(CLR.System)) - self.failUnless(CLR.System.__name__ == 'CLR.System') - - import xml.dom - self.failUnless(type(xml.dom) == types.ModuleType) - self.failUnless(xml.dom.__name__ == 'xml.dom') - - - def testDottedNameImportWithAlias(self): - """Test dotted-name import with aliasing.""" - import CLR.System as mySystem - self.failUnless(self.isCLRModule(mySystem)) - self.failUnless(mySystem.__name__ == 'CLR.System') - - import xml.dom as myDom - self.failUnless(type(myDom) == types.ModuleType) - self.failUnless(myDom.__name__ == 'xml.dom') - - - def testSimpleImportFrom(self): - """Test simple 'import from'.""" - from CLR import System - self.failUnless(self.isCLRModule(System)) - self.failUnless(System.__name__ == 'CLR.System') - - from xml import dom - self.failUnless(type(dom) == types.ModuleType) - self.failUnless(dom.__name__ == 'xml.dom') - - - def testSimpleImportFromWithAlias(self): - """Test simple 'import from' with aliasing.""" - from CLR import System as mySystem - self.failUnless(self.isCLRModule(mySystem)) - self.failUnless(mySystem.__name__ == 'CLR.System') - - from xml import dom as myDom - self.failUnless(type(myDom) == types.ModuleType) - self.failUnless(myDom.__name__ == 'xml.dom') - - - def testDottedNameImportFrom(self): - """Test dotted-name 'import from'.""" - from CLR.System import Xml - self.failUnless(self.isCLRModule(Xml)) - self.failUnless(Xml.__name__ == 'CLR.System.Xml') - - from CLR.System.Xml import XmlDocument - self.failUnless(self.isCLRClass(XmlDocument)) - self.failUnless(XmlDocument.__name__ == 'XmlDocument') - - from xml.dom import pulldom - self.failUnless(type(pulldom) == types.ModuleType) - self.failUnless(pulldom.__name__ == 'xml.dom.pulldom') - - from xml.dom.pulldom import PullDOM - self.failUnless(type(PullDOM) == types.ClassType) - self.failUnless(PullDOM.__name__ == 'PullDOM') - - - def testDottedNameImportFromWithAlias(self): - """Test dotted-name 'import from' with aliasing.""" - from CLR.System import Xml as myXml - self.failUnless(self.isCLRModule(myXml)) - self.failUnless(myXml.__name__ == 'CLR.System.Xml') - - from CLR.System.Xml import XmlDocument as myXmlDocument - self.failUnless(self.isCLRClass(myXmlDocument)) - self.failUnless(myXmlDocument.__name__ == 'XmlDocument') - - from xml.dom import pulldom as myPulldom - self.failUnless(type(myPulldom) == types.ModuleType) - self.failUnless(myPulldom.__name__ == 'xml.dom.pulldom') - - from xml.dom.pulldom import PullDOM as myPullDOM - self.failUnless(type(myPullDOM) == types.ClassType) - self.failUnless(myPullDOM.__name__ == 'PullDOM') - - - def testFromModuleImportStar(self): - """Test from module import * behavior.""" - # Using 'from x import *' is considered evil generally, more so - # in this case where you may have hundreds of defined types in - # a namespace. The intended behavior is that doing 'import *' - # from a CLR module won't blow up, but it also won't really do - # anything to get names into your namespace. - m = __import__('CLR.System.Xml', globals(), locals(), ['*']) - self.failUnless(m.__name__ == 'CLR.System.Xml') - self.failUnless(self.isCLRModule(m)) - - - def testImplicitAssemblyLoad(self): - """Test implicit assembly loading via import.""" - - def test(): - # This should fail until CLR.System.Windows.Forms has been - # imported or that assembly has been explicitly loaded. - import CLR.System.Windows - - self.failUnlessRaises(ImportError, test) - - import CLR.System.Windows.Forms as Forms - self.failUnless(self.isCLRModule(Forms)) - self.failUnless(Forms.__name__ == 'CLR.System.Windows.Forms') - - from CLR.System.Drawing import Graphics - self.failUnless(self.isCLRClass(Graphics)) - self.failUnless(Graphics.__name__ == 'Graphics') - - - def testExplicitAssemblyLoad(self): - """Test explicit assembly loading using standard CLR tools.""" - from CLR.System.Reflection import Assembly - import sys - - assembly = Assembly.LoadWithPartialName('System.Data') - self.failUnless(assembly != None) - - import CLR.System.Data - self.failUnless(sys.modules.has_key('CLR.System.Data')) - - assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') - self.failUnless(assembly == None) - - - def testImplicitLoadAlreadyValidNamespace(self): - """Test implicit assembly load over an already valid namespace.""" - # In this case, the mscorlib assembly (loaded by default) defines - # a number of types in the System namespace. There is also a System - # assembly, which is _not_ loaded by default, which also contains - # types in the System namespace. The desired behavior is for the - # Python runtime to "do the right thing", allowing types from both - # assemblies to be found in the CLR.System module implicitly. - import CLR.System - self.failUnless(self.isCLRClass(CLR.System.UriBuilder)) - - - def testImportNonExistantModule(self): - """Test import failure for a non-existant module.""" - def test(): - import CLR.System.SpamSpamSpam - - self.failUnlessRaises(ImportError, test) - - - def testLookupNoNamespaceType(self): - """Test lookup of types without a qualified namespace.""" - import CLR.Python.Test - import CLR - self.failUnless(self.isCLRClass(CLR.NoNamespaceType)) - - - def testModuleLookupRecursion(self): - """Test for recursive lookup handling.""" - def test1(): - from CLR import CLR - - self.failUnlessRaises(ImportError, test1) - - def test2(): - import CLR - x = CLR.CLR - - self.failUnlessRaises(AttributeError, test2) - - - def testModuleGetAttr(self): - """Test module getattr behavior.""" - import CLR.System as System - - int_type = System.Int32 - self.failUnless(self.isCLRClass(int_type)) - - module = System.Xml - self.failUnless(self.isCLRModule(module)) - - def test(): - spam = System.Spam - - self.failUnlessRaises(AttributeError, test) - - def test(): - spam = getattr(System, 1) - - self.failUnlessRaises(TypeError, test) - - - def testModuleAttrAbuse(self): - """Test handling of attempts to set module attributes.""" - - # It would be safer to use a dict-proxy as the __dict__ for CLR - # modules, but as of Python 2.3 some parts of the CPython runtime - # like dir() will fail if a module dict is not a real dictionary. - - def test(): - import CLR.System - CLR.System.__dict__['foo'] = 0 - return 1 - - self.failUnless(test()) - - - def testModuleTypeAbuse(self): - """Test handling of attempts to break the module type.""" - import CLR.System as System - mtype = type(System) - - def test(): - mtype.__getattribute__(0, 'spam') - - self.failUnlessRaises(TypeError, test) - - def test(): - mtype.__setattr__(0, 'spam', 1) - - self.failUnlessRaises(TypeError, test) - - def test(): - mtype.__repr__(0) - - self.failUnlessRaises(TypeError, test) - - - -def test_suite(): - return unittest.makeSuite(ModuleTests) - -def main(): - unittest.TextTestRunner().run(test_suite()) - -if __name__ == '__main__': - testcase.setup() - main() - diff --git a/pythonnet/src/tools/callconvutil.cs b/pythonnet/src/tools/callconvutil.cs deleted file mode 100755 index 55be03aa3..000000000 --- a/pythonnet/src/tools/callconvutil.cs +++ /dev/null @@ -1,145 +0,0 @@ -// CallConvUtil.cs - A utility to rewrite IL and insert calling -// convention metadata. This is needed to ensure that Python -// type callbacks are called using cdecl rather than stdcall. -// -// Author: Brian Lloyd -// -// (c) 2002 Brian Lloyd - -using System; -using System.IO; -using System.Collections; - - -public class CallConvUtil { - - static string ccAttr = - ".custom instance void Python.Runtime.CallConvCdeclAttribute"; - - static string modOpt = - "\n modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)"; - - StreamReader reader; - StreamWriter writer; - - - public static int Main(string[] args) { - CallConvUtil munger = new CallConvUtil(); - return munger.Run(); - } - - public int Run() { - string inputFile = "Python.Runtime.il"; - string outputFile = "Python.Runtime.il2"; - string buff; - string line; - - if (!File.Exists(inputFile)) { - Console.WriteLine("{0} does not exist!", inputFile); - return -1; - } - - reader = File.OpenText(inputFile); - writer = File.CreateText(outputFile); - - while ((line = reader.ReadLine())!= null) { - - buff = line.Trim(); - if (buff.StartsWith(".class ")) { - ReadClass(line, false); - } - else { - writer.WriteLine(line); - } - - } - - reader.Close(); - writer.Close(); - - return 0; - } - - public void ReadClass(string line, bool nested) { - ArrayList lines = new ArrayList(); - bool hasAttr = false; - string data; - string buff; - - if (!nested) { - lines.Add(line); - } - - while ((data = reader.ReadLine()) != null) { - buff = data.Trim(); - - if (buff.StartsWith(".class ")) { - WriteBuffer(lines); - writer.WriteLine(data); - ReadClass(data, true); - lines = new ArrayList(); - } - - else if (buff.StartsWith(ccAttr)) { - hasAttr = true; - lines.Add(data); - } - - else if ( (!hasAttr) && buff.StartsWith(".method ")) { - WriteBuffer(lines); - ReadMethod(data); - lines = new ArrayList(); - } - else if (buff.StartsWith("} // end of class")) { - WriteBuffer(lines); - writer.WriteLine(data); - return; - } - else if (hasAttr && buff.StartsWith("Invoke(")) { - WriteBuffer(lines); - writer.WriteLine(modOpt); - writer.WriteLine(data); - lines = new ArrayList(); - - } - else { - lines.Add(data); - } - } - } - - public void ReadMethod(string line) { - ArrayList lines = new ArrayList(); - string mline = line; - - string data; - string buff; - - while ((data = reader.ReadLine()) != null) { - buff = data.Trim(); - if (buff.StartsWith(ccAttr)) { - writer.WriteLine(mline); - writer.WriteLine(modOpt); - WriteBuffer(lines); - writer.WriteLine(data); - return; - } - else if (buff.StartsWith("} // end of method")) { - writer.WriteLine(mline); - WriteBuffer(lines); - writer.WriteLine(data); - return; - } - lines.Add(data); - } - } - - public void WriteBuffer(ArrayList data) { - IEnumerator iter = data.GetEnumerator(); - while (iter.MoveNext()) { - writer.WriteLine((String)iter.Current); - } - } - - -} diff --git a/pythonnet_8.sln b/pythonnet_8.sln new file mode 100644 index 000000000..e30c01be0 --- /dev/null +++ b/pythonnet_8.sln @@ -0,0 +1,86 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Runtime", "src\runtime\Python.Runtime.csproj", "{097B4AC0-74E9-4C58-BCF8-C69746EC8271}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Test", "src\testing\Python.Test.csproj", "{6F401A34-273B-450F-9A4C-13550BE0767B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.EmbeddingTest", "src\embed_tests\Python.EmbeddingTest.csproj", "{4165C59D-2822-499F-A6DB-EACA4C331EB5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "src\console\Console.csproj", "{E29DCF0A-5114-4A98-B1DD-71264B6EA349}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + EmbeddingTest|Any CPU = EmbeddingTest|Any CPU + EmbeddingTest|x64 = EmbeddingTest|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + UnitTests|Any CPU = UnitTests|Any CPU + UnitTests|x64 = UnitTests|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|Any CPU.Build.0 = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|x64.ActiveCfg = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|x64.Build.0 = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|Any CPU.ActiveCfg = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|Any CPU.Build.0 = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|x64.ActiveCfg = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|x64.Build.0 = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|Any CPU.ActiveCfg = Release|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|Any CPU.Build.0 = Release|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|x64.ActiveCfg = Release|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|x64.Build.0 = Release|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|Any CPU.ActiveCfg = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|Any CPU.Build.0 = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|x64.ActiveCfg = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|x64.Build.0 = Debug|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|x64.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|x64.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|Any CPU.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|Any CPU.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|x64.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|x64.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|Any CPU.Build.0 = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|x64.ActiveCfg = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|x64.Build.0 = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|Any CPU.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|Any CPU.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|x64.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|x64.Build.0 = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Debug|x64.ActiveCfg = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|Any CPU.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|Any CPU.Build.0 = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|x64.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|x64.Build.0 = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Release|x64.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.UnitTests|Any CPU.ActiveCfg = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.UnitTests|x64.ActiveCfg = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|x64.ActiveCfg = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|x64.Build.0 = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|Any CPU.ActiveCfg = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|Any CPU.Build.0 = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|x64.ActiveCfg = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|x64.Build.0 = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|Any CPU.Build.0 = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|x64.ActiveCfg = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|x64.Build.0 = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|Any CPU.ActiveCfg = UnitTests|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|Any CPU.Build.0 = UnitTests|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|x64.ActiveCfg = UnitTests|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|x64.Build.0 = UnitTests|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/pythonnet_9.sln b/pythonnet_9.sln new file mode 100644 index 000000000..1d11d7fd8 --- /dev/null +++ b/pythonnet_9.sln @@ -0,0 +1,87 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Runtime", "src\runtime\Python.Runtime.csproj", "{097B4AC0-74E9-4C58-BCF8-C69746EC8271}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Test", "src\testing\Python.Test.csproj", "{6F401A34-273B-450F-9A4C-13550BE0767B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.EmbeddingTest", "src\embed_tests\Python.EmbeddingTest.csproj", "{4165C59D-2822-499F-A6DB-EACA4C331EB5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "src\console\Console.csproj", "{E29DCF0A-5114-4A98-B1DD-71264B6EA349}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + EmbeddingTest|Any CPU = EmbeddingTest|Any CPU + EmbeddingTest|x64 = EmbeddingTest|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + UnitTests|Any CPU = UnitTests|Any CPU + UnitTests|x64 = UnitTests|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|Any CPU.Build.0 = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|x64.ActiveCfg = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Debug|x64.Build.0 = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|Any CPU.ActiveCfg = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|Any CPU.Build.0 = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|x64.ActiveCfg = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.EmbeddingTest|x64.Build.0 = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|Any CPU.ActiveCfg = Release|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|Any CPU.Build.0 = Release|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|x64.ActiveCfg = Release|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.Release|x64.Build.0 = Release|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|Any CPU.ActiveCfg = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|Any CPU.Build.0 = Debug|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|x64.ActiveCfg = Debug|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.UnitTests|x64.Build.0 = Debug|x64 + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|x64.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Debug|x64.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|Any CPU.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|Any CPU.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|x64.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.EmbeddingTest|x64.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|Any CPU.Build.0 = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|x64.ActiveCfg = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.Release|x64.Build.0 = Release|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|Any CPU.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|Any CPU.Build.0 = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|x64.ActiveCfg = Debug|Any CPU + {6F401A34-273B-450F-9A4C-13550BE0767B}.UnitTests|x64.Build.0 = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Debug|x64.ActiveCfg = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|Any CPU.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|Any CPU.Build.0 = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|x64.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.EmbeddingTest|x64.Build.0 = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.Release|x64.ActiveCfg = Release|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.UnitTests|Any CPU.ActiveCfg = Debug|Any CPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5}.UnitTests|x64.ActiveCfg = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|x64.ActiveCfg = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Debug|x64.Build.0 = Debug|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|Any CPU.ActiveCfg = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|Any CPU.Build.0 = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|x64.ActiveCfg = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.EmbeddingTest|x64.Build.0 = EmbeddingTest|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|Any CPU.Build.0 = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|x64.ActiveCfg = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.Release|x64.Build.0 = Release|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|Any CPU.ActiveCfg = UnitTests|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|Any CPU.Build.0 = UnitTests|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|x64.ActiveCfg = UnitTests|Any CPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349}.UnitTests|x64.Build.0 = UnitTests|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..7926c663d --- /dev/null +++ b/setup.py @@ -0,0 +1,348 @@ +""" +Setup script for building clr.pyd and dependencies using mono and into +an egg or wheel. +""" +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 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 +DEVTOOLS = "MsDev" if sys.platform == "win32" else "Mono" +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 + + 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", + ] + 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" + ] + + hreg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) + try: + hkey = None + for key in keys_to_check: + try: + hkey = _winreg.OpenKey(hreg, key) + break + 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: + hreg.Close() + + 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) + + +class PythonNET_BuildExt(build_ext): + + def build_extension(self, ext): + """ + Builds the .pyd file using msbuild or xbuild. + """ + if ext.name != "clr": + return build_ext.build_extension(self, ext) + + # install packages using nuget + self._install_packages() + + dest_file = self.get_ext_fullpath(ext.name) + dest_dir = os.path.dirname(dest_file) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + + defines = [ + "PYTHON%d%s" % (sys.version_info[:2]), + "UCS2" if sys.maxunicode < 0x10FFFF else "UCS4", + ] + + if CONFIG == "Debug": + defines.extend(["DEBUG", "TRACE"]) + + 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), + "/verbosity:%s" % VERBOSITY, + ] + + manifest = self._get_manifest(dest_dir) + if manifest: + cmd.append("/p:PythonManifest=\"%s\"" % manifest) + + self.announce("Building: %s" % " ".join(cmd)) + use_shell = True if DEVTOOLS == "Mono" else False + check_call(" ".join(cmd + ["/t:Clean"]), shell=use_shell) + check_call(" ".join(cmd + ["/t:Build"]), shell=use_shell) + + 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) + manifest = os.path.abspath(os.path.join(build_dir, "app.manifest")) + cmd = [mt, '-inputresource:"%s"' % sys.executable, '-out:"%s"' % manifest] + self.announce("Extracting manifest from %s" % sys.executable) + 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) + glib_libs = _check_output("pkg-config --libs glib-2.0", shell=True) + glib_cflags = _check_output("pkg-config --cflags glib-2.0", shell=True) + cflags = mono_cflags.strip() + " " + glib_cflags.strip() + libs = mono_libs.strip() + " " + glib_libs.strip() + + # build the clr python module + clr_ext = Extension("clr", + sources=[ + "src/monoclr/pynetinit.c", + "src/monoclr/clrmod.c" + ], + extra_compile_args=cflags.split(" "), + extra_link_args=libs.split(" ")) + + 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") + use_shell = False + if DEVTOOLS == "Mono": + nuget = "mono %s" % nuget + use_shell = True + + cmd = "%s restore pythonnet.sln -o packages" % nuget + self.announce("Installing packages: %s" % cmd) + check_call(cmd, shell=use_shell) + + +class PythonNET_InstallLib(install_lib): + + def install(self): + if not os.path.isdir(self.build_dir): + self.warn("'%s' does not exist -- no Python modules to install" % + self.build_dir) + return + + if not os.path.exists(self.install_dir): + self.mkpath(self.install_dir) + + # only copy clr.pyd/.so + for srcfile in glob(os.path.join(self.build_dir, "clr.*")): + destfile = os.path.join(self.install_dir, os.path.basename(srcfile)) + self.copy_file(srcfile, destfile) + + +class PythonNET_InstallData(install_data): + + def run(self): + build_cmd = self.get_finalized_command("build_ext") + install_cmd = self.get_finalized_command("install") + build_lib = os.path.abspath(build_cmd.build_lib) + install_platlib = os.path.relpath(install_cmd.install_platlib, self.install_dir) + + for i, data_files in enumerate(self.data_files): + if isinstance(data_files, str): + self.data_files[i] = data_files[i].format(build_lib=build_lib) + else: + for j, filename in enumerate(data_files[1]): + data_files[1][j] = filename.format(build_lib=build_lib) + dest = data_files[0].format(install_platlib=install_platlib) + 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): + """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, output=output) + return output + + +if __name__ == "__main__": + setupdir = os.path.dirname(__file__) + if setupdir: + os.chdir(setupdir) + + sources = [] + for ext in (".sln", ".snk", ".config"): + sources.extend(glob("*" + ext)) + + for root, dirnames, filenames in os.walk("src"): + for ext in (".cs", ".csproj", ".sln", ".snk", ".config", ".il", ".py", ".c", ".h", ".ico"): + for filename in fnmatch.filter(filenames, "*" + ext): + sources.append(os.path.join(root, filename)) + + for root, dirnames, filenames in os.walk("tools"): + for ext in (".exe"): + for filename in fnmatch.filter(filenames, "*" + ext): + sources.append(os.path.join(root, filename)) + + setup( + name="pythonnet", + version="2.0.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 :: C#', + 'License :: OSI Approved :: Zope Public License', + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Operating System :: Microsoft :: Windows', + 'Operating System :: POSIX :: Linux', + 'Operating System :: MacOS :: MacOS X', + ], + ext_modules=[ + Extension("clr", sources=sources) + ], + data_files=[ + ("{install_platlib}", [ + "{build_lib}/Python.Runtime.dll", + "Python.Runtime.dll.config"]), + ], + scripts=[_npython_exe], + zip_safe=False, + cmdclass={ + "build_ext" : PythonNET_BuildExt, + "build_scripts" : PythonNET_BuildScripts, + "install_lib" : PythonNET_InstallLib, + "install_data": PythonNET_InstallData, + } + ) + diff --git a/src/clrmodule/ClrModule.cs b/src/clrmodule/ClrModule.cs new file mode 100644 index 000000000..3347d55a9 --- /dev/null +++ b/src/clrmodule/ClrModule.cs @@ -0,0 +1,115 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +//============================================================================ +// This file replaces the hand-maintained stub that used to implement clr.dll. +// This is a line-by-line port from IL back to C#. +// We now use RGiesecke.DllExport on the required static init method so it can be +// loaded by a standard CPython interpreter as an extension module. When it +// is loaded, it bootstraps the managed runtime integration layer and defers +// to it to do initialization and put the clr module into sys.modules, etc. + +// The "USE_PYTHON_RUNTIME_*" defines control what extra evidence is used +// to help the CLR find the appropriate Python.Runtime assembly. + +// If defined, the "pythonRuntimeVersionString" variable must be set to +// Python.Runtime's current version. + +#define USE_PYTHON_RUNTIME_VERSION + +// If defined, the "PythonRuntimePublicKeyTokenData" data array must be +// set to Python.Runtime's public key token. (sn -T Python.Runtin.dll) +#define USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + +// 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... +//============================================================================ + + +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +public class clrModule +// ReSharper restore InconsistentNaming +// ReSharper restore CheckNamespace +{ + + [RGiesecke.DllExport.DllExport("initclr", System.Runtime.InteropServices.CallingConvention.StdCall)] +// ReSharper disable InconsistentNaming + public static void initclr() +// ReSharper restore InconsistentNaming + { +#if DEBUG_PRINT + System.Console.WriteLine("Attempting to load Python.Runtime using standard binding rules... "); +#endif +#if USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + var pythonRuntimePublicKeyTokenData = new byte[] { 0x50, 0x00, 0xfe, 0xa6, 0xcb, 0xa7, 0x02, 0xdd }; +#endif + + // Attempt to find and load Python.Runtime using standard assembly binding rules. + // This roughly translates into looking in order: + // - GAC + // - ApplicationBase + // - A PrivateBinPath under ApplicationBase + // With an unsigned assembly, the GAC is skipped. + var pythonRuntimeName = new System.Reflection.AssemblyName("Python.Runtime") + { +#if USE_PYTHON_RUNTIME_VERSION + Version = new System.Version("4.0.0.1"), +#endif + CultureInfo = System.Globalization.CultureInfo.InvariantCulture, + }; +#if USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + pythonRuntimeName.SetPublicKeyToken(pythonRuntimePublicKeyTokenData); +#endif + // We've got the AssemblyName with optional features; try to load it. + System.Reflection.Assembly pythonRuntime; + try + { + pythonRuntime = System.Reflection.Assembly.Load(pythonRuntimeName); +#if DEBUG_PRINT + System.Console.WriteLine("Success!"); +#endif + } + catch (System.IO.FileNotFoundException) + { + try + { + // If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll" + // from the directory this assembly is running in. "This assembly" is probably "clr.pyd", + // sitting somewhere in PYTHONPATH. This is using Assembly.LoadFrom, and inherits all the + // caveats of that call. See MSDN docs for details. + // Suzanne Cook's blog is also an excellent source of info on this: + // http://blogs.msdn.com/suzcook/ + // http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx + // http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx + + var executingAssembly = System.Reflection.Assembly.GetExecutingAssembly(); + var assemblyDirectory = System.IO.Path.GetDirectoryName(executingAssembly.Location); + if (assemblyDirectory == null) + throw new System.InvalidOperationException(executingAssembly.Location); + var pythonRuntimeDllPath = System.IO.Path.Combine(assemblyDirectory, "Python.Runtime.dll"); +#if DEBUG_PRINT + System.Console.WriteLine("Attempting to load Python.Runtime from: '{0}'...", pythonRuntimeDllPath); +#endif + pythonRuntime = System.Reflection.Assembly.LoadFrom(pythonRuntimeDllPath); + } + catch (System.InvalidOperationException) { +#if DEBUG_PRINT + System.Console.WriteLine("Could not load Python.Runtime, so sad."); +#endif + return; + } + } + + // 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"); + pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null); + } +} diff --git a/src/clrmodule/Properties/AssemblyInfo.cs b/src/clrmodule/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..dbf311d9a --- /dev/null +++ b/src/clrmodule/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("clrmodule")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("clrmodule")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ae10d6a4-55c2-482f-9716-9988e6c169e3")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/clrmodule/clrmodule.csproj b/src/clrmodule/clrmodule.csproj new file mode 100644 index 000000000..92dc2a945 --- /dev/null +++ b/src/clrmodule/clrmodule.csproj @@ -0,0 +1,126 @@ + + + + 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 diff --git a/src/clrmodule/packages.config b/src/clrmodule/packages.config new file mode 100644 index 000000000..05f605e37 --- /dev/null +++ b/src/clrmodule/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/console/Console.csproj b/src/console/Console.csproj new file mode 100644 index 000000000..95c1214d1 --- /dev/null +++ b/src/console/Console.csproj @@ -0,0 +1,218 @@ + + + + Debug + AnyCPU + {E29DCF0A-5114-4A98-B1DD-71264B6EA349} + Exe + false + nPython + Python.Runtime + OnBuildSuccess + + + + + 3.5 + python-clear.ico + 10.0.0 + 2.0 + ..\..\ + $(SolutionDir) + + + True + full + False + bin\Debug\ + DEBUG;TRACE + 4 + + + pdbonly + True + bin\Release\ + TRACE + True + false + 4 + + + True + bin\EmbeddingTest\ + DEBUG;TRACE + full + AnyCPU + 4 + False + + + True + bin\UnitTests\ + DEBUG;TRACE + full + AnyCPU + 4 + False + + + True + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + true + true + True + 4 + False + False + + + True + bin\x86\Release\ + TRACE + True + pdbonly + x86 + false + true + true + 4 + + + True + bin\x86\EmbeddingTest\ + DEBUG;TRACE + full + x86 + 4 + False + + + True + bin\x86\UnitTests\ + DEBUG;TRACE + full + x86 + false + false + 4 + False + + + True + bin\DebugMono_x86\ + DEBUG;TRACE + full + AnyCPU + 4 + False + + + True + bin\x86\DebugMono_x86\ + DEBUG;TRACE + full + x86 + true + true + 4 + False + + + True + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + true + true + false + 4 + False + + + True + bin\x64\Release\ + TRACE + True + pdbonly + x64 + false + true + true + false + 4 + + + True + bin\x64\EmbeddingTest\ + DEBUG;TRACE + full + x64 + false + false + false + 4 + False + + + True + bin\x64\UnitTests\ + DEBUG;TRACE + full + x64 + false + false + 4 + False + + + True + bin\x64\DebugMono_x86\ + DEBUG;TRACE + full + x64 + true + true + false + 4 + False + + + $(PythonManifest) + + + + + 3.5 + + + + + + + + + + Python.Runtime.dll + + + + + + + + {097b4ac0-74e9-4c58-bcf8-c69746ec8271} + Python.Runtime + + + + + + + + + + \ No newline at end of file diff --git a/src/console/Console.mdp b/src/console/Console.mdp new file mode 100644 index 000000000..45c23241d --- /dev/null +++ b/src/console/Console.mdp @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/console/app.config b/src/console/app.config new file mode 100644 index 000000000..e36560333 --- /dev/null +++ b/src/console/app.config @@ -0,0 +1,3 @@ + + + diff --git a/pythonnet/src/console/assemblyinfo.cs b/src/console/assemblyinfo.cs old mode 100755 new mode 100644 similarity index 61% rename from pythonnet/src/console/assemblyinfo.cs rename to src/console/assemblyinfo.cs index 781c0ec36..90ddd10b7 --- a/pythonnet/src/console/assemblyinfo.cs +++ b/src/console/assemblyinfo.cs @@ -1,21 +1,20 @@ -// Copyright (c) 2004 Zope Corporation and Contributors. -// -// All Rights Reserved. -// +// ========================================================================== // This software is subject to the provisions of the Zope Public License, // Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. // THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED // WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS // FOR A PARTICULAR PURPOSE. +// ========================================================================== using System; using System.Reflection; using System.Security.Permissions; using System.Runtime.InteropServices; +using System.Resources; [assembly: System.Reflection.AssemblyProduct("Python for .NET")] -[assembly: System.Reflection.AssemblyVersion("1.0.0.0")] +[assembly: System.Reflection.AssemblyVersion("2.4.2.7")] [assembly: AssemblyTitleAttribute("Python Console")] [assembly: AssemblyDefaultAliasAttribute("python.exe")] [assembly: CLSCompliant(true)] @@ -23,4 +22,8 @@ [assembly:PermissionSetAttribute(SecurityAction.RequestMinimum, - Name = "FullTrust")] + Name = "FullTrust")] +[assembly: AssemblyDescriptionAttribute("")] +[assembly: AssemblyCopyrightAttribute("Zope Public License, Version 2.0 (ZPL)")] +[assembly: AssemblyFileVersionAttribute("2.0.0.4")] +[assembly: NeutralResourcesLanguageAttribute("en")] diff --git a/src/console/python-clear.ico b/src/console/python-clear.ico new file mode 100644 index 000000000..b37050cce Binary files /dev/null and b/src/console/python-clear.ico differ diff --git a/src/console/pythonconsole.cs b/src/console/pythonconsole.cs new file mode 100644 index 000000000..26fc756d5 --- /dev/null +++ b/src/console/pythonconsole.cs @@ -0,0 +1,72 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; +using System.Collections.Generic; +using Python.Runtime; + +namespace Python.Runtime { + +public sealed class PythonConsole { + + private PythonConsole() {} + + [STAThread] + public static int Main(string[] args) { + // reference the static assemblyLoader to stop it being optimized away + AssemblyLoader a = assemblyLoader; + + string [] cmd = Environment.GetCommandLineArgs(); + PythonEngine.Initialize(); + + int i = Runtime.Py_Main(cmd.Length, cmd); + PythonEngine.Shutdown(); + + return i; + } + + // Register a callback function to load embedded assmeblies. + // (Python.Runtime.dll is included as a resource) + private sealed class AssemblyLoader { + Dictionary loadedAssemblies; + + public AssemblyLoader() { + loadedAssemblies = new Dictionary(); + + AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => { + string shortName = args.Name.Split(',')[0]; + String resourceName = shortName + ".dll"; + + if (loadedAssemblies.ContainsKey(resourceName)) { + return loadedAssemblies[resourceName]; + } + + // looks for the assembly from the resources and load it + using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) { + if (stream != null) { + Byte[] assemblyData = new Byte[stream.Length]; + stream.Read(assemblyData, 0, assemblyData.Length); + Assembly assembly = Assembly.Load(assemblyData); + loadedAssemblies[resourceName] = assembly; + return assembly; + } + } + + return null; + }; + } + }; + + private static AssemblyLoader assemblyLoader = new AssemblyLoader(); + +}; + + +} diff --git a/src/console/sourceforge-logo.png b/src/console/sourceforge-logo.png new file mode 100644 index 000000000..14c4143cc Binary files /dev/null and b/src/console/sourceforge-logo.png differ diff --git a/src/embed_tests/Embeddingtest.VisualState.xml b/src/embed_tests/Embeddingtest.VisualState.xml new file mode 100644 index 000000000..4909bca42 --- /dev/null +++ b/src/embed_tests/Embeddingtest.VisualState.xml @@ -0,0 +1,21 @@ + + + [0-1000]C:\Users\Barton\Documents\Visual Studio 2008\Projects\PySharp\trunk\pythonnet\src\embed_tests\Embeddingtest.nunit + [0-1003]Python.EmbeddingTest.PyImportTest + false + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/embed_tests/Embeddingtest.nunit b/src/embed_tests/Embeddingtest.nunit new file mode 100644 index 000000000..ab4a73f4e --- /dev/null +++ b/src/embed_tests/Embeddingtest.nunit @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj new file mode 100644 index 000000000..14f97f5fb --- /dev/null +++ b/src/embed_tests/Python.EmbeddingTest.csproj @@ -0,0 +1,178 @@ + + + + Debug + AnyCPU + {4165C59D-2822-499F-A6DB-EACA4C331EB5} + Library + false + Python.EmbeddingTest + Python.EmbeddingTest + OnBuildSuccess + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + 10.0.0 + 2.0 + ..\..\ + $(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\ + DEBUG;TRACE + 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 + + + + + 3.5 + + + ..\..\packages\NUnit.2.6.2\lib\nunit.framework.dll + + + + + + + + + + + Code + + + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + {097B4AC0-74E9-4C58-BCF8-C69746EC8271} + Python.Runtime + + + + + + + + + + diff --git a/src/embed_tests/packages.config b/src/embed_tests/packages.config new file mode 100644 index 000000000..5c3ca54dd --- /dev/null +++ b/src/embed_tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/embed_tests/pyimport.cs b/src/embed_tests/pyimport.cs new file mode 100644 index 000000000..35b81f80b --- /dev/null +++ b/src/embed_tests/pyimport.cs @@ -0,0 +1,74 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + [TestFixture] + public class PyImportTest + { + private IntPtr gs; + + [SetUp] + public void SetUp() + { + PythonEngine.Initialize(); + gs = PythonEngine.AcquireLock(); + + //string here = Environment.CurrentDirectory; + //trunk\pythonnet\src\embed_tests\bin\x86\DebugWin + + /* + * Append the tests directory to sys.path + * using reflection to circumvent the private modifires placed on most Runtime methods. + */ + const string s = @"../../../../tests"; + + Type RTClass = typeof(Runtime.Runtime); + + /* pyStrPtr = PyString_FromString(s); */ + MethodInfo PyString_FromString = RTClass.GetMethod("PyString_FromString", BindingFlags.NonPublic | BindingFlags.Static); + object[] funcArgs = new object[1]; + funcArgs[0] = s; + IntPtr pyStrPtr = (IntPtr)PyString_FromString.Invoke(null, funcArgs); + + /* SysDotPath = sys.path */ + MethodInfo PySys_GetObject = RTClass.GetMethod("PySys_GetObject", BindingFlags.NonPublic | BindingFlags.Static); + funcArgs[0] = "path"; + IntPtr SysDotPath = (IntPtr)PySys_GetObject.Invoke(null, funcArgs); + + /* SysDotPath.append(*pyStrPtr) */ + MethodInfo PyList_Append = RTClass.GetMethod("PyList_Append", BindingFlags.NonPublic | BindingFlags.Static); + funcArgs = new object[] {SysDotPath, pyStrPtr}; + int r = (int)PyList_Append.Invoke(null, funcArgs); + } + + [TearDown] + public void TearDown() + { + PythonEngine.ReleaseLock(gs); + PythonEngine.Shutdown(); + } + + /// + /// Test subdirectory import + /// + /// + /// The required directory structure was added to the \trunk\pythonnet\src\tests directory: + /// + /// PyImportTest/ + /// __init__.py + /// test/ + /// __init__.py + /// one.py + /// + [Test] + public void TestDottedName() + { + PyObject module = PythonEngine.ImportModule("PyImportTest.test.one"); + Assert.IsNotNull(module, ">>> import PyImportTest.test.one # FAILED"); + } + } +} diff --git a/src/embed_tests/pyiter.cs b/src/embed_tests/pyiter.cs new file mode 100644 index 000000000..fe1298d51 --- /dev/null +++ b/src/embed_tests/pyiter.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + [TestFixture] + public class PyIterTest + { + private IntPtr gs; + + [SetUp] + public void SetUp() + { + PythonEngine.Initialize(); + gs = PythonEngine.AcquireLock(); + } + + [TearDown] + public void TearDown() + { + PythonEngine.ReleaseLock(gs); + PythonEngine.Shutdown(); + } + + [Test] + public void TestOnPyList() + { + PyList list = new PyList(); + list.Append(new PyString("foo")); + list.Append(new PyString("bar")); + list.Append(new PyString("baz")); + List result = new List(); + foreach (PyObject item in list) + result.Add(item.ToString()); + Assert.AreEqual(3, result.Count); + Assert.AreEqual("foo",result[0]); + Assert.AreEqual("bar",result[1]); + Assert.AreEqual("baz",result[2]); + } + } +} diff --git a/src/embed_tests/pylong.cs b/src/embed_tests/pylong.cs new file mode 100644 index 000000000..1b5ffdb66 --- /dev/null +++ b/src/embed_tests/pylong.cs @@ -0,0 +1,34 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + [TestFixture] + public class PyLongTest + { + private IntPtr gs; + + [SetUp] + public void SetUp() + { + PythonEngine.Initialize(); + gs = PythonEngine.AcquireLock(); + } + + [TearDown] + public void TearDown() + { + PythonEngine.ReleaseLock(gs); + PythonEngine.Shutdown(); + } + + [Test] + public void TestToInt64() + { + long largeNumber = 8L * 1024L * 1024L * 1024L; // 8 GB + PyLong pyLargeNumber = new PyLong(largeNumber); + Assert.AreEqual(largeNumber, pyLargeNumber.ToInt64()); + } + } +} diff --git a/src/embed_tests/pyobject.cs b/src/embed_tests/pyobject.cs new file mode 100644 index 000000000..62d24da0c --- /dev/null +++ b/src/embed_tests/pyobject.cs @@ -0,0 +1,33 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + [TestFixture] + public class PyObjectTest + { + private IntPtr gs; + + [SetUp] + public void SetUp() + { + PythonEngine.Initialize(); + gs = PythonEngine.AcquireLock(); + } + + [TearDown] + public void TearDown() + { + PythonEngine.ReleaseLock(gs); + PythonEngine.Shutdown(); + } + + [Test] + public void TestUnicode() + { + PyObject s = new PyString("foo\u00e9"); + Assert.AreEqual("foo\u00e9",s.ToString()); + } + } +} diff --git a/src/embed_tests/pythonexception.cs b/src/embed_tests/pythonexception.cs new file mode 100644 index 000000000..f0bc39def --- /dev/null +++ b/src/embed_tests/pythonexception.cs @@ -0,0 +1,47 @@ +using System; +using NUnit.Framework; +using Python.Runtime; + +namespace Python.EmbeddingTest +{ + [TestFixture] + public class PythonExceptionTest + { + private IntPtr gs; + + [SetUp] + public void SetUp() + { + PythonEngine.Initialize(); + gs = PythonEngine.AcquireLock(); + } + + [TearDown] + public void TearDown() + { + PythonEngine.ReleaseLock(gs); + PythonEngine.Shutdown(); + } + + [Test] + public void TestMessage() + { + PyList list = new PyList(); + try + { + PyObject junk = list[0]; + } + catch (PythonException e) + { + Assert.AreEqual("IndexError : list index out of range", e.Message); + } + } + + [Test] + public void TestNoError() + { + PythonException e = new PythonException(); //There is no PyErr to fetch + Assert.AreEqual("", e.Message); + } + } +} diff --git a/src/monoclr/clrmod.c b/src/monoclr/clrmod.c new file mode 100644 index 000000000..8b809b28f --- /dev/null +++ b/src/monoclr/clrmod.c @@ -0,0 +1,45 @@ +// ========================================================================== +// 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. +// ========================================================================== +// +// Author: Christian Heimes + +#include "pynetclr.h" + +/* List of functions defined in the module */ +static PyMethodDef clr_methods[] = { + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(clr_module_doc, +"clr facade module to initialize the CLR. It's later " +"replaced by the real clr module. This module has a facade " +"attribute to make it distinguishable from the real clr module." +); + +static PyNet_Args *pn_args; +char** environ = NULL; + +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; + } +} + diff --git a/src/monoclr/clrpython.c b/src/monoclr/clrpython.c new file mode 100644 index 000000000..5fddabf22 --- /dev/null +++ b/src/monoclr/clrpython.c @@ -0,0 +1,29 @@ +// ========================================================================== +// 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 new file mode 100644 index 000000000..c97db10cb --- /dev/null +++ b/src/monoclr/pynetclr.h @@ -0,0 +1,43 @@ +// ========================================================================== +// 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. +// ========================================================================== +// +// Author: Christian Heimes + +#ifndef PYNET_CLR_H +#define PYNET_CLR_H + +#include +#include +#include +#include +#include +#include +#include + +#define MONO_VERSION "v4.0.30319.1" +#define MONO_DOMAIN "Python.Runtime" +#define PR_ASSEMBLY "Python.Runtime.dll" + +typedef struct { + MonoDomain *domain; + MonoAssembly *pr_assm; + MonoMethod *shutdown; + char *pr_file; + char *error; + char *init_name; + char *shutdown_name; +} PyNet_Args; + +PyNet_Args* PyNet_Init(int); +void PyNet_Finalize(PyNet_Args*); +void main_thread_handler(gpointer user_data); +char* PyNet_ExceptionToString(MonoObject *); + +#endif // PYNET_CLR_H + diff --git a/src/monoclr/pynetinit.c b/src/monoclr/pynetinit.c new file mode 100644 index 000000000..eaa1d9c8b --- /dev/null +++ b/src/monoclr/pynetinit.c @@ -0,0 +1,191 @@ +// ========================================================================== +// 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. +// ========================================================================== +// +// Author: Christian Heimes + +#include "pynetclr.h" + +#ifndef _WIN32 +#include "dirent.h" +#endif + +// initialize Mono and PythonNet +PyNet_Args* PyNet_Init(int ext) { + PyNet_Args *pn_args; + pn_args = (PyNet_Args *)malloc(sizeof(PyNet_Args)); + pn_args->pr_file = PR_ASSEMBLY; + pn_args->error = NULL; + pn_args->shutdown = NULL; + + if (ext == 0) { + pn_args->init_name = "Python.Runtime:Initialize()"; + } else { + pn_args->init_name = "Python.Runtime:InitExt()"; + } + pn_args->shutdown_name = "Python.Runtime:Shutdown()"; + + pn_args->domain = mono_jit_init_version(MONO_DOMAIN, MONO_VERSION); + + /* + * Load the default Mono configuration file, this is needed + * if you are planning on using the dllmaps defined on the + * system configuration + */ + mono_config_parse(NULL); + + /* I can't use this call to run the main_thread_handler. The function + * runs it in another thread but *this* thread holds the Python + * import lock -> DEAD LOCK. + * + * mono_runtime_exec_managed_code(pn_args->domain, main_thread_handler, + * pn_args); + */ + + main_thread_handler(pn_args); + + if (pn_args->error != NULL) { + PyErr_SetString(PyExc_ImportError, pn_args->error); + } + return pn_args; +} + +// Shuts down PythonNet and cleans up Mono +void PyNet_Finalize(PyNet_Args *pn_args) { + MonoObject *exception = NULL; + + if (pn_args->shutdown) { + mono_runtime_invoke(pn_args->shutdown, NULL, NULL, &exception); + if (exception) { + pn_args->error = PyNet_ExceptionToString(exception); + } + pn_args->shutdown = NULL; + } + + if (pn_args->domain) { + mono_jit_cleanup(pn_args->domain); + pn_args->domain = NULL; + } + free(pn_args); +} + +MonoMethod *getMethodFromClass(MonoClass *cls, char *name) { + MonoMethodDesc *mdesc; + MonoMethod *method; + + mdesc = mono_method_desc_new(name, 1); + method = mono_method_desc_search_in_class(mdesc, cls); + mono_method_desc_free(mdesc); + + return method; +} + +void main_thread_handler (gpointer user_data) { + PyNet_Args *pn_args=(PyNet_Args *)user_data; + MonoMethod *init; + MonoImage *pr_image; + MonoClass *pythonengine; + MonoObject *exception = NULL; + +#ifndef _WIN32 + + //get python path system variable + PyObject* syspath = PySys_GetObject("path"); + char* runtime_full_path = (char*) malloc(1024); + const char* slash = "/"; + int found = 0; + + int ii = 0; + for (ii = 0; ii < PyList_Size(syspath); ++ii) { + const char* pydir = PyString_AsString(PyList_GetItem(syspath, ii)); + char* curdir = (char*) malloc(1024); + strncpy(curdir, strlen(pydir) > 0 ? pydir : ".", 1024); + strncat(curdir, slash, 1024); + + //look in this directory for the pn_args->pr_file + DIR* dirp = opendir(curdir); + if (dirp != NULL) { + + struct dirent *dp; + while ((dp = readdir(dirp)) != NULL) { + if (strcmp(dp->d_name, pn_args->pr_file) == 0) { + strcpy(runtime_full_path, curdir); + strcat(runtime_full_path, pn_args->pr_file); + found = 1; + break; + } + } + closedir(dirp); + } + free(curdir); + + if (found) { + pn_args->pr_file = runtime_full_path; + break; + } + } + + if (!found) { + fprintf(stderr, "Could not find assembly %s. \n", pn_args->pr_file); + return; + } +#endif + + + pn_args->pr_assm = mono_domain_assembly_open(pn_args->domain, pn_args->pr_file); + if (!pn_args->pr_assm) { + pn_args->error = "Unable to load assembly"; + return; + } +#ifndef _WIN32 + free(runtime_full_path); +#endif + + pr_image = mono_assembly_get_image(pn_args->pr_assm); + if (!pr_image) { + pn_args->error = "Unable to get image"; + return; + } + + pythonengine = mono_class_from_name(pr_image, "Python.Runtime", "PythonEngine"); + if (!pythonengine) { + pn_args->error = "Unable to load class PythonEngine from Python.Runtime"; + return; + } + + init = getMethodFromClass(pythonengine, pn_args->init_name); + if (!init) { + pn_args->error = "Unable to fetch Init method from PythonEngine"; + return; + } + + pn_args->shutdown = getMethodFromClass(pythonengine, pn_args->shutdown_name); + if (!pn_args->shutdown) { + pn_args->error = "Unable to fetch shutdown method from PythonEngine"; + return; + } + + mono_runtime_invoke(init, NULL, NULL, &exception); + if (exception) { + pn_args->error = PyNet_ExceptionToString(exception); + return; + } +} + +// Get string from a Mono exception +char* PyNet_ExceptionToString(MonoObject *e) { + MonoMethodDesc* mdesc = mono_method_desc_new(":ToString()", FALSE); + MonoMethod* mmethod = mono_method_desc_search_in_class(mdesc, mono_get_object_class()); + mono_method_desc_free(mdesc); + + mmethod = mono_object_get_virtual_method(e, mmethod); + MonoString* monoString = (MonoString*) mono_runtime_invoke(mmethod, e, NULL, NULL); + mono_runtime_invoke(mmethod, e, NULL, NULL); + return mono_string_to_utf8(monoString); +} + diff --git a/src/monoclr/python.c b/src/monoclr/python.c new file mode 100644 index 000000000..aa340491f --- /dev/null +++ b/src/monoclr/python.c @@ -0,0 +1,22 @@ +// ========================================================================== +// 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 new file mode 100644 index 000000000..f5bf3378a --- /dev/null +++ b/src/runtime/Python.Runtime.csproj @@ -0,0 +1,190 @@ + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/runtime/Python.Runtime.mdp b/src/runtime/Python.Runtime.mdp new file mode 100644 index 000000000..845407ec2 --- /dev/null +++ b/src/runtime/Python.Runtime.mdp @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/runtime/arrayobject.cs b/src/runtime/arrayobject.cs new file mode 100644 index 000000000..c96fbd23c --- /dev/null +++ b/src/runtime/arrayobject.cs @@ -0,0 +1,252 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + /// + /// Implements a Python type for managed arrays. This type is essentially + /// the same as a ClassObject, except that it provides sequence semantics + /// to support natural array usage (indexing) from Python. + /// + + internal class ArrayObject : ClassBase { + + internal ArrayObject(Type tp) : base(tp) {} + + internal override bool CanSubclass() { + return false; + } + + public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { + ArrayObject self = GetManagedObject(tp) as ArrayObject; + if (Runtime.PyTuple_Size(args) != 1) { + return Exceptions.RaiseTypeError("array expects 1 argument"); + } + IntPtr op = Runtime.PyTuple_GetItem(args, 0); + Object result; + + if (!Converter.ToManaged(op, self.type, out result, true)) { + return IntPtr.Zero; + } + return CLRObject.GetInstHandle(result, tp); + } + + + //==================================================================== + // Implements __getitem__ for array types. + //==================================================================== + + public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { + CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); + Array items = obj.inst as Array; + Type itemType = obj.inst.GetType().GetElementType(); + int rank = items.Rank; + int index = 0; + object value; + + // Note that CLR 1.0 only supports int indexes - methods to + // support long indices were introduced in 1.1. We could + // support long indices automatically, but given that long + // indices are not backward compatible and a relative edge + // case, we won't bother for now. + + // Single-dimensional arrays are the most common case and are + // cheaper to deal with than multi-dimensional, so check first. + + if (rank == 1) { + index = (int)Runtime.PyInt_AsLong(idx); + + if (Exceptions.ErrorOccurred()) { + return Exceptions.RaiseTypeError("invalid index value"); + } + + if (index < 0) { + index = items.Length + index; + } + + try { + value = items.GetValue(index); + } + catch (IndexOutOfRangeException) { + Exceptions.SetError(Exceptions.IndexError, + "array index out of range" + ); + return IntPtr.Zero; + } + + return Converter.ToPython(items.GetValue(index), itemType); + } + + // Multi-dimensional arrays can be indexed a la: list[1, 2, 3]. + + if (!Runtime.PyTuple_Check(idx)) { + Exceptions.SetError(Exceptions.TypeError, + "invalid index value" + ); + return IntPtr.Zero; + } + + int count = Runtime.PyTuple_Size(idx); + + Array args = Array.CreateInstance(typeof(Int32), count); + + for (int i = 0; i < count; i++) { + IntPtr op = Runtime.PyTuple_GetItem(idx, i); + index = (int)Runtime.PyInt_AsLong(op); + + if (Exceptions.ErrorOccurred()) { + return Exceptions.RaiseTypeError("invalid index value"); + } + + if (index < 0) { + index = items.GetLength(i) + index; + } + + args.SetValue(index, i); + } + + try { + value = items.GetValue((int[]) args); + } + catch (IndexOutOfRangeException) { + Exceptions.SetError(Exceptions.IndexError, + "array index out of range" + ); + return IntPtr.Zero; + } + + return Converter.ToPython(value, itemType); + } + + + //==================================================================== + // Implements __setitem__ for array types. + //==================================================================== + + public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { + CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); + Array items = obj.inst as Array; + Type itemType = obj.inst.GetType().GetElementType(); + int rank = items.Rank; + int index = 0; + object value; + + if (items.IsReadOnly) { + Exceptions.RaiseTypeError("array is read-only"); + return -1; + } + + if (!Converter.ToManaged(v, itemType, out value, true)) { + return -1; + } + + if (rank == 1) { + index = (int)Runtime.PyInt_AsLong(idx); + + if (Exceptions.ErrorOccurred()) { + Exceptions.RaiseTypeError("invalid index value"); + return -1; + } + + if (index < 0) { + index = items.Length + index; + } + + try { + items.SetValue(value, index); + } + catch (IndexOutOfRangeException) { + Exceptions.SetError(Exceptions.IndexError, + "array index out of range" + ); + return -1; + } + + return 0; + } + + if (!Runtime.PyTuple_Check(idx)) { + Exceptions.RaiseTypeError("invalid index value"); + return -1; + } + + int count = Runtime.PyTuple_Size(idx); + + Array args = Array.CreateInstance(typeof(Int32), count); + + for (int i = 0; i < count; i++) { + IntPtr op = Runtime.PyTuple_GetItem(idx, i); + index = (int)Runtime.PyInt_AsLong(op); + + if (Exceptions.ErrorOccurred()) { + Exceptions.RaiseTypeError("invalid index value"); + return -1; + } + + if (index < 0) { + index = items.GetLength(i) + index; + } + + args.SetValue(index, i); + } + + try { + items.SetValue(value, (int[])args); + } + catch (IndexOutOfRangeException) { + Exceptions.SetError(Exceptions.IndexError, + "array index out of range" + ); + return -1; + } + + return 0; + } + + + //==================================================================== + // Implements __contains__ for array types. + //==================================================================== + + public static int sq_contains(IntPtr ob, IntPtr v) { + CLRObject obj = (CLRObject)ManagedType.GetManagedObject(ob); + Type itemType = obj.inst.GetType().GetElementType(); + IList items = obj.inst as IList; + object value; + + if (!Converter.ToManaged(v, itemType, out value, false)) { + return 0; + } + + if (items.Contains(value)) { + return 1; + } + + return 0; + } + + + //==================================================================== + // Implements __len__ for array types. + //==================================================================== + + public static int mp_length(IntPtr ob) { + CLRObject self = (CLRObject)ManagedType.GetManagedObject(ob); + Array items = self.inst as Array; + return items.Length; + } + + + } + +} diff --git a/src/runtime/assemblyinfo.cs b/src/runtime/assemblyinfo.cs new file mode 100644 index 000000000..d1645d402 --- /dev/null +++ b/src/runtime/assemblyinfo.cs @@ -0,0 +1,44 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Resources; + +[assembly: AssemblyProduct("Python for .NET")] +[assembly: AssemblyVersion("4.0.0.1")] +[assembly: AssemblyDefaultAliasAttribute("Python.Runtime.dll")] +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] + +[assembly: AssemblyCopyrightAttribute("Zope Public License, Version 2.0 (ZPL)")] +[assembly: AssemblyFileVersionAttribute("2.0.0.2")] +[assembly: NeutralResourcesLanguageAttribute("en")] + +#if (PYTHON23) +[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.3")] +[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.3")] +#endif +#if (PYTHON24) +[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.4")] +[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.4")] +#endif +#if (PYTHON25) +[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.5")] +[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.5")] +#endif +#if (PYTHON26) +[assembly: AssemblyTitleAttribute("Python.Runtime for Python 2.6")] +[assembly: AssemblyDescriptionAttribute("Python Runtime for Python 2.6")] +#endif +#if (PYTHON27) +[assembly: AssemblyTitle("Python.Runtime for Python 2.7")] +[assembly: AssemblyDescription("Python Runtime for Python 2.7")] +#endif diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs new file mode 100644 index 000000000..583b5c945 --- /dev/null +++ b/src/runtime/assemblymanager.cs @@ -0,0 +1,398 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.IO; +using System.Collections; +using System.Collections.Specialized; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace Python.Runtime { + + /// + /// The AssemblyManager maintains information about loaded assemblies + /// namespaces and provides an interface for name-based type lookup. + /// + + internal class AssemblyManager { + + static Dictionary> namespaces; + //static Dictionary> generics; + static AssemblyLoadEventHandler lhandler; + static ResolveEventHandler rhandler; + static Dictionary probed; + static List assemblies; + internal static List pypath; + + private AssemblyManager() {} + + //=================================================================== + // Initialization performed on startup of the Python runtime. Here we + // scan all of the currently loaded assemblies to determine exported + // names, and register to be notified of new assembly loads. + //=================================================================== + + internal static void Initialize() { + namespaces = new + Dictionary>(32); + probed = new Dictionary(32); + //generics = new Dictionary>(); + assemblies = new List(16); + pypath = new List(16); + + AppDomain domain = AppDomain.CurrentDomain; + + lhandler = new AssemblyLoadEventHandler(AssemblyLoadHandler); + domain.AssemblyLoad += lhandler; + + rhandler = new ResolveEventHandler(ResolveHandler); + domain.AssemblyResolve += rhandler; + + Assembly[] items = domain.GetAssemblies(); + for (int i = 0; i < items.Length; i++) { + Assembly a = items[i]; + assemblies.Add(a); + ScanAssembly(a); + } + } + + + //=================================================================== + // Cleanup resources upon shutdown of the Python runtime. + //=================================================================== + + internal static void Shutdown() { + AppDomain domain = AppDomain.CurrentDomain; + domain.AssemblyLoad -= lhandler; + domain.AssemblyResolve -= rhandler; + } + + + //=================================================================== + // Event handler for assembly load events. At the time the Python + // runtime loads, we scan the app domain to map the assemblies that + // are loaded at the time. We also have to register this event handler + // so that we can know about assemblies that get loaded after the + // Python runtime is initialized. + //=================================================================== + + static void AssemblyLoadHandler(Object ob, AssemblyLoadEventArgs args){ + Assembly assembly = args.LoadedAssembly; + assemblies.Add(assembly); + ScanAssembly(assembly); + } + + + //=================================================================== + // Event handler for assembly resolve events. This is needed because + // we augment the assembly search path with the PYTHONPATH when we + // load an assembly from Python. Because of that, we need to listen + // for failed loads, because they might be dependencies of something + // we loaded from Python which also needs to be found on PYTHONPATH. + //=================================================================== + + static Assembly ResolveHandler(Object ob, ResolveEventArgs args){ + string name = args.Name.ToLower(); + for (int i = 0; i < assemblies.Count; i++) { + Assembly a = (Assembly)assemblies[i]; + string full = a.FullName.ToLower(); + if (full.StartsWith(name)) { + return a; + } + } + return LoadAssemblyPath(args.Name); + } + + + //=================================================================== + // We __really__ want to avoid using Python objects or APIs when + // probing for assemblies to load, since our ResolveHandler may be + // called in contexts where we don't have the Python GIL and can't + // even safely try to get it without risking a deadlock ;( + // + // To work around that, we update a managed copy of sys.path (which + // is the main thing we care about) when UpdatePath is called. The + // import hook calls this whenever it knows its about to use the + // assembly manager, which lets us keep up with changes to sys.path + // in a relatively lightweight and low-overhead way. + //=================================================================== + + internal static void UpdatePath() { + IntPtr list = Runtime.PySys_GetObject("path"); + int count = Runtime.PyList_Size(list); + if (count != pypath.Count) { + pypath.Clear(); + probed.Clear(); + for (int i = 0; i < count; i++) { + IntPtr item = Runtime.PyList_GetItem(list, i); + string path = Runtime.GetManagedString(item); + if (path != null) { + pypath.Add(path); + } + } + } + } + + + //=================================================================== + // Given an assembly name, try to find this assembly file using the + // PYTHONPATH. If not found, return null to indicate implicit load + // using standard load semantics (app base directory then GAC, etc.) + //=================================================================== + + public static string FindAssembly(string name) { + char sep = Path.DirectorySeparatorChar; + string path; + string temp; + + for (int i = 0; i < pypath.Count; i++) { + string head = pypath[i]; + if (head == null || head.Length == 0) { + path = name; + } + else { + path = head + sep + name; + } + + temp = path + ".dll"; + if (File.Exists(temp)) { + return temp; + } + temp = path + ".exe"; + if (File.Exists(temp)) { + return temp; + } + } + return null; + } + + + //=================================================================== + // Loads an assembly from the application directory or the GAC + // given a simple assembly name. Returns the assembly if loaded. + //=================================================================== + + public static Assembly LoadAssembly(string name) { + Assembly assembly = null; + try { + assembly = Assembly.Load(name); + } + catch (System.Exception e) { + //if (!(e is System.IO.FileNotFoundException)) { + // throw; + //} + } + return assembly; + } + + + //=================================================================== + // Loads an assembly using an augmented search path (the python path). + //=================================================================== + + public static Assembly LoadAssemblyPath(string name) { + string path = FindAssembly(name); + Assembly assembly = null; + if (path != null) { + try { assembly = Assembly.LoadFrom(path); } + catch {} + } + return assembly; + } + + //=================================================================== + // Returns an assembly that's already been loaded + //=================================================================== + + public static Assembly FindLoadedAssembly(string name) { + for (int i = 0; i < assemblies.Count; i++) { + Assembly a = (Assembly)assemblies[i]; + if (a.GetName().Name == name) { + return a; + } + } + return null; + } + + //=================================================================== + // Given a qualified name of the form A.B.C.D, attempt to load + // an assembly named after each of A.B.C.D, A.B.C, A.B, A. This + // will only actually probe for the assembly once for each unique + // namespace. Returns true if any assemblies were loaded. + // TODO item 3 "* Deprecate implicit loading of assemblies": + // Set the fromFile flag if the name of the loaded assembly matches + // the fully qualified name that was requested if the framework + // actually loads an assembly. + // Call ONLY for namespaces that HAVE NOT been cached yet. + //=================================================================== + + public static bool LoadImplicit(string name, bool warn=true) { + string[] names = name.Split('.'); + bool loaded = false; + string s = ""; + Assembly lastAssembly = null; + HashSet assemblies = null; + for (int i = 0; i < names.Length; i++) { + s = (i == 0) ? names[0] : s + "." + names[i]; + if (!probed.ContainsKey(s)) { + if (assemblies == null) { + assemblies = new HashSet(AppDomain.CurrentDomain.GetAssemblies()); + } + Assembly a = FindLoadedAssembly(s); + if (a == null) { + a = LoadAssemblyPath(s); + } + if (a == null) { + a = LoadAssembly(s); + } + if (a != null && !assemblies.Contains(a)) { + loaded = true; + lastAssembly = a; + } + probed[s] = 1; + } + } + + // Deprecation warning + if (warn && loaded) + { + string deprWarning = String.Format( + "\nThe module was found, but not in a referenced namespace.\n" + + "Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", + Path.GetFileNameWithoutExtension(lastAssembly.Location)); + Exceptions.deprecation(deprWarning); + } + + return loaded; + } + + + //=================================================================== + // Scans an assembly for exported namespaces, adding them to the + // mapping of valid namespaces. Note that for a given namespace + // a.b.c.d, each of a, a.b, a.b.c and a.b.c.d are considered to + // be valid namespaces (to better match Python import semantics). + //=================================================================== + + static void ScanAssembly(Assembly assembly) { + + // A couple of things we want to do here: first, we want to + // gather a list of all of the namespaces contributed to by + // the assembly. + + Type[] types = assembly.GetTypes(); + for (int i = 0; i < types.Length; i++) { + Type t = types[i]; + string ns = t.Namespace; + if ((ns != null) && (!namespaces.ContainsKey(ns))) { + string[] names = ns.Split('.'); + string s = ""; + for (int n = 0; n < names.Length; n++) { + s = (n == 0) ? names[0] : s + "." + names[n]; + if (!namespaces.ContainsKey(s)) { + namespaces.Add(s, + new Dictionary() + ); + } + } + } + + if (ns != null && !namespaces[ns].ContainsKey(assembly)) { + namespaces[ns].Add(assembly, String.Empty); + } + + if (ns != null && t.IsGenericTypeDefinition) { + GenericUtil.Register(t); + } + } + } + + public static AssemblyName[] ListAssemblies() + { + AssemblyName[] names = new AssemblyName[assemblies.Count]; + Assembly assembly; + for (int i=0; i < assemblies.Count; i++) + { + assembly = assemblies[i]; + names.SetValue(assembly.GetName(), i); + } + return names; + } + + //=================================================================== + // Returns true if the given qualified name matches a namespace + // exported by an assembly loaded in the current app domain. + //=================================================================== + + public static bool IsValidNamespace(string name) { + return namespaces.ContainsKey(name); + } + + + //=================================================================== + // Returns the current list of valid names for the input namespace. + //=================================================================== + + public static List GetNames(string nsname) { + //Dictionary seen = new Dictionary(); + List names = new List(8); + + List g = GenericUtil.GetGenericBaseNames(nsname); + if (g != null) { + foreach (string n in g) { + names.Add(n); + } + } + + if (namespaces.ContainsKey(nsname)) { + foreach (Assembly a in namespaces[nsname].Keys) { + Type[] types = a.GetTypes(); + for (int i = 0; i < types.Length; i++) { + Type t = types[i]; + if (t.Namespace == nsname) { + names.Add(t.Name); + } + } + } + int nslen = nsname.Length; + foreach (string key in namespaces.Keys) { + if (key.Length > nslen && key.StartsWith(nsname)) { + //string tail = key.Substring(nslen); + if (key.IndexOf('.') == -1) { + names.Add(key); + } + } + } + } + return names; + } + + //=================================================================== + // Returns the System.Type object for a given qualified name, + // looking in the currently loaded assemblies for the named + // type. Returns null if the named type cannot be found. + //=================================================================== + + public static Type LookupType(string qname) { + for (int i = 0; i < assemblies.Count; i++) { + Assembly assembly = (Assembly)assemblies[i]; + Type type = assembly.GetType(qname); + if (type != null) { + return type; + } + } + return null; + } + + } + + +} diff --git a/src/runtime/buildclrmodule.bat b/src/runtime/buildclrmodule.bat new file mode 100644 index 000000000..125ff9090 --- /dev/null +++ b/src/runtime/buildclrmodule.bat @@ -0,0 +1,36 @@ +:: Call with buildclrmodule.bat + +@echo off + +set TARGET_PLATFORM=%1 +set INPUT_DIRECTORY=%~2 +set INPUT_PATH="%INPUT_DIRECTORY%\clrmodule.il" +set OUTPUT_PATH=%3 + +if %TARGET_PLATFORM%==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 new file mode 100644 index 000000000..1541b12cd --- /dev/null +++ b/src/runtime/classbase.cs @@ -0,0 +1,170 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; +using System.Security; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// Base class for Python types that reflect managed types / classes. + /// Concrete subclasses include ClassObject and DelegateObject. This + /// class provides common attributes and common machinery for doing + /// class initialization (initialization of the class __dict__). The + /// concrete subclasses provide slot implementations appropriate for + /// each variety of reflected type. + /// + + internal class ClassBase : ManagedType { + + internal Indexer indexer; + internal Type type; + + internal ClassBase(Type tp) : base() { + indexer = null; + type = tp; + } + + internal virtual bool CanSubclass() { + return (!this.type.IsEnum); + } + + //==================================================================== + // Implements __init__ for reflected classes and value types. + //==================================================================== + + public static int tp_init(IntPtr ob, IntPtr args, IntPtr kw) { + return 0; + } + + //==================================================================== + // Default implementation of [] semantics for reflected types. + //==================================================================== + + public virtual IntPtr type_subscript(IntPtr idx) { + return Exceptions.RaiseTypeError("unsubscriptable object"); + } + + //==================================================================== + // Standard comparison implementation for instances of reflected types. + //==================================================================== + + public static int tp_compare(IntPtr ob, IntPtr other) { + if (ob == other) { + return 0; + } + + CLRObject co1 = GetManagedObject(ob) as CLRObject; + CLRObject co2 = GetManagedObject(other) as CLRObject; + Object o1 = co1.inst; + Object o2 = co2.inst; + + if (Object.Equals(o1, o2)) { + return 0; + } + return -1; + } + + + //==================================================================== + // Standard iteration support for instances of reflected types. This + // allows natural iteration over objects that either are IEnumerable + // or themselves support IEnumerator directly. + //==================================================================== + + public static IntPtr tp_iter(IntPtr ob) { + CLRObject co = GetManagedObject(ob) as CLRObject; + if (co == null) { + return Exceptions.RaiseTypeError("invalid object"); + } + + IEnumerable e = co.inst as IEnumerable; + IEnumerator o; + + if (e != null) { + o = e.GetEnumerator(); + } + else { + o = co.inst as IEnumerator; + + if (o == null) { + string message = "iteration over non-sequence"; + return Exceptions.RaiseTypeError(message); + } + } + + return new Iterator(o).pyHandle; + } + + + //==================================================================== + // Standard __hash__ implementation for instances of reflected types. + //==================================================================== + + public static IntPtr tp_hash(IntPtr ob) { + CLRObject co = GetManagedObject(ob) as CLRObject; + if (co == null) { + return Exceptions.RaiseTypeError("unhashable type"); + } + return new IntPtr(co.inst.GetHashCode()); + } + + + //==================================================================== + // Standard __str__ implementation for instances of reflected types. + //==================================================================== + + public static IntPtr tp_str(IntPtr ob) { + CLRObject co = GetManagedObject(ob) as CLRObject; + if (co == null) { + return Exceptions.RaiseTypeError("invalid object"); + } + return Runtime.PyString_FromString(co.inst.ToString()); + } + + + //==================================================================== + // Default implementations for required Python GC support. + //==================================================================== + + public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) { + return 0; + } + + public static int tp_clear(IntPtr ob) { + return 0; + } + + public static int tp_is_gc(IntPtr type) { + return 1; + } + + //==================================================================== + // Standard dealloc implementation for instances of reflected types. + //==================================================================== + + public static void tp_dealloc(IntPtr ob) { + ManagedType self = GetManagedObject(ob); + IntPtr dict = Marshal.ReadIntPtr(ob, ObjectOffset.ob_dict); + if (dict != IntPtr.Zero) { + Runtime.Decref(dict); + } + Runtime.PyObject_GC_UnTrack(self.pyHandle); + Runtime.PyObject_GC_Del(self.pyHandle); + Runtime.Decref(self.tpHandle); + self.gcHandle.Free(); + } + + + } + +} diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs new file mode 100644 index 000000000..164c37cb6 --- /dev/null +++ b/src/runtime/classmanager.cs @@ -0,0 +1,373 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Collections; +using System.Reflection; +using System.Security; + +namespace Python.Runtime { + + /// + /// The ClassManager is responsible for creating and managing instances + /// that implement the Python type objects that reflect managed classes. + /// + /// Each managed type reflected to Python is represented by an instance + /// of a concrete subclass of ClassBase. Each instance is associated with + /// a generated Python type object, whose slots point to static methods + /// of the managed instance's class. + /// + + internal class ClassManager { + + static Dictionary cache; + static Type dtype; + + private ClassManager() {} + + static ClassManager() { + cache = new Dictionary(128); + // SEE: http://msdn.microsoft.com/en-us/library/96b1ayy4%28VS.90%29.aspx + // ""All delegates inherit from MulticastDelegate, which inherits from Delegate."" + // Was Delegate, which caused a null MethodInfo returned from GetMethode("Invoke") + // and crashed on Linux under Mono. + dtype = typeof(System.MulticastDelegate); + } + + //==================================================================== + // Return the ClassBase-derived instance that implements a particular + // reflected managed type, creating it if it doesn't yet exist. + //==================================================================== + + internal static ClassBase GetClass(Type type) { + ClassBase cb = null; + cache.TryGetValue(type, out cb); + if (cb != null) { + return cb; + } + cb = CreateClass(type); + cache.Add(type, cb); + return cb; + } + + + //==================================================================== + // Create a new ClassBase-derived instance that implements a reflected + // managed type. The new object will be associated with a generated + // Python type object. + //==================================================================== + + private static ClassBase CreateClass(Type type) { + + // First, we introspect the managed type and build some class + // information, including generating the member descriptors + // that we'll be putting in the Python class __dict__. + + ClassInfo info = GetClassInfo(type); + + // Next, select the appropriate managed implementation class. + // Different kinds of types, such as array types or interface + // types, want to vary certain implementation details to make + // sure that the type semantics are consistent in Python. + + ClassBase impl; + + // Check to see if the given type extends System.Exception. This + // lets us check once (vs. on every lookup) in case we need to + // wrap Exception-derived types in old-style classes + + if (type.ContainsGenericParameters) { + impl = new GenericType(type); + } + + else if (type.IsSubclassOf(dtype)) { + impl = new DelegateObject(type); + } + + else if (type.IsArray) { + impl = new ArrayObject(type); + } + + else if (type.IsInterface) { + impl = new InterfaceObject(type); + } + + else if (type == typeof(Exception) || + type.IsSubclassOf(typeof(Exception))) { + impl = new ExceptionClassObject(type); + } + + else { + impl = new ClassObject(type); + } + + impl.indexer = info.indexer; + + // Now we allocate the Python type object to reflect the given + // managed type, filling the Python type slots with thunks that + // point to the managed methods providing the implementation. + + + IntPtr tp = TypeManager.GetTypeHandle(impl, type); + impl.tpHandle = tp; + + // Finally, initialize the class __dict__ and return the object. + IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict); + + + IDictionaryEnumerator iter = info.members.GetEnumerator(); + while(iter.MoveNext()) { + ManagedType item = (ManagedType)iter.Value; + string name = (string)iter.Key; + Runtime.PyDict_SetItemString(dict, name, item.pyHandle); + } + + // If class has constructors, generate an __doc__ attribute. + + IntPtr doc = IntPtr.Zero; + Type marker = typeof(DocStringAttribute); + Attribute[] attrs = (Attribute[])type.GetCustomAttributes(marker, false); + if (attrs.Length == 0) { + doc = IntPtr.Zero; + } + else { + DocStringAttribute attr = (DocStringAttribute)attrs[0]; + string docStr = attr.DocString; + doc = Runtime.PyString_FromString(docStr); + Runtime.PyDict_SetItemString(dict, "__doc__", doc); + Runtime.Decref(doc); + } + + ClassObject co = impl as ClassObject; + // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. + // required that the ClassObject.ctors be changed to internal + if (co != null) { + if (co.ctors.Length > 0) { + // Implement Overloads on the class object + if (!CLRModule._SuppressOverloads) + { + ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder); + // ExtensionType types are untracked, so don't Incref() them. + // XXX deprecate __overloads__ soon... + Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); + Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); + } + + // don't generate the docstring if one was already set from a DocStringAttribute. + if (!CLRModule._SuppressDocs && doc == IntPtr.Zero) + { + doc = co.GetDocString(); + Runtime.PyDict_SetItemString(dict, "__doc__", doc); + Runtime.Decref(doc); + } + } + } + + return impl; + } + + + + + private static ClassInfo GetClassInfo(Type type) { + ClassInfo ci = new ClassInfo(type); + Hashtable methods = new Hashtable(); + ArrayList list; + MethodInfo meth; + ManagedType ob; + String name; + Object item; + Type tp; + int i, n; + + // This is complicated because inheritance in Python is name + // based. We can't just find DeclaredOnly members, because we + // could have a base class A that defines two overloads of a + // method and a class B that defines two more. The name-based + // descriptor Python will find needs to know about inherited + // overloads as well as those declared on the sub class. + + BindingFlags flags = BindingFlags.Static | + BindingFlags.Instance | + BindingFlags.Public | + BindingFlags.NonPublic; + + MemberInfo[] info = type.GetMembers(flags); + Hashtable local = new Hashtable(); + ArrayList items = new ArrayList(); + MemberInfo m; + + // Loop through once to find out which names are declared + for (i = 0; i < info.Length; i++) { + m = info[i]; + if (m.DeclaringType == type) { + local[m.Name] = 1; + } + } + + // Now again to filter w/o losing overloaded member info + for (i = 0; i < info.Length; i++) { + m = info[i]; + if (local[m.Name] != null) { + items.Add(m); + } + } + + if (type.IsInterface) { + // Interface inheritance seems to be a different animal: + // more contractual, less structural. Thus, a Type that + // represents an interface that inherits from another + // interface does not return the inherited interface's + // methods in GetMembers. For example ICollection inherits + // from IEnumerable, but ICollection's GetMemebers does not + // return GetEnumerator. + // + // Not sure if this is the correct way to fix this, but it + // seems to work. Thanks to Bruce Dodson for the fix. + + Type[] inheritedInterfaces = type.GetInterfaces(); + + for (i = 0; i < inheritedInterfaces.Length; ++i) { + Type inheritedType = inheritedInterfaces[i]; + MemberInfo[] imembers = inheritedType.GetMembers(flags); + for (n = 0; n < imembers.Length; n++) { + m = imembers[n]; + if (local[m.Name] == null) { + items.Add(m); + } + } + } + } + + for (i = 0; i < items.Count; i++) { + + MemberInfo mi = (MemberInfo)items[i]; + + switch(mi.MemberType) { + + case MemberTypes.Method: + meth = (MethodInfo) mi; + if (!(meth.IsPublic || meth.IsFamily || + meth.IsFamilyOrAssembly)) + continue; + name = meth.Name; + item = methods[name]; + if (item == null) { + item = methods[name] = new ArrayList(); + } + list = (ArrayList) item; + list.Add(meth); + continue; + + case MemberTypes.Property: + PropertyInfo pi = (PropertyInfo) mi; + + MethodInfo mm = null; + try { + mm = pi.GetGetMethod(true); + if (mm == null) { + mm = pi.GetSetMethod(true); + } + } + catch (SecurityException) { + // GetGetMethod may try to get a method protected by + // StrongNameIdentityPermission - effectively private. + continue; + } + + if (mm == null) { + continue; + } + + if (!(mm.IsPublic || mm.IsFamily || mm.IsFamilyOrAssembly)) + continue; + + // Check for indexer + ParameterInfo[] args = pi.GetIndexParameters(); + if (args.GetLength(0) > 0) { + Indexer idx = ci.indexer; + if (idx == null) { + ci.indexer = new Indexer(); + idx = ci.indexer; + } + idx.AddProperty(pi); + continue; + } + + ob = new PropertyObject(pi); + ci.members[pi.Name] = ob; + continue; + + case MemberTypes.Field: + FieldInfo fi = (FieldInfo) mi; + if (!(fi.IsPublic || fi.IsFamily || fi.IsFamilyOrAssembly)) + continue; + ob = new FieldObject(fi); + ci.members[mi.Name] = ob; + continue; + + case MemberTypes.Event: + EventInfo ei = (EventInfo)mi; + MethodInfo me = ei.GetAddMethod(true); + if (!(me.IsPublic || me.IsFamily || me.IsFamilyOrAssembly)) + continue; + ob = new EventObject(ei); + ci.members[ei.Name] = ob; + continue; + + case MemberTypes.NestedType: + tp = (Type) mi; + if (!(tp.IsNestedPublic || tp.IsNestedFamily || + tp.IsNestedFamORAssem)) + continue; + ob = ClassManager.GetClass(tp); + ci.members[mi.Name] = ob; + continue; + + } + } + + IDictionaryEnumerator iter = methods.GetEnumerator(); + + while(iter.MoveNext()) { + name = (string) iter.Key; + list = (ArrayList) iter.Value; + + MethodInfo[] mlist = (MethodInfo[])list.ToArray( + typeof(MethodInfo) + ); + + ob = new MethodObject(name, mlist); + ci.members[name] = ob; + } + + return ci; + + } + + + } + + + internal class ClassInfo { + + internal ClassInfo(Type t) { + members = new Hashtable(); + indexer = null; + } + + public Hashtable members; + public Indexer indexer; + } + + + +} diff --git a/src/runtime/classobject.cs b/src/runtime/classobject.cs new file mode 100644 index 000000000..5e79e8253 --- /dev/null +++ b/src/runtime/classobject.cs @@ -0,0 +1,299 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; + +namespace Python.Runtime { + + /// + /// Managed class that provides the implementation for reflected types. + /// Managed classes and value types are represented in Python by actual + /// Python type objects. Each of those type objects is associated with + /// an instance of ClassObject, which provides its implementation. + /// + + internal class ClassObject : ClassBase { + + internal ConstructorBinder binder; + internal ConstructorInfo[] ctors; + + internal ClassObject(Type tp) : base(tp) { + ctors = type.GetConstructors(); + binder = new ConstructorBinder(type); + + for (int i = 0; i < ctors.Length; i++) { + binder.AddMethod(ctors[i]); + } + } + + + //==================================================================== + // Helper to get docstring from reflected constructor info. + //==================================================================== + + internal IntPtr GetDocString() { + MethodBase[] methods = binder.GetMethods(); + string str = ""; + for (int i = 0; i < methods.Length; i++) { + if (str.Length > 0) + str += Environment.NewLine; + str += methods[i].ToString(); + } + return Runtime.PyString_FromString(str); + } + + + //==================================================================== + // Implements __new__ for reflected classes and value types. + //==================================================================== + + public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { + + ClassObject self = GetManagedObject(tp) as ClassObject; + + // Sanity check: this ensures a graceful error if someone does + // something intentially wrong like use the managed metatype for + // a class that is not really derived from a managed class. + + if (self == null) { + return Exceptions.RaiseTypeError("invalid object"); + } + + Type type = self.type; + + // Primitive types do not have constructors, but they look like + // they do from Python. If the ClassObject represents one of the + // convertible primitive types, just convert the arg directly. + + if (type.IsPrimitive || type == typeof(String)) { + if (Runtime.PyTuple_Size(args) != 1) { + Exceptions.SetError(Exceptions.TypeError, + "no constructors match given arguments" + ); + return IntPtr.Zero; + } + + IntPtr op = Runtime.PyTuple_GetItem(args, 0); + Object result; + + if (!Converter.ToManaged(op, type, out result, true)) { + return IntPtr.Zero; + } + + return CLRObject.GetInstHandle(result, tp); + } + + if (type.IsAbstract) { + Exceptions.SetError(Exceptions.TypeError, + "cannot instantiate abstract class" + ); + return IntPtr.Zero; + } + + if (type.IsEnum) { + Exceptions.SetError(Exceptions.TypeError, + "cannot instantiate enumeration" + ); + return IntPtr.Zero; + } + + Object obj = self.binder.InvokeRaw(IntPtr.Zero, args, kw); + if (obj == null) { + return IntPtr.Zero; + } + + return CLRObject.GetInstHandle(obj, tp); + } + + + //==================================================================== + // Implementation of [] semantics for reflected types. This exists + // both to implement the Array[int] syntax for creating arrays and + // to support generic name overload resolution using []. + //==================================================================== + + public override IntPtr type_subscript(IntPtr idx) { + + // If this type is the Array type, the [] means we need to + // construct and return an array type of the given element type. + + if ((this.type) == typeof(Array)) { + if (Runtime.PyTuple_Check(idx)) { + return Exceptions.RaiseTypeError("type expected"); + } + ClassBase c = GetManagedObject(idx) as ClassBase; + Type t = (c != null) ? c.type : Converter.GetTypeByAlias(idx); + if (t == null) { + return Exceptions.RaiseTypeError("type expected"); + } + Type a = t.MakeArrayType(); + ClassBase o = ClassManager.GetClass(a); + Runtime.Incref(o.pyHandle); + return o.pyHandle; + } + + // If there are generics in our namespace with the same base name + // as the current type, then [] means the caller wants to + // bind the generic type matching the given type parameters. + + Type[] types = Runtime.PythonArgsToTypeArray(idx); + if (types == null) { + return Exceptions.RaiseTypeError("type(s) expected"); + } + + string gname = this.type.FullName + "`" + types.Length.ToString(); + Type gtype = AssemblyManager.LookupType(gname); + if (gtype != null) { + GenericType g = ClassManager.GetClass(gtype) as GenericType; + return g.type_subscript(idx); + /*Runtime.Incref(g.pyHandle); + return g.pyHandle;*/ + } + return Exceptions.RaiseTypeError("unsubscriptable object"); + } + + + //==================================================================== + // Implements __getitem__ for reflected classes and value types. + //==================================================================== + + public static IntPtr mp_subscript(IntPtr ob, IntPtr idx) { + //ManagedType self = GetManagedObject(ob); + IntPtr tp = Runtime.PyObject_TYPE(ob); + ClassBase cls = (ClassBase)GetManagedObject(tp); + + if (cls.indexer == null || !cls.indexer.CanGet) { + Exceptions.SetError(Exceptions.TypeError, + "unindexable object" + ); + return IntPtr.Zero; + } + + // Arg may be a tuple in the case of an indexer with multiple + // parameters. If so, use it directly, else make a new tuple + // with the index arg (method binders expect arg tuples). + + IntPtr args = idx; + bool free = false; + + if (!Runtime.PyTuple_Check(idx)) { + args = Runtime.PyTuple_New(1); + Runtime.Incref(idx); + Runtime.PyTuple_SetItem(args, 0, idx); + free = true; + } + + IntPtr value = IntPtr.Zero; + + try { + value = cls.indexer.GetItem(ob, args); + } + finally { + if (free) { + Runtime.Decref(args); + } + } + return value; + } + + + //==================================================================== + // Implements __setitem__ for reflected classes and value types. + //==================================================================== + + public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) { + //ManagedType self = GetManagedObject(ob); + IntPtr tp = Runtime.PyObject_TYPE(ob); + ClassBase cls = (ClassBase)GetManagedObject(tp); + + if (cls.indexer == null || !cls.indexer.CanSet) { + Exceptions.SetError(Exceptions.TypeError, + "object doesn't support item assignment" + ); + return -1; + } + + // Arg may be a tuple in the case of an indexer with multiple + // parameters. If so, use it directly, else make a new tuple + // with the index arg (method binders expect arg tuples). + + IntPtr args = idx; + bool free = false; + + if (!Runtime.PyTuple_Check(idx)) { + args = Runtime.PyTuple_New(1); + Runtime.Incref(idx); + Runtime.PyTuple_SetItem(args, 0, idx); + free = true; + } + + int i = Runtime.PyTuple_Size(args); + IntPtr real = Runtime.PyTuple_New(i + 1); + for (int n = 0; n < i; n++) { + IntPtr item = Runtime.PyTuple_GetItem(args, n); + Runtime.Incref(item); + Runtime.PyTuple_SetItem(real, n, item); + } + Runtime.Incref(v); + Runtime.PyTuple_SetItem(real, i, v); + + try { + cls.indexer.SetItem(ob, real); + } + finally { + Runtime.Decref(real); + + if (free) { + Runtime.Decref(args); + } + } + + if (Exceptions.ErrorOccurred()) { + return -1; + } + + return 0; + } + + + //==================================================================== + // This is a hack. Generally, no managed class is considered callable + // from Python - with the exception of System.Delegate. It is useful + // to be able to call a System.Delegate instance directly, especially + // when working with multicast delegates. + //==================================================================== + + public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { + //ManagedType self = GetManagedObject(ob); + IntPtr tp = Runtime.PyObject_TYPE(ob); + ClassBase cb = (ClassBase)GetManagedObject(tp); + + if (cb.type != typeof(System.Delegate)) { + Exceptions.SetError(Exceptions.TypeError, + "object is not callable"); + return IntPtr.Zero; + } + + CLRObject co = (CLRObject)ManagedType.GetManagedObject(ob); + Delegate d = co.inst as Delegate; + BindingFlags flags = BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.Static; + + MethodInfo method = d.GetType().GetMethod("Invoke", flags); + MethodBinder binder = new MethodBinder(method); + return binder.Invoke(ob, args, kw); + } + + + } + +} diff --git a/src/runtime/clrmodule.il b/src/runtime/clrmodule.il new file mode 100644 index 000000000..e1289eb4a --- /dev/null +++ b/src/runtime/clrmodule.il @@ -0,0 +1,305 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +//============================================================================ +// This file is a hand-maintained stub - it implements clr.dll, which can be +// loaded by a standard CPython interpreter (on Windows) as an extension module. +// When it is loaded, it bootstraps the managed runtime integration layer and defers +// to it to do initialization and put the clr module into sys.modules, etc. + +// The "USE_PYTHON_RUNTIME_*" defines control what extra evidence is used +// to help the CLR find the appropriate Python.Runtime assembly. + +// If defined, the "pythonRuntimeVersionString" variable must be set to +// Python.Runtime's current version. +#define USE_PYTHON_RUNTIME_VERSION + +// If defined, the "PythonRuntimePublicKeyTokenData" data array must be +// set to Python.Runtime's public key token. (sn -T Python.Runtin.dll) +#define USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + +// If DEBUG_PRINT is defined, a few System.Console.WriteLine calls are made +// to indicate what's going on during the load... +//#define DEBUG_PRINT +//============================================================================ + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 4:0:0:0 +} + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 2:0:0:0 +} + +.assembly clr +{ + .hash algorithm 0x00008004 + .ver 4:0:0:1 +} + +.module clr.dll +.imagebase 0x00400000 +.subsystem 0x00000003 +.file alignment 512 + +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN +.data PythonRuntimePublicKeyTokenData = bytearray (50 00 fe a6 cb a7 02 dd) +//.data PythonRuntimePublicKeyTokenData = bytearray (64 e1 4e 84 5a bf 2e 60) +#endif + +// This includes the platform-specific IL. The include search path +// is set depending on whether we're compiling 32 or 64 bit. +// This MUST come before any other .data directives! +// Why, oh why, can't ilasm support command line #defines? :( +// + +//#include "clrmodule-platform.il" + +// From the manifest as seen by ildasm +//%windir%\Microsoft.NET\Framework\v4.0.30319\ilasm /dll /pe64 /x64 clrmodule.il +//.corflags 0x00000000 +// Image base: 0x01550000 +// .vtfixup [1] int64 fromunmanaged at D_00004008 // 0000000006000002 + +//%windir%\Microsoft.NET\Framework\v4.0.30319\ilasm /dll clrmodule.il +// .vtfixup [1] int32 fromunmanaged at D_00004008 // 06000002 +//.corflags 0x00000002 // 32BITREQUIRED +// Image base: 0x015A0000 + +// With or without /pe64 /x64 switches. +//{ +// .vtentry 1 : 1 +// .export [1] as initclr +// ... } + + +.class public auto ansi beforefieldinit clrModule extends [mscorlib]System.Object +{ +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + .field static assembly int64 PythonRuntimePublicKeyToken at PythonRuntimePublicKeyTokenData +#endif + + .method public hidebysig specialname rtspecialname instance void + .ctor() cil managed + { + .maxstack 1 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig static void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) + initclr() cil managed + { +// .vtentry 1:1 + .export [1] as initclr + + .maxstack 6 + .locals init ( + class [mscorlib]System.Reflection.Assembly pythonRuntime, + class [mscorlib]System.Reflection.Assembly executingAssembly, + class [mscorlib]System.Reflection.AssemblyName pythonRuntimeName, + class [mscorlib]System.Type pythonEngineType, + int8[] publicKeyToken, + string assemblyDirectory, + string pythonRuntimeVersionString, + string pythonRuntimeDllPath) + + // pythonRuntime = null; + ldnull + stloc pythonRuntime + + .try + { +#ifdef DEBUG_PRINT + ldstr "Attempting to load Python.Runtime using standard binding rules... " + call void [mscorlib]System.Console::Write(string) +#endif + + // Attempt to find and load Python.Runtime using standard assembly binding rules. + // This roughly translates into looking in order: + // - GAC + // - ApplicationBase + // - A PrivateBinPath under ApplicationBase + // With an unsigned assembly, the GAC is skipped. + + // System.Reflection.AssemblyName pythonRuntimeName = new System.Reflection.AssemblyName(); + newobj instance void [mscorlib]System.Reflection.AssemblyName::.ctor() + stloc pythonRuntimeName + + // pythonRuntimeName.Name = "Python.Runtime"; + ldloc pythonRuntimeName + ldstr "Python.Runtime" + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Name(string) + +#ifdef USE_PYTHON_RUNTIME_VERSION + // pythonRuntimeVersionString = "..."; + ldstr "4.0.0.1" + stloc pythonRuntimeVersionString + + // pythonRuntimeName.Version = new Version(pythonRuntimeVersionString); + ldloc pythonRuntimeName + ldloc pythonRuntimeVersionString + newobj instance void [mscorlib]System.Version::.ctor(string) + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Version(class [mscorlib]System.Version) +#endif + +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + // publicKeyToken = new byte[] { ... }; + ldc.i4.8 + newarr [mscorlib]System.Byte + dup + ldtoken field int64 clrModule::PythonRuntimePublicKeyToken + call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle) + stloc publicKeyToken + + // pythonRuntimeName.SetPublicKeyToken(publicKeyToken); + ldloc pythonRuntimeName + ldloc publicKeyToken + callvirt instance void [mscorlib]System.Reflection.AssemblyName::SetPublicKeyToken(uint8[]) +#endif + + // pythonRuntimeName.CultureInfo = System.Globalization.CultureInfo.InvariantCulture; + ldloc pythonRuntimeName + call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture() + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_CultureInfo(class [mscorlib]System.Globalization.CultureInfo) + + // return System.Reflection.Assembly.Load(pythonRuntimeName); + ldloc pythonRuntimeName + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::Load(class [mscorlib]System.Reflection.AssemblyName) + stloc pythonRuntime + +#ifdef DEBUG_PRINT + ldstr "Success!" + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s LOADED_PYTHON_RUNTIME + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Failed." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_CLR_LOAD + } + EXIT_CLR_LOAD: nop + + .try + { + // If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll" + // from the directory this assembly is running in. "This assembly" is probably "clr.pyd", + // sitting somewhere in PYTHONPATH. This is using Assembly.LoadFrom, and inherits all the + // caveats of that call. See MSDN docs for details. + // Suzanne Cook's blog is also an excellent source of info on this: + // http://blogs.msdn.com/suzcook/ + // http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx + // http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx + // executingAssembly = System.Reflection.Assembly.GetExecutingAssembly(); + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly() + stloc executingAssembly + + // assemblyDirectory = System.IO.Path.GetDirectoryName(executingAssembly.Location); + ldloc executingAssembly + callvirt instance string [mscorlib]System.Reflection.Assembly::get_Location() + call string [mscorlib]System.IO.Path::GetDirectoryName(string) + stloc assemblyDirectory + + // pythonRuntimeDllPath = System.IO.Path.Combine(assemblyDirectory, "Python.Runtime.dll"); + ldloc assemblyDirectory + ldstr "Python.Runtime.dll" + call string [mscorlib]System.IO.Path::Combine(string, string) + stloc pythonRuntimeDllPath + +#ifdef DEBUG_PRINT + ldstr "Attempting to load Python.Runtime from: '{0}'... " + ldloc pythonRuntimeDllPath + call void [mscorlib]System.Console::Write(string, object) +#endif + + // pythonRuntime = System.Reflection.Assembly.LoadFrom(pythonRuntimeDllPath); + ldloc pythonRuntimeDllPath + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::LoadFrom(string) + stloc pythonRuntime + +#ifdef DEBUG_PRINT + ldstr "Success!" + call void [mscorlib]System.Console::WriteLine(string) + + ldloc pythonRuntime + callvirt instance string [mscorlib]System.Reflection.Assembly::get_CodeBase() + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s LOADED_PYTHON_RUNTIME + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Failed." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_PYTHONPATH_LOAD + } + EXIT_PYTHONPATH_LOAD: nop + + // If we get here, we haven't loaded Python.Runtime, so bail. +#ifdef DEBUG_PRINT + ldstr "Could not load Python.Runtime, so sad." + call void [mscorlib]System.Console::WriteLine(string) +#endif + ret; + + // Once here, we've successfully loaded SOME version of Python.Runtime + // So now we get the PythonEngine and execute the InitExt method on it. + LOADED_PYTHON_RUNTIME: nop + .try + { +#ifdef DEBUG_PRINT + ldstr "Running Python.Runtime.PythonEngine.InitExt()" + call void [mscorlib]System.Console::WriteLine(string) +#endif + // pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine"); + ldloc pythonRuntime + ldstr "Python.Runtime.PythonEngine" + callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string) + stloc pythonEngineType + + // pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null); + ldloc pythonEngineType + ldstr "InitExt" + ldc.i4 0x100 + ldnull + ldnull + ldnull + callvirt instance object [mscorlib]System.Type::InvokeMember( string, + valuetype [mscorlib]System.Reflection.BindingFlags, + class [mscorlib]System.Reflection.Binder, + object, + object[]) + pop + leave.s EXIT_TRY_INVOKE + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Error calling Python.Runtime.PythonEngine.InitExt()." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_TRY_INVOKE + } + EXIT_TRY_INVOKE: nop + + ret + } +} + diff --git a/src/runtime/clrmodule.pp.il b/src/runtime/clrmodule.pp.il new file mode 100644 index 000000000..59b289379 --- /dev/null +++ b/src/runtime/clrmodule.pp.il @@ -0,0 +1,279 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +//============================================================================ +// This file is a hand-maintained stub - it implements clr.dll, which can be +// loaded by a standard CPython interpreter as an extension module. When it +// is loaded, it bootstraps the managed runtime integration layer and defers +// to it to do initialization and put the clr module into sys.modules, etc. + +// The "USE_PYTHON_RUNTIME_*" defines control what extra evidence is used +// to help the CLR find the appropriate Python.Runtime assembly. + +// If defined, the "pythonRuntimeVersionString" variable must be set to +// Python.Runtime's current version. +#define USE_PYTHON_RUNTIME_VERSION + +// If defined, the "PythonRuntimePublicKeyTokenData" data array must be +// set to Python.Runtime's public key token. +//#define USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + +// If DEBUG_PRINT is defined, a few System.Console.WriteLine calls are made +// to indicate what's going on during the load... +//#define DEBUG_PRINT +//============================================================================ + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 2:0:0:0 +} + +.assembly clr +{ + .hash algorithm 0x00008004 + .ver 2:0:0:2 +} + +.module clr.dll +.imagebase 0x00400000 +.subsystem 0x00000003 +.file alignment 512 + +// This includes the platform-specific IL. The include search path +// is set depending on whether we're compiling 32 or 64 bit. +// This MUST come before any other .data directives! +// Why, oh why, can't ilasm support command line #defines? :( + +// Contributed by VIKAS DHIMAN - Handled by /home/barton/Projects/PyDotNet/pythonnet/makefile +// gcc -C -P -x c++ -I $(ARCH) clrmodule.pp.il -o clrmodule.il +// to copy the correct architecture to the clrModule. +// Nice formating, as well - Thanks, Vikas! +#include "clrmodule-platform.il" + +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN +.data PythonRuntimePublicKeyTokenData = bytearray (64 e1 4e 84 5a bf 2e 60) +#endif + +.class public auto ansi beforefieldinit clrModule extends [mscorlib]System.Object +{ +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + .field static assembly int64 PythonRuntimePublicKeyToken at PythonRuntimePublicKeyTokenData +#endif + + .method public hidebysig specialname rtspecialname instance void + .ctor() cil managed + { + .maxstack 1 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig static void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) + initclr() cil managed + { + .vtentry 1:1 + .export [1] as initclr + + .maxstack 6 + .locals init ( + class [mscorlib]System.Reflection.Assembly pythonRuntime, + class [mscorlib]System.Reflection.Assembly executingAssembly, + class [mscorlib]System.Reflection.AssemblyName pythonRuntimeName, + class [mscorlib]System.Type pythonEngineType, + int8[] publicKeyToken, + string assemblyDirectory, + string pythonRuntimeVersionString, + string pythonRuntimeDllPath) + + // pythonRuntime = null; + ldnull + stloc pythonRuntime + + .try + { +#ifdef DEBUG_PRINT + ldstr "Attempting to load Python.Runtime using standard binding rules... " + call void [mscorlib]System.Console::Write(string) +#endif + + // Attempt to find and load Python.Runtime using standard assembly binding rules. + // This roughly translates into looking in order: + // - GAC + // - ApplicationBase + // - A PrivateBinPath under ApplicationBase + // With an unsigned assembly, the GAC is skipped. + + // System.Reflection.AssemblyName pythonRuntimeName = new System.Reflection.AssemblyName(); + newobj instance void [mscorlib]System.Reflection.AssemblyName::.ctor() + stloc pythonRuntimeName + + // pythonRuntimeName.Name = "Python.Runtime"; + ldloc pythonRuntimeName + ldstr "Python.Runtime" + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Name(string) + +#ifdef USE_PYTHON_RUNTIME_VERSION + // pythonRuntimeVersionString = "..."; + ldstr "2.0.0.2" + stloc pythonRuntimeVersionString + + // pythonRuntimeName.Version = new Version(pythonRuntimeVersionString); + ldloc pythonRuntimeName + ldloc pythonRuntimeVersionString + newobj instance void [mscorlib]System.Version::.ctor(string) + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Version(class [mscorlib]System.Version) +#endif + +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + // publicKeyToken = new byte[] { ... }; + ldc.i4.8 + newarr [mscorlib]System.Byte + dup + ldtoken field int64 clrModule::PythonRuntimePublicKeyToken + call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle) + stloc publicKeyToken + + // pythonRuntimeName.SetPublicKeyToken(publicKeyToken); + ldloc pythonRuntimeName + ldloc publicKeyToken + callvirt instance void [mscorlib]System.Reflection.AssemblyName::SetPublicKeyToken(uint8[]) +#endif + + // pythonRuntimeName.CultureInfo = System.Globalization.CultureInfo.InvariantCulture; + ldloc pythonRuntimeName + call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture() + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_CultureInfo(class [mscorlib]System.Globalization.CultureInfo) + + // return System.Reflection.Assembly.Load(pythonRuntimeName); + ldloc pythonRuntimeName + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::Load(class [mscorlib]System.Reflection.AssemblyName) + stloc pythonRuntime + +#ifdef DEBUG_PRINT + ldstr "Success!" + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s LOADED_PYTHON_RUNTIME + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Failed." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_CLR_LOAD + } + EXIT_CLR_LOAD: nop + + .try + { + // If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll" + // from the directory this assembly is running in. "This assembly" is probably "clr.pyd", + // sitting somewhere in PYTHONPATH. This is using Assembly.LoadFrom, and inherits all the + // caveats of that call. See MSDN docs for details. + // Suzanne Cook's blog is also an excellent source of info on this: + // http://blogs.msdn.com/suzcook/ + // http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx + // http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx + // executingAssembly = System.Reflection.Assembly.GetExecutingAssembly(); + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly() + stloc executingAssembly + + // assemblyDirectory = System.IO.Path.GetDirectoryName(executingAssembly.Location); + ldloc executingAssembly + callvirt instance string [mscorlib]System.Reflection.Assembly::get_Location() + call string [mscorlib]System.IO.Path::GetDirectoryName(string) + stloc assemblyDirectory + + // pythonRuntimeDllPath = System.IO.Path.Combine(assemblyDirectory, "Python.Runtime.dll"); + ldloc assemblyDirectory + ldstr "Python.Runtime.dll" + call string [mscorlib]System.IO.Path::Combine(string, string) + stloc pythonRuntimeDllPath + +#ifdef DEBUG_PRINT + ldstr "Attempting to load Python.Runtime from: '{0}'... " + ldloc pythonRuntimeDllPath + call void [mscorlib]System.Console::Write(string, object) +#endif + + // pythonRuntime = System.Reflection.Assembly.LoadFrom(pythonRuntimeDllPath); + ldloc pythonRuntimeDllPath + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::LoadFrom(string) + stloc pythonRuntime + +#ifdef DEBUG_PRINT + ldstr "Success!" + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s LOADED_PYTHON_RUNTIME + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Failed." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_PYTHONPATH_LOAD + } + EXIT_PYTHONPATH_LOAD: nop + + // If we get here, we haven't loaded Python.Runtime, so bail. +#ifdef DEBUG_PRINT + ldstr "Could not load Python.Runtime, so sad." + call void [mscorlib]System.Console::WriteLine(string) +#endif + ret + + // Once here, we've successfully loaded SOME version of Python.Runtime + // So now we get the PythonEngine and execute the InitExt method on it. + LOADED_PYTHON_RUNTIME: nop + .try + { +#ifdef DEBUG_PRINT + ldstr "Running Python.Runtime.PythonEngine.InitExt()" + call void [mscorlib]System.Console::WriteLine(string) +#endif + // pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine"); + ldloc pythonRuntime + ldstr "Python.Runtime.PythonEngine" + callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string) + stloc pythonEngineType + + // pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null); + ldloc pythonEngineType + ldstr "InitExt" + ldc.i4 0x100 + ldnull + ldnull + ldnull + callvirt instance object [mscorlib]System.Type::InvokeMember( string, + valuetype [mscorlib]System.Reflection.BindingFlags, + class [mscorlib]System.Reflection.Binder, + object, + object[]) + pop + leave.s EXIT_TRY_INVOKE + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Error calling Python.Runtime.PythonEngine.InitExt()." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_TRY_INVOKE + } + EXIT_TRY_INVOKE: nop + + ret + } +} + diff --git a/src/runtime/clrobject.cs b/src/runtime/clrobject.cs new file mode 100644 index 000000000..c61f9523d --- /dev/null +++ b/src/runtime/clrobject.cs @@ -0,0 +1,78 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + + internal class CLRObject : ManagedType { + + internal Object inst; + + internal CLRObject(Object ob, IntPtr tp) : base() { + + IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); + + int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + if ((flags & TypeFlags.Subclass) != 0) { + IntPtr dict = Marshal.ReadIntPtr(py, ObjectOffset.ob_dict); + if (dict == IntPtr.Zero) { + dict = Runtime.PyDict_New(); + Marshal.WriteIntPtr(py, ObjectOffset.ob_dict, dict); + } + } + + GCHandle gc = GCHandle.Alloc(this); + Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc); + this.tpHandle = tp; + this.pyHandle = py; + this.gcHandle = gc; + inst = ob; + } + + + internal static CLRObject GetInstance(Object ob, IntPtr pyType) { + return new CLRObject(ob, pyType); + } + + + internal static CLRObject GetInstance(Object ob) { + ClassBase cc = ClassManager.GetClass(ob.GetType()); + return GetInstance(ob, cc.tpHandle); + } + + + internal static IntPtr GetInstHandle(Object ob, IntPtr pyType) { + CLRObject co = GetInstance(ob, pyType); + return co.pyHandle; + } + + + internal static IntPtr GetInstHandle(Object ob, Type type) { + ClassBase cc = ClassManager.GetClass(type); + CLRObject co = GetInstance(ob, cc.tpHandle); + return co.pyHandle; + } + + + internal static IntPtr GetInstHandle(Object ob) { + CLRObject co = GetInstance(ob); + return co.pyHandle; + } + + + } + + +} + diff --git a/src/runtime/codegenerator.cs b/src/runtime/codegenerator.cs new file mode 100644 index 000000000..4305471e0 --- /dev/null +++ b/src/runtime/codegenerator.cs @@ -0,0 +1,62 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Threading; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Collections; +using System.Reflection; +using System.Reflection.Emit; + +namespace Python.Runtime { + + /// + /// Several places in the runtime generate code on the fly to support + /// dynamic functionality. The CodeGenerator class manages the dynamic + /// assembly used for code generation and provides utility methods for + /// certain repetitive tasks. + /// + + internal class CodeGenerator { + + AssemblyBuilder aBuilder; + ModuleBuilder mBuilder; + + internal CodeGenerator() { + AssemblyName aname = new AssemblyName(); + aname.Name = "__CodeGenerator_Assembly"; + AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run; + + aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); + mBuilder = aBuilder.DefineDynamicModule("__CodeGenerator_Module"); + } + + //==================================================================== + // DefineType is a shortcut utility to get a new TypeBuilder. + //==================================================================== + + internal TypeBuilder DefineType(string name) { + TypeAttributes attrs = TypeAttributes.Public; + return mBuilder.DefineType(name, attrs); + } + + //==================================================================== + // DefineType is a shortcut utility to get a new TypeBuilder. + //==================================================================== + + internal TypeBuilder DefineType(string name, Type basetype) { + TypeAttributes attrs = TypeAttributes.Public; + return mBuilder.DefineType(name, attrs, basetype); + } + + } + + +} diff --git a/src/runtime/constructorbinder.cs b/src/runtime/constructorbinder.cs new file mode 100644 index 000000000..82be07e1f --- /dev/null +++ b/src/runtime/constructorbinder.cs @@ -0,0 +1,121 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // A ConstructorBinder encapsulates information about one or more managed + // constructors, and is responsible for selecting the right constructor + // given a set of Python arguments. This is slightly different than the + // standard MethodBinder because of a difference in invoking constructors + // using reflection (which is seems to be a CLR bug). + //======================================================================== + + internal class ConstructorBinder : MethodBinder { + private Type _containingType = null; + + internal ConstructorBinder(Type containingType) : base() { + _containingType = containingType; + } + + //==================================================================== + // Constructors get invoked when an instance of a wrapped managed + // class or a subclass of a managed class is created. This differs + // from the MethodBinder implementation in that we return the raw + // result of the constructor rather than wrapping it as a Python + // object - the reason is that only the caller knows the correct + // Python type to use when wrapping the result (may be a subclass). + //==================================================================== + + internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw) { + return this.InvokeRaw(inst, args, kw, null); + } + /// + /// Allows ctor selection to be limited to a single attempt at a + /// match by providing the MethodBase to use instead of searching + /// the entire MethodBinder.list (generic ArrayList) + /// + /// (possibly null) instance + /// PyObject* to the arg tuple + /// PyObject* to the keyword args dict + /// The sole ContructorInfo to use or null + /// The result of the constructor call with converted params + /// + /// 2010-07-24 BC: I added the info parameter to the call to Bind() + /// Binding binding = this.Bind(inst, args, kw, info); + /// to take advantage of Bind()'s ability to use a single MethodBase (CI or MI). + /// + internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, + MethodBase info) { + Object result; + + if (_containingType.IsValueType && !_containingType.IsPrimitive && + !_containingType.IsEnum && _containingType != typeof (decimal) && + Runtime.PyTuple_Size(args) == 0) { + // If you are trying to construct an instance of a struct by + // calling its default constructor, that ConstructorInfo + // instance will not appear in reflection and the object must + // instead be constructed via a call to + // Activator.CreateInstance(). + try { + result = Activator.CreateInstance(_containingType); + } + catch (Exception e) { + if (e.InnerException != null) { + e = e.InnerException; + } + Exceptions.SetError(e); + return null; + } + return result; + } + + Binding binding = this.Bind(inst, args, kw, info); + + if (binding == null) { + // It is possible for __new__ to be invoked on construction + // of a Python subclass of a managed class, so args may + // reflect more args than are required to instantiate the + // class. So if we cant find a ctor that matches, we'll see + // if there is a default constructor and, if so, assume that + // any extra args are intended for the subclass' __init__. + + IntPtr eargs = Runtime.PyTuple_New(0); + binding = this.Bind(inst, eargs, kw); + Runtime.Decref(eargs); + + if (binding == null) { + Exceptions.SetError(Exceptions.TypeError, + "no constructor matches given arguments" + ); + return null; + } + } + + // Fire the selected ctor and catch errors... + ConstructorInfo ci = (ConstructorInfo)binding.info; + // Object construction is presumed to be non-blocking and fast + // enough that we shouldn't really need to release the GIL. + try { + result = ci.Invoke(binding.args); + } + catch (Exception e) { + if (e.InnerException != null) { + e = e.InnerException; + } + Exceptions.SetError(e); + return null; + } + return result; + } + } +} diff --git a/src/runtime/constructorbinding.cs b/src/runtime/constructorbinding.cs new file mode 100644 index 000000000..c5f014469 --- /dev/null +++ b/src/runtime/constructorbinding.cs @@ -0,0 +1,237 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; + +namespace Python.Runtime { + + /// + /// Implements a Python type that wraps a CLR ctor call. Constructor objects + /// support a .Overloads[] syntax to allow explicit ctor overload selection. + /// + /// + /// ClassManager stores a ConstructorBinding instance in the class's __dict__['Overloads'] + /// + /// SomeType.Overloads[Type, ...] works like this: + /// 1) Python retreives the Overloads attribute from this ClassObject's dictionary normally + /// and finds a non-null tp_descr_get slot which is called by the interpreter + /// and returns an IncRef()ed pyHandle to itself. + /// 2) The ConstructorBinding object handles the [] syntax in its mp_subscript by matching + /// the Type object parameters to a contructor overload using Type.GetConstructor() + /// [NOTE: I don't know why method overloads are not searched the same way.] + /// and creating the BoundContructor oject which contains ContructorInfo object. + /// 3) In tp_call, if ctorInfo is not null, ctorBinder.InvokeRaw() is called. + /// + internal class ConstructorBinding : ExtensionType + { + Type type; // The managed Type being wrapped in a ClassObject + IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. + ConstructorBinder ctorBinder; + IntPtr repr; + + public ConstructorBinding(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder) : base() { + this.type = type; + Runtime.Incref(pyTypeHndl); + this.pyTypeHndl = pyTypeHndl; + this.ctorBinder = ctorBinder; + repr = IntPtr.Zero; + } + + /// + /// Descriptor __get__ implementation. + /// Implements a Python type that wraps a CLR ctor call that requires the use + /// of a .Overloads[pyTypeOrType...] syntax to allow explicit ctor overload + /// selection. + /// + /// PyObject* to a Constructors wrapper + /// the instance that the attribute was accessed through, + /// or None when the attribute is accessed through the owner + /// always the owner class + /// a CtorMapper (that borrows a reference to this python type and the + /// ClassObject's ConstructorBinder) wrapper. + /// + /// + /// Python 2.6.5 docs: + /// object.__get__(self, instance, owner) + /// Called to get the attribute of the owner class (class attribute access) + /// or of an instance of that class (instance attribute access). + /// owner is always the owner class, while instance is the instance that + /// the attribute was accessed through, or None when the attribute is accessed through the owner. + /// This method should return the (computed) attribute value or raise an AttributeError exception. + /// + public static IntPtr tp_descr_get(IntPtr op, IntPtr instance, IntPtr owner) + { + ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); + if (self == null) { + return IntPtr.Zero; + } + + // It doesn't seem to matter if it's accessed through an instance (rather than via the type). + /*if (instance != IntPtr.Zero) { + // This is ugly! PyObject_IsInstance() returns 1 for true, 0 for false, -1 for error... + if (Runtime.PyObject_IsInstance(instance, owner) < 1) { + return Exceptions.RaiseTypeError("How in the world could that happen!"); + } + }*/ + Runtime.Incref(self.pyHandle); // Decref'd by the interpreter. + return self.pyHandle; + } + + //==================================================================== + // Implement explicit overload selection using subscript syntax ([]). + //==================================================================== + /// + /// ConstructorBinding.GetItem(PyObject *o, PyObject *key) + /// Return element of o corresponding to the object key or NULL on failure. + /// This is the equivalent of the Python expression o[key]. + /// + /// + /// + /// + public static IntPtr mp_subscript(IntPtr op, IntPtr key) { + ConstructorBinding self = (ConstructorBinding)GetManagedObject(op); + + Type[] types = Runtime.PythonArgsToTypeArray(key); + if (types == null) { + return Exceptions.RaiseTypeError("type(s) expected"); + } + //MethodBase[] methBaseArray = self.ctorBinder.GetMethods(); + //MethodBase ci = MatchSignature(methBaseArray, types); + ConstructorInfo ci = self.type.GetConstructor(types); + if (ci == null) { + string msg = "No match found for constructor signature"; + return Exceptions.RaiseTypeError(msg); + } + BoundContructor boundCtor = new BoundContructor(self.type, self.pyTypeHndl, self.ctorBinder, ci); + + /* Since nothing's chached, do we need the increment??? + Runtime.Incref(boundCtor.pyHandle); // Decref'd by the interpreter??? */ + return boundCtor.pyHandle; + } + + //==================================================================== + // ConstructorBinding __repr__ implementation [borrowed from MethodObject]. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); + if (self.repr != IntPtr.Zero) { + Runtime.Incref(self.repr); + return self.repr; + } + MethodBase[] methods = self.ctorBinder.GetMethods(); + string name = self.type.FullName; + string doc = ""; + for (int i = 0; i < methods.Length; i++) { + if (doc.Length > 0) + doc += "\n"; + string str = methods[i].ToString(); + int idx = str.IndexOf("("); + doc += String.Format("{0}{1}", name, str.Substring(idx)); + } + self.repr = Runtime.PyString_FromString(doc); + Runtime.Incref(self.repr); + return self.repr; + } + + //==================================================================== + // ConstructorBinding dealloc implementation. + //==================================================================== + + public static new void tp_dealloc(IntPtr ob) { + ConstructorBinding self = (ConstructorBinding)GetManagedObject(ob); + Runtime.Decref(self.repr); + Runtime.Decref(self.pyTypeHndl); + ExtensionType.FinalizeObject(self); + } + } + + /// + /// Implements a Python type that constucts the given Type given a particular ContructorInfo. + /// + /// + /// Here mostly because I wanted a new __repr__ function for the selected constructor. + /// An earlier implementation hung the __call__ on the ContructorBinding class and + /// returned an Incref()ed self.pyHandle from the __get__ function. + /// + internal class BoundContructor : ExtensionType { + Type type; // The managed Type being wrapped in a ClassObject + IntPtr pyTypeHndl; // The python type tells GetInstHandle which Type to create. + ConstructorBinder ctorBinder; + ConstructorInfo ctorInfo; + IntPtr repr; + + public BoundContructor(Type type, IntPtr pyTypeHndl, ConstructorBinder ctorBinder, ConstructorInfo ci) + : base() { + this.type = type; + Runtime.Incref(pyTypeHndl); + this.pyTypeHndl = pyTypeHndl; + this.ctorBinder = ctorBinder; + ctorInfo = ci; + repr = IntPtr.Zero; + } + + /// + /// BoundContructor.__call__(PyObject *callable_object, PyObject *args, PyObject *kw) + /// + /// PyObject *callable_object + /// PyObject *args + /// PyObject *kw + /// A reference to a new instance of the class by invoking the selected ctor(). + public static IntPtr tp_call(IntPtr op, IntPtr args, IntPtr kw) { + BoundContructor self = (BoundContructor)GetManagedObject(op); + // Even though a call with null ctorInfo just produces the old behavior + /*if (self.ctorInfo == null) { + string msg = "Usage: Class.Overloads[CLR_or_python_Type, ...]"; + return Exceptions.RaiseTypeError(msg); + }*/ + // Bind using ConstructorBinder.Bind and invoke the ctor providing a null instancePtr + // which will fire self.ctorInfo using ConstructorInfo.Invoke(). + Object obj = self.ctorBinder.InvokeRaw(IntPtr.Zero, args, kw, self.ctorInfo); + if (obj == null) { + // XXX set an error + return IntPtr.Zero; + } + // Instantiate the python object that wraps the result of the method call + // and return the PyObject* to it. + return CLRObject.GetInstHandle(obj, self.pyTypeHndl); + } + + //==================================================================== + // BoundContructor __repr__ implementation [borrowed from MethodObject]. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + BoundContructor self = (BoundContructor)GetManagedObject(ob); + if (self.repr != IntPtr.Zero) { + Runtime.Incref(self.repr); + return self.repr; + } + string name = self.type.FullName; + string str = self.ctorInfo.ToString(); + int idx = str.IndexOf("("); + str = String.Format("returns a new {0}{1}", name, str.Substring(idx)); + self.repr = Runtime.PyString_FromString(str); + Runtime.Incref(self.repr); + return self.repr; + } + + //==================================================================== + // ConstructorBinding dealloc implementation. + //==================================================================== + + public static new void tp_dealloc(IntPtr ob) { + BoundContructor self = (BoundContructor)GetManagedObject(ob); + Runtime.Decref(self.repr); + Runtime.Decref(self.pyTypeHndl); + ExtensionType.FinalizeObject(self); + } + } +} diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs new file mode 100644 index 000000000..650a6178a --- /dev/null +++ b/src/runtime/converter.cs @@ -0,0 +1,722 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Globalization; +using System.Security; + +namespace Python.Runtime { + + //======================================================================== + // Performs data conversions between managed types and Python types. + //======================================================================== + + [SuppressUnmanagedCodeSecurityAttribute()] + + internal class Converter { + + private Converter() {} + + static NumberFormatInfo nfi; + static Type objectType; + static Type stringType; + static Type doubleType; + static Type int32Type; + static Type int64Type; + static Type flagsType; + static Type boolType; + //static Type typeType; + + static Converter () { + nfi = NumberFormatInfo.InvariantInfo; + objectType = typeof(Object); + stringType = typeof(String); + int32Type = typeof(Int32); + int64Type = typeof(Int64); + doubleType = typeof(Double); + flagsType = typeof(FlagsAttribute); + boolType = typeof(Boolean); + //typeType = typeof(Type); + } + + + //==================================================================== + // Given a builtin Python type, return the corresponding CLR type. + //==================================================================== + + internal static Type GetTypeByAlias(IntPtr op) { + if ((op == Runtime.PyStringType) || + (op == Runtime.PyUnicodeType)) { + return stringType; + } + else if (op == Runtime.PyIntType) { + return int32Type; + } + else if (op == Runtime.PyLongType) { + return int64Type; + } + else if (op == Runtime.PyFloatType) { + return doubleType; + } + else if (op == Runtime.PyBoolType) { + return boolType; + } + return null; + } + + + //==================================================================== + // Return a Python object for the given native object, converting + // basic types (string, int, etc.) into equivalent Python objects. + // This always returns a new reference. Note that the System.Decimal + // type has no Python equivalent and converts to a managed instance. + //==================================================================== + + internal static IntPtr ToPython(Object value, Type type) { + IntPtr result = IntPtr.Zero; + + // Null always converts to None in Python. + + if (value == null) { + result = Runtime.PyNone; + Runtime.Incref(result); + return result; + } + + // hmm - from Python, we almost never care what the declared + // type is. we'd rather have the object bound to the actual + // implementing class. + + type = value.GetType(); + + TypeCode tc = Type.GetTypeCode(type); + + switch(tc) { + + case TypeCode.Object: + result = CLRObject.GetInstHandle(value, type); + + // XXX - hack to make sure we convert new-style class based + // managed exception instances to wrappers ;( + if (Runtime.wrap_exceptions) { + Exception e = value as Exception; + if (e != null) { + return Exceptions.GetExceptionInstanceWrapper(result); + } + } + + return result; + + case TypeCode.String: + return Runtime.PyUnicode_FromString((string)value); + + case TypeCode.Int32: + return Runtime.PyInt_FromInt32((int)value); + + case TypeCode.Boolean: + if ((bool)value) { + Runtime.Incref(Runtime.PyTrue); + return Runtime.PyTrue; + } + Runtime.Incref(Runtime.PyFalse); + return Runtime.PyFalse; + + case TypeCode.Byte: + return Runtime.PyInt_FromInt32((int)((byte)value)); + + case TypeCode.Char: + return Runtime.PyUnicode_FromOrdinal((int)((char)value)); + + case TypeCode.Int16: + return Runtime.PyInt_FromInt32((int)((short)value)); + + case TypeCode.Int64: + return Runtime.PyLong_FromLongLong((long)value); + + case TypeCode.Single: + // return Runtime.PyFloat_FromDouble((double)((float)value)); + string ss = ((float)value).ToString(nfi); + IntPtr ps = Runtime.PyString_FromString(ss); + IntPtr op = Runtime.PyFloat_FromString(ps, IntPtr.Zero); + Runtime.Decref(ps); + return op; + + case TypeCode.Double: + return Runtime.PyFloat_FromDouble((double)value); + + case TypeCode.SByte: + return Runtime.PyInt_FromInt32((int)((sbyte)value)); + + case TypeCode.UInt16: + return Runtime.PyInt_FromInt32((int)((ushort)value)); + + case TypeCode.UInt32: + return Runtime.PyLong_FromUnsignedLong((uint)value); + + case TypeCode.UInt64: + return Runtime.PyLong_FromUnsignedLongLong((ulong)value); + + default: + result = CLRObject.GetInstHandle(value, type); + return result; + } + + } + + + //==================================================================== + // In a few situations, we don't have any advisory type information + // when we want to convert an object to Python. + //==================================================================== + + internal static IntPtr ToPythonImplicit(Object value) { + if (value == null) { + IntPtr result = Runtime.PyNone; + Runtime.Incref(result); + return result; + } + + return ToPython(value, objectType); + } + + + //==================================================================== + // Return a managed object for the given Python object, taking funny + // byref types into account. + //==================================================================== + + internal static bool ToManaged(IntPtr value, Type type, + out object result, bool setError) { + if (type.IsByRef) { + type = type.GetElementType(); + } + return Converter.ToManagedValue(value, type, out result, setError); + } + + + internal static bool ToManagedValue(IntPtr value, Type obType, + out Object result, bool setError) { + // Common case: if the Python value is a wrapped managed object + // instance, just return the wrapped object. + ManagedType mt = ManagedType.GetManagedObject(value); + result = null; + + // XXX - hack to support objects wrapped in old-style classes + // (such as exception objects). + if (Runtime.wrap_exceptions) { + if (mt == null) { + if (Runtime.PyObject_IsInstance( + value, Exceptions.Exception + ) > 0) { + IntPtr p = Runtime.PyObject_GetAttrString(value, "_inner"); + if (p != IntPtr.Zero) { + // This is safe because we know that the __dict__ of + // value holds a reference to _inner. + value = p; + Runtime.Decref(p); + mt = ManagedType.GetManagedObject(value); + } + } + IntPtr c = Exceptions.UnwrapExceptionClass(value); + if ((c != IntPtr.Zero) && (c != value)) { + value = c; + Runtime.Decref(c); + mt = ManagedType.GetManagedObject(value); + } + } + } + + if (mt != null) { + if (mt is CLRObject) { + object tmp = ((CLRObject)mt).inst; + if (obType.IsInstanceOfType(tmp)) { + result = tmp; + return true; + } + string err = "value cannot be converted to {0}"; + err = String.Format(err, obType); + Exceptions.SetError(Exceptions.TypeError, err); + return false; + } + if (mt is ClassBase) { + result = ((ClassBase)mt).type; + return true; + } + // shouldnt happen + return false; + } + + if (value == Runtime.PyNone && !obType.IsValueType) { + result = null; + return true; + } + + if (obType.IsArray) { + return ToArray(value, obType, out result, setError); + } + + if (obType.IsEnum) { + return ToEnum(value, obType, out result, setError); + } + + // Conversion to 'Object' is done based on some reasonable + // default conversions (Python string -> managed string, + // Python int -> Int32 etc.). + + if (obType == objectType) { + if (Runtime.IsStringType(value)) { + return ToPrimitive(value, stringType, out result, + setError); + } + + else if (Runtime.PyBool_Check(value)) { + return ToPrimitive(value, boolType, out result, setError); + } + + else if (Runtime.PyInt_Check(value)) { + return ToPrimitive(value, int32Type, out result, setError); + } + + else if (Runtime.PyLong_Check(value)) { + return ToPrimitive(value, int64Type, out result, setError); + } + + else if (Runtime.PyFloat_Check(value)) { + return ToPrimitive(value, doubleType, out result, setError); + } + + else if (Runtime.PySequence_Check(value)) { + return ToArray(value, typeof(object[]), out result, + setError); + } + + if (setError) { + Exceptions.SetError(Exceptions.TypeError, + "value cannot be converted to Object" + ); + } + + return false; + } + + return ToPrimitive(value, obType, out result, setError); + + } + + //==================================================================== + // Convert a Python value to an instance of a primitive managed type. + //==================================================================== + + static bool ToPrimitive(IntPtr value, Type obType, out Object result, + bool setError) { + + IntPtr overflow = Exceptions.OverflowError; + TypeCode tc = Type.GetTypeCode(obType); + result = null; + IntPtr op; + int ival; + + switch(tc) { + + case TypeCode.String: + string st = Runtime.GetManagedString(value); + if (st == null) { + goto type_error; + } + result = st; + return true; + + case TypeCode.Int32: + // Trickery to support 64-bit platforms. + if (IntPtr.Size == 4) { + op = Runtime.PyNumber_Int(value); + + // As of Python 2.3, large ints magically convert :( + if (Runtime.PyLong_Check(op) ) { + Runtime.Decref(op); + goto overflow; + } + + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + ival = (int)Runtime.PyInt_AsLong(op); + Runtime.Decref(op); + result = ival; + return true; + } + else { + op = Runtime.PyNumber_Long(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + long ll = (long)Runtime.PyLong_AsLongLong(op); + Runtime.Decref(op); + if ((ll == -1) && Exceptions.ErrorOccurred()) { + goto overflow; + } + if (ll > Int32.MaxValue || ll < Int32.MinValue) { + goto overflow; + } + result = (int)ll; + return true; + } + + case TypeCode.Boolean: + result = (Runtime.PyObject_IsTrue(value) != 0); + return true; + + case TypeCode.Byte: + if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { + if (Runtime.PyString_Size(value) == 1) { + op = Runtime.PyString_AS_STRING(value); + result = (byte)Marshal.ReadByte(op); + return true; + } + goto type_error; + } + + op = Runtime.PyNumber_Int(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + ival = (int) Runtime.PyInt_AsLong(op); + Runtime.Decref(op); + + if (ival > Byte.MaxValue || ival < Byte.MinValue) { + goto overflow; + } + byte b = (byte) ival; + result = b; + return true; + + case TypeCode.SByte: + if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { + if (Runtime.PyString_Size(value) == 1) { + op = Runtime.PyString_AS_STRING(value); + result = (sbyte)Marshal.ReadByte(op); + return true; + } + goto type_error; + } + + op = Runtime.PyNumber_Int(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + ival = (int) Runtime.PyInt_AsLong(op); + Runtime.Decref(op); + + if (ival > SByte.MaxValue || ival < SByte.MinValue) { + goto overflow; + } + sbyte sb = (sbyte) ival; + result = sb; + return true; + + case TypeCode.Char: + + if (Runtime.PyObject_TypeCheck(value, Runtime.PyStringType)) { + if (Runtime.PyString_Size(value) == 1) { + op = Runtime.PyString_AS_STRING(value); + result = (char)Marshal.ReadByte(op); + return true; + } + goto type_error; + } + + else if (Runtime.PyObject_TypeCheck(value, + Runtime.PyUnicodeType)) { + if (Runtime.PyUnicode_GetSize(value) == 1) { + op = Runtime.PyUnicode_AS_UNICODE(value); +#if (!UCS4) + // 2011-01-02: Marshal as character array because the cast + // result = (char)Marshal.ReadInt16(op); throws an OverflowException + // on negative numbers with Check Overflow option set on the project + Char[] buff = new Char[1]; + Marshal.Copy(op, buff, 0, 1); + result = buff[0]; +#else + // XXX this is probably NOT correct? + result = (char)Marshal.ReadInt32(op); +#endif + return true; + } + goto type_error; + } + + op = Runtime.PyNumber_Int(value); + if (op == IntPtr.Zero) { + goto type_error; + } + ival = Runtime.PyInt_AsLong(op); + if (ival > Char.MaxValue || ival < Char.MinValue) { + goto overflow; + } + Runtime.Decref(op); + result = (char)ival; + return true; + + case TypeCode.Int16: + op = Runtime.PyNumber_Int(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + ival = (int) Runtime.PyInt_AsLong(op); + Runtime.Decref(op); + if (ival > Int16.MaxValue || ival < Int16.MinValue) { + goto overflow; + } + short s = (short) ival; + result = s; + return true; + + case TypeCode.Int64: + op = Runtime.PyNumber_Long(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + long l = (long)Runtime.PyLong_AsLongLong(op); + Runtime.Decref(op); + if ((l == -1) && Exceptions.ErrorOccurred()) { + goto overflow; + } + result = l; + return true; + + case TypeCode.UInt16: + op = Runtime.PyNumber_Int(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + ival = (int) Runtime.PyInt_AsLong(op); + Runtime.Decref(op); + if (ival > UInt16.MaxValue || ival < UInt16.MinValue) { + goto overflow; + } + ushort us = (ushort) ival; + result = us; + return true; + + case TypeCode.UInt32: + op = Runtime.PyNumber_Long(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + uint ui = (uint)Runtime.PyLong_AsUnsignedLong(op); + Runtime.Decref(op); + if (Exceptions.ErrorOccurred()) { + goto overflow; + } + + IntPtr check = Runtime.PyLong_FromUnsignedLong(ui); + int err = Runtime.PyObject_Compare(check, op); + Runtime.Decref(check); + if (0 != err || Exceptions.ErrorOccurred()) { + goto overflow; + } + + result = ui; + return true; + + case TypeCode.UInt64: + op = Runtime.PyNumber_Long(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + ulong ul = (ulong)Runtime.PyLong_AsUnsignedLongLong(op); + Runtime.Decref(op); + if (Exceptions.ErrorOccurred()) { + goto overflow; + } + result = ul; + return true; + + + case TypeCode.Single: + op = Runtime.PyNumber_Float(value); + if (op == IntPtr.Zero) { + if (Exceptions.ExceptionMatches(overflow)) { + goto overflow; + } + goto type_error; + } + double dd = Runtime.PyFloat_AsDouble(value); + if (dd > Single.MaxValue || dd < Single.MinValue) { + goto overflow; + } + result = (float)dd; + return true; + + case TypeCode.Double: + op = Runtime.PyNumber_Float(value); + if (op == IntPtr.Zero) { + goto type_error; + } + double d = Runtime.PyFloat_AsDouble(op); + Runtime.Decref(op); + if (d > Double.MaxValue || d < Double.MinValue) { + goto overflow; + } + result = d; + return true; + + } + + + type_error: + + if (setError) { + string format = "'{0}' value cannot be converted to {1}"; + string tpName = Runtime.PyObject_GetTypeName(value); + string error = String.Format(format, tpName, obType); + Exceptions.SetError(Exceptions.TypeError, error); + } + + return false; + + overflow: + + if (setError) { + string error = "value too large to convert"; + Exceptions.SetError(Exceptions.OverflowError, error); + } + + return false; + + } + + + static void SetConversionError(IntPtr value, Type target) { + IntPtr ob = Runtime.PyObject_Repr(value); + string src = Runtime.GetManagedString(ob); + Runtime.Decref(ob); + string error = String.Format( + "Cannot convert {0} to {1}", src, target + ); + Exceptions.SetError(Exceptions.TypeError, error); + } + + + //==================================================================== + // Convert a Python value to a correctly typed managed array instance. + // The Python value must support the Python sequence protocol and the + // items in the sequence must be convertible to the target array type. + //==================================================================== + + static bool ToArray(IntPtr value, Type obType, out Object result, + bool setError) { + + Type elementType = obType.GetElementType(); + int size = Runtime.PySequence_Size(value); + result = null; + + if (size < 0) { + if (setError) { + SetConversionError(value, obType); + } + return false; + } + + Array items = Array.CreateInstance(elementType, size); + + // XXX - is there a better way to unwrap this if it is a real + // array? + for (int i = 0; i < size; i++) { + Object obj = null; + IntPtr item = Runtime.PySequence_GetItem(value, i); + if (item == IntPtr.Zero) { + if (setError) { + SetConversionError(value, obType); + return false; + } + } + + if (!Converter.ToManaged(item, elementType, out obj, true)) { + Runtime.Decref(item); + return false; + } + + items.SetValue(obj, i); + Runtime.Decref(item); + } + + result = items; + return true; + } + + + //==================================================================== + // Convert a Python value to a correctly typed managed enum instance. + //==================================================================== + + static bool ToEnum(IntPtr value, Type obType, out Object result, + bool setError) { + + Type etype = Enum.GetUnderlyingType(obType); + result = null; + + if (!ToPrimitive(value, etype, out result, setError)) { + return false; + } + + if (Enum.IsDefined(obType, result)) { + result = Enum.ToObject(obType, result); + return true; + } + + if (obType.GetCustomAttributes(flagsType, true).Length > 0) { + result = Enum.ToObject(obType, result); + return true; + } + + if (setError) { + string error = "invalid enumeration value"; + Exceptions.SetError(Exceptions.ValueError, error); + } + + return false; + + } + + + + } + + +} diff --git a/src/runtime/debughelper.cs b/src/runtime/debughelper.cs new file mode 100644 index 000000000..2c7c6a054 --- /dev/null +++ b/src/runtime/debughelper.cs @@ -0,0 +1,128 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Threading; + +namespace Python.Runtime { + + /// + /// Debugging helper utilities. + /// The methods are only executed when the DEBUG flag is set. Otherwise + /// they are automagically hidden by the compiler and silently surpressed. + /// + + internal class DebugUtil { + + [Conditional("DEBUG")] + public static void Print(string msg, params IntPtr[] args) { + string result = msg; + result += " "; + + for (int i = 0; i < args.Length; i++) { + if (args[i] == IntPtr.Zero) { + Console.WriteLine("null arg to print"); + } + IntPtr ob = Runtime.PyObject_Repr(args[i]); + result += Runtime.GetManagedString(ob); + Runtime.Decref(ob); + result += " "; + } + Console.WriteLine(result); + return; + } + + [Conditional("DEBUG")] + public static void Print(string msg) { + Console.WriteLine(msg); + } + + [Conditional("DEBUG")] + internal static void DumpType(IntPtr type) { + IntPtr op = Marshal.ReadIntPtr(type, TypeOffset.tp_name); + string name = Marshal.PtrToStringAnsi(op); + + Console.WriteLine("Dump type: {0}", name); + + op = Marshal.ReadIntPtr(type, TypeOffset.ob_type); + DebugUtil.Print(" type: ", op); + + op = Marshal.ReadIntPtr(type, TypeOffset.tp_base); + DebugUtil.Print(" base: ", op); + + op = Marshal.ReadIntPtr(type, TypeOffset.tp_bases); + DebugUtil.Print(" bases: ", op); + + //op = Marshal.ReadIntPtr(type, TypeOffset.tp_mro); + //DebugUtil.Print(" mro: ", op); + + + FieldInfo[] slots = typeof(TypeOffset).GetFields(); + int size = IntPtr.Size; + + for (int i = 0; i < slots.Length; i++) { + int offset = i * size; + name = slots[i].Name; + op = Marshal.ReadIntPtr(type, offset); + Console.WriteLine(" {0}: {1}", name, op); + } + + Console.WriteLine(""); + Console.WriteLine(""); + + op = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); + if (op == IntPtr.Zero) { + Console.WriteLine(" dict: null"); + } + else { + DebugUtil.Print(" dict: ", op); + } + + } + + [Conditional("DEBUG")] + internal static void DumpInst(IntPtr ob) { + IntPtr tp = Runtime.PyObject_TYPE(ob); + int sz = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_basicsize); + + for (int i = 0; i < sz; i += IntPtr.Size) { + IntPtr pp = new IntPtr(ob.ToInt64() + i); + IntPtr v = Marshal.ReadIntPtr(pp); + Console.WriteLine("offset {0}: {1}", i, v); + } + + Console.WriteLine(""); + Console.WriteLine(""); + } + + [Conditional("DEBUG")] + internal static void debug(string msg) { + StackTrace st = new StackTrace(1, true); + StackFrame sf = st.GetFrame(0); + MethodBase mb = sf.GetMethod(); + Type mt = mb.DeclaringType; + string caller = mt.Name + "." + sf.GetMethod().Name; + Thread t = Thread.CurrentThread; + string tid = t.GetHashCode().ToString(); + Console.WriteLine("thread {0} : {1}", tid, caller); + Console.WriteLine(" {0}", msg); + return; + } + + + } + + +} + + diff --git a/src/runtime/delegatemanager.cs b/src/runtime/delegatemanager.cs new file mode 100644 index 000000000..ddbabf872 --- /dev/null +++ b/src/runtime/delegatemanager.cs @@ -0,0 +1,289 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Threading; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Collections; +using System.Reflection; +using System.Reflection.Emit; + +namespace Python.Runtime { + + /// + /// The DelegateManager class manages the creation of true managed + /// delegate instances that dispatch calls to Python methods. + /// + + internal class DelegateManager { + + Hashtable cache; + Type basetype; + Type listtype; + Type voidtype; + Type typetype; + Type ptrtype; + CodeGenerator codeGenerator; + + public DelegateManager() { + basetype = typeof(Dispatcher); + listtype = typeof(ArrayList); + voidtype = typeof(void); + typetype = typeof(Type); + ptrtype = typeof(IntPtr); + cache = new Hashtable(); + codeGenerator = new CodeGenerator(); + } + + //==================================================================== + // Given a true delegate instance, return the PyObject handle of the + // Python object implementing the delegate (or IntPtr.Zero if the + // delegate is not implemented in Python code. + //==================================================================== + + public IntPtr GetPythonHandle(Delegate d) { + if ((d != null) && (d.Target is Dispatcher)) { + Dispatcher disp = d.Target as Dispatcher; + return disp.target; + } + return IntPtr.Zero; + } + + //==================================================================== + // GetDispatcher is responsible for creating a class that provides + // an appropriate managed callback method for a given delegate type. + //==================================================================== + + private Type GetDispatcher(Type dtype) { + + // If a dispatcher type for the given delegate type has already + // been generated, get it from the cache. The cache maps delegate + // types to generated dispatcher types. A possible optimization + // for the future would be to generate dispatcher types based on + // unique signatures rather than delegate types, since multiple + // delegate types with the same sig could use the same dispatcher. + + Object item = cache[dtype]; + if (item != null) { + return (Type)item; + } + + string name = "__" + dtype.FullName + "Dispatcher"; + name = name.Replace('.', '_'); + name = name.Replace('+', '_'); + TypeBuilder tb = codeGenerator.DefineType(name, basetype); + + // Generate a constructor for the generated type that calls the + // appropriate constructor of the Dispatcher base type. + + MethodAttributes ma = MethodAttributes.Public | + MethodAttributes.HideBySig | + MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + CallingConventions cc = CallingConventions.Standard; + Type[] args = {ptrtype, typetype}; + ConstructorBuilder cb = tb.DefineConstructor(ma, cc, args); + ConstructorInfo ci = basetype.GetConstructor(args); + ILGenerator il = cb.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Call, ci); + il.Emit(OpCodes.Ret); + + // Method generation: we generate a method named "Invoke" on the + // dispatcher type, whose signature matches the delegate type for + // which it is generated. The method body simply packages the + // arguments and hands them to the Dispatch() method, which deals + // with converting the arguments, calling the Python method and + // converting the result of the call. + + MethodInfo method = dtype.GetMethod("Invoke"); + ParameterInfo[] pi = method.GetParameters(); + + Type[] signature = new Type[pi.Length]; + for (int i = 0; i < pi.Length; i++) { + signature[i] = pi[i].ParameterType; + } + + MethodBuilder mb = tb.DefineMethod( + "Invoke", + MethodAttributes.Public, + method.ReturnType, + signature + ); + + ConstructorInfo ctor = listtype.GetConstructor(Type.EmptyTypes); + MethodInfo dispatch = basetype.GetMethod("Dispatch"); + MethodInfo add = listtype.GetMethod("Add"); + + il = mb.GetILGenerator(); + il.DeclareLocal(listtype); + il.Emit(OpCodes.Newobj, ctor); + il.Emit(OpCodes.Stloc_0); + + for (int c = 0; c < signature.Length; c++) { + Type t = signature[c]; + il.Emit(OpCodes.Ldloc_0); + il.Emit(OpCodes.Ldarg_S, (byte)(c + 1)); + + if (t.IsValueType) { + il.Emit(OpCodes.Box, t); + } + + il.Emit(OpCodes.Callvirt, add); + il.Emit(OpCodes.Pop); + } + + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldloc_0); + il.Emit(OpCodes.Call, dispatch); + + if (method.ReturnType == voidtype) { + il.Emit(OpCodes.Pop); + } + else if (method.ReturnType.IsValueType) { + il.Emit(OpCodes.Unbox_Any, method.ReturnType); + } + + il.Emit(OpCodes.Ret); + + Type disp = tb.CreateType(); + cache[dtype] = disp; + return disp; + } + + //==================================================================== + // Given a delegate type and a callable Python object, GetDelegate + // returns an instance of the delegate type. The delegate instance + // returned will dispatch calls to the given Python object. + //==================================================================== + + internal Delegate GetDelegate(Type dtype, IntPtr callable) { + Type dispatcher = GetDispatcher(dtype); + object[] args = {callable, dtype}; + object o = Activator.CreateInstance(dispatcher, args); + return Delegate.CreateDelegate(dtype, o, "Invoke"); + } + + + + } + + + /* When a delegate instance is created that has a Python implementation, + the delegate manager generates a custom subclass of Dispatcher and + instantiates it, passing the IntPtr of the Python callable. + + The "real" delegate is created using CreateDelegate, passing the + instance of the generated type and the name of the (generated) + implementing method (Invoke). + + The true delegate instance holds the only reference to the dispatcher + instance, which ensures that when the delegate dies, the finalizer + of the referenced instance will be able to decref the Python + callable. + + A possible alternate strategy would be to create custom subclasses + of the required delegate type, storing the IntPtr in it directly. + This would be slightly cleaner, but I'm not sure if delegates are + too "special" for this to work. It would be more work, so for now + the 80/20 rule applies :) + + */ + + public class Dispatcher { + + public IntPtr target; + public Type dtype; + + public Dispatcher(IntPtr target, Type dtype) { + Runtime.Incref(target); + this.target = target; + this.dtype = dtype; + } + + ~Dispatcher() { + // Note: the managed GC thread can run and try to free one of + // these *after* the Python runtime has been finalized! + if (Runtime.Py_IsInitialized() > 0) { + IntPtr gs = PythonEngine.AcquireLock(); + Runtime.Decref(target); + PythonEngine.ReleaseLock(gs); + } + } + + public object Dispatch(ArrayList args) { + IntPtr gs = PythonEngine.AcquireLock(); + object ob = null; + + try { + ob = TrueDispatch(args); + } + catch (Exception e) { + PythonEngine.ReleaseLock(gs); + throw e; + } + + PythonEngine.ReleaseLock(gs); + return ob; + } + + public object TrueDispatch(ArrayList args) { + MethodInfo method = dtype.GetMethod("Invoke"); + ParameterInfo[] pi = method.GetParameters(); + IntPtr pyargs = Runtime.PyTuple_New(pi.Length); + Type rtype = method.ReturnType; + + for (int i = 0; i < pi.Length; i++) { + // Here we own the reference to the Python value, and we + // give the ownership to the arg tuple. + IntPtr arg = Converter.ToPython(args[i], pi[i].ParameterType); + Runtime.PyTuple_SetItem(pyargs, i, arg); + } + + IntPtr op = Runtime.PyObject_Call(target, pyargs, IntPtr.Zero); + Runtime.Decref(pyargs); + + if (op == IntPtr.Zero) { + PythonException e = new PythonException(); + throw e; + } + + if (rtype == typeof(void)) { + return null; + } + + Object result = null; + if (!Converter.ToManaged(op, rtype, out result, false)) { + string s = "could not convert Python result to " + + rtype.ToString(); + Runtime.Decref(op); + throw new ConversionException(s); + } + + Runtime.Decref(op); + return result; + } + + + } + + + public class ConversionException : System.Exception { + + public ConversionException() : base() {} + + public ConversionException(string msg) : base(msg) {} + + } + + +} diff --git a/src/runtime/delegateobject.cs b/src/runtime/delegateobject.cs new file mode 100644 index 000000000..839fb71e5 --- /dev/null +++ b/src/runtime/delegateobject.cs @@ -0,0 +1,120 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// Managed class that provides the implementation for reflected delegate + /// types. Delegates are represented in Python by generated type objects. + /// Each of those type objects is associated an instance of this class, + /// which provides its implementation. + /// + + internal class DelegateObject : ClassBase { + + MethodBinder binder; + + internal DelegateObject(Type tp) : base(tp) { + binder = new MethodBinder(tp.GetMethod("Invoke")); + } + + + //==================================================================== + // Given a PyObject pointer to an instance of a delegate type, return + // the true managed delegate the Python object represents (or null). + //==================================================================== + + private static Delegate GetTrueDelegate(IntPtr op) { + CLRObject o = GetManagedObject(op) as CLRObject; + if (o != null) { + Delegate d = o.inst as Delegate; + return d; + } + return null; + } + + + internal override bool CanSubclass() { + return false; + } + + + //==================================================================== + // DelegateObject __new__ implementation. The result of this is a new + // PyObject whose type is DelegateObject and whose ob_data is a handle + // to an actual delegate instance. The method wrapped by the actual + // delegate instance belongs to an object generated to relay the call + // to the Python callable passed in. + //==================================================================== + + public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { + DelegateObject self = (DelegateObject)GetManagedObject(tp); + + if (Runtime.PyTuple_Size(args) != 1) { + string message = "class takes exactly one argument"; + return Exceptions.RaiseTypeError(message); + } + + IntPtr method = Runtime.PyTuple_GetItem(args, 0); + + if (Runtime.PyCallable_Check(method) != 1) { + return Exceptions.RaiseTypeError("argument must be callable"); + } + + Delegate d = PythonEngine.DelegateManager.GetDelegate(self.type, method); + return CLRObject.GetInstHandle(d, self.pyHandle); + } + + + + //==================================================================== + // Implements __call__ for reflected delegate types. + //==================================================================== + + public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { + // todo: add fast type check! + IntPtr pytype = Runtime.PyObject_TYPE(ob); + DelegateObject self = (DelegateObject)GetManagedObject(pytype); + CLRObject o = GetManagedObject(ob) as CLRObject; + + if (o == null) { + return Exceptions.RaiseTypeError("invalid argument"); + } + + Delegate d = o.inst as Delegate; + + if (d == null) { + return Exceptions.RaiseTypeError("invalid argument"); + } + return self.binder.Invoke(ob, args, kw); + } + + + //==================================================================== + // Implements __cmp__ for reflected delegate types. + //==================================================================== + + public static new int tp_compare(IntPtr ob, IntPtr other) { + Delegate d1 = GetTrueDelegate(ob); + Delegate d2 = GetTrueDelegate(other); + if (d1 == d2) { + return 0; + } + return -1; + } + + + } + + +} diff --git a/src/runtime/eventbinding.cs b/src/runtime/eventbinding.cs new file mode 100644 index 000000000..6135c1d68 --- /dev/null +++ b/src/runtime/eventbinding.cs @@ -0,0 +1,132 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python event binding type, similar to a method binding. + //======================================================================== + + internal class EventBinding : ExtensionType { + + EventObject e; + IntPtr target; + + public EventBinding(EventObject e, IntPtr target) : base() { + Runtime.Incref(target); + this.target = target; + this.e = e; + } + + + //==================================================================== + // EventBinding += operator implementation. + //==================================================================== + + public static IntPtr nb_inplace_add(IntPtr ob, IntPtr arg) { + EventBinding self = (EventBinding)GetManagedObject(ob); + + if (Runtime.PyCallable_Check(arg) < 1) { + Exceptions.SetError(Exceptions.TypeError, + "event handlers must be callable" + ); + return IntPtr.Zero; + } + + if(!self.e.AddEventHandler(self.target, arg)) { + return IntPtr.Zero; + } + + Runtime.Incref(self.pyHandle); + return self.pyHandle; + } + + + //==================================================================== + // EventBinding -= operator implementation. + //==================================================================== + + public static IntPtr nb_inplace_subtract(IntPtr ob, IntPtr arg) { + EventBinding self = (EventBinding)GetManagedObject(ob); + + if (Runtime.PyCallable_Check(arg) < 1) { + Exceptions.SetError(Exceptions.TypeError, + "invalid event handler" + ); + return IntPtr.Zero; + } + + if (!self.e.RemoveEventHandler(self.target, arg)) { + return IntPtr.Zero; + } + + Runtime.Incref(self.pyHandle); + return self.pyHandle; + } + + + //==================================================================== + // EventBinding __hash__ implementation. + //==================================================================== + + public static IntPtr tp_hash(IntPtr ob) { + EventBinding self = (EventBinding)GetManagedObject(ob); + long x = 0; + long y = 0; + + if (self.target != IntPtr.Zero) { + x = Runtime.PyObject_Hash(self.target).ToInt64(); + if (x == -1) { + return new IntPtr(-1); + } + } + + y = Runtime.PyObject_Hash(self.e.pyHandle).ToInt64(); + if (y == -1) { + return new IntPtr(-1); + } + + x ^= y; + + if (x == -1) { + x = -1; + } + + return new IntPtr(x); + } + + + //==================================================================== + // EventBinding __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + EventBinding self = (EventBinding)GetManagedObject(ob); + string type = (self.target == IntPtr.Zero) ? "unbound" : "bound"; + string s = String.Format("<{0} event '{1}'>", type, self.e.name); + return Runtime.PyString_FromString(s); + } + + + //==================================================================== + // EventBinding dealloc implementation. + //==================================================================== + + public static new void tp_dealloc(IntPtr ob) { + EventBinding self = (EventBinding)GetManagedObject(ob); + Runtime.Decref(self.target); + ExtensionType.FinalizeObject(self); + } + + } + + +} diff --git a/src/runtime/eventobject.cs b/src/runtime/eventobject.cs new file mode 100644 index 000000000..0e9122f49 --- /dev/null +++ b/src/runtime/eventobject.cs @@ -0,0 +1,230 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python descriptor type that provides access to CLR events. + //======================================================================== + + internal class EventObject : ExtensionType { + + internal string name; + internal EventBinding unbound; + internal EventInfo info; + internal Hashtable reg; + + public EventObject(EventInfo info) : base() { + this.name = info.Name; + this.info = info; + } + + + //==================================================================== + // Register a new Python object event handler with the event. + //==================================================================== + + internal bool AddEventHandler(IntPtr target, IntPtr handler) { + Object obj = null; + if (target != IntPtr.Zero) { + CLRObject co = (CLRObject)ManagedType.GetManagedObject(target); + obj = co.inst; + } + + // Create a true delegate instance of the appropriate type to + // wrap the Python handler. Note that wrapper delegate creation + // always succeeds, though calling the wrapper may fail. + + Type type = this.info.EventHandlerType; + Delegate d = PythonEngine.DelegateManager.GetDelegate(type, handler); + + // Now register the handler in a mapping from instance to pairs + // of (handler hash, delegate) so we can lookup to remove later. + // All this is done lazily to avoid overhead until an event is + // actually subscribed to by a Python event handler. + + if (reg == null) { + reg = new Hashtable(); + } + object key = (obj != null) ? obj : this.info.ReflectedType; + ArrayList list = reg[key] as ArrayList; + if (list == null) { + list = new ArrayList(); + reg[key] = list; + } + list.Add(new Handler(Runtime.PyObject_Hash(handler), d)); + + // Note that AddEventHandler helper only works for public events, + // so we have to get the underlying add method explicitly. + + object[] args = { d }; + MethodInfo mi = this.info.GetAddMethod(true); + mi.Invoke(obj, BindingFlags.Default, null, args, null); + + return true; + } + + + //==================================================================== + // Remove the given Python object event handler. + //==================================================================== + + internal bool RemoveEventHandler(IntPtr target, IntPtr handler) { + Object obj = null; + if (target != IntPtr.Zero) { + CLRObject co = (CLRObject)ManagedType.GetManagedObject(target); + obj = co.inst; + } + + IntPtr hash = Runtime.PyObject_Hash(handler); + if (Exceptions.ErrorOccurred() || (reg == null)) { + Exceptions.SetError(Exceptions.ValueError, + "unknown event handler" + ); + return false; + } + + object key = (obj != null) ? obj : this.info.ReflectedType; + ArrayList list = reg[key] as ArrayList; + + if (list == null) { + Exceptions.SetError(Exceptions.ValueError, + "unknown event handler" + ); + return false; + } + + object[] args = { null }; + MethodInfo mi = this.info.GetRemoveMethod(true); + + for (int i = 0; i < list.Count; i++) { + Handler item = (Handler)list[i]; + if (item.hash != hash) { + continue; + } + args[0] = item.del; + try { + mi.Invoke(obj, BindingFlags.Default, null, args, null); + } + catch { + continue; + } + list.RemoveAt(i); + return true; + } + + Exceptions.SetError(Exceptions.ValueError, + "unknown event handler" + ); + return false; + } + + + //==================================================================== + // Descriptor __get__ implementation. A getattr on an event returns + // a "bound" event that keeps a reference to the object instance. + //==================================================================== + + public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { + EventObject self = GetManagedObject(ds) as EventObject; + EventBinding binding; + + if (self == null) { + return Exceptions.RaiseTypeError("invalid argument"); + } + + // If the event is accessed through its type (rather than via + // an instance) we return an 'unbound' EventBinding that will + // be cached for future accesses through the type. + + if (ob == IntPtr.Zero) { + if (self.unbound == null) { + self.unbound = new EventBinding(self, IntPtr.Zero); + } + binding = self.unbound; + Runtime.Incref(binding.pyHandle); + return binding.pyHandle; + } + + if (Runtime.PyObject_IsInstance(ob, tp) < 1) { + return Exceptions.RaiseTypeError("invalid argument"); + } + + binding = new EventBinding(self, ob); + return binding.pyHandle; + } + + + //==================================================================== + // Descriptor __set__ implementation. This actually never allows you + // to set anything; it exists solely to support the '+=' spelling of + // event handler registration. The reason is that given code like: + // 'ob.SomeEvent += method', Python will attempt to set the attribute + // SomeEvent on ob to the result of the '+=' operation. + //==================================================================== + + public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { + EventBinding e = GetManagedObject(val) as EventBinding; + + if (e != null) { + return 0; + } + + string message = "cannot set event attributes"; + Exceptions.RaiseTypeError(message); + return -1; + } + + + //==================================================================== + // Descriptor __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + EventObject self = (EventObject)GetManagedObject(ob); + string s = String.Format("", self.name); + return Runtime.PyString_FromString(s); + } + + + //==================================================================== + // Descriptor dealloc implementation. + //==================================================================== + + public static new void tp_dealloc(IntPtr ob) { + EventObject self = (EventObject)GetManagedObject(ob); + if (self.unbound != null) { + Runtime.Decref(self.unbound.pyHandle); + } + ExtensionType.FinalizeObject(self); + } + + + } + + + + internal class Handler { + + public IntPtr hash; + public Delegate del; + + public Handler(IntPtr hash, Delegate d) { + this.hash = hash; + this.del = d; + } + + } + + +} diff --git a/src/runtime/exceptions.cs b/src/runtime/exceptions.cs new file mode 100644 index 000000000..f08217dac --- /dev/null +++ b/src/runtime/exceptions.cs @@ -0,0 +1,639 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; +using System.Collections; +using System.Runtime.InteropServices; + + +namespace Python.Runtime { + + /// + /// Base class for Python types that reflect managed exceptions based on + /// System.Exception + /// + /// + /// The Python wrapper for managed exceptions LIES about its inheritance + /// tree. Although the real System.Exception is a subclass of + /// System.Object the Python type for System.Exception does NOT claim that + /// it subclasses System.Object. Instead TypeManager.CreateType() uses + /// Python's exception.Exception class as base class for System.Exception. + /// + internal class ExceptionClassObject : ClassObject { + + internal ExceptionClassObject(Type tp) : base(tp) { + } + +#if (PYTHON25 || PYTHON26 || PYTHON27) + internal static Exception ToException(IntPtr ob) { + CLRObject co = GetManagedObject(ob) as CLRObject; + if (co == null) { + return null; + } + Exception e = co.inst as Exception; + if (e == null) { + return null; + } + return e; + } + + //==================================================================== + // Exception __str__ implementation + //==================================================================== + + public new static IntPtr tp_str(IntPtr ob) { + Exception e = ToException(ob); + if (e == null) { + return Exceptions.RaiseTypeError("invalid object"); + } + + string message = String.Empty; + if (e.Message != String.Empty) { + message = e.Message; + } + if ((e.StackTrace != null) && (e.StackTrace != String.Empty)) { + message = message + "\n" + e.StackTrace; + } + return Runtime.PyUnicode_FromString(message); + } + + //==================================================================== + // Exception __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + Exception e = ToException(ob); + if (e == null) { + return Exceptions.RaiseTypeError("invalid object"); + } + string name = e.GetType().Name; + string message; + if (e.Message != String.Empty) { + message = String.Format("{0}('{1}',)", name, e.Message); + } else { + message = String.Format("{0}()", name); + } + return Runtime.PyUnicode_FromString(message); + } + //==================================================================== + // Exceptions __getattribute__ implementation. + // handles Python's args and message attributes + //==================================================================== + + public static IntPtr tp_getattro(IntPtr ob, IntPtr key) + { + if (!Runtime.PyString_Check(key)) { + Exceptions.SetError(Exceptions.TypeError, "string expected"); + return IntPtr.Zero; + } + + string name = Runtime.GetManagedString(key); + if (name == "args") { + Exception e = ToException(ob); + IntPtr args; + if (e.Message != String.Empty) { + args = Runtime.PyTuple_New(1); + IntPtr msg = Runtime.PyUnicode_FromString(e.Message); + Runtime.PyTuple_SetItem(args, 0, msg); + } else { + args = Runtime.PyTuple_New(0); + } + return args; + } + + if (name == "message") { + return ExceptionClassObject.tp_str(ob); + } + + return Runtime.PyObject_GenericGetAttr(ob, key); + } +#endif // (PYTHON25 || PYTHON26 || PYTHON27) + } + + /// + /// Encapsulates the Python exception APIs. + /// + /// + /// Readability of the Exceptions class improvements as we look toward version 2.7 ... + /// + + public class Exceptions { + + internal static IntPtr warnings_module; + internal static IntPtr exceptions_module; + + private Exceptions() {} + + //=================================================================== + // Initialization performed on startup of the Python runtime. + //=================================================================== + + internal static void Initialize() { + exceptions_module = Runtime.PyImport_ImportModule("exceptions"); + Exceptions.ErrorCheck(exceptions_module); + warnings_module = Runtime.PyImport_ImportModule("warnings"); + Exceptions.ErrorCheck(warnings_module); + Type type = typeof(Exceptions); + foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | + BindingFlags.Static)) { + IntPtr op = Runtime.PyObject_GetAttrString(exceptions_module, fi.Name); + if (op != IntPtr.Zero) { + fi.SetValue(type, op); + } + else { + fi.SetValue(type, IntPtr.Zero); + DebugUtil.Print("Unknown exception: " + fi.Name); + } + } + Runtime.PyErr_Clear(); + if (Runtime.wrap_exceptions) { + SetupExceptionHack(); + } + } + + + //=================================================================== + // Cleanup resources upon shutdown of the Python runtime. + //=================================================================== + + internal static void Shutdown() { + Type type = typeof(Exceptions); + foreach (FieldInfo fi in type.GetFields(BindingFlags.Public | + BindingFlags.Static)) { + IntPtr op = (IntPtr)fi.GetValue(type); + if (op != IntPtr.Zero) { + Runtime.Decref(op); + } + } + Runtime.Decref(exceptions_module); + Runtime.Decref(warnings_module); + } + + /// + /// Shortcut for (pointer == NULL) -> throw PythonException + /// + /// Pointer to a Python object + internal unsafe static void ErrorCheck(IntPtr pointer) { + if (pointer == IntPtr.Zero) { + throw new PythonException(); + } + } + + /// + /// Shortcut for (pointer == NULL or ErrorOccurred()) -> throw PythonException + /// + /// Shortcut for (pointer == NULL) -> throw PythonException + internal unsafe static void ErrorOccurredCheck(IntPtr pointer) { + if ((pointer == IntPtr.Zero) || Exceptions.ErrorOccurred()) { + throw new PythonException(); + } + } + + // Versions of CPython up to 2.4 do not allow exceptions to be + // new-style classes. To get around that restriction and provide + // a consistent user experience for programmers, we wrap managed + // exceptions in an old-style class that (through some dont-try- + // this-at-home hackery) delegates to the managed exception and + // obeys the conventions of both Python and managed exceptions. + + /// + /// Conditionally initialized variables! + /// + static IntPtr ns_exc; // new-style class for System.Exception + static IntPtr os_exc; // old-style class for System.Exception + static Hashtable cache; + + /// + /// the lines + /// // XXX - hack to raise a compatible old-style exception ;( + /// if (Runtime.wrap_exceptions) { + /// CallOneOfTheseMethods(); + /// + /// + internal static void SetupExceptionHack() { + ns_exc = ClassManager.GetClass(typeof(Exception)).pyHandle; + cache = new Hashtable(); + + string code = + "import exceptions\n" + + "class Exception(exceptions.Exception):\n" + + " _class = None\n" + + " _inner = None\n" + + " \n" + + " #@property\n" + + " def message(self):\n" + + " return self.Message\n" + + " message = property(message)\n" + + " \n" + + " def __init__(self, *args, **kw):\n" + + " inst = self.__class__._class(*args, **kw)\n" + + " self.__dict__['_inner'] = inst\n" + + " exceptions.Exception.__init__(self, *args, **kw)\n" + + "\n" + + " def __getattr__(self, name, _marker=[]):\n" + + " inner = self.__dict__['_inner']\n" + + " v = getattr(inner, name, _marker)\n" + + " if v is not _marker:\n" + + " return v\n" + + " v = self.__dict__.get(name, _marker)\n" + + " if v is not _marker:\n" + + " return v\n" + + " raise AttributeError(name)\n" + + "\n" + + " def __setattr__(self, name, value):\n" + + " inner = self.__dict__['_inner']\n" + + " setattr(inner, name, value)\n" + + "\n" + + " def __str__(self):\n" + + " inner = self.__dict__.get('_inner')\n" + + " msg = getattr(inner, 'Message', '')\n" + + " st = getattr(inner, 'StackTrace', '')\n" + + " st = st and '\\n' + st or ''\n" + + " return msg + st\n" + + " \n" + + " def __repr__(self):\n" + + " inner = self.__dict__.get('_inner')\n" + + " msg = getattr(inner, 'Message', '')\n" + + " name = self.__class__.__name__\n" + + " return '%s(\\'%s\\',)' % (name, msg) \n" + + "\n"; + + IntPtr dict = Runtime.PyDict_New(); + + IntPtr builtins = Runtime.PyEval_GetBuiltins(); + Runtime.PyDict_SetItemString(dict, "__builtins__", builtins); + + IntPtr namestr = Runtime.PyString_FromString("System"); + Runtime.PyDict_SetItemString(dict, "__name__", namestr); + Runtime.Decref(namestr); + + Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone); + Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone); + + IntPtr flag = Runtime.Py_file_input; + IntPtr result = Runtime.PyRun_String(code, flag, dict, dict); + Exceptions.ErrorCheck(result); + Runtime.Decref(result); + + os_exc = Runtime.PyDict_GetItemString(dict, "Exception"); + Runtime.PyObject_SetAttrString(os_exc, "_class", ns_exc); + Runtime.PyErr_Clear(); + } + + + internal static IntPtr GenerateExceptionClass(IntPtr real) { + if (real == ns_exc) { + return os_exc; + } + + IntPtr nbases = Runtime.PyObject_GetAttrString(real, "__bases__"); + if (Runtime.PyTuple_Size(nbases) != 1) { + throw new SystemException("Invalid __bases__"); + } + IntPtr nsbase = Runtime.PyTuple_GetItem(nbases, 0); + Runtime.Decref(nbases); + + IntPtr osbase = GetExceptionClassWrapper(nsbase); + IntPtr baselist = Runtime.PyTuple_New(1); + Runtime.Incref(osbase); + Runtime.PyTuple_SetItem(baselist, 0, osbase); + IntPtr name = Runtime.PyObject_GetAttrString(real, "__name__"); + + IntPtr dict = Runtime.PyDict_New(); + IntPtr mod = Runtime.PyObject_GetAttrString(real, "__module__"); + Runtime.PyDict_SetItemString(dict, "__module__", mod); + Runtime.Decref(mod); + + IntPtr subc = Runtime.PyClass_New(baselist, dict, name); + Runtime.Decref(baselist); + Runtime.Decref(dict); + Runtime.Decref(name); + + Runtime.PyObject_SetAttrString(subc, "_class", real); + return subc; + } + + internal static IntPtr GetExceptionClassWrapper(IntPtr real) { + // Given the pointer to a new-style class representing a managed + // exception, return an appropriate old-style class wrapper that + // maintains all of the expectations and delegates to the wrapped + // class. + object ob = cache[real]; + if (ob == null) { + IntPtr op = GenerateExceptionClass(real); + cache[real] = op; + return op; + } + return (IntPtr)ob; + } + + internal static IntPtr GetExceptionInstanceWrapper(IntPtr real) { + // Given the pointer to a new-style class instance representing a + // managed exception, return an appropriate old-style class + // wrapper instance that delegates to the wrapped instance. + IntPtr tp = Runtime.PyObject_TYPE(real); + if (Runtime.PyObject_TYPE(tp) == Runtime.PyInstanceType) { + return real; + } + // Get / generate a class wrapper, instantiate it and set its + // _inner attribute to the real new-style exception instance. + IntPtr ct = GetExceptionClassWrapper(tp); + Exceptions.ErrorCheck(ct); + IntPtr op = Runtime.PyInstance_NewRaw(ct, IntPtr.Zero); + Exceptions.ErrorCheck(op); + IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__"); + Exceptions.ErrorCheck(d); + Runtime.PyDict_SetItemString(d, "_inner", real); + Runtime.Decref(d); + return op; + } + + internal static IntPtr UnwrapExceptionClass(IntPtr op) { + // In some cases its necessary to recognize an exception *class*, + // and obtain the inner (wrapped) exception class. This method + // returns the inner class if found, or a null pointer. + + IntPtr d = Runtime.PyObject_GetAttrString(op, "__dict__"); + if (d == IntPtr.Zero) { + Exceptions.Clear(); + return IntPtr.Zero; + } + IntPtr c = Runtime.PyDict_GetItemString(d, "_class"); + Runtime.Decref(d); + if (c == IntPtr.Zero) { + Exceptions.Clear(); + } + return c; + } + + /// + /// GetException Method + /// + /// + /// + /// Retrieve Python exception information as a PythonException + /// instance. The properties of the PythonException may be used + /// to access the exception type, value and traceback info. + /// + + public static PythonException GetException() { + // TODO: implement this. + return null; + } + + /// + /// ExceptionMatches Method + /// + /// + /// + /// Returns true if the current Python exception matches the given + /// Python object. This is a wrapper for PyErr_ExceptionMatches. + /// + + public static bool ExceptionMatches(IntPtr ob) { + return Runtime.PyErr_ExceptionMatches(ob) != 0; + } + + /// + /// ExceptionMatches Method + /// + /// + /// + /// Returns true if the given Python exception matches the given + /// Python object. This is a wrapper for PyErr_GivenExceptionMatches. + /// + + public static bool ExceptionMatches(IntPtr exc, IntPtr ob) { + int i = Runtime.PyErr_GivenExceptionMatches(exc, ob); + return (i != 0); + } + + /// + /// SetError Method + /// + /// + /// + /// Sets the current Python exception given a native string. + /// This is a wrapper for the Python PyErr_SetString call. + /// + + public static void SetError(IntPtr ob, string value) { + Runtime.PyErr_SetString(ob, value); + } + + /// + /// SetError Method + /// + /// + /// + /// Sets the current Python exception given a Python object. + /// This is a wrapper for the Python PyErr_SetObject call. + /// + + public static void SetError(IntPtr ob, IntPtr value) { + Runtime.PyErr_SetObject(ob, value); + } + + /// + /// SetError Method + /// + /// + /// + /// Sets the current Python exception given a CLR exception + /// object. The CLR exception instance is wrapped as a Python + /// object, allowing it to be handled naturally from Python. + /// + + public static void SetError(Exception e) { + + // Because delegates allow arbitrary nestings of Python calling + // managed calling Python calling... etc. it is possible that we + // might get a managed exception raised that is a wrapper for a + // Python exception. In that case we'd rather have the real thing. + + PythonException pe = e as PythonException; + if (pe != null) { + Runtime.PyErr_SetObject(pe.PyType, pe.PyValue); + return; + } + + IntPtr op = CLRObject.GetInstHandle(e); + + // XXX - hack to raise a compatible old-style exception ;( + if (Runtime.wrap_exceptions) { + op = GetExceptionInstanceWrapper(op); + } + IntPtr etype = Runtime.PyObject_GetAttrString(op, "__class__"); + Runtime.PyErr_SetObject(etype, op); + Runtime.Decref(etype); + Runtime.Decref(op); + } + + /// + /// ErrorOccurred Method + /// + /// + /// + /// Returns true if an exception occurred in the Python runtime. + /// This is a wrapper for the Python PyErr_Occurred call. + /// + + public static bool ErrorOccurred() { + return Runtime.PyErr_Occurred() != 0; + } + + /// + /// Clear Method + /// + /// + /// + /// Clear any exception that has been set in the Python runtime. + /// + + public static void Clear() { + Runtime.PyErr_Clear(); + } + + //==================================================================== + // helper methods for raising warnings + //==================================================================== + + /// + /// Alias for Python's warnings.warn() function. + /// + public static void warn(string message, IntPtr exception, int stacklevel) + { + if ((exception == IntPtr.Zero) || + (Runtime.PyObject_IsSubclass(exception, Exceptions.Warning) != 1)) { + Exceptions.RaiseTypeError("Invalid exception"); + } + + Runtime.Incref(warnings_module); + IntPtr warn = Runtime.PyObject_GetAttrString(warnings_module, "warn"); + Runtime.Decref(warnings_module); + Exceptions.ErrorCheck(warn); + + IntPtr args = Runtime.PyTuple_New(3); + IntPtr msg = Runtime.PyString_FromString(message); + Runtime.Incref(exception); // PyTuple_SetItem steals a reference + IntPtr level = Runtime.PyInt_FromInt32(stacklevel); + Runtime.PyTuple_SetItem(args, 0, msg); + Runtime.PyTuple_SetItem(args, 1, exception); + Runtime.PyTuple_SetItem(args, 2, level); + + IntPtr result = Runtime.PyObject_CallObject(warn, args); + Exceptions.ErrorCheck(result); + + Runtime.Decref(warn); + Runtime.Decref(result); + Runtime.Decref(args); + } + + public static void warn(string message, IntPtr exception) + { + warn(message, exception, 1); + } + + public static void deprecation(string message, int stacklevel) + { + warn(message, Exceptions.DeprecationWarning, stacklevel); + } + + public static void deprecation(string message) + { + deprecation(message, 1); + } + + //==================================================================== + // Internal helper methods for common error handling scenarios. + //==================================================================== + + internal static IntPtr RaiseTypeError(string message) { + Exceptions.SetError(Exceptions.TypeError, message); + return IntPtr.Zero; + } + + // 2010-11-16: Arranged in python (2.6 & 2.7) source header file order + /* Predefined exceptions are + puplic static variables on the Exceptions class filled in from + the python class using reflection in Initialize() looked up by + name, not posistion. */ +#if (PYTHON25 || PYTHON26 || PYTHON27) + public static IntPtr BaseException; +#endif + public static IntPtr Exception; + public static IntPtr StopIteration; +#if (PYTHON25 || PYTHON26 || PYTHON27) + public static IntPtr GeneratorExit; +#endif + public static IntPtr StandardError; + public static IntPtr ArithmeticError; + public static IntPtr LookupError; + + public static IntPtr AssertionError; + public static IntPtr AttributeError; + public static IntPtr EOFError; + public static IntPtr FloatingPointError; + public static IntPtr EnvironmentError; + public static IntPtr IOError; + public static IntPtr OSError; + public static IntPtr ImportError; + public static IntPtr IndexError; + public static IntPtr KeyError; + public static IntPtr KeyboardInterrupt; + public static IntPtr MemoryError; + public static IntPtr NameError; + public static IntPtr OverflowError; + public static IntPtr RuntimeError; + public static IntPtr NotImplementedError; + public static IntPtr SyntaxError; + public static IntPtr IndentationError; + public static IntPtr TabError; + public static IntPtr ReferenceError; + public static IntPtr SystemError; + public static IntPtr SystemExit; + public static IntPtr TypeError; + public static IntPtr UnboundLocalError; + public static IntPtr UnicodeError; + public static IntPtr UnicodeEncodeError; + public static IntPtr UnicodeDecodeError; + public static IntPtr UnicodeTranslateError; + public static IntPtr ValueError; + public static IntPtr ZeroDivisionError; +//#ifdef MS_WINDOWS + //public static IntPtr WindowsError; +//#endif +//#ifdef __VMS + //public static IntPtr VMSError; +//#endif + + //PyAPI_DATA(PyObject *) PyExc_BufferError; + + //PyAPI_DATA(PyObject *) PyExc_MemoryErrorInst; + //PyAPI_DATA(PyObject *) PyExc_RecursionErrorInst; + + + /* Predefined warning categories */ + public static IntPtr Warning; + public static IntPtr UserWarning; + public static IntPtr DeprecationWarning; + public static IntPtr PendingDeprecationWarning; + public static IntPtr SyntaxWarning; + public static IntPtr RuntimeWarning; + public static IntPtr FutureWarning; +#if (PYTHON25 || PYTHON26 || PYTHON27) + public static IntPtr ImportWarning; + public static IntPtr UnicodeWarning; + //PyAPI_DATA(PyObject *) PyExc_BytesWarning; +#endif + } + + +} diff --git a/src/runtime/extensiontype.cs b/src/runtime/extensiontype.cs new file mode 100644 index 000000000..b0499bb0a --- /dev/null +++ b/src/runtime/extensiontype.cs @@ -0,0 +1,129 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + /// + /// Base class for extensions whose instances *share* a single Python + /// type object, such as the types that represent CLR methods, fields, + /// etc. Instances implemented by this class do not support subtyping. + /// + + internal abstract class ExtensionType : ManagedType { + + public ExtensionType() : base() { + + // Create a new PyObject whose type is a generated type that is + // implemented by the particuar concrete ExtensionType subclass. + // The Python instance object is related to an instance of a + // particular concrete subclass with a hidden CLR gchandle. + + IntPtr tp = TypeManager.GetTypeHandle(this.GetType()); + +// int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt); +// if (rc > 1050) { +// DebugUtil.Print("tp is: ", tp); +// DebugUtil.DumpType(tp); +// } + + IntPtr py = Runtime.PyType_GenericAlloc(tp, 0); + + GCHandle gc = GCHandle.Alloc(this); + Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc); + + // We have to support gc because the type machinery makes it very + // hard not to - but we really don't have a need for it in most + // concrete extension types, so untrack the object to save calls + // from Python into the managed runtime that are pure overhead. + + Runtime.PyObject_GC_UnTrack(py); + + this.tpHandle = tp; + this.pyHandle = py; + this.gcHandle = gc; + } + + + //==================================================================== + // Common finalization code to support custom tp_deallocs. + //==================================================================== + + public static void FinalizeObject(ManagedType self) { + Runtime.PyObject_GC_Del(self.pyHandle); + Runtime.Decref(self.tpHandle); + self.gcHandle.Free(); + } + + + //==================================================================== + // Type __setattr__ implementation. + //==================================================================== + + public static int tp_setattro(IntPtr ob, IntPtr key, IntPtr val) { + string message = "type does not support setting attributes"; + if (val == IntPtr.Zero) { + message = "readonly attribute"; + } + Exceptions.SetError(Exceptions.TypeError, message); + return -1; + } + + + //==================================================================== + // Default __set__ implementation - this prevents descriptor instances + // being silently replaced in a type __dict__ by default __setattr__. + //==================================================================== + + public static int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { + string message = "attribute is read-only"; + Exceptions.SetError(Exceptions.AttributeError, message); + return -1; + } + + + //==================================================================== + // Required Python GC support. + //==================================================================== + + public static int tp_traverse(IntPtr ob, IntPtr func, IntPtr args) { + return 0; + } + + + public static int tp_clear(IntPtr ob) { + return 0; + } + + + public static int tp_is_gc(IntPtr type) { + return 1; + } + + + //==================================================================== + // Default dealloc implementation. + //==================================================================== + + public static void tp_dealloc(IntPtr ob) { + // Clean up a Python instance of this extension type. This + // frees the allocated Python object and decrefs the type. + ManagedType self = GetManagedObject(ob); + FinalizeObject(self); + } + + + } + + +} diff --git a/src/runtime/fieldobject.cs b/src/runtime/fieldobject.cs new file mode 100644 index 000000000..ee9d3392a --- /dev/null +++ b/src/runtime/fieldobject.cs @@ -0,0 +1,150 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python descriptor type that provides access to CLR fields. + //======================================================================== + + internal class FieldObject : ExtensionType { + + FieldInfo info; + + public FieldObject(FieldInfo info) : base() { + this.info = info; + } + + //==================================================================== + // Descriptor __get__ implementation. This method returns the + // value of the field on the given object. The returned value + // is converted to an appropriately typed Python object. + //==================================================================== + + public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { + FieldObject self = (FieldObject)GetManagedObject(ds); + Object result; + + if (self == null) { + return IntPtr.Zero; + } + + FieldInfo info = self.info; + + if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { + if (!info.IsStatic) { + Exceptions.SetError(Exceptions.TypeError, + "instance attribute must be accessed " + + "through a class instance" + ); + return IntPtr.Zero; + } + try { + result = info.GetValue(null); + return Converter.ToPython(result, info.FieldType); + } + catch(Exception e) { + Exceptions.SetError(Exceptions.TypeError, e.Message); + return IntPtr.Zero; + } + } + + try { + CLRObject co = (CLRObject)GetManagedObject(ob); + result = info.GetValue(co.inst); + return Converter.ToPython(result, info.FieldType); + } + catch(Exception e) { + Exceptions.SetError(Exceptions.TypeError, e.Message); + return IntPtr.Zero; + } + } + + //==================================================================== + // Descriptor __set__ implementation. This method sets the value of + // a field based on the given Python value. The Python value must be + // convertible to the type of the field. + //==================================================================== + + public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { + FieldObject self = (FieldObject)GetManagedObject(ds); + Object newval; + + if (self == null) { + return -1; + } + + if (val == IntPtr.Zero) { + Exceptions.SetError(Exceptions.TypeError, + "cannot delete field" + ); + return -1; + } + + FieldInfo info = self.info; + + if (info.IsLiteral || info.IsInitOnly) { + Exceptions.SetError(Exceptions.TypeError, + "field is read-only" + ); + return -1; + } + + bool is_static = info.IsStatic; + + if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { + if (!is_static) { + Exceptions.SetError(Exceptions.TypeError, + "instance attribute must be set " + + "through a class instance" + ); + return -1; + } + } + + if (!Converter.ToManaged(val, info.FieldType, out newval, + true)) { + return -1; + } + + try { + if (!is_static) { + CLRObject co = (CLRObject)GetManagedObject(ob); + info.SetValue(co.inst, newval); + } + else { + info.SetValue(null, newval); + } + return 0; + } + catch(Exception e) { + Exceptions.SetError(Exceptions.TypeError, e.Message); + return -1; + } + } + + //==================================================================== + // Descriptor __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + FieldObject self = (FieldObject)GetManagedObject(ob); + string s = String.Format("", self.info.Name); + return Runtime.PyString_FromStringAndSize(s, s.Length); + } + + } + + +} diff --git a/src/runtime/generictype.cs b/src/runtime/generictype.cs new file mode 100644 index 000000000..082bc768c --- /dev/null +++ b/src/runtime/generictype.cs @@ -0,0 +1,100 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; + +namespace Python.Runtime { + + /// + /// Implements reflected generic types. Note that the Python behavior + /// is the same for both generic type definitions and constructed open + /// generic types. Both are essentially factories for creating closed + /// types based on the required generic type parameters. + /// + + internal class GenericType : ClassBase { + + internal GenericType(Type tp) : base(tp) {} + + //==================================================================== + // Implements __new__ for reflected generic types. + //==================================================================== + + public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { + Exceptions.SetError(Exceptions.TypeError, + "cannot instantiate an open generic type" + ); + return IntPtr.Zero; + } + + + //==================================================================== + // Implements __call__ for reflected generic types. + //==================================================================== + + public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { + Exceptions.SetError(Exceptions.TypeError, + "object is not callable"); + return IntPtr.Zero; + } + + //==================================================================== + // Implements subscript syntax for reflected generic types. A closed + // type is created by binding the generic type via subscript syntax: + // inst = List[str]() + //==================================================================== + + public override IntPtr type_subscript(IntPtr idx) { + Type[] types = Runtime.PythonArgsToTypeArray(idx); + if (types == null) { + return Exceptions.RaiseTypeError("type(s) expected"); + } + if (!this.type.IsGenericTypeDefinition) { + return Exceptions.RaiseTypeError( + "type is not a generic type definition" + ); + } + + // This is a little tricky, because an instance of GenericType + // may represent either a specific generic type, or act as an + // alias for one or more generic types with the same base name. + + if (this.type.ContainsGenericParameters) { + Type[] args = this.type.GetGenericArguments(); + Type target = null; + + if (args.Length == types.Length) { + target = this.type; + } + else { + foreach (Type t in + GenericUtil.GenericsForType(this.type)) { + if (t.GetGenericArguments().Length == types.Length) { + target = t; + break; + } + } + } + + if (target != null) { + Type t = target.MakeGenericType(types); + ManagedType c = (ManagedType)ClassManager.GetClass(t); + Runtime.Incref(c.pyHandle); + return c.pyHandle; + } + return Exceptions.RaiseTypeError("no type matches params"); + } + + return Exceptions.RaiseTypeError("unsubscriptable object"); + } + + } + +} diff --git a/src/runtime/genericutil.cs b/src/runtime/genericutil.cs new file mode 100644 index 000000000..c3de0aa56 --- /dev/null +++ b/src/runtime/genericutil.cs @@ -0,0 +1,138 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Collections; +using System.Reflection; +using System.Security; + +namespace Python.Runtime { + + /// + /// This class is responsible for efficiently maintaining the bits + /// of information we need to support aliases with 'nice names'. + /// + + internal class GenericUtil { + + static Dictionary>> mapping; + + private GenericUtil() {} + + static GenericUtil() { + mapping = new + Dictionary>>(); + } + + //==================================================================== + // Register a generic type that appears in a given namespace. + //==================================================================== + + internal static void Register(Type t) { + Dictionary> nsmap = null; + mapping.TryGetValue(t.Namespace, out nsmap); + if (nsmap == null) { + nsmap = new Dictionary>(); + mapping[t.Namespace] = nsmap; + } + string basename = t.Name; + int tick = basename.IndexOf("`"); + if (tick > -1) { + basename = basename.Substring(0, tick); + } + List gnames = null; + nsmap.TryGetValue(basename, out gnames); + if (gnames == null) { + gnames = new List(); + nsmap[basename] = gnames; + } + gnames.Add(t.Name); + } + + //==================================================================== + // xxx + //==================================================================== + + public static List GetGenericBaseNames(string ns) { + Dictionary> nsmap = null; + mapping.TryGetValue(ns, out nsmap); + if (nsmap == null) { + return null; + } + List names = new List(); + foreach (string key in nsmap.Keys) { + names.Add(key); + } + return names; + } + + //==================================================================== + // xxx + //==================================================================== + + public static List GenericsForType(Type t) { + Dictionary> nsmap = null; + mapping.TryGetValue(t.Namespace, out nsmap); + if (nsmap == null) { + return null; + } + + string basename = t.Name; + int tick = basename.IndexOf("`"); + if (tick > -1) { + basename = basename.Substring(0, tick); + } + + List names = null; + nsmap.TryGetValue(basename, out names); + if (names == null) { + return null; + } + + List result = new List(); + foreach (string name in names) { + string qname = t.Namespace + "." + name; + Type o = AssemblyManager.LookupType(qname); + if (o != null) { + result.Add(o); + } + } + + return result; + } + + //==================================================================== + // xxx + //==================================================================== + + public static string GenericNameForBaseName(string ns, string name) { + Dictionary> nsmap = null; + mapping.TryGetValue(ns, out nsmap); + if (nsmap == null) { + return null; + } + List gnames = null; + nsmap.TryGetValue(name, out gnames); + if (gnames == null) { + return null; + } + if (gnames.Count > 0) { + return gnames[0]; + } + return null; + } + + + } + + + +} diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs new file mode 100644 index 000000000..c736f0645 --- /dev/null +++ b/src/runtime/importhook.cs @@ -0,0 +1,234 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + //======================================================================== + // Implements the "import hook" used to integrate Python with the CLR. + //======================================================================== + + internal class ImportHook { + + static IntPtr py_import; + static CLRModule root; + static MethodWrapper hook; + + //=================================================================== + // Initialization performed on startup of the Python runtime. + //=================================================================== + + internal static void Initialize() { + + // Initialize the Python <--> CLR module hook. We replace the + // built-in Python __import__ with our own. This isn't ideal, + // but it provides the most "Pythonic" way of dealing with CLR + // modules (Python doesn't provide a way to emulate packages). + + IntPtr dict = Runtime.PyImport_GetModuleDict(); + IntPtr mod = Runtime.PyDict_GetItemString(dict, "__builtin__"); + py_import = Runtime.PyObject_GetAttrString(mod, "__import__"); + + hook = new MethodWrapper(typeof(ImportHook), "__import__"); + Runtime.PyObject_SetAttrString(mod, "__import__", hook.ptr); + Runtime.Decref(hook.ptr); + + root = new CLRModule(); + Runtime.Incref(root.pyHandle); // we are using the module two times + Runtime.PyDict_SetItemString(dict, "CLR", root.pyHandle); + Runtime.PyDict_SetItemString(dict, "clr", root.pyHandle); + } + + + //=================================================================== + // Cleanup resources upon shutdown of the Python runtime. + //=================================================================== + + internal static void Shutdown() { + Runtime.Decref(root.pyHandle); + Runtime.Decref(root.pyHandle); + Runtime.Decref(py_import); + } + + + //=================================================================== + // The actual import hook that ties Python to the managed world. + //=================================================================== + + public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw) { + + // Replacement for the builtin __import__. The original import + // hook is saved as this.py_import. This version handles CLR + // import and defers to the normal builtin for everything else. + + int num_args = Runtime.PyTuple_Size(args); + if (num_args < 1) { + return Exceptions.RaiseTypeError( + "__import__() takes at least 1 argument (0 given)" + ); + } + + // borrowed reference + IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0); + if ((py_mod_name == IntPtr.Zero) || + (!Runtime.IsStringType(py_mod_name))) { + return Exceptions.RaiseTypeError("string expected"); + } + + // Check whether the import is of the form 'from x import y'. + // This determines whether we return the head or tail module. + + IntPtr fromList = IntPtr.Zero; + bool fromlist = false; + if (num_args >= 4) { + fromList = Runtime.PyTuple_GetItem(args, 3); + if ((fromList != IntPtr.Zero) && + (Runtime.PyObject_IsTrue(fromList) == 1)) { + fromlist = true; + } + } + + string mod_name = Runtime.GetManagedString(py_mod_name); + // Check these BEFORE the built-in import runs; may as well + // do the Incref()ed return here, since we've already found + // the module. + if (mod_name == "clr") { + root.InitializePreload(); + Runtime.Incref(root.pyHandle); + return root.pyHandle; + } + if (mod_name == "CLR") { + Exceptions.deprecation("The CLR module is deprecated. " + + "Please use 'clr'."); + root.InitializePreload(); + Runtime.Incref(root.pyHandle); + return root.pyHandle; + } + string realname = mod_name; + if (mod_name.StartsWith("CLR.")) { + realname = mod_name.Substring(4); + string msg = String.Format("Importing from the CLR.* namespace "+ + "is deprecated. Please import '{0}' directly.", realname); + Exceptions.deprecation(msg); + } + else { + // 2010-08-15: Always seemed smart to let python try first... + // This shaves off a few tenths of a second on test_module.py + // and works around a quirk where 'sys' is found by the + // LoadImplicit() deprecation logic. + // Turns out that the AssemblyManager.ResolveHandler() checks to see if any + // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very + // little sense to me. + IntPtr res = Runtime.PyObject_Call(py_import, args, kw); + if (res != IntPtr.Zero) { + // There was no error. + return res; + } + // There was an error + if (!Exceptions.ExceptionMatches(Exceptions.ImportError)) { + // and it was NOT an ImportError; bail out here. + return IntPtr.Zero; + } + // Otherwise, just clear the it. + Exceptions.Clear(); + } + + string[] names = realname.Split('.'); + + // Now we need to decide if the name refers to a CLR module, + // and may have to do an implicit load (for b/w compatibility) + // using the AssemblyManager. The assembly manager tries + // really hard not to use Python objects or APIs, because + // parts of it can run recursively and on strange threads. + // + // It does need an opportunity from time to time to check to + // see if sys.path has changed, in a context that is safe. Here + // we know we have the GIL, so we'll let it update if needed. + + AssemblyManager.UpdatePath(); + if (!AssemblyManager.IsValidNamespace(realname)) { + if (!AssemblyManager.LoadImplicit(realname)) + { + // May be called when a module being imported imports a module. + // In particular, I've seen decimal import copy import org.python.core + return Runtime.PyObject_Call(py_import, args, kw); + } + } + + // See if sys.modules for this interpreter already has the + // requested module. If so, just return the exising module. + IntPtr modules = Runtime.PyImport_GetModuleDict(); + IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name); + + if (module != IntPtr.Zero) { + if (fromlist) { + Runtime.Incref(module); + return module; + } + module = Runtime.PyDict_GetItemString(modules, names[0]); + Runtime.Incref(module); + return module; + } + Exceptions.Clear(); + + // Traverse the qualified module name to get the named module + // and place references in sys.modules as we go. Note that if + // we are running in interactive mode we pre-load the names in + // each module, which is often useful for introspection. If we + // are not interactive, we stick to just-in-time creation of + // objects at lookup time, which is much more efficient. + // NEW: The clr got a new module variable preload. You can + // enable preloading in a non-interactive python processing by + // setting clr.preload = True + + ModuleObject head = (mod_name == realname) ? null : root; + ModuleObject tail = root; + root.InitializePreload(); + + for (int i = 0; i < names.Length; i++) { + string name = names[i]; + ManagedType mt = tail.GetAttribute(name, true); + if (!(mt is ModuleObject)) { + string error = String.Format("No module named {0}", name); + Exceptions.SetError(Exceptions.ImportError, error); + return IntPtr.Zero; + } + if (head == null) { + head = (ModuleObject)mt; + } + tail = (ModuleObject) mt; + if (CLRModule.preload) { + tail.LoadNames(); + } + Runtime.PyDict_SetItemString(modules, tail.moduleName, + tail.pyHandle + ); + } + + ModuleObject mod = fromlist ? tail : head; + + if (fromlist && Runtime.PySequence_Size(fromList) == 1) { + IntPtr fp = Runtime.PySequence_GetItem(fromList, 0); + if ((!CLRModule.preload) && Runtime.GetManagedString(fp) == "*") { + mod.LoadNames(); + } + Runtime.Decref(fp); + } + + Runtime.Incref(mod.pyHandle); + return mod.pyHandle; + } + + } + + +} diff --git a/src/runtime/indexer.cs b/src/runtime/indexer.cs new file mode 100644 index 000000000..8118dc339 --- /dev/null +++ b/src/runtime/indexer.cs @@ -0,0 +1,68 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; +using System.Security.Permissions; + +namespace Python.Runtime { + + //======================================================================== + // Bundles the information required to support an indexer property. + //======================================================================== + + internal class Indexer { + + public MethodBinder GetterBinder; + public MethodBinder SetterBinder; + + public Indexer() { + GetterBinder = new MethodBinder(); + SetterBinder = new MethodBinder(); + } + + + public bool CanGet { + get { + return GetterBinder.Count > 0; + } + } + + public bool CanSet { + get { + return SetterBinder.Count > 0; + } + } + + + public void AddProperty(PropertyInfo pi) { + MethodInfo getter = pi.GetGetMethod(true); + MethodInfo setter = pi.GetSetMethod(true); + if (getter != null) { + GetterBinder.AddMethod(getter); + } + if (setter != null) { + SetterBinder.AddMethod(setter); + } + } + + internal IntPtr GetItem(IntPtr inst, IntPtr args) { + return GetterBinder.Invoke(inst, args, IntPtr.Zero); + } + + + internal void SetItem(IntPtr inst, IntPtr args) { + SetterBinder.Invoke(inst, args, IntPtr.Zero); + } + + } + + +} diff --git a/src/runtime/interfaceobject.cs b/src/runtime/interfaceobject.cs new file mode 100644 index 000000000..7c2aead1f --- /dev/null +++ b/src/runtime/interfaceobject.cs @@ -0,0 +1,89 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// Provides the implementation for reflected interface types. Managed + /// interfaces are represented in Python by actual Python type objects. + /// Each of those type objects is associated with an instance of this + /// class, which provides the implementation for the Python type. + /// + + internal class InterfaceObject : ClassBase { + + internal ConstructorInfo ctor; + + internal InterfaceObject(Type tp) : base(tp) { + CoClassAttribute coclass = (CoClassAttribute) + Attribute.GetCustomAttribute(tp, cc_attr); + if (coclass != null) { + ctor = coclass.CoClass.GetConstructor(Type.EmptyTypes); + } + } + + static Type cc_attr; + + static InterfaceObject() { + cc_attr = typeof(CoClassAttribute); + } + + //==================================================================== + // Implements __new__ for reflected interface types. + //==================================================================== + + public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { + InterfaceObject self = (InterfaceObject)GetManagedObject(tp); + int nargs = Runtime.PyTuple_Size(args); + Type type = self.type; + Object obj; + + if (nargs == 1) { + IntPtr inst = Runtime.PyTuple_GetItem(args, 0); + CLRObject co = GetManagedObject(inst) as CLRObject; + + if ((co == null) || (!type.IsInstanceOfType(co.inst))) { + string msg = "object does not implement " + type.Name; + Exceptions.SetError(Exceptions.TypeError, msg); + return IntPtr.Zero; + } + + obj = co.inst; + } + + else if ((nargs == 0) && (self.ctor != null)) { + obj = self.ctor.Invoke(null); + + if (obj == null || !type.IsInstanceOfType(obj)) { + Exceptions.SetError(Exceptions.TypeError, + "CoClass default constructor failed" + ); + return IntPtr.Zero; + } + } + + else { + Exceptions.SetError(Exceptions.TypeError, + "interface takes exactly one argument" + ); + return IntPtr.Zero; + } + + return CLRObject.GetInstHandle(obj, self.pyHandle); + } + + + } + + +} diff --git a/src/runtime/interfaces.cs b/src/runtime/interfaces.cs new file mode 100644 index 000000000..484a9ad5d --- /dev/null +++ b/src/runtime/interfaces.cs @@ -0,0 +1,40 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// xxx + /// + + internal interface IReflectedType { + string PythonTypeName(); + Type GetReflectedType(); + } + + internal interface IReflectedClass : IReflectedType { + bool IsException(); + } + + internal interface IReflectedInterface : IReflectedType { + + } + + internal interface IReflectedArray : IReflectedType { + } + + internal interface IReflectedGenericClass : IReflectedClass { + } + + +} diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs new file mode 100644 index 000000000..9aad4c6e4 --- /dev/null +++ b/src/runtime/interop.cs @@ -0,0 +1,545 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Runtime.InteropServices; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================= + // This file defines objects to support binary interop with the Python + // runtime. Generally, the definitions here need to be kept up to date + // when moving to new Python versions. + //======================================================================= + + [Serializable()] + [AttributeUsage(AttributeTargets.All)] + public class DocStringAttribute : Attribute { + public DocStringAttribute(string docStr) { + DocString = docStr; + } + public string DocString { + get { return docStr; } + set { docStr = value; } + } + private string docStr; + } + + [Serializable()] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] + internal class PythonMethodAttribute : Attribute { + public PythonMethodAttribute() {} + } + + [Serializable()] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] + internal class ModuleFunctionAttribute : Attribute { + public ModuleFunctionAttribute() {} + } + + [Serializable()] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Delegate)] + internal class ForbidPythonThreadsAttribute : Attribute { + public ForbidPythonThreadsAttribute() { } + } + + + [Serializable()] + [AttributeUsage(AttributeTargets.Property)] + internal class ModulePropertyAttribute : Attribute { + public ModulePropertyAttribute() {} + } + + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] + internal class ObjectOffset { + + static ObjectOffset() { + int size = IntPtr.Size; + int n = 0; // Py_TRACE_REFS add two pointers to PyObject_HEAD +#if (Py_DEBUG) + _ob_next = 0; + _ob_prev = 1 * size; + n = 2; +#endif + ob_refcnt = (n+0) * size; + ob_type = (n+1) * size; + ob_dict = (n+2) * size; + ob_data = (n+3) * size; + } + + public static int magic() { + return ob_data; + } + + public static int Size() { +#if (Py_DEBUG) + return 6 * IntPtr.Size; +#else + return 4 * IntPtr.Size; +#endif + } + +#if (Py_DEBUG) + public static int _ob_next; + public static int _ob_prev; +#endif + public static int ob_refcnt; + public static int ob_type; + public static int ob_dict; + public static int ob_data; + } + + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] + internal class TypeOffset { + + static TypeOffset() { + Type type = typeof(TypeOffset); + FieldInfo[] fi = type.GetFields(); + int size = IntPtr.Size; + for (int i = 0; i < fi.Length; i++) { + fi[i].SetValue(null, i * size); + } + } + + public static int magic() { + return ob_size; + } + +/* The *real* layout of a type object when allocated on the heap */ +//typedef struct _heaptypeobject { +#if (Py_DEBUG) // #ifdef Py_TRACE_REFS +/* _PyObject_HEAD_EXTRA defines pointers to support a doubly-linked list of all live heap objects. */ + public static int _ob_next = 0; + public static int _ob_prev = 0; +#endif +// PyObject_VAR_HEAD { +// PyObject_HEAD { + public static int ob_refcnt = 0; + public static int ob_type = 0; + // } + public static int ob_size = 0; /* Number of items in _VAR_iable part */ +// } + public static int tp_name = 0; /* For printing, in format "." */ + public static int tp_basicsize = 0; /* For allocation */ + public static int tp_itemsize = 0; + + /* Methods to implement standard operations */ + public static int tp_dealloc = 0; + public static int tp_print = 0; + public static int tp_getattr = 0; + public static int tp_setattr = 0; + public static int tp_compare = 0; + public static int tp_repr = 0; + + /* Method suites for standard classes */ + public static int tp_as_number = 0; + public static int tp_as_sequence = 0; + public static int tp_as_mapping = 0; + + /* More standard operations (here for binary compatibility) */ + public static int tp_hash = 0; + public static int tp_call = 0; + public static int tp_str = 0; + public static int tp_getattro = 0; + public static int tp_setattro = 0; + + /* Functions to access object as input/output buffer */ + public static int tp_as_buffer = 0; + + /* Flags to define presence of optional/expanded features */ + public static int tp_flags = 0; + + public static int tp_doc = 0; /* Documentation string */ + + /* Assigned meaning in release 2.0 */ + /* call function for all accessible objects */ + public static int tp_traverse = 0; + /* delete references to contained objects */ + public static int tp_clear = 0; + + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + public static int tp_richcompare = 0; + /* weak reference enabler */ + public static int tp_weaklistoffset = 0; + + /* Added in release 2.2 */ + /* Iterators */ + public static int tp_iter = 0; + public static int tp_iternext = 0; + /* Attribute descriptor and subclassing stuff */ + public static int tp_methods = 0; + public static int tp_members = 0; + public static int tp_getset = 0; + public static int tp_base = 0; + public static int tp_dict = 0; + public static int tp_descr_get = 0; + public static int tp_descr_set = 0; + public static int tp_dictoffset = 0; + public static int tp_init = 0; + public static int tp_alloc = 0; + public static int tp_new = 0; + public static int tp_free = 0; /* Low-level free-memory routine */ + public static int tp_is_gc = 0; /* For PyObject_IS_GC */ + public static int tp_bases = 0; + public static int tp_mro = 0; /* method resolution order */ + public static int tp_cache = 0; + public static int tp_subclasses = 0; + public static int tp_weaklist = 0; + public static int tp_del = 0; +#if (PYTHON26 || PYTHON27) + /* Type attribute cache version tag. Added in version 2.6 */ + public static int tp_version_tag; +#endif + // COUNT_ALLOCS adds some more stuff to PyTypeObject +#if (Py_COUNT_ALLOCS) + /* these must be last and never explicitly initialized */ + public static int tp_allocs = 0; + public static int tp_frees = 0; + public static int tp_maxalloc = 0; + public static int tp_prev = 0; + public static int tp_next = 0; +#endif +//} PyTypeObject; +//typedef struct { + public static int nb_add = 0; + public static int nb_subtract = 0; + public static int nb_multiply = 0; + public static int nb_divide = 0; + public static int nb_remainder = 0; + public static int nb_divmod = 0; + public static int nb_power = 0; + public static int nb_negative = 0; + public static int nb_positive = 0; + public static int nb_absolute = 0; + public static int nb_nonzero = 0; + public static int nb_invert = 0; + public static int nb_lshift = 0; + public static int nb_rshift = 0; + public static int nb_and = 0; + public static int nb_xor = 0; + public static int nb_or = 0; + public static int nb_coerce = 0; + public static int nb_int = 0; + public static int nb_long = 0; + public static int nb_float = 0; + public static int nb_oct = 0; + public static int nb_hex = 0; + /* Added in release 2.0 */ + public static int nb_inplace_add = 0; + public static int nb_inplace_subtract = 0; + public static int nb_inplace_multiply = 0; + public static int nb_inplace_divide = 0; + public static int nb_inplace_remainder = 0; + public static int nb_inplace_power = 0; + public static int nb_inplace_lshift = 0; + public static int nb_inplace_rshift = 0; + public static int nb_inplace_and = 0; + public static int nb_inplace_xor = 0; + public static int nb_inplace_or = 0; + /* Added in release 2.2 */ + /* The following require the Py_TPFLAGS_HAVE_CLASS flag */ + public static int nb_floor_divide = 0; + public static int nb_true_divide = 0; + public static int nb_inplace_floor_divide = 0; + public static int nb_inplace_true_divide = 0; +#if (PYTHON25 || PYTHON26 || PYTHON27) + /* Added in release 2.5 */ + public static int nb_index = 0; +#endif + //} PyNumberMethods; +//typedef struct { + public static int mp_length = 0; + public static int mp_subscript = 0; + public static int mp_ass_subscript = 0; +//} PyMappingMethods; +//typedef struct { + public static int sq_length = 0; + public static int sq_concat = 0; + public static int sq_repeat = 0; + public static int sq_item = 0; + public static int sq_slice = 0; + public static int sq_ass_item = 0; + public static int sq_ass_slice = 0; + public static int sq_contains = 0; + /* Added in release 2.0 */ + public static int sq_inplace_concat = 0; + public static int sq_inplace_repeat = 0; +//} PySequenceMethods; +//typedef struct { + public static int bf_getreadbuffer = 0; + public static int bf_getwritebuffer = 0; + public static int bf_getsegcount = 0; + public static int bf_getcharbuffer = 0; +#if (PYTHON26 || PYTHON27) + // This addition is not actually noted in the 2.6.5 object.h + public static int bf_getbuffer = 0; + public static int bf_releasebuffer = 0; +//} PyBufferProcs; +#endif + //PyObject *ht_name, *ht_slots; + public static int name = 0; + public static int slots = 0; + /* here are optional user slots, followed by the members. */ + public static int members = 0; + } + + /// + /// TypeFlags(): The actual bit values for the Type Flags stored + /// in a class. + /// Note that the two values reserved for stackless have been put + /// to good use as PythonNet specific flags (Managed and Subclass) + /// + internal class TypeFlags { + public static int HaveGetCharBuffer = (1 << 0); + public static int HaveSequenceIn = (1 << 1); + public static int GC = 0; + public static int HaveInPlaceOps = (1 << 3); + public static int CheckTypes = (1 << 4); + public static int HaveRichCompare = (1 << 5); + public static int HaveWeakRefs = (1 << 6); + public static int HaveIter = (1 << 7); + public static int HaveClass = (1 << 8); + public static int HeapType = (1 << 9); + public static int BaseType = (1 << 10); + public static int Ready = (1 << 12); + public static int Readying = (1 << 13); + public static int HaveGC = (1 << 14); + // 15 and 16 are reserved for stackless + public static int HaveStacklessExtension = 0; + /* XXX Reusing reserved constants */ + public static int Managed = (1 << 15); // PythonNet specific + public static int Subclass = (1 << 16); // PythonNet specific +#if (PYTHON25 || PYTHON26 || PYTHON27) + public static int HaveIndex = (1 << 17); +#endif +#if (PYTHON26 || PYTHON27) + /* Objects support nb_index in PyNumberMethods */ + public static int HaveVersionTag = (1 << 18); + public static int ValidVersionTag = (1 << 19); + public static int IsAbstract = (1 << 20); + public static int HaveNewBuffer = (1 << 21); + // TODO: Implement FastSubclass functions + public static int IntSubclass = (1 << 23); + public static int LongSubclass = (1 << 24); + public static int ListSubclass = (1 << 25); + public static int TupleSubclass = (1 << 26); + public static int StringSubclass = (1 << 27); + public static int UnicodeSubclass = (1 << 28); + public static int DictSubclass = (1 << 29); + public static int BaseExceptionSubclass = (1 << 30); + public static int TypeSubclass = (1 << 31); +#endif + public static int Default = (HaveGetCharBuffer | + HaveSequenceIn | + HaveInPlaceOps | + HaveRichCompare | + HaveWeakRefs | + HaveIter | + HaveClass | + HaveStacklessExtension | +#if (PYTHON25 || PYTHON26 || PYTHON27) + HaveIndex | +#endif + 0); + } + + + // This class defines the function prototypes (delegates) used for low + // level integration with the CPython runtime. It also provides name + // based lookup of the correct prototype for a particular Python type + // slot and utilities for generating method thunks for managed methods. + + internal class Interop { + + static ArrayList keepAlive; + static Hashtable pmap; + + static Interop() { + + // Here we build a mapping of PyTypeObject slot names to the + // appropriate prototype (delegate) type to use for the slot. + + Type[] items = typeof(Interop).GetNestedTypes(); + Hashtable p = new Hashtable(); + + for (int i = 0; i < items.Length; i++) { + Type item = items[i]; + p[item.Name] = item; + } + + keepAlive = new ArrayList(); + Marshal.AllocHGlobal(IntPtr.Size); + pmap = new Hashtable(); + + pmap["tp_dealloc"] = p["DestructorFunc"]; + pmap["tp_print"] = p["PrintFunc"]; + pmap["tp_getattr"] = p["BinaryFunc"]; + pmap["tp_setattr"] = p["ObjObjArgFunc"]; + pmap["tp_compare"] = p["ObjObjFunc"]; + pmap["tp_repr"] = p["UnaryFunc"]; + pmap["tp_hash"] = p["UnaryFunc"]; + pmap["tp_call"] = p["TernaryFunc"]; + pmap["tp_str"] = p["UnaryFunc"]; + pmap["tp_getattro"] = p["BinaryFunc"]; + pmap["tp_setattro"] = p["ObjObjArgFunc"]; + pmap["tp_traverse"] = p["ObjObjArgFunc"]; + pmap["tp_clear"] = p["InquiryFunc"]; + pmap["tp_richcompare"] = p["RichCmpFunc"]; + pmap["tp_iter"] = p["UnaryFunc"]; + pmap["tp_iternext"] = p["UnaryFunc"]; + pmap["tp_descr_get"] = p["TernaryFunc"]; + pmap["tp_descr_set"] = p["ObjObjArgFunc"]; + pmap["tp_init"] = p["ObjObjArgFunc"]; + pmap["tp_alloc"] = p["IntArgFunc"]; + pmap["tp_new"] = p["TernaryFunc"]; + pmap["tp_free"] = p["DestructorFunc"]; + pmap["tp_is_gc"] = p["InquiryFunc"]; + + pmap["nb_add"] = p["BinaryFunc"]; + pmap["nb_subtract"] = p["BinaryFunc"]; + pmap["nb_multiply"] = p["BinaryFunc"]; + pmap["nb_divide"] = p["BinaryFunc"]; + pmap["nb_remainder"] = p["BinaryFunc"]; + pmap["nb_divmod"] = p["BinaryFunc"]; + pmap["nb_power"] = p["TernaryFunc"]; + pmap["nb_negative"] = p["UnaryFunc"]; + pmap["nb_positive"] = p["UnaryFunc"]; + pmap["nb_absolute"] = p["UnaryFunc"]; + pmap["nb_nonzero"] = p["InquiryFunc"]; + pmap["nb_invert"] = p["UnaryFunc"]; + pmap["nb_lshift"] = p["BinaryFunc"]; + pmap["nb_rshift"] = p["BinaryFunc"]; + pmap["nb_and"] = p["BinaryFunc"]; + pmap["nb_xor"] = p["BinaryFunc"]; + pmap["nb_or"] = p["BinaryFunc"]; + pmap["nb_coerce"] = p["ObjObjFunc"]; + pmap["nb_int"] = p["UnaryFunc"]; + pmap["nb_long"] = p["UnaryFunc"]; + pmap["nb_float"] = p["UnaryFunc"]; + pmap["nb_oct"] = p["UnaryFunc"]; + pmap["nb_hex"] = p["UnaryFunc"]; + pmap["nb_inplace_add"] = p["BinaryFunc"]; + pmap["nb_inplace_subtract"] = p["BinaryFunc"]; + pmap["nb_inplace_multiply"] = p["BinaryFunc"]; + pmap["nb_inplace_divide"] = p["BinaryFunc"]; + pmap["nb_inplace_remainder"] = p["BinaryFunc"]; + pmap["nb_inplace_power"] = p["TernaryFunc"]; + pmap["nb_inplace_lshift"] = p["BinaryFunc"]; + pmap["nb_inplace_rshift"] = p["BinaryFunc"]; + pmap["nb_inplace_and"] = p["BinaryFunc"]; + pmap["nb_inplace_xor"] = p["BinaryFunc"]; + pmap["nb_inplace_or"] = p["BinaryFunc"]; + pmap["nb_floor_divide"] = p["BinaryFunc"]; + pmap["nb_true_divide"] = p["BinaryFunc"]; + pmap["nb_inplace_floor_divide"] = p["BinaryFunc"]; + pmap["nb_inplace_true_divide"] = p["BinaryFunc"]; +#if (PYTHON25 || PYTHON26 || PYTHON27) + pmap["nb_index"] = p["UnaryFunc"]; +#endif + + pmap["sq_length"] = p["InquiryFunc"]; + pmap["sq_concat"] = p["BinaryFunc"]; + pmap["sq_repeat"] = p["IntArgFunc"]; + pmap["sq_item"] = p["IntArgFunc"]; + pmap["sq_slice"] = p["IntIntArgFunc"]; + pmap["sq_ass_item"] = p["IntObjArgFunc"]; + pmap["sq_ass_slice"] = p["IntIntObjArgFunc"]; + pmap["sq_contains"] = p["ObjObjFunc"]; + pmap["sq_inplace_concat"] = p["BinaryFunc"]; + pmap["sq_inplace_repeat"] = p["IntArgFunc"]; + + pmap["mp_length"] = p["InquiryFunc"]; + pmap["mp_subscript"] = p["BinaryFunc"]; + pmap["mp_ass_subscript"] = p["ObjObjArgFunc"]; + + pmap["bf_getreadbuffer"] = p["IntObjArgFunc"]; + pmap["bf_getwritebuffer"] = p["IntObjArgFunc"]; + pmap["bf_getsegcount"] = p["ObjObjFunc"]; + pmap["bf_getcharbuffer"] = p["IntObjArgFunc"]; + + pmap["__import__"] = p["TernaryFunc"]; + } + + internal static Type GetPrototype(string name) { + return pmap[name] as Type; + } + + internal static IntPtr GetThunk(MethodInfo method) { + Type dt = Interop.GetPrototype(method.Name); + if (dt != null) { + IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size); + Delegate d = Delegate.CreateDelegate(dt, method); + Thunk cb = new Thunk(d); + Marshal.StructureToPtr(cb, tmp, false); + IntPtr fp = Marshal.ReadIntPtr(tmp, 0); + Marshal.FreeHGlobal(tmp); + keepAlive.Add(d); + return fp; + } + return IntPtr.Zero; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr UnaryFunc(IntPtr ob); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr BinaryFunc(IntPtr ob, IntPtr arg); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr TernaryFunc(IntPtr ob, IntPtr a1, IntPtr a2); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int InquiryFunc(IntPtr ob); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr IntArgFunc(IntPtr ob, int arg); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr IntIntArgFunc(IntPtr ob, int a1, int a2); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int IntObjArgFunc(IntPtr ob, int a1, IntPtr a2); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int IntIntObjArgFunc(IntPtr o, int a, int b, IntPtr c); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int ObjObjArgFunc(IntPtr o, IntPtr a, IntPtr b); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int ObjObjFunc(IntPtr ob, IntPtr arg); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void DestructorFunc(IntPtr ob); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate int PrintFunc(IntPtr ob, IntPtr a, int b); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr RichCmpFunc(IntPtr ob, IntPtr a, int b); + + } + + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)] + internal struct Thunk { + public Delegate fn; + + public Thunk(Delegate d) { + fn = d; + } + } + +} diff --git a/src/runtime/iterator.cs b/src/runtime/iterator.cs new file mode 100644 index 000000000..3d34760c3 --- /dev/null +++ b/src/runtime/iterator.cs @@ -0,0 +1,52 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Implements a generic Python iterator for IEnumerable objects and + // managed array objects. This supports 'for i in object:' in Python. + //======================================================================== + + internal class Iterator : ExtensionType { + + IEnumerator iter; + + public Iterator(IEnumerator e) : base() { + this.iter = e; + } + + + //==================================================================== + // Implements support for the Python iteration protocol. + //==================================================================== + + public static IntPtr tp_iternext(IntPtr ob) { + Iterator self = GetManagedObject(ob) as Iterator; + if (!self.iter.MoveNext()) { + Exceptions.SetError(Exceptions.StopIteration, Runtime.PyNone); + return IntPtr.Zero; + } + object item = self.iter.Current; + return Converter.ToPythonImplicit(item); + } + + public static IntPtr tp_iter(IntPtr ob) { + Runtime.Incref(ob); + return ob; + } + + } + + +} diff --git a/src/runtime/managedtype.cs b/src/runtime/managedtype.cs new file mode 100644 index 000000000..670bcd2b3 --- /dev/null +++ b/src/runtime/managedtype.cs @@ -0,0 +1,97 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Common base class for all objects that are implemented in managed + // code. It defines the common fields that associate CLR and Python + // objects and common utilities to convert between those identities. + //======================================================================== + + internal abstract class ManagedType { + + internal GCHandle gcHandle; // Native handle + internal IntPtr pyHandle; // PyObject * + internal IntPtr tpHandle; // PyType * + + + //==================================================================== + // Given a Python object, return the associated managed object or null. + //==================================================================== + + internal static ManagedType GetManagedObject(IntPtr ob) { + if (ob != IntPtr.Zero) { + IntPtr tp = Runtime.PyObject_TYPE(ob); + if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) { + tp = ob; + } + + int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + if ((flags & TypeFlags.Managed) != 0) { + IntPtr op = (tp == ob) ? + Marshal.ReadIntPtr(tp, TypeOffset.magic()) : + Marshal.ReadIntPtr(ob, ObjectOffset.magic()); + GCHandle gc = (GCHandle)op; + return (ManagedType)gc.Target; + } + + // In certain situations, we need to recognize a wrapped + // exception class and be willing to unwrap the class :( + + if (Runtime.wrap_exceptions) { + IntPtr e = Exceptions.UnwrapExceptionClass(ob); + if ((e != IntPtr.Zero) && (e != ob)) { + ManagedType m = GetManagedObject(e); + Runtime.Decref(e); + return m; + } + } + } + return null; + } + + + internal static ManagedType GetManagedObjectErr(IntPtr ob) { + ManagedType result = GetManagedObject(ob); + if (result == null) { + Exceptions.SetError(Exceptions.TypeError, + "invalid argument, expected CLR type" + ); + } + return result; + } + + + internal static bool IsManagedType(IntPtr ob) { + if (ob != IntPtr.Zero) { + IntPtr tp = Runtime.PyObject_TYPE(ob); + if (tp == Runtime.PyTypeType || tp == Runtime.PyCLRMetaType) { + tp = ob; + } + + int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + if ((flags & TypeFlags.Managed) != 0) { + return true; + } + } + return false; + } + + + } + + +} + diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs new file mode 100644 index 000000000..305437c84 --- /dev/null +++ b/src/runtime/metatype.cs @@ -0,0 +1,265 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // The managed metatype. This object implements the type of all reflected + // types. It also provides support for single-inheritance from reflected + // managed types. + //======================================================================== + + internal class MetaType : ManagedType { + + static IntPtr PyCLRMetaType; + + + //==================================================================== + // Metatype initialization. This bootstraps the CLR metatype to life. + //==================================================================== + + public static IntPtr Initialize() { + PyCLRMetaType = TypeManager.CreateMetaType(typeof(MetaType)); + return PyCLRMetaType; + } + + + //==================================================================== + // Metatype __new__ implementation. This is called to create a new + // class / type when a reflected class is subclassed. + //==================================================================== + + public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) { + int len = Runtime.PyTuple_Size(args); + if (len < 3) { + return Exceptions.RaiseTypeError("invalid argument list"); + } + + //IntPtr name = Runtime.PyTuple_GetItem(args, 0); + IntPtr bases = Runtime.PyTuple_GetItem(args, 1); + IntPtr dict = Runtime.PyTuple_GetItem(args, 2); + + // We do not support multiple inheritance, so the bases argument + // should be a 1-item tuple containing the type we are subtyping. + // That type must itself have a managed implementation. We check + // that by making sure its metatype is the CLR metatype. + + if (Runtime.PyTuple_Size(bases) != 1) { + return Exceptions.RaiseTypeError( + "cannot use multiple inheritance with managed classes" + ); + + } + + IntPtr base_type = Runtime.PyTuple_GetItem(bases, 0); + IntPtr mt = Runtime.PyObject_TYPE(base_type); + + if (!((mt == PyCLRMetaType) || (mt == Runtime.PyTypeType))) { + return Exceptions.RaiseTypeError("invalid metatype"); + } + + // Ensure that the reflected type is appropriate for subclassing, + // disallowing subclassing of delegates, enums and array types. + + ClassBase cb = GetManagedObject(base_type) as ClassBase; + if (cb != null) { + if (! cb.CanSubclass() ) { + return Exceptions.RaiseTypeError( + "delegates, enums and array types cannot be subclassed" + ); + } + } + + IntPtr slots = Runtime.PyDict_GetItemString(dict, "__slots__"); + if (slots != IntPtr.Zero) { + return Exceptions.RaiseTypeError( + "subclasses of managed classes do not support __slots__" + ); + } + + // hack for now... fix for 1.0 + //return TypeManager.CreateSubType(args); + + + // right way + + IntPtr func = Marshal.ReadIntPtr(Runtime.PyTypeType, + TypeOffset.tp_new); + IntPtr type = NativeCall.Call_3(func, tp, args, kw); + if (type == IntPtr.Zero) { + return IntPtr.Zero; + } + + int flags = TypeFlags.Default; + flags |= TypeFlags.Managed; + flags |= TypeFlags.HeapType; + flags |= TypeFlags.BaseType; + flags |= TypeFlags.Subclass; + flags |= TypeFlags.HaveGC; + Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + + TypeManager.CopySlot(base_type, type, TypeOffset.tp_dealloc); + + // Hmm - the standard subtype_traverse, clear look at ob_size to + // do things, so to allow gc to work correctly we need to move + // our hidden handle out of ob_size. Then, in theory we can + // comment this out and still not crash. + TypeManager.CopySlot(base_type, type, TypeOffset.tp_traverse); + TypeManager.CopySlot(base_type, type, TypeOffset.tp_clear); + + + // for now, move up hidden handle... + IntPtr gc = Marshal.ReadIntPtr(base_type, TypeOffset.magic()); + Marshal.WriteIntPtr(type, TypeOffset.magic(), gc); + + //DebugUtil.DumpType(base_type); + //DebugUtil.DumpType(type); + + return type; + } + + + public static IntPtr tp_alloc(IntPtr mt, int n) { + IntPtr type = Runtime.PyType_GenericAlloc(mt, n); + return type; + } + + + public static void tp_free(IntPtr tp) { + Runtime.PyObject_GC_Del(tp); + } + + + //==================================================================== + // Metatype __call__ implementation. This is needed to ensure correct + // initialization (__init__ support), because the tp_call we inherit + // from PyType_Type won't call __init__ for metatypes it doesnt know. + //==================================================================== + + public static IntPtr tp_call(IntPtr tp, IntPtr args, IntPtr kw) { + IntPtr func = Marshal.ReadIntPtr(tp, TypeOffset.tp_new); + if (func == IntPtr.Zero) { + return Exceptions.RaiseTypeError("invalid object"); + } + + IntPtr obj = NativeCall.Call_3(func, tp, args, kw); + if (obj == IntPtr.Zero) { + return IntPtr.Zero; + } + + IntPtr py__init__ = Runtime.PyString_FromString("__init__"); + IntPtr type = Runtime.PyObject_TYPE(obj); + IntPtr init = Runtime._PyType_Lookup(type, py__init__); + Runtime.Decref(py__init__); + Runtime.PyErr_Clear(); + + if (init != IntPtr.Zero) { + IntPtr bound = Runtime.GetBoundArgTuple(obj, args); + if (bound == IntPtr.Zero) { + Runtime.Decref(obj); + return IntPtr.Zero; + } + + IntPtr result = Runtime.PyObject_Call(init, bound, kw); + Runtime.Decref(bound); + + if (result == IntPtr.Zero) { + Runtime.Decref(obj); + return IntPtr.Zero; + } + + Runtime.Decref(result); + } + + return obj; + } + + + //==================================================================== + // Type __setattr__ implementation for reflected types. Note that this + // is slightly different than the standard setattr implementation for + // the normal Python metatype (PyTypeType). We need to look first in + // the type object of a reflected type for a descriptor in order to + // support the right setattr behavior for static fields and properties. + //==================================================================== + + public static int tp_setattro(IntPtr tp, IntPtr name, IntPtr value) { + IntPtr descr = Runtime._PyType_Lookup(tp, name); + + if (descr != IntPtr.Zero) { + IntPtr dt = Runtime.PyObject_TYPE(descr); + IntPtr fp = Marshal.ReadIntPtr(dt, TypeOffset.tp_descr_set); + if (fp != IntPtr.Zero) { + return NativeCall.Impl.Int_Call_3(fp, descr, name, value); + } + Exceptions.SetError(Exceptions.AttributeError, + "attribute is read-only"); + return -1; + } + + if (Runtime.PyObject_GenericSetAttr(tp, name, value) < 0) { + return -1; + } + + return 0; + } + + //==================================================================== + // The metatype has to implement [] semantics for generic types, so + // here we just delegate to the generic type def implementation. Its + // own mp_subscript + //==================================================================== + public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { + ClassBase cb = GetManagedObject(tp) as ClassBase; + if (cb != null) { + return cb.type_subscript(idx); + } + return Exceptions.RaiseTypeError("unsubscriptable object"); + } + + //==================================================================== + // Dealloc implementation. This is called when a Python type generated + // by this metatype is no longer referenced from the Python runtime. + //==================================================================== + + public static void tp_dealloc(IntPtr tp) { + // Fix this when we dont cheat on the handle for subclasses! + + int flags = (int)Marshal.ReadIntPtr(tp, TypeOffset.tp_flags); + if ((flags & TypeFlags.Subclass) == 0) { + IntPtr gc = Marshal.ReadIntPtr(tp, TypeOffset.magic()); + ((GCHandle)gc).Free(); + } + + IntPtr op = Marshal.ReadIntPtr(tp, TypeOffset.ob_type); + Runtime.Decref(op); + + // Delegate the rest of finalization the Python metatype. Note + // that the PyType_Type implementation of tp_dealloc will call + // tp_free on the type of the type being deallocated - in this + // case our CLR metatype. That is why we implement tp_free. + + op = Marshal.ReadIntPtr(Runtime.PyTypeType, TypeOffset.tp_dealloc); + NativeCall.Void_Call_1(op, tp); + + return; + } + + + + + } + + +} diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs new file mode 100644 index 000000000..80d3968fd --- /dev/null +++ b/src/runtime/methodbinder.cs @@ -0,0 +1,465 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // A MethodBinder encapsulates information about a (possibly overloaded) + // managed method, and is responsible for selecting the right method given + // a set of Python arguments. This is also used as a base class for the + // ConstructorBinder, a minor variation used to invoke constructors. + //======================================================================== + + internal class MethodBinder { + + public ArrayList list; + public MethodBase[] methods; + public bool init = false; + public bool allow_threads = true; + + internal MethodBinder () { + this.list = new ArrayList(); + } + + internal MethodBinder(MethodInfo mi) : base () { + this.list = new ArrayList(); + this.list.Add(mi); + } + + public int Count { + get { return this.list.Count; } + } + + internal void AddMethod(MethodBase m) { + this.list.Add(m); + } + + //==================================================================== + // Given a sequence of MethodInfo and a sequence of types, return the + // MethodInfo that matches the signature represented by those types. + //==================================================================== + + internal static MethodInfo MatchSignature(MethodInfo[] mi, Type[] tp) { + int count = tp.Length; + for (int i = 0; i < mi.Length; i++) { + ParameterInfo[] pi = mi[i].GetParameters(); + if (pi.Length != count) { + continue; + } + for (int n = 0; n < pi.Length; n++) { + if (tp[n]!= pi[n].ParameterType) { + break; + } + if (n == (pi.Length - 1)) { + return mi[i]; + } + } + } + return null; + } + + //==================================================================== + // Given a sequence of MethodInfo and a sequence of type parameters, + // return the MethodInfo that represents the matching closed generic. + //==================================================================== + + internal static MethodInfo MatchParameters(MethodInfo[] mi,Type[] tp) { + int count = tp.Length; + for (int i = 0; i < mi.Length; i++) { + if (!mi[i].IsGenericMethodDefinition) { + continue; + } + Type[] args = mi[i].GetGenericArguments(); + if (args.Length != count) { + continue; + } + return mi[i].MakeGenericMethod(tp); + } + return null; + } + + + //==================================================================== + // Given a sequence of MethodInfo and two sequences of type parameters, + // return the MethodInfo that matches the signature and the closed generic. + //==================================================================== + + internal static MethodInfo MatchSignatureAndParameters(MethodInfo[] mi, Type[] genericTp, Type[] sigTp) + { + int genericCount = genericTp.Length; + int signatureCount = sigTp.Length; + for (int i = 0; i < mi.Length; i++) + { + if (!mi[i].IsGenericMethodDefinition) + { + continue; + } + Type[] genericArgs = mi[i].GetGenericArguments(); + if (genericArgs.Length != genericCount) + { + continue; + } + ParameterInfo[] pi = mi[i].GetParameters(); + if (pi.Length != signatureCount) + { + continue; + } + for (int n = 0; n < pi.Length; n++) + { + if (sigTp[n] != pi[n].ParameterType) + { + break; + } + if (n == (pi.Length - 1)) + { + MethodInfo match = mi[i]; + if (match.IsGenericMethodDefinition) + { + Type[] typeArgs = match.GetGenericArguments(); + return match.MakeGenericMethod(genericTp); + } + return match; + } + } + } + return null; + } + + + //==================================================================== + // Return the array of MethodInfo for this method. The result array + // is arranged in order of precendence (done lazily to avoid doing it + // at all for methods that are never called). + //==================================================================== + + internal MethodBase[] GetMethods() { + if (!init) { + // I'm sure this could be made more efficient. + list.Sort(new MethodSorter()); + methods = (MethodBase[])list.ToArray(typeof(MethodBase)); + init = true; + } + return methods; + } + + //==================================================================== + // Precedence algorithm largely lifted from jython - the concerns are + // generally the same so we'll start w/this and tweak as necessary. + //==================================================================== + + internal static int GetPrecedence(MethodBase mi) { + ParameterInfo[] pi = mi.GetParameters(); + int val = mi.IsStatic ? 3000 : 0; + int num = pi.Length; + + val += (mi.IsGenericMethod ? 1 : 0); + for (int i = 0; i < num; i++) { + val += ArgPrecedence(pi[i].ParameterType); + } + + return val; + } + + //==================================================================== + // Return a precedence value for a particular Type object. + //==================================================================== + + internal static int ArgPrecedence(Type t) { + Type objectType = typeof(Object); + if (t == objectType) return 3000; + + TypeCode tc = Type.GetTypeCode(t); + if (tc == TypeCode.Object) return 1; + if (tc == TypeCode.UInt64) return 10; + if (tc == TypeCode.UInt32) return 11; + if (tc == TypeCode.UInt16) return 12; + if (tc == TypeCode.Int64) return 13; + if (tc == TypeCode.Int32) return 14; + if (tc == TypeCode.Int16) return 15; + if (tc == TypeCode.Char) return 16; + if (tc == TypeCode.SByte) return 17; + if (tc == TypeCode.Byte) return 18; + if (tc == TypeCode.Single) return 20; + if (tc == TypeCode.Double) return 21; + if (tc == TypeCode.String) return 30; + if (tc == TypeCode.Boolean) return 40; + + if (t.IsArray) { + Type e = t.GetElementType(); + if (e == objectType) + return 2500; + return 100 + ArgPrecedence(e); + } + + return 2000; + } + + //==================================================================== + // Bind the given Python instance and arguments to a particular method + // overload and return a structure that contains the converted Python + // instance, converted arguments and the correct method to call. + //==================================================================== + + internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw) { + return this.Bind(inst, args, kw, null, null); + } + + internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, + MethodBase info) { + return this.Bind(inst, args, kw, info, null); + } + + internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, + MethodBase info, MethodInfo[] methodinfo) { + // loop to find match, return invoker w/ or /wo error + MethodBase[] _methods = null; + int pynargs = Runtime.PyTuple_Size(args); + object arg; + bool isGeneric = false; + + if (info != null) { + _methods = (MethodBase[])Array.CreateInstance( + typeof(MethodBase), 1 + ); + _methods.SetValue(info, 0); + } + else { + _methods = GetMethods(); + } + + for (int i = 0; i < _methods.Length; i++) { + MethodBase mi = _methods[i]; + if (mi.IsGenericMethod) { isGeneric = true; } + ParameterInfo[] pi = mi.GetParameters(); + int clrnargs = pi.Length; + bool match = false; + int arrayStart = -1; + int outs = 0; + + if (pynargs == clrnargs) { + match = true; + } else if ((pynargs > clrnargs) && (clrnargs > 0) && + (pi[clrnargs-1].ParameterType.IsArray)) { + // The last argument of the mananged functions seems to + // accept multiple arguments as a array. Hopefully it's a + // spam(params object[] egg) style method + match = true; + arrayStart = clrnargs - 1; + } + + if (match) { + Object[] margs = new Object[clrnargs]; + + for (int n = 0; n < clrnargs; n++) { + IntPtr op; + if (arrayStart == n) { + // map remaining Python arguments to a tuple since + // the managed function accepts it - hopefully :] + op = Runtime.PyTuple_GetSlice(args, arrayStart, pynargs); + } + else { + op = Runtime.PyTuple_GetItem(args, n); + } + Type type = pi[n].ParameterType; + if (pi[n].IsOut || type.IsByRef) { + outs++; + } + + if (!Converter.ToManaged(op, type, out arg, false)) { + Exceptions.Clear(); + margs = null; + break; + } + if (arrayStart == n) { + // GetSlice() creates a new reference but GetItem() + // returns only a borrow reference. + Runtime.Decref(op); + } + margs[n] = arg; + } + + if (margs == null) { + continue; + } + + Object target = null; + if ((!mi.IsStatic) && (inst != IntPtr.Zero)) { + //CLRObject co = (CLRObject)ManagedType.GetManagedObject(inst); + // InvalidCastException: Unable to cast object of type + // 'Python.Runtime.ClassObject' to type 'Python.Runtime.CLRObject' + CLRObject co = ManagedType.GetManagedObject(inst) as CLRObject; + + // Sanity check: this ensures a graceful exit if someone does + // something intentionally wrong like call a non-static method + // on the class rather than on an instance of the class. + // XXX maybe better to do this before all the other rigmarole. + if (co == null) { + return null; + } + target = co.inst; + } + + return new Binding(mi, target, margs, outs); + } + } + // We weren't able to find a matching method but at least one + // is a generic method and info is null. That happens when a generic + // method was not called using the [] syntax. Let's introspect the + // type of the arguments and use it to construct the correct method. + if (isGeneric && (info == null) && (methodinfo != null)) + { + Type[] types = Runtime.PythonArgsToTypeArray(args, true); + MethodInfo mi = MethodBinder.MatchParameters(methodinfo, types); + return Bind(inst, args, kw, mi, null); + } + return null; + } + + internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) { + return this.Invoke(inst, args, kw, null, null); + + } + + internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, + MethodBase info) { + return this.Invoke(inst, args, kw, info, null); + } + + internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, + MethodBase info, MethodInfo[] methodinfo) { + Binding binding = this.Bind(inst, args, kw, info, methodinfo); + Object result; + IntPtr ts = IntPtr.Zero; + + if (binding == null) { + Exceptions.SetError(Exceptions.TypeError, + "No method matches given arguments" + ); + return IntPtr.Zero; + } + + if (allow_threads) { + ts = PythonEngine.BeginAllowThreads(); + } + + try { + result = binding.info.Invoke(binding.inst, + BindingFlags.Default, + null, + binding.args, + null); + } + catch (Exception e) { + if (e.InnerException != null) { + e = e.InnerException; + } + if (allow_threads) { + PythonEngine.EndAllowThreads(ts); + } + Exceptions.SetError(e); + return IntPtr.Zero; + } + + if (allow_threads) { + PythonEngine.EndAllowThreads(ts); + } + + // If there are out parameters, we return a tuple containing + // the result followed by the out parameters. If there is only + // one out parameter and the return type of the method is void, + // we return the out parameter as the result to Python (for + // code compatibility with ironpython). + + MethodInfo mi = (MethodInfo)binding.info; + + if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) { + + } + + if (binding.outs > 0) { + ParameterInfo[] pi = mi.GetParameters(); + int c = pi.Length; + int n = 0; + + IntPtr t = Runtime.PyTuple_New(binding.outs + 1); + IntPtr v = Converter.ToPython(result, mi.ReturnType); + Runtime.PyTuple_SetItem(t, n, v); + n++; + + for (int i=0; i < c; i++) { + Type pt = pi[i].ParameterType; + if (pi[i].IsOut || pt.IsByRef) { + v = Converter.ToPython(binding.args[i], pt); + Runtime.PyTuple_SetItem(t, n, v); + n++; + } + } + + if ((binding.outs == 1) && (mi.ReturnType == typeof(void))) { + v = Runtime.PyTuple_GetItem(t, 1); + Runtime.Incref(v); + Runtime.Decref(t); + return v; + } + + return t; + } + + return Converter.ToPython(result, mi.ReturnType); + } + + } + + + + //======================================================================== + // Utility class to sort method info by parameter type precedence. + //======================================================================== + + internal class MethodSorter : IComparer { + + int IComparer.Compare(Object m1, Object m2) { + int p1 = MethodBinder.GetPrecedence((MethodBase)m1); + int p2 = MethodBinder.GetPrecedence((MethodBase)m2); + if (p1 < p2) return -1; + if (p1 > p2) return 1; + return 0; + } + + } + + + //======================================================================== + // A Binding is a utility instance that bundles together a MethodInfo + // representing a method to call, a (possibly null) target instance for + // the call, and the arguments for the call (all as managed values). + //======================================================================== + + internal class Binding { + + public MethodBase info; + public Object[] args; + public Object inst; + public int outs; + + internal Binding(MethodBase info, Object inst, Object[] args, + int outs) { + this.info = info; + this.inst = inst; + this.args = args; + this.outs = outs; + } + + } + +} diff --git a/src/runtime/methodbinding.cs b/src/runtime/methodbinding.cs new file mode 100644 index 000000000..0459d36b2 --- /dev/null +++ b/src/runtime/methodbinding.cs @@ -0,0 +1,193 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python binding type for CLR methods. These work much like + // standard Python method bindings, but the same type is used to bind + // both static and instance methods. + //======================================================================== + + internal class MethodBinding : ExtensionType { + + internal MethodInfo info; + internal MethodObject m; + internal IntPtr target; + + public MethodBinding(MethodObject m, IntPtr target) : base() { + Runtime.Incref(target); + this.target = target; + this.info = null; + this.m = m; + } + + //==================================================================== + // Implement binding of generic methods using the subscript syntax []. + //==================================================================== + + public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { + MethodBinding self = (MethodBinding)GetManagedObject(tp); + + Type[] types = Runtime.PythonArgsToTypeArray(idx); + if (types == null) { + return Exceptions.RaiseTypeError("type(s) expected"); + } + + MethodInfo mi = MethodBinder.MatchParameters(self.m.info, types); + if (mi == null) { + string e = "No match found for given type params"; + return Exceptions.RaiseTypeError(e); + } + + MethodBinding mb = new MethodBinding(self.m, self.target); + mb.info = mi; + Runtime.Incref(mb.pyHandle); + return mb.pyHandle; + } + + + //==================================================================== + // MethodBinding __getattribute__ implementation. + //==================================================================== + + public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { + MethodBinding self = (MethodBinding)GetManagedObject(ob); + + if (!Runtime.PyString_Check(key)) { + Exceptions.SetError(Exceptions.TypeError, "string expected"); + return IntPtr.Zero; + } + + string name = Runtime.GetManagedString(key); + if (name == "__doc__") { + IntPtr doc = self.m.GetDocString(); + Runtime.Incref(doc); + return doc; + } + + // XXX deprecate __overloads__ soon... + if (name == "__overloads__" || name == "Overloads") { + OverloadMapper om = new OverloadMapper(self.m, self.target); + Runtime.Incref(om.pyHandle); + return om.pyHandle; + } + + return Runtime.PyObject_GenericGetAttr(ob, key); + } + + + //==================================================================== + // MethodBinding __call__ implementation. + //==================================================================== + + public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) { + MethodBinding self = (MethodBinding)GetManagedObject(ob); + + // This works around a situation where the wrong generic method is picked, + // for example this method in the tests: string Overloaded(int arg1, int arg2, string arg3) + if (self.info != null) + { + if (self.info.IsGenericMethod) + { + int len = Runtime.PyTuple_Size(args); + Type[] sigTp = Runtime.PythonArgsToTypeArray(args, true); + if (sigTp != null) + { + Type[] genericTp = self.info.GetGenericArguments(); + MethodInfo betterMatch = MethodBinder.MatchSignatureAndParameters(self.m.info, genericTp, sigTp); + if (betterMatch != null) self.info = betterMatch; + } + } + } + + // This supports calling a method 'unbound', passing the instance + // as the first argument. Note that this is not supported if any + // of the overloads are static since we can't know if the intent + // was to call the static method or the unbound instance method. + + if ((self.target == IntPtr.Zero) && (!self.m.IsStatic())) + { + int len = Runtime.PyTuple_Size(args); + if (len < 1) + { + Exceptions.SetError(Exceptions.TypeError, "not enough arguments"); + return IntPtr.Zero; + } + IntPtr uargs = Runtime.PyTuple_GetSlice(args, 1, len); + IntPtr inst = Runtime.PyTuple_GetItem(args, 0); + Runtime.Incref(inst); + IntPtr r = self.m.Invoke(inst, uargs, kw, self.info); + Runtime.Decref(inst); + Runtime.Decref(uargs); + return r; + } + + return self.m.Invoke(self.target, args, kw, self.info); + } + + + //==================================================================== + // MethodBinding __hash__ implementation. + //==================================================================== + + public static IntPtr tp_hash(IntPtr ob) { + MethodBinding self = (MethodBinding)GetManagedObject(ob); + long x = 0; + long y = 0; + + if (self.target != IntPtr.Zero) { + x = Runtime.PyObject_Hash(self.target).ToInt64(); + if (x == -1) { + return new IntPtr(-1); + } + } + + y = Runtime.PyObject_Hash(self.m.pyHandle).ToInt64(); + if (y == -1) { + return new IntPtr(-1); + } + + x ^= y; + + if (x == -1) { + x = -1; + } + + return new IntPtr(x); + } + + //==================================================================== + // MethodBinding __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + MethodBinding self = (MethodBinding)GetManagedObject(ob); + string type = (self.target == IntPtr.Zero) ? "unbound" : "bound"; + string s = String.Format("<{0} method '{1}'>", type, self.m.name); + return Runtime.PyString_FromStringAndSize(s, s.Length); + } + + //==================================================================== + // MethodBinding dealloc implementation. + //==================================================================== + + public static new void tp_dealloc(IntPtr ob) { + MethodBinding self = (MethodBinding)GetManagedObject(ob); + Runtime.Decref(self.target); + ExtensionType.FinalizeObject(self); + } + + } + + +} diff --git a/src/runtime/methodobject.cs b/src/runtime/methodobject.cs new file mode 100644 index 000000000..15a5cd547 --- /dev/null +++ b/src/runtime/methodobject.cs @@ -0,0 +1,189 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python type that represents a CLR method. Method objects + // support a subscript syntax [] to allow explicit overload selection. + //======================================================================== + // TODO: ForbidPythonThreadsAttribute per method info + + internal class MethodObject : ExtensionType { + + internal MethodInfo[] info; + internal string name; + internal MethodBinding unbound; + internal MethodBinder binder; + internal bool is_static = false; + internal IntPtr doc; + + public MethodObject(string name, MethodInfo[] info) : base() { + _MethodObject(name, info); + } + + public MethodObject(string name, MethodInfo[] info, bool allow_threads) : base() + { + _MethodObject(name, info); + binder.allow_threads = allow_threads; + } + + private void _MethodObject(string name, MethodInfo[] info) + { + this.name = name; + this.info = info; + binder = new MethodBinder(); + for (int i = 0; i < info.Length; i++) + { + MethodInfo item = (MethodInfo)info[i]; + binder.AddMethod(item); + if (item.IsStatic) + { + this.is_static = true; + } + } + } + + public virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) { + return this.Invoke(inst, args, kw, null); + } + + public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw, + MethodBase info) { + return binder.Invoke(target, args, kw, info, this.info); + } + + //==================================================================== + // Helper to get docstrings from reflected method / param info. + //==================================================================== + + internal IntPtr GetDocString() { + if (doc != IntPtr.Zero) { + return doc; + } + string str = ""; + Type marker = typeof(DocStringAttribute); + MethodBase[] methods = binder.GetMethods(); + foreach (MethodBase method in methods) { + if (str.Length > 0) + str += Environment.NewLine; + Attribute[] attrs = (Attribute[]) method.GetCustomAttributes(marker, false); + if (attrs.Length == 0) { + str += method.ToString(); + } + else { + DocStringAttribute attr = (DocStringAttribute)attrs[0]; + str += attr.DocString; + } + } + doc = Runtime.PyString_FromString(str); + return doc; + } + + + //==================================================================== + // This is a little tricky: a class can actually have a static method + // and instance methods all with the same name. That makes it tough + // to support calling a method 'unbound' (passing the instance as the + // first argument), because in this case we can't know whether to call + // the instance method unbound or call the static method. + // + // The rule we is that if there are both instance and static methods + // with the same name, then we always call the static method. So this + // method returns true if any of the methods that are represented by + // the descriptor are static methods (called by MethodBinding). + //==================================================================== + + internal bool IsStatic() { + return this.is_static; + } + + //==================================================================== + // Descriptor __getattribute__ implementation. + //==================================================================== + + public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { + MethodObject self = (MethodObject)GetManagedObject(ob); + + if (!Runtime.PyString_Check(key)) { + return Exceptions.RaiseTypeError("string expected"); + } + + string name = Runtime.GetManagedString(key); + if (name == "__doc__") { + IntPtr doc = self.GetDocString(); + Runtime.Incref(doc); + return doc; + } + + return Runtime.PyObject_GenericGetAttr(ob, key); + } + + //==================================================================== + // Descriptor __get__ implementation. Accessing a CLR method returns + // a "bound" method similar to a Python bound method. + //==================================================================== + + public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { + MethodObject self = (MethodObject)GetManagedObject(ds); + MethodBinding binding; + + // If the method is accessed through its type (rather than via + // an instance) we return an 'unbound' MethodBinding that will + // cached for future accesses through the type. + + if (ob == IntPtr.Zero) { + if (self.unbound == null) { + self.unbound = new MethodBinding(self, IntPtr.Zero); + } + binding = self.unbound; + Runtime.Incref(binding.pyHandle);; + return binding.pyHandle; + } + + if (Runtime.PyObject_IsInstance(ob, tp) < 1) { + return Exceptions.RaiseTypeError("invalid argument"); + } + + binding = new MethodBinding(self, ob); + return binding.pyHandle; + } + + //==================================================================== + // Descriptor __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + MethodObject self = (MethodObject)GetManagedObject(ob); + string s = String.Format("", self.name); + return Runtime.PyString_FromStringAndSize(s, s.Length); + } + + //==================================================================== + // Descriptor dealloc implementation. + //==================================================================== + + public static new void tp_dealloc(IntPtr ob) { + MethodObject self = (MethodObject)GetManagedObject(ob); + Runtime.Decref(self.doc); + if (self.unbound != null) { + Runtime.Decref(self.unbound.pyHandle); + } + ExtensionType.FinalizeObject(self); + } + + + } + + +} diff --git a/src/runtime/methodwrapper.cs b/src/runtime/methodwrapper.cs new file mode 100644 index 000000000..04a49d592 --- /dev/null +++ b/src/runtime/methodwrapper.cs @@ -0,0 +1,61 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// A MethodWrapper wraps a static method of a managed type, + /// making it callable by Python as a PyCFunction object. This is + /// currently used mainly to implement special cases like the CLR + /// import hook. + /// + + internal class MethodWrapper { + + public IntPtr mdef; + public IntPtr ptr; + + public MethodWrapper(Type type, string name) { + + // Turn the managed method into a function pointer + + IntPtr fp = Interop.GetThunk(type.GetMethod(name)); + + // XXX - here we create a Python string object, then take the + // char * of the internal string to pass to our methoddef + // structure. Its a hack, and the name is leaked! + + IntPtr ps = Runtime.PyString_FromString(name); + IntPtr sp = Runtime.PyString_AS_STRING(ps); + + // Allocate and initialize a PyMethodDef structure to represent + // the managed method, then create a PyCFunction. + + mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size); + Marshal.WriteIntPtr(mdef, sp); + Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), fp); + Marshal.WriteIntPtr(mdef, (2 * IntPtr.Size), (IntPtr)0x0002); + Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), IntPtr.Zero); + ptr = Runtime.PyCFunction_New(mdef, IntPtr.Zero); + } + + public IntPtr Call(IntPtr args, IntPtr kw) { + return Runtime.PyCFunction_Call(ptr, args, kw); + } + + + } + + +} + diff --git a/src/runtime/modulefunctionobject.cs b/src/runtime/modulefunctionobject.cs new file mode 100644 index 000000000..5c9a4de21 --- /dev/null +++ b/src/runtime/modulefunctionobject.cs @@ -0,0 +1,58 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime +{ + /// + /// Module level functions + /// + internal class ModuleFunctionObject : MethodObject + { + + public ModuleFunctionObject(string name, MethodInfo[] info, bool allow_threads) + : base(name, info, allow_threads) + { + for (int i = 0; i < info.Length; i++) + { + MethodInfo item = (MethodInfo)info[i]; + if (!item.IsStatic) + { + throw new Exception("Module function must be static."); + } + } + } + + //==================================================================== + // __call__ implementation. + //==================================================================== + + public static IntPtr tp_call(IntPtr ob, IntPtr args, IntPtr kw) + { + ModuleFunctionObject self = (ModuleFunctionObject)GetManagedObject(ob); + return self.Invoke(ob, args, kw); + } + + //==================================================================== + // __repr__ implementation. + //==================================================================== + + public static new IntPtr tp_repr(IntPtr ob) + { + ModuleFunctionObject self = (ModuleFunctionObject)GetManagedObject(ob); + string s = String.Format("", self.name); + return Runtime.PyString_FromStringAndSize(s, s.Length); + } + + } +} + diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs new file mode 100644 index 000000000..c5735ca4a --- /dev/null +++ b/src/runtime/moduleobject.cs @@ -0,0 +1,430 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections.Specialized; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python type that provides access to CLR namespaces. The + // type behaves like a Python module, and can contain other sub-modules. + //======================================================================== + + internal class ModuleObject : ExtensionType { + + Dictionary cache; + internal string moduleName; + internal IntPtr dict; + protected string _namespace; + + public ModuleObject(string name) : base() { + if (name == String.Empty) + { + throw new ArgumentException("Name must not be empty!"); + } + moduleName = name; + cache = new Dictionary(); + _namespace = name; + + dict = Runtime.PyDict_New(); + IntPtr pyname = Runtime.PyString_FromString(moduleName); + Runtime.PyDict_SetItemString(dict, "__name__", pyname); + Runtime.PyDict_SetItemString(dict, "__file__", Runtime.PyNone); + Runtime.PyDict_SetItemString(dict, "__doc__", Runtime.PyNone); + Runtime.Decref(pyname); + + Marshal.WriteIntPtr(this.pyHandle, ObjectOffset.ob_dict, dict); + + InitializeModuleMembers(); + } + + + //=================================================================== + // Returns a ClassBase object representing a type that appears in + // this module's namespace or a ModuleObject representing a child + // namespace (or null if the name is not found). This method does + // not increment the Python refcount of the returned object. + //=================================================================== + + public ManagedType GetAttribute(string name, bool guess) { + ManagedType cached = null; + this.cache.TryGetValue(name, out cached); + if (cached != null) { + return cached; + } + + ModuleObject m; + ClassBase c; + Type type; + + //if (AssemblyManager.IsValidNamespace(name)) + //{ + // IntPtr py_mod_name = Runtime.PyString_FromString(name); + // IntPtr modules = Runtime.PyImport_GetModuleDict(); + // IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name); + // if (module != IntPtr.Zero) + // return (ManagedType)this; + // return null; + //} + + string qname = (_namespace == String.Empty) ? name : + _namespace + "." + name; + + // If the fully-qualified name of the requested attribute is + // a namespace exported by a currently loaded assembly, return + // a new ModuleObject representing that namespace. + + if (AssemblyManager.IsValidNamespace(qname)) { + m = new ModuleObject(qname); + StoreAttribute(name, m); + return (ManagedType) m; + } + + // Look for a type in the current namespace. Note that this + // includes types, delegates, enums, interfaces and structs. + // Only public namespace members are exposed to Python. + + type = AssemblyManager.LookupType(qname); + if (type != null) { + if (!type.IsPublic) { + return null; + } + c = ClassManager.GetClass(type); + StoreAttribute(name, c); + return (ManagedType) c; + } + + // This is a little repetitive, but it ensures that the right + // thing happens with implicit assembly loading at a reasonable + // cost. Ask the AssemblyManager to do implicit loading for each + // of the steps in the qualified name, then try it again. + bool ignore = name.StartsWith("__"); + if (AssemblyManager.LoadImplicit(qname, !ignore)) { + if (AssemblyManager.IsValidNamespace(qname)) { + m = new ModuleObject(qname); + StoreAttribute(name, m); + return (ManagedType) m; + } + + type = AssemblyManager.LookupType(qname); + if (type != null) { + if (!type.IsPublic) { + return null; + } + c = ClassManager.GetClass(type); + StoreAttribute(name, c); + return (ManagedType) c; + } + } + + // We didn't find the name, so we may need to see if there is a + // generic type with this base name. If so, we'll go ahead and + // return it. Note that we store the mapping of the unmangled + // name to generic type - it is technically possible that some + // future assembly load could contribute a non-generic type to + // the current namespace with the given basename, but unlikely + // enough to complicate the implementation for now. + + if (guess) { + string gname = GenericUtil.GenericNameForBaseName( + _namespace, name); + if (gname != null) { + ManagedType o = GetAttribute(gname, false); + if (o != null) { + StoreAttribute(name, o); + return o; + } + } + } + + return null; + } + + + //=================================================================== + // Stores an attribute in the instance dict for future lookups. + //=================================================================== + + private void StoreAttribute(string name, ManagedType ob) { + Runtime.PyDict_SetItemString(dict, name, ob.pyHandle); + cache[name] = ob; + } + + + //=================================================================== + // Preloads all currently-known names for the module namespace. This + // can be called multiple times, to add names from assemblies that + // may have been loaded since the last call to the method. + //=================================================================== + + public void LoadNames() { + ManagedType m = null; + foreach (string name in AssemblyManager.GetNames(_namespace)) { + this.cache.TryGetValue(name, out m); + if (m == null) { + ManagedType attr = this.GetAttribute(name, true); + if (Runtime.wrap_exceptions) { + if (attr is ExceptionClassObject) { + ExceptionClassObject c = attr as ExceptionClassObject; + if (c != null) { + IntPtr p = attr.pyHandle; + IntPtr r =Exceptions.GetExceptionClassWrapper(p); + Runtime.PyDict_SetItemString(dict, name, r); + Runtime.Incref(r); + + } + } + } + } + } + } + + /// + /// Initialize module level functions and attributes + /// + internal void InitializeModuleMembers() + { + Type funcmarker = typeof(ModuleFunctionAttribute); + Type propmarker = typeof(ModulePropertyAttribute); + Type ftmarker = typeof(ForbidPythonThreadsAttribute); + Type type = this.GetType(); + + BindingFlags flags = BindingFlags.Public | BindingFlags.Static; + + while (type != null) + { + MethodInfo[] methods = type.GetMethods(flags); + for (int i = 0; i < methods.Length; i++) + { + MethodInfo method = methods[i]; + object[] attrs = method.GetCustomAttributes(funcmarker, false); + object[] forbid = method.GetCustomAttributes(ftmarker, false); + bool allow_threads = (forbid.Length == 0); + if (attrs.Length > 0) + { + string name = method.Name; + MethodInfo[] mi = new MethodInfo[1]; + mi[0] = method; + ModuleFunctionObject m = new ModuleFunctionObject(name, mi, allow_threads); + StoreAttribute(name, m); + } + } + + PropertyInfo[] properties = type.GetProperties(); + for (int i = 0; i < properties.Length; i++) + { + PropertyInfo property = properties[i]; + object[] attrs = property.GetCustomAttributes(propmarker, false); + if (attrs.Length > 0) + { + string name = property.Name; + ModulePropertyObject p = new ModulePropertyObject(property); + StoreAttribute(name, p); + } + } + type = type.BaseType; + } + } + + + //==================================================================== + // ModuleObject __getattribute__ implementation. Module attributes + // are always either classes or sub-modules representing subordinate + // namespaces. CLR modules implement a lazy pattern - the sub-modules + // and classes are created when accessed and cached for future use. + //==================================================================== + + public static IntPtr tp_getattro(IntPtr ob, IntPtr key) { + ModuleObject self = (ModuleObject)GetManagedObject(ob); + + if (!Runtime.PyString_Check(key)) { + Exceptions.SetError(Exceptions.TypeError, "string expected"); + return IntPtr.Zero; + } + + IntPtr op = Runtime.PyDict_GetItem(self.dict, key); + if (op != IntPtr.Zero) { + Runtime.Incref(op); + return op; + } + + string name = Runtime.GetManagedString(key); + if (name == "__dict__") { + Runtime.Incref(self.dict); + return self.dict; + } + + ManagedType attr = self.GetAttribute(name, true); + + if (attr == null) { + Exceptions.SetError(Exceptions.AttributeError, name); + return IntPtr.Zero; + } + + // XXX - hack required to recognize exception types. These types + // may need to be wrapped in old-style class wrappers in versions + // of Python where new-style classes cannot be used as exceptions. + + if (Runtime.wrap_exceptions) { + if (attr is ExceptionClassObject) { + ExceptionClassObject c = attr as ExceptionClassObject; + if (c != null) { + IntPtr p = attr.pyHandle; + IntPtr r = Exceptions.GetExceptionClassWrapper(p); + Runtime.PyDict_SetItemString(self.dict, name, r); + Runtime.Incref(r); + return r; + } + } + } + + Runtime.Incref(attr.pyHandle); + return attr.pyHandle; + } + + //==================================================================== + // ModuleObject __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + ModuleObject self = (ModuleObject)GetManagedObject(ob); + string s = String.Format("", self.moduleName); + return Runtime.PyString_FromString(s); + } + + + + } + + /// + /// The CLR module is the root handler used by the magic import hook + /// to import assemblies. It has a fixed module name "clr" and doesn't + /// provide a namespace. + /// + internal class CLRModule : ModuleObject + { + protected static bool hacked = false; + protected static bool interactive_preload = true; + internal static bool preload; + // XXX Test performance of new features // + internal static bool _SuppressDocs = false; + internal static bool _SuppressOverloads = false; + + public CLRModule() : base("clr") { + _namespace = String.Empty; + + // This hackery is required in order to allow a plain Python to + // import the managed runtime via the CLR bootstrapper module. + // The standard Python machinery in control at the time of the + // import requires the module to pass PyModule_Check. :( + if (!hacked) + { + IntPtr type = this.tpHandle; + IntPtr mro = Marshal.ReadIntPtr(type, TypeOffset.tp_mro); + IntPtr ext = Runtime.ExtendTuple(mro, Runtime.PyModuleType); + Marshal.WriteIntPtr(type, TypeOffset.tp_mro, ext); + Runtime.Decref(mro); + hacked = true; + } + } + + /// + /// The initializing of the preload hook has to happen as late as + /// possible since sys.ps1 is created after the CLR module is + /// created. + /// + internal void InitializePreload() { + if (interactive_preload) { + interactive_preload = false; + if (Runtime.PySys_GetObject("ps1") != IntPtr.Zero) { + preload = true; + } else { + Exceptions.Clear(); + preload = false; + } + } + } + + [ModuleFunctionAttribute()] + public static bool getPreload() { + return preload; + } + + [ModuleFunctionAttribute()] + public static void setPreload(bool preloadFlag) + { + preload = preloadFlag; + } + + //[ModulePropertyAttribute] + public static bool SuppressDocs { + get { return _SuppressDocs; } + set { _SuppressDocs = value; } + } + + //[ModulePropertyAttribute] + public static bool SuppressOverloads { + get { return _SuppressOverloads; } + set { _SuppressOverloads = value; } + } + + [ModuleFunctionAttribute()] + [ForbidPythonThreadsAttribute()] + public static Assembly AddReference(string name) + { + AssemblyManager.UpdatePath(); + Assembly assembly = null; + assembly = AssemblyManager.FindLoadedAssembly(name); + if (assembly == null) + { + assembly = AssemblyManager.LoadAssemblyPath(name); + } + if (assembly == null) + { + assembly = AssemblyManager.LoadAssembly(name); + } + if (assembly == null) + { + string msg = String.Format("Unable to find assembly '{0}'.", name); + throw new System.IO.FileNotFoundException(msg); + } + return assembly ; + } + + [ModuleFunctionAttribute()] + [ForbidPythonThreadsAttribute()] + public static string FindAssembly(string name) + { + AssemblyManager.UpdatePath(); + return AssemblyManager.FindAssembly(name); + } + + [ModuleFunctionAttribute()] + public static String[] ListAssemblies(bool verbose) + { + AssemblyName[] assnames = AssemblyManager.ListAssemblies(); + String[] names = new String[assnames.Length]; + for (int i = 0; i < assnames.Length; i++) + { + if (verbose) + names[i] = assnames[i].FullName; + else + names[i] = assnames[i].Name; + } + return names; + } + + } + +} diff --git a/src/runtime/modulepropertyobject.cs b/src/runtime/modulepropertyobject.cs new file mode 100644 index 000000000..f833696bf --- /dev/null +++ b/src/runtime/modulepropertyobject.cs @@ -0,0 +1,30 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; +using System.Security.Permissions; + +namespace Python.Runtime { + + /// + /// Module level properties (attributes) + /// + internal class ModulePropertyObject : ExtensionType { + + public ModulePropertyObject(PropertyInfo md) : base() + { + throw new NotImplementedException("ModulePropertyObject"); + } + + } + +} + diff --git a/src/runtime/monosupport.cs b/src/runtime/monosupport.cs new file mode 100644 index 000000000..6208b498e --- /dev/null +++ b/src/runtime/monosupport.cs @@ -0,0 +1,60 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +#if (UCS4) +using System; +using System.Runtime.InteropServices; +using System.Text; +using Mono.Unix; + +namespace Python.Runtime { + // The Utf32Marshaler was written Jonathan Pryor and has been placed + // in the PUBLIC DOMAIN. + public class Utf32Marshaler : ICustomMarshaler { + private static Utf32Marshaler instance = new + Utf32Marshaler (); + + public static ICustomMarshaler GetInstance (string s) + { + return instance; + } + + public void CleanUpManagedData (object o) + { + } + + public void CleanUpNativeData (IntPtr pNativeData) + { + UnixMarshal.FreeHeap (pNativeData); + } + + public int GetNativeDataSize () + { + return IntPtr.Size; + } + + public IntPtr MarshalManagedToNative (object obj) + { + string s = obj as string; + if (s == null) + return IntPtr.Zero; + return UnixMarshal.StringToHeap (s, + Encoding.UTF32); + } + + public object MarshalNativeToManaged (IntPtr + pNativeData) + { + return UnixMarshal.PtrToString (pNativeData, + Encoding.UTF32); + } + } +} +#endif + diff --git a/src/runtime/nativecall.cs b/src/runtime/nativecall.cs new file mode 100644 index 000000000..d2c4bf5b3 --- /dev/null +++ b/src/runtime/nativecall.cs @@ -0,0 +1,166 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Threading; +using System.Runtime.InteropServices; +using System.Collections; +using System.Reflection; +using System.Reflection.Emit; + +namespace Python.Runtime { + + /// + /// Provides support for calling native code indirectly through + /// function pointers. Most of the important parts of the Python + /// C API can just be wrapped with p/invoke, but there are some + /// situations (specifically, calling functions through Python + /// type structures) where we need to call functions indirectly. + /// + /// This class uses Reflection.Emit to generate IJW thunks that + /// support indirect calls to native code using various common + /// call signatures. This is mainly a workaround for the fact + /// that you can't spell an indirect call in C# (but can in IL). + /// + /// Another approach that would work is for this to be turned + /// into a separate utility program that could be run during the + /// build process to generate the thunks as a separate assembly + /// that could then be referenced by the main Python runtime. + /// + + internal class NativeCall { + + static AssemblyBuilder aBuilder; + static ModuleBuilder mBuilder; + + public static INativeCall Impl; + + static NativeCall() { + + // The static constructor is responsible for generating the + // assembly and the methods that implement the IJW thunks. + // + // To do this, we actually use reflection on the INativeCall + // interface (defined below) and generate the required thunk + // code based on the method signatures. + + AssemblyName aname = new AssemblyName(); + aname.Name = "e__NativeCall_Assembly"; + AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run; + + aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); + mBuilder = aBuilder.DefineDynamicModule("e__NativeCall_Module"); + + TypeAttributes ta = TypeAttributes.Public; + TypeBuilder tBuilder = mBuilder.DefineType("e__NativeCall", ta); + + Type iType = typeof(INativeCall); + tBuilder.AddInterfaceImplementation(iType); + + // Use reflection to loop over the INativeCall interface methods, + // calling GenerateThunk to create a managed thunk for each one. + + foreach (MethodInfo method in iType.GetMethods()) { + GenerateThunk(tBuilder, method); + } + + Type theType = tBuilder.CreateType(); + + Impl = (INativeCall)Activator.CreateInstance(theType); + + } + + private static void GenerateThunk(TypeBuilder tb, MethodInfo method) { + + ParameterInfo[] pi = method.GetParameters(); + int count = pi.Length; + int argc = count - 1; + + Type[] args = new Type[count]; + for (int i = 0; i < count; i++) { + args[i] = pi[i].ParameterType; + } + + MethodBuilder mb = tb.DefineMethod( + method.Name, + MethodAttributes.Public | + MethodAttributes.Virtual, + method.ReturnType, + args + ); + + // Build the method signature for the actual native function. + // This is essentially the signature of the wrapper method + // minus the first argument (the passed in function pointer). + + Type[] nargs = new Type[argc]; + for (int i = 1; i < count; i++) { + nargs[(i - 1)] = args[i]; + } + + // IL generation: the (implicit) first argument of the method + // is the 'this' pointer and the second is the function pointer. + // This code pushes the real args onto the stack, followed by + // the function pointer, then the calli opcode to make the call. + + ILGenerator il = mb.GetILGenerator(); + + for (int i = 0; i < argc; i++) { + il.Emit(OpCodes.Ldarg_S, (i + 2)); + } + + il.Emit(OpCodes.Ldarg_1); + + il.EmitCalli(OpCodes.Calli, + CallingConvention.Cdecl, + method.ReturnType, + nargs + ); + + il.Emit(OpCodes.Ret); + + tb.DefineMethodOverride(mb, method); + return; + } + + + public static void Void_Call_1(IntPtr fp, IntPtr a1) { + Impl.Void_Call_1(fp, a1); + } + + public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2, + IntPtr a3) { + return Impl.Call_3(fp, a1, a2, a3); + } + + public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2, + IntPtr a3) { + return Impl.Int_Call_3(fp, a1, a2, a3); + } + + } + + + /// + /// Defines native call signatures to be generated by NativeCall. + /// + + public interface INativeCall { + + void Void_Call_0(IntPtr funcPtr); + + void Void_Call_1(IntPtr funcPtr, IntPtr arg1); + + int Int_Call_3(IntPtr funcPtr, IntPtr t, IntPtr n, IntPtr v); + + IntPtr Call_3(IntPtr funcPtr, IntPtr a1, IntPtr a2, IntPtr a3); + + } + +} diff --git a/src/runtime/oldmodule.il b/src/runtime/oldmodule.il new file mode 100644 index 000000000..6ecd2c136 --- /dev/null +++ b/src/runtime/oldmodule.il @@ -0,0 +1,274 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +//============================================================================ +// This file is a hand-maintained stub - it implements clr.dll, which can be +// loaded by a standard CPython interpreter as an extension module. When it +// is loaded, it bootstraps the managed runtime integration layer and defers +// to it to do initialization and put the clr module into sys.modules, etc. + +// The "USE_PYTHON_RUNTIME_*" defines control what extra evidence is used +// to help the CLR find the appropriate Python.Runtime assembly. + +// If defined, the "pythonRuntimeVersionString" variable must be set to +// Python.Runtime's current version. +#define USE_PYTHON_RUNTIME_VERSION + +// If defined, the "PythonRuntimePublicKeyTokenData" data array must be +// set to Python.Runtime's public key token. +//#define USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + +// If DEBUG_PRINT is defined, a few System.Console.WriteLine calls are made +// to indicate what's going on during the load... +//#define DEBUG_PRINT +//============================================================================ + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 2:0:0:0 +} + +.assembly clr +{ + .hash algorithm 0x00008004 + .ver 2:0:0:2 +} + +.module clr.dll +.imagebase 0x00400000 +.subsystem 0x00000003 +.file alignment 512 + +// This includes the platform-specific IL. The include search path +// is set depending on whether we're compiling 32 or 64 bit. +// This MUST come before any other .data directives! +// Why, oh why, can't ilasm support command line #defines? :( +#include "clrmodule-platform.il" + +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN +.data PythonRuntimePublicKeyTokenData = bytearray (64 e1 4e 84 5a bf 2e 60) +#endif + +.class public auto ansi beforefieldinit clrModule extends [mscorlib]System.Object +{ +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + .field static assembly int64 PythonRuntimePublicKeyToken at PythonRuntimePublicKeyTokenData +#endif + + .method public hidebysig specialname rtspecialname instance void + .ctor() cil managed + { + .maxstack 1 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } + + .method public hidebysig static void modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) + initclr() cil managed + { + .vtentry 1:1 + .export [1] as initclr + + .maxstack 6 + .locals init ( + class [mscorlib]System.Reflection.Assembly pythonRuntime, + class [mscorlib]System.Reflection.Assembly executingAssembly, + class [mscorlib]System.Reflection.AssemblyName pythonRuntimeName, + class [mscorlib]System.Type pythonEngineType, + int8[] publicKeyToken, + string assemblyDirectory, + string pythonRuntimeVersionString, + string pythonRuntimeDllPath) + + // pythonRuntime = null; + ldnull + stloc pythonRuntime + + .try + { +#ifdef DEBUG_PRINT + ldstr "Attempting to load Python.Runtime using standard binding rules... " + call void [mscorlib]System.Console::Write(string) +#endif + + // Attempt to find and load Python.Runtime using standard assembly binding rules. + // This roughly translates into looking in order: + // - GAC + // - ApplicationBase + // - A PrivateBinPath under ApplicationBase + // With an unsigned assembly, the GAC is skipped. + + // System.Reflection.AssemblyName pythonRuntimeName = new System.Reflection.AssemblyName(); + newobj instance void [mscorlib]System.Reflection.AssemblyName::.ctor() + stloc pythonRuntimeName + + // pythonRuntimeName.Name = "Python.Runtime"; + ldloc pythonRuntimeName + ldstr "Python.Runtime" + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Name(string) + +#ifdef USE_PYTHON_RUNTIME_VERSION + // pythonRuntimeVersionString = "..."; + ldstr "2.0.0.2" + stloc pythonRuntimeVersionString + + // pythonRuntimeName.Version = new Version(pythonRuntimeVersionString); + ldloc pythonRuntimeName + ldloc pythonRuntimeVersionString + newobj instance void [mscorlib]System.Version::.ctor(string) + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_Version(class [mscorlib]System.Version) +#endif + +#ifdef USE_PYTHON_RUNTIME_PUBLIC_KEY_TOKEN + // publicKeyToken = new byte[] { ... }; + ldc.i4.8 + newarr [mscorlib]System.Byte + dup + ldtoken field int64 clrModule::PythonRuntimePublicKeyToken + call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle) + stloc publicKeyToken + + // pythonRuntimeName.SetPublicKeyToken(publicKeyToken); + ldloc pythonRuntimeName + ldloc publicKeyToken + callvirt instance void [mscorlib]System.Reflection.AssemblyName::SetPublicKeyToken(uint8[]) +#endif + + // pythonRuntimeName.CultureInfo = System.Globalization.CultureInfo.InvariantCulture; + ldloc pythonRuntimeName + call class [mscorlib]System.Globalization.CultureInfo [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture() + callvirt instance void [mscorlib]System.Reflection.AssemblyName::set_CultureInfo(class [mscorlib]System.Globalization.CultureInfo) + + // return System.Reflection.Assembly.Load(pythonRuntimeName); + ldloc pythonRuntimeName + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::Load(class [mscorlib]System.Reflection.AssemblyName) + stloc pythonRuntime + +#ifdef DEBUG_PRINT + ldstr "Success!" + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s LOADED_PYTHON_RUNTIME + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Failed." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_CLR_LOAD + } + EXIT_CLR_LOAD: nop + + .try + { + // If the above fails for any reason, we fallback to attempting to load "Python.Runtime.dll" + // from the directory this assembly is running in. "This assembly" is probably "clr.pyd", + // sitting somewhere in PYTHONPATH. This is using Assembly.LoadFrom, and inherits all the + // caveats of that call. See MSDN docs for details. + // Suzanne Cook's blog is also an excellent source of info on this: + // http://blogs.msdn.com/suzcook/ + // http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx + // http://blogs.msdn.com/suzcook/archive/2003/06/13/57180.aspx + // executingAssembly = System.Reflection.Assembly.GetExecutingAssembly(); + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetExecutingAssembly() + stloc executingAssembly + + // assemblyDirectory = System.IO.Path.GetDirectoryName(executingAssembly.Location); + ldloc executingAssembly + callvirt instance string [mscorlib]System.Reflection.Assembly::get_Location() + call string [mscorlib]System.IO.Path::GetDirectoryName(string) + stloc assemblyDirectory + + // pythonRuntimeDllPath = System.IO.Path.Combine(assemblyDirectory, "Python.Runtime.dll"); + ldloc assemblyDirectory + ldstr "Python.Runtime.dll" + call string [mscorlib]System.IO.Path::Combine(string, string) + stloc pythonRuntimeDllPath + +#ifdef DEBUG_PRINT + ldstr "Attempting to load Python.Runtime from: '{0}'... " + ldloc pythonRuntimeDllPath + call void [mscorlib]System.Console::Write(string, object) +#endif + + // pythonRuntime = System.Reflection.Assembly.LoadFrom(pythonRuntimeDllPath); + ldloc pythonRuntimeDllPath + call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::LoadFrom(string) + stloc pythonRuntime + +#ifdef DEBUG_PRINT + ldstr "Success!" + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s LOADED_PYTHON_RUNTIME + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Failed." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_PYTHONPATH_LOAD + } + EXIT_PYTHONPATH_LOAD: nop + + // If we get here, we haven't loaded Python.Runtime, so bail. +#ifdef DEBUG_PRINT + ldstr "Could not load Python.Runtime, so sad." + call void [mscorlib]System.Console::WriteLine(string) +#endif + ret; + + // Once here, we've successfully loaded SOME version of Python.Runtime + // So now we get the PythonEngine and execute the InitExt method on it. + LOADED_PYTHON_RUNTIME: nop + .try + { +#ifdef DEBUG_PRINT + ldstr "Running Python.Runtime.PythonEngine.InitExt()" + call void [mscorlib]System.Console::WriteLine(string) +#endif + // pythonEngineType = pythonRuntime.GetType("Python.Runtime.PythonEngine"); + ldloc pythonRuntime + ldstr "Python.Runtime.PythonEngine" + callvirt instance class [mscorlib]System.Type [mscorlib]System.Reflection.Assembly::GetType(string) + stloc pythonEngineType + + // pythonEngineType.InvokeMember("InitExt", System.Reflection.BindingFlags.InvokeMethod, null, null, null); + ldloc pythonEngineType + ldstr "InitExt" + ldc.i4 0x100 + ldnull + ldnull + ldnull + callvirt instance object [mscorlib]System.Type::InvokeMember( string, + valuetype [mscorlib]System.Reflection.BindingFlags, + class [mscorlib]System.Reflection.Binder, + object, + object[]) + pop + leave.s EXIT_TRY_INVOKE + } + catch [mscorlib]System.Object + { +#ifdef DEBUG_PRINT + ldstr "Error calling Python.Runtime.PythonEngine.InitExt()." + call void [mscorlib]System.Console::WriteLine(string) +#endif + leave.s EXIT_TRY_INVOKE + } + EXIT_TRY_INVOKE: nop + + ret + } +} + diff --git a/src/runtime/overload.cs b/src/runtime/overload.cs new file mode 100644 index 000000000..0b7ef248c --- /dev/null +++ b/src/runtime/overload.cs @@ -0,0 +1,83 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Implements the __overloads__ attribute of method objects. This object + // supports the [] syntax to explicitly select an overload by signature. + //======================================================================== + + internal class OverloadMapper : ExtensionType { + + MethodObject m; + IntPtr target; + + public OverloadMapper(MethodObject m, IntPtr target) : base() { + Runtime.Incref(target); + this.target = target; + this.m = m; + } + + //==================================================================== + // Implement explicit overload selection using subscript syntax ([]). + //==================================================================== + + public static IntPtr mp_subscript(IntPtr tp, IntPtr idx) { + OverloadMapper self = (OverloadMapper)GetManagedObject(tp); + + // Note: if the type provides a non-generic method with N args + // and a generic method that takes N params, then we always + // prefer the non-generic version in doing overload selection. + + Type[] types = Runtime.PythonArgsToTypeArray(idx); + if (types == null) { + return Exceptions.RaiseTypeError("type(s) expected"); + } + + MethodInfo mi = MethodBinder.MatchSignature(self.m.info, types); + if (mi == null) { + string e = "No match found for signature"; + return Exceptions.RaiseTypeError(e); + } + + MethodBinding mb = new MethodBinding(self.m, self.target); + mb.info = mi; + Runtime.Incref(mb.pyHandle); + return mb.pyHandle; + } + + //==================================================================== + // OverloadMapper __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr op) { + OverloadMapper self = (OverloadMapper)GetManagedObject(op); + IntPtr doc = self.m.GetDocString(); + Runtime.Incref(doc); + return doc; + } + + //==================================================================== + // OverloadMapper dealloc implementation. + //==================================================================== + + public static new void tp_dealloc(IntPtr ob) { + OverloadMapper self = (OverloadMapper)GetManagedObject(ob); + Runtime.Decref(self.target); + ExtensionType.FinalizeObject(self); + } + + } + + +} diff --git a/src/runtime/propertyobject.cs b/src/runtime/propertyobject.cs new file mode 100644 index 000000000..d61dc0134 --- /dev/null +++ b/src/runtime/propertyobject.cs @@ -0,0 +1,164 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; +using System.Security.Permissions; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python descriptor type that manages CLR properties. + //======================================================================== + + internal class PropertyObject : ExtensionType { + + PropertyInfo info; + MethodInfo getter; + MethodInfo setter; + + [StrongNameIdentityPermissionAttribute(SecurityAction.Assert)] + public PropertyObject(PropertyInfo md) : base() { + getter = md.GetGetMethod(true); + setter = md.GetSetMethod(true); + info = md; + } + + + //==================================================================== + // Descriptor __get__ implementation. This method returns the + // value of the property on the given object. The returned value + // is converted to an appropriately typed Python object. + //==================================================================== + + public static IntPtr tp_descr_get(IntPtr ds, IntPtr ob, IntPtr tp) { + PropertyObject self = (PropertyObject)GetManagedObject(ds); + MethodInfo getter = self.getter; + Object result; + + + if (getter == null) { + return Exceptions.RaiseTypeError("property cannot be read"); + } + + if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { + if (!(getter.IsStatic)) { + Exceptions.SetError(Exceptions.TypeError, + "instance property must be accessed through " + + "a class instance" + ); + return IntPtr.Zero; + } + + try { + result = self.info.GetValue(null, null); + return Converter.ToPython(result, self.info.PropertyType); + } + catch(Exception e) { + return Exceptions.RaiseTypeError(e.Message); + } + } + + CLRObject co = GetManagedObject(ob) as CLRObject; + if (co == null) { + return Exceptions.RaiseTypeError("invalid target"); + } + + try { + result = self.info.GetValue(co.inst, null); + return Converter.ToPython(result, self.info.PropertyType); + } + catch(Exception e) { + if (e.InnerException != null) { + e = e.InnerException; + } + Exceptions.SetError(e); + return IntPtr.Zero; + } + } + + + //==================================================================== + // Descriptor __set__ implementation. This method sets the value of + // a property based on the given Python value. The Python value must + // be convertible to the type of the property. + //==================================================================== + + public static new int tp_descr_set(IntPtr ds, IntPtr ob, IntPtr val) { + PropertyObject self = (PropertyObject)GetManagedObject(ds); + MethodInfo setter = self.setter; + Object newval; + + if (val == IntPtr.Zero) { + Exceptions.RaiseTypeError("cannot delete property"); + return -1; + } + + if (setter == null) { + Exceptions.RaiseTypeError("property is read-only"); + return -1; + } + + + if (!Converter.ToManaged(val, self.info.PropertyType, out newval, + true)) { + return -1; + } + + bool is_static = setter.IsStatic; + + if ((ob == IntPtr.Zero) || (ob == Runtime.PyNone)) { + if (!(is_static)) { + Exceptions.RaiseTypeError( + "instance property must be set on an instance" + ); + return -1; + } + } + + try { + if (!is_static) { + CLRObject co = GetManagedObject(ob) as CLRObject; + if (co == null) { + Exceptions.RaiseTypeError("invalid target"); + return -1; + } + self.info.SetValue(co.inst, newval, null); + } + else { + self.info.SetValue(null, newval, null); + } + return 0; + } + catch(Exception e) { + if (e.InnerException != null) { + e = e.InnerException; + } + Exceptions.SetError(e); + return -1; + } + + } + + + //==================================================================== + // Descriptor __repr__ implementation. + //==================================================================== + + public static IntPtr tp_repr(IntPtr ob) { + PropertyObject self = (PropertyObject)GetManagedObject(ob); + string s = String.Format("", self.info.Name); + return Runtime.PyString_FromStringAndSize(s, s.Length); + } + + } + + +} diff --git a/src/runtime/pyansistring.cs b/src/runtime/pyansistring.cs new file mode 100644 index 000000000..db8e249a1 --- /dev/null +++ b/src/runtime/pyansistring.cs @@ -0,0 +1,82 @@ +// ========================================================================== +// This is a user contribution to the pythondotnet project. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + public class PyAnsiString : PySequence + { + /// + /// PyAnsiString Constructor + /// + /// + /// + /// Creates a new PyAnsiString from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyAnsiString(IntPtr ptr) : base(ptr) { } + + + /// + /// PyString Constructor + /// + /// + /// + /// Copy constructor - obtain a PyAnsiString from a generic PyObject. + /// An ArgumentException will be thrown if the given object is not + /// a Python string object. + /// + + public PyAnsiString(PyObject o) + : base() + { + if (!IsStringType(o)) + { + throw new ArgumentException("object is not a string"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// PyAnsiString Constructor + /// + /// + /// + /// Creates a Python string from a managed string. + /// + + public PyAnsiString(string s) + : base() + { + obj = Runtime.PyString_FromStringAndSize(s, s.Length); + if (obj == IntPtr.Zero) + { + throw new PythonException(); + } + } + + + /// + /// IsStringType Method + /// + /// + /// + /// Returns true if the given object is a Python string. + /// + + public static bool IsStringType(PyObject value) + { + return Runtime.PyString_Check(value.obj); + } + } +} \ No newline at end of file diff --git a/src/runtime/pydict.cs b/src/runtime/pydict.cs new file mode 100644 index 000000000..cd85c7126 --- /dev/null +++ b/src/runtime/pydict.cs @@ -0,0 +1,208 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// Represents a Python dictionary object. See the documentation at + /// http://www.python.org/doc/current/api/dictObjects.html for details. + /// + + public class PyDict : PyObject { + + /// + /// PyDict Constructor + /// + /// + /// + /// Creates a new PyDict from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyDict(IntPtr ptr) : base(ptr) {} + + + /// + /// PyDict Constructor + /// + /// + /// + /// Creates a new Python dictionary object. + /// + + public PyDict() : base() { + obj = Runtime.PyDict_New(); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyDict Constructor + /// + /// + /// + /// Copy constructor - obtain a PyDict from a generic PyObject. An + /// ArgumentException will be thrown if the given object is not a + /// Python dictionary object. + /// + + public PyDict(PyObject o) : base() { + if (!IsDictType(o)) { + throw new ArgumentException("object is not a dict"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// IsDictType Method + /// + /// + /// + /// Returns true if the given object is a Python dictionary. + /// + + public static bool IsDictType(PyObject value) { + return Runtime.PyDict_Check(value.obj); + } + + + /// + /// HasKey Method + /// + /// + /// + /// Returns true if the object key appears in the dictionary. + /// + + public bool HasKey(PyObject key) { + return (Runtime.PyMapping_HasKey(obj, key.obj) != 0); + } + + + /// + /// HasKey Method + /// + /// + /// + /// Returns true if the string key appears in the dictionary. + /// + + public bool HasKey(string key) { + return HasKey(new PyString(key)); + } + + + /// + /// Keys Method + /// + /// + /// + /// Returns a sequence containing the keys of the dictionary. + /// + + public PyObject Keys() { + IntPtr items = Runtime.PyDict_Keys(obj); + if (items == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(items); + } + + + /// + /// Values Method + /// + /// + /// + /// Returns a sequence containing the values of the dictionary. + /// + + public PyObject Values() { + IntPtr items = Runtime.PyDict_Values(obj); + if (items == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(items); + } + + + /// + /// Items Method + /// + /// + /// + /// Returns a sequence containing the items of the dictionary. + /// + + public PyObject Items() { + IntPtr items = Runtime.PyDict_Items(obj); + if (items == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(items); + } + + + /// + /// Copy Method + /// + /// + /// + /// Returns a copy of the dictionary. + /// + + public PyDict Copy() { + IntPtr op = Runtime.PyDict_Copy(obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyDict(op); + } + + + /// + /// Update Method + /// + /// + /// + /// Update the dictionary from another dictionary. + /// + + public void Update(PyObject other) { + int result = Runtime.PyDict_Update(obj, other.obj); + if (result < 0) { + throw new PythonException(); + } + } + + + /// + /// Clear Method + /// + /// + /// + /// Clears the dictionary. + /// + + public void Clear() { + Runtime.PyDict_Clear(obj); + } + + + } + +} diff --git a/src/runtime/pyfloat.cs b/src/runtime/pyfloat.cs new file mode 100644 index 000000000..960892594 --- /dev/null +++ b/src/runtime/pyfloat.cs @@ -0,0 +1,122 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// Represents a Python float object. See the documentation at + /// http://www.python.org/doc/current/api/floatObjects.html + /// + + public class PyFloat : PyNumber { + + /// + /// PyFloat Constructor + /// + /// + /// + /// Creates a new PyFloat from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyFloat(IntPtr ptr) : base(ptr) {} + + + /// + /// PyFloat Constructor + /// + /// + /// + /// Copy constructor - obtain a PyFloat from a generic PyObject. An + /// ArgumentException will be thrown if the given object is not a + /// Python float object. + /// + + public PyFloat(PyObject o) : base() { + if (!IsFloatType(o)) { + throw new ArgumentException("object is not a float"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// PyFloat Constructor + /// + /// + /// + /// Creates a new Python float from a double value. + /// + + public PyFloat(double value) : base() { + obj = Runtime.PyFloat_FromDouble(value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyFloat Constructor + /// + /// + /// + /// Creates a new Python float from a string value. + /// + + public PyFloat(string value) : base() { + PyString s = new PyString(value); + obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// IsFloatType Method + /// + /// + /// + /// Returns true if the given object is a Python float. + /// + + public static bool IsFloatType(PyObject value) { + return Runtime.PyFloat_Check(value.obj); + } + + + /// + /// AsFloat Method + /// + /// + /// + /// + /// Convert a Python object to a Python float if possible, raising + /// a PythonException if the conversion is not possible. This is + /// equivalent to the Python expression "float(object)". + /// + + public static PyFloat AsFloat(PyObject value) { + IntPtr op = Runtime.PyNumber_Float(value.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyFloat(op); + } + + + } + +} diff --git a/src/runtime/pyint.cs b/src/runtime/pyint.cs new file mode 100644 index 000000000..7e5f07b6a --- /dev/null +++ b/src/runtime/pyint.cs @@ -0,0 +1,257 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; + +namespace Python.Runtime { + + /// + /// Represents a Python integer object. See the documentation at + /// http://www.python.org/doc/current/api/intObjects.html for details. + /// + + public class PyInt : PyNumber { + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new PyInt from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyInt(IntPtr ptr) : base(ptr) {} + + + /// + /// PyInt Constructor + /// + /// + /// + /// Copy constructor - obtain a PyInt from a generic PyObject. An + /// ArgumentException will be thrown if the given object is not a + /// Python int object. + /// + + public PyInt(PyObject o) : base() { + if (!IsIntType(o)) { + throw new ArgumentException("object is not an int"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from an int32 value. + /// + + public PyInt(int value) : base() { + obj = Runtime.PyInt_FromInt32(value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from a uint32 value. + /// + + [CLSCompliant(false)] + public PyInt(uint value) : base(IntPtr.Zero) { + obj = Runtime.PyInt_FromInt64((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from an int64 value. + /// + + public PyInt(long value) : base(IntPtr.Zero) { + obj = Runtime.PyInt_FromInt64(value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from a uint64 value. + /// + + [CLSCompliant(false)] + public PyInt(ulong value) : base(IntPtr.Zero) { + obj = Runtime.PyInt_FromInt64((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from an int16 value. + /// + + public PyInt(short value) : this((int)value) {} + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from a uint16 value. + /// + + [CLSCompliant(false)] + public PyInt(ushort value) : this((int)value) {} + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from a byte value. + /// + + public PyInt(byte value) : this((int)value) {} + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from an sbyte value. + /// + + [CLSCompliant(false)] + public PyInt(sbyte value) : this((int)value) {} + + + /// + /// PyInt Constructor + /// + /// + /// + /// Creates a new Python int from a string value. + /// + + public PyInt(string value) : base() { + obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// IsIntType Method + /// + /// + /// + /// Returns true if the given object is a Python int. + /// + + public static bool IsIntType(PyObject value) { + return Runtime.PyInt_Check(value.obj); + } + + + /// + /// AsInt Method + /// + /// + /// + /// + /// Convert a Python object to a Python int if possible, raising + /// a PythonException if the conversion is not possible. This is + /// equivalent to the Python expression "int(object)". + /// + + public static PyInt AsInt(PyObject value) { + IntPtr op = Runtime.PyNumber_Int(value.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyInt(op); + } + + + /// + /// ToInt16 Method + /// + /// + /// + /// Return the value of the Python int object as an int16. + /// + + public short ToInt16() { + return System.Convert.ToInt16(this.ToInt32()); + } + + + /// + /// ToInt32 Method + /// + /// + /// + /// Return the value of the Python int object as an int32. + /// + + public int ToInt32() { + return Runtime.PyInt_AsLong(obj); + } + + + /// + /// ToInt64 Method + /// + /// + /// + /// Return the value of the Python int object as an int64. + /// + + public long ToInt64() { + return System.Convert.ToInt64(this.ToInt32()); + } + + + + } + +} diff --git a/src/runtime/pyiter.cs b/src/runtime/pyiter.cs new file mode 100644 index 000000000..8d8ad44d7 --- /dev/null +++ b/src/runtime/pyiter.cs @@ -0,0 +1,76 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections.Generic; + +namespace Python.Runtime +{ + /// + /// Represents a standard Python iterator object. See the documentation at + /// http://www.python.org/doc/2.4.4/api/iterator.html for details. + /// + public class PyIter : PyObject, IEnumerator + { + private PyObject _current = null; + + /// + /// PyIter Constructor + /// + /// + /// + /// 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) {} + + /// + /// PyIter Constructor + /// + /// + /// + /// Creates a Python iterator from an iterable. Like doing "iter(iterable)" in python. + /// + + public PyIter(PyObject iterable) : base() + { + obj = Runtime.PyObject_GetIter(iterable.obj); + if (obj == IntPtr.Zero) + throw new PythonException(); + } + + #region IEnumerator Members + + public bool MoveNext() + { + IntPtr next = Runtime.PyIter_Next(obj); + if (next == IntPtr.Zero) + { + _current = null; //release reference + return false; + } + _current = new PyObject(next); + return true; + } + + public void Reset() + { + //Not supported in python. + } + + public object Current + { + get { return _current; } + } + + #endregion + } +} diff --git a/src/runtime/pylist.cs b/src/runtime/pylist.cs new file mode 100644 index 000000000..395482332 --- /dev/null +++ b/src/runtime/pylist.cs @@ -0,0 +1,189 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + /// + /// Represents a standard Python list object. See the documentation at + /// http://www.python.org/doc/current/api/listObjects.html for details. + /// + + public class PyList : PySequence { + + /// + /// PyList Constructor + /// + /// + /// + /// Creates a new PyList from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyList(IntPtr ptr) : base(ptr) {} + + + /// + /// PyList Constructor + /// + /// + /// + /// Copy constructor - obtain a PyList from a generic PyObject. An + /// ArgumentException will be thrown if the given object is not a + /// Python list object. + /// + + public PyList(PyObject o) : base() { + if (!IsListType(o)) { + throw new ArgumentException("object is not a list"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// PyList Constructor + /// + /// + /// + /// Creates a new empty Python list object. + /// + + public PyList() : base() { + obj = Runtime.PyList_New(0); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyList Constructor + /// + /// + /// + /// Creates a new Python list object from an array of PyObjects. + /// + + public PyList(PyObject[] items) : base() { + int count = items.Length; + obj = Runtime.PyList_New(count); + for (int i = 0; i < count; i++) { + IntPtr ptr = items[i].obj; + Runtime.Incref(ptr); + int r = Runtime.PyList_SetItem(obj, i, ptr); + if (r < 0) { + throw new PythonException(); + } + } + } + + + /// + /// IsListType Method + /// + /// + /// + /// Returns true if the given object is a Python list. + /// + + public static bool IsListType(PyObject value) { + return Runtime.PyList_Check(value.obj); + } + + + /// + /// AsList Method + /// + /// + /// + /// Converts a Python object to a Python list if possible, raising + /// a PythonException if the conversion is not possible. This is + /// equivalent to the Python expression "list(object)". + /// + + public static PyList AsList(PyObject value) { + IntPtr op = Runtime.PySequence_List(value.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyList(op); + } + + + /// + /// Append Method + /// + /// + /// + /// Append an item to the list object. + /// + + public void Append(PyObject item) { + int r = Runtime.PyList_Append(obj, item.obj); + if (r < 0) { + throw new PythonException(); + } + } + + /// + /// Insert Method + /// + /// + /// + /// Insert an item in the list object at the given index. + /// + + public void Insert(int index, PyObject item) { + int r = Runtime.PyList_Insert(obj, index, item.obj); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// Reverse Method + /// + /// + /// + /// Reverse the order of the list object in place. + /// + + public void Reverse() { + int r = Runtime.PyList_Reverse(obj); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// Sort Method + /// + /// + /// + /// Sort the list in place. + /// + + public void Sort() { + int r = Runtime.PyList_Sort(obj); + if (r < 0) { + throw new PythonException(); + } + } + + + } + + +} diff --git a/src/runtime/pylong.cs b/src/runtime/pylong.cs new file mode 100644 index 000000000..999c75adc --- /dev/null +++ b/src/runtime/pylong.cs @@ -0,0 +1,291 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + /// + /// Represents a Python long int object. See the documentation at + /// http://www.python.org/doc/current/api/longObjects.html + /// + + public class PyLong : PyNumber { + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyLong(IntPtr ptr) : base(ptr) {} + + + /// + /// PyLong Constructor + /// + /// + /// + /// Copy constructor - obtain a PyLong from a generic PyObject. An + /// ArgumentException will be thrown if the given object is not a + /// Python long object. + /// + + public PyLong(PyObject o) : base() { + if (!IsLongType(o)) { + throw new ArgumentException("object is not a long"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from an int32 value. + /// + + public PyLong(int value) : base() { + obj = Runtime.PyLong_FromLong((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from a uint32 value. + /// + + [CLSCompliant(false)] + public PyLong(uint value) : base() { + obj = Runtime.PyLong_FromLong((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from an int64 value. + /// + + public PyLong(long value) : base() { + obj = Runtime.PyLong_FromLongLong(value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from a uint64 value. + /// + + [CLSCompliant(false)] + public PyLong(ulong value) : base() { + obj = Runtime.PyLong_FromUnsignedLongLong(value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from an int16 value. + /// + + public PyLong(short value) : base() { + obj = Runtime.PyLong_FromLong((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from an uint16 value. + /// + + [CLSCompliant(false)] + public PyLong(ushort value) : base() { + obj = Runtime.PyLong_FromLong((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from a byte value. + /// + + public PyLong(byte value) : base() { + obj = Runtime.PyLong_FromLong((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from an sbyte value. + /// + + [CLSCompliant(false)] + public PyLong(sbyte value) : base() { + obj = Runtime.PyLong_FromLong((long)value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from an double value. + /// + + public PyLong(double value) : base() { + obj = Runtime.PyLong_FromDouble(value); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyLong Constructor + /// + /// + /// + /// Creates a new PyLong from a string value. + /// + + public PyLong(string value) : base() { + obj = Runtime.PyLong_FromString(value, IntPtr.Zero, 0); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// IsLongType Method + /// + /// + /// + /// Returns true if the given object is a Python long. + /// + + public static bool IsLongType(PyObject value) { + return Runtime.PyLong_Check(value.obj); + } + + + /// + /// AsLong Method + /// + /// + /// + /// + /// Convert a Python object to a Python long if possible, raising + /// a PythonException if the conversion is not possible. This is + /// equivalent to the Python expression "long(object)". + /// + + public static PyLong AsLong(PyObject value) { + IntPtr op = Runtime.PyNumber_Long(value.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyLong(op); + } + + /// + /// ToInt16 Method + /// + /// + /// + /// Return the value of the Python long object as an int16. + /// + + public short ToInt16() + { + return System.Convert.ToInt16(this.ToInt64()); + } + + + /// + /// ToInt32 Method + /// + /// + /// + /// Return the value of the Python long object as an int32. + /// + + public int ToInt32() + { + return System.Convert.ToInt32(this.ToInt64()); + } + + + /// + /// ToInt64 Method + /// + /// + /// + /// Return the value of the Python long object as an int64. + /// + + public long ToInt64() + { + return Runtime.PyLong_AsLongLong(obj); + } + } + +} diff --git a/pythonnet/src/runtime/pynumber.cs b/src/runtime/pynumber.cs old mode 100755 new mode 100644 similarity index 54% rename from pythonnet/src/runtime/pynumber.cs rename to src/runtime/pynumber.cs index 43bdd204e..16927dac3 --- a/pythonnet/src/runtime/pynumber.cs +++ b/src/runtime/pynumber.cs @@ -1,13 +1,11 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// +// ========================================================================== // 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; @@ -21,25 +19,25 @@ namespace Python.Runtime { public class PyNumber : PyObject { - protected PyNumber(IntPtr ptr) : base(ptr) {} + protected PyNumber(IntPtr ptr) : base(ptr) {} - protected PyNumber() : base() {} + protected PyNumber() : base() {} - /// - /// IsNumberType Method - /// - /// - /// - /// Returns true if the given object is a Python numeric type. - /// + /// + /// IsNumberType Method + /// + /// + /// + /// Returns true if the given object is a Python numeric type. + /// - public static bool IsNumberType(PyObject value) { - return Runtime.PyNumber_Check(value.obj); - } + public static bool IsNumberType(PyObject value) { + return Runtime.PyNumber_Check(value.obj); + } - // TODO: add all of the PyNumber_XXX methods. + // TODO: add all of the PyNumber_XXX methods. diff --git a/src/runtime/pyobject.cs b/src/runtime/pyobject.cs new file mode 100644 index 000000000..099b9fdf4 --- /dev/null +++ b/src/runtime/pyobject.cs @@ -0,0 +1,869 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + /// + /// Represents a generic Python object. The methods of this class are + /// generally equivalent to the Python "abstract object API". See + /// http://www.python.org/doc/current/api/object.html for details. + /// + + public class PyObject : IDisposable { + + protected internal IntPtr obj = IntPtr.Zero; + private bool disposed = false; + + /// + /// PyObject Constructor + /// + /// + /// + /// Creates a new PyObject from an IntPtr object reference. Note that + /// the PyObject instance assumes ownership of the object reference + /// and the reference will be DECREFed when the PyObject is garbage + /// collected or explicitly disposed. + /// + + public PyObject(IntPtr ptr) { + obj = ptr; + } + + // Protected default constructor to allow subclasses to manage + // initialization in different ways as appropriate. + + protected PyObject() {} + + // Ensure that encapsulated Python object is decref'ed appropriately + // when the managed wrapper is garbage-collected. + + ~PyObject() { + Dispose(); + } + + + /// + /// Handle Property + /// + /// + /// + /// Gets the native handle of the underlying Python object. This + /// value is generally for internal use by the PythonNet runtime. + /// + + public IntPtr Handle { + get { return obj; } + } + + + /// + /// FromManagedObject Method + /// + /// + /// + /// Given an arbitrary managed object, return a Python instance that + /// reflects the managed object. + /// + + public static PyObject FromManagedObject(object ob) { + // Special case: if ob is null, we return None. + if (ob == null) { + Runtime.Incref(Runtime.PyNone); + return new PyObject(Runtime.PyNone); + } + IntPtr op = CLRObject.GetInstHandle(ob); + return new PyObject(op); + } + + + /// + /// AsManagedObject Method + /// + /// + /// + /// Return a managed object of the given type, based on the + /// value of the Python object. + /// + + public object AsManagedObject(Type t) { + Object result; + if (!Converter.ToManaged(this.Handle, t, out result, false)) { + throw new InvalidCastException("cannot convert object to target type"); + } + return result; + } + + + /// + /// Dispose Method + /// + /// + /// + /// The Dispose method provides a way to explicitly release the + /// Python object represented by a PyObject instance. It is a good + /// idea to call Dispose on PyObjects that wrap resources that are + /// limited or need strict lifetime control. Otherwise, references + /// to Python objects will not be released until a managed garbage + /// collection occurs. + /// + + public void Dispose() { + if (!disposed) { + if (Runtime.Py_IsInitialized() > 0) { + IntPtr gs = PythonEngine.AcquireLock(); + Runtime.Decref(obj); + obj = IntPtr.Zero; + PythonEngine.ReleaseLock(gs); + } + GC.SuppressFinalize(this); + disposed = true; + } + } + + + /// + /// GetPythonType Method + /// + /// + /// + /// Returns the Python type of the object. This method is equivalent + /// to the Python expression: type(object). + /// + + public PyObject GetPythonType() { + IntPtr tp = Runtime.PyObject_Type(obj); + return new PyObject(tp); + } + + + /// + /// TypeCheck Method + /// + /// + /// + /// Returns true if the object o is of type typeOrClass or a subtype + /// of typeOrClass. + /// + + public bool TypeCheck(PyObject typeOrClass) { + return Runtime.PyObject_TypeCheck(obj, typeOrClass.obj); + } + + + /// + /// HasAttr Method + /// + /// + /// + /// Returns true if the object has an attribute with the given name. + /// + + public bool HasAttr(string name) { + return (Runtime.PyObject_HasAttrString(obj, name) != 0); + } + + + /// + /// HasAttr Method + /// + /// + /// + /// Returns true if the object has an attribute with the given name, + /// where name is a PyObject wrapping a string or unicode object. + /// + + public bool HasAttr(PyObject name) { + return (Runtime.PyObject_HasAttr(obj, name.obj) != 0); + } + + + /// + /// GetAttr Method + /// + /// + /// + /// Returns the named attribute of the Python object, or raises a + /// PythonException if the attribute access fails. + /// + + public PyObject GetAttr(string name) { + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(op); + } + + + /// + /// GetAttr Method + /// + /// + /// + /// Returns the named attribute of the Python object, or the given + /// default object if the attribute access fails. + /// + + public PyObject GetAttr(string name, PyObject _default) { + IntPtr op = Runtime.PyObject_GetAttrString(obj, name); + if (op == IntPtr.Zero) { + Runtime.PyErr_Clear(); + return _default; + } + return new PyObject(op); + } + + + /// + /// GetAttr Method + /// + /// + /// + /// Returns the named attribute of the Python object or raises a + /// PythonException if the attribute access fails. The name argument + /// is a PyObject wrapping a Python string or unicode object. + /// + + public PyObject GetAttr(PyObject name) { + IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(op); + } + + + /// + /// GetAttr Method + /// + /// + /// + /// Returns the named attribute of the Python object, or the given + /// default object if the attribute access fails. The name argument + /// is a PyObject wrapping a Python string or unicode object. + /// + + public PyObject GetAttr(PyObject name, PyObject _default) { + IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj); + if (op == IntPtr.Zero) { + Runtime.PyErr_Clear(); + return _default; + } + return new PyObject(op); + } + + + /// + /// SetAttr Method + /// + /// + /// + /// Set an attribute of the object with the given name and value. This + /// method throws a PythonException if the attribute set fails. + /// + + public void SetAttr(string name, PyObject value) { + int r = Runtime.PyObject_SetAttrString(obj, name, value.obj); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// SetAttr Method + /// + /// + /// + /// Set an attribute of the object with the given name and value, + /// where the name is a Python string or unicode object. This method + /// throws a PythonException if the attribute set fails. + /// + + public void SetAttr(PyObject name, PyObject value) { + int r = Runtime.PyObject_SetAttr(obj, name.obj, value.obj); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// DelAttr Method + /// + /// + /// + /// Delete the named attribute of the Python object. This method + /// throws a PythonException if the attribute set fails. + /// + + public void DelAttr(string name) { + int r = Runtime.PyObject_SetAttrString(obj, name, IntPtr.Zero); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// DelAttr Method + /// + /// + /// + /// Delete the named attribute of the Python object, where name is a + /// PyObject wrapping a Python string or unicode object. This method + /// throws a PythonException if the attribute set fails. + /// + + public void DelAttr(PyObject name) { + int r = Runtime.PyObject_SetAttr(obj, name.obj, IntPtr.Zero); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// GetItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// return the item at the given object index. This method raises a + /// PythonException if the indexing operation fails. + /// + + public virtual PyObject GetItem(PyObject key) { + IntPtr op = Runtime.PyObject_GetItem(obj, key.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(op); + } + + + /// + /// GetItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// return the item at the given string index. This method raises a + /// PythonException if the indexing operation fails. + /// + + public virtual PyObject GetItem(string key) { + return GetItem(new PyString(key)); + } + + + /// + /// GetItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// return the item at the given numeric index. This method raises a + /// PythonException if the indexing operation fails. + /// + + public virtual PyObject GetItem(int index) { + PyInt key = new PyInt(index); + return GetItem((PyObject)key); + } + + + /// + /// SetItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// set the item at the given object index to the given value. This + /// method raises a PythonException if the set operation fails. + /// + + public virtual void SetItem(PyObject key, PyObject value) { + int r = Runtime.PyObject_SetItem(obj, key.obj, value.obj); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// SetItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// set the item at the given string index to the given value. This + /// method raises a PythonException if the set operation fails. + /// + + public virtual void SetItem(string key, PyObject value) { + SetItem(new PyString(key), value); + } + + + /// + /// SetItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// set the item at the given numeric index to the given value. This + /// method raises a PythonException if the set operation fails. + /// + + public virtual void SetItem(int index, PyObject value) { + SetItem(new PyInt(index), value); + } + + + /// + /// DelItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// delete the item at the given object index. This method raises a + /// PythonException if the delete operation fails. + /// + + public virtual void DelItem(PyObject key) { + int r = Runtime.PyObject_DelItem(obj, key.obj); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// DelItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// delete the item at the given string index. This method raises a + /// PythonException if the delete operation fails. + /// + + public virtual void DelItem(string key) { + DelItem(new PyString(key)); + } + + + /// + /// DelItem Method + /// + /// + /// + /// For objects that support the Python sequence or mapping protocols, + /// delete the item at the given numeric index. This method raises a + /// PythonException if the delete operation fails. + /// + + public virtual void DelItem(int index) { + DelItem(new PyInt(index)); + } + + + /// + /// Length Method + /// + /// + /// + /// Returns the length for objects that support the Python sequence + /// protocol, or 0 if the object does not support the protocol. + /// + + public virtual int Length() { + int s = Runtime.PyObject_Size(obj); + if (s < 0) { + Runtime.PyErr_Clear(); + return 0; + } + return s; + } + + + /// + /// String Indexer + /// + /// + /// + /// Provides a shorthand for the string versions of the GetItem and + /// SetItem methods. + /// + + public virtual PyObject this[string key] { + get { return GetItem(key); } + set { SetItem(key, value); } + } + + + /// + /// PyObject Indexer + /// + /// + /// + /// Provides a shorthand for the object versions of the GetItem and + /// SetItem methods. + /// + + public virtual PyObject this[PyObject key] { + get { return GetItem(key); } + set { SetItem(key, value); } + } + + + /// + /// Numeric Indexer + /// + /// + /// + /// Provides a shorthand for the numeric versions of the GetItem and + /// SetItem methods. + /// + + public virtual PyObject this[int index] { + get { return GetItem(index); } + set { SetItem(index, value); } + } + + + /// + /// GetIterator Method + /// + /// + /// + /// Return a new (Python) iterator for the object. This is equivalent + /// to the Python expression "iter(object)". A PythonException will be + /// raised if the object cannot be iterated. + /// + + public PyObject GetIterator() { + IntPtr r = Runtime.PyObject_GetIter(obj); + if (r == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(r); + } + + + /// + /// Invoke Method + /// + /// + /// + /// Invoke the callable object with the given arguments, passed as a + /// PyObject[]. A PythonException is raised if the invokation fails. + /// + + public PyObject Invoke(params PyObject[] args) { + PyTuple t = new PyTuple(args); + IntPtr r = Runtime.PyObject_Call(obj, t.obj, IntPtr.Zero); + t.Dispose(); + if (r == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(r); + } + + + /// + /// Invoke Method + /// + /// + /// + /// Invoke the callable object with the given arguments, passed as a + /// Python tuple. A PythonException is raised if the invokation fails. + /// + + public PyObject Invoke(PyTuple args) { + IntPtr r = Runtime.PyObject_Call(obj, args.obj, IntPtr.Zero); + if (r == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(r); + } + + + /// + /// Invoke Method + /// + /// + /// + /// Invoke the callable object with the given positional and keyword + /// arguments. A PythonException is raised if the invokation fails. + /// + + public PyObject Invoke(PyObject[] args, PyDict kw) { + PyTuple t = new PyTuple(args); + IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw.obj); + t.Dispose(); + if (r == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(r); + } + + + /// + /// Invoke Method + /// + /// + /// + /// Invoke the callable object with the given positional and keyword + /// arguments. A PythonException is raised if the invokation fails. + /// + + public PyObject Invoke(PyTuple args, PyDict kw) { + IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw.obj); + if (r == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(r); + } + + + /// + /// InvokeMethod Method + /// + /// + /// + /// Invoke the named method of the object with the given arguments. + /// A PythonException is raised if the invokation is unsuccessful. + /// + + public PyObject InvokeMethod(string name, params PyObject[] args) { + PyObject method = GetAttr(name); + PyObject result = method.Invoke(args); + method.Dispose(); + return result; + } + + + /// + /// InvokeMethod Method + /// + /// + /// + /// Invoke the named method of the object with the given arguments. + /// A PythonException is raised if the invokation is unsuccessful. + /// + + public PyObject InvokeMethod(string name, PyTuple args) { + PyObject method = GetAttr(name); + PyObject result = method.Invoke(args); + method.Dispose(); + return result; + } + + + /// + /// InvokeMethod Method + /// + /// + /// + /// Invoke the named method of the object with the given arguments + /// and keyword arguments. Keyword args are passed as a PyDict object. + /// A PythonException is raised if the invokation is unsuccessful. + /// + + public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) { + PyObject method = GetAttr(name); + PyObject result = method.Invoke(args, kw); + method.Dispose(); + return result; + } + + + /// + /// InvokeMethod Method + /// + /// + /// + /// Invoke the named method of the object with the given arguments + /// and keyword arguments. Keyword args are passed as a PyDict object. + /// A PythonException is raised if the invokation is unsuccessful. + /// + + public PyObject InvokeMethod(string name, PyTuple args, PyDict kw) { + PyObject method = GetAttr(name); + PyObject result = method.Invoke(args, kw); + method.Dispose(); + return result; + } + + + /// + /// IsInstance Method + /// + /// + /// + /// Return true if the object is an instance of the given Python type + /// or class. This method always succeeds. + /// + + public bool IsInstance(PyObject typeOrClass) { + int r = Runtime.PyObject_IsInstance(obj, typeOrClass.obj); + if (r < 0) { + Runtime.PyErr_Clear(); + return false; + } + return (r != 0); + } + + + /// + /// IsSubclass Method + /// + /// + /// + /// Return true if the object is identical to or derived from the + /// given Python type or class. This method always succeeds. + /// + + public bool IsSubclass(PyObject typeOrClass) { + int r = Runtime.PyObject_IsSubclass(obj, typeOrClass.obj); + if (r < 0) { + Runtime.PyErr_Clear(); + return false; + } + return (r != 0); + } + + + /// + /// IsCallable Method + /// + /// + /// + /// Returns true if the object is a callable object. This method + /// always succeeds. + /// + + public bool IsCallable() { + return (Runtime.PyCallable_Check(obj) != 0); + } + + + /// + /// IsTrue Method + /// + /// + /// + /// Return true if the object is true according to Python semantics. + /// This method always succeeds. + /// + + public bool IsTrue() { + return (Runtime.PyObject_IsTrue(obj) != 0); + } + + + /// + /// Dir Method + /// + /// + /// + /// Return a list of the names of the attributes of the object. This + /// is equivalent to the Python expression "dir(object)". + /// + + public PyList Dir() { + IntPtr r = Runtime.PyObject_Dir(obj); + if (r == IntPtr.Zero) { + throw new PythonException(); + } + return new PyList(r); + } + + + /// + /// Repr Method + /// + /// + /// + /// Return a string representation of the object. This method is + /// the managed equivalent of the Python expression "repr(object)". + /// + + public string Repr() { + IntPtr strval = Runtime.PyObject_Repr(obj); + string result = Runtime.GetManagedString(strval); + Runtime.Decref(strval); + return result; + } + + + /// + /// ToString Method + /// + /// + /// + /// Return the string representation of the object. This method is + /// the managed equivalent of the Python expression "str(object)". + /// + + public override string ToString() { + IntPtr strval = Runtime.PyObject_Unicode(obj); + string result = Runtime.GetManagedString(strval); + Runtime.Decref(strval); + return result; + } + + + /// + /// Equals Method + /// + /// + /// + /// Return true if this object is equal to the given object. This + /// method is based on Python equality semantics. + /// + + public override bool Equals(object o) { + if (!(o is PyObject)) { + return false; + } + if (obj == ((PyObject) o).obj) { + return true; + } + int r = Runtime.PyObject_Compare(obj, ((PyObject) o).obj); + if (Exceptions.ErrorOccurred()) { + throw new PythonException(); + } + return (r == 0); + } + + + /// + /// GetHashCode Method + /// + /// + /// + /// Return a hashcode based on the Python object. This returns the + /// hash as computed by Python, equivalent to the Python expression + /// "hash(obj)". + /// + + public override int GetHashCode() { + return Runtime.PyObject_Hash(obj).ToInt32(); + } + + + } + + +} diff --git a/src/runtime/pysequence.cs b/src/runtime/pysequence.cs new file mode 100644 index 000000000..9b41c308b --- /dev/null +++ b/src/runtime/pysequence.cs @@ -0,0 +1,172 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; + +namespace Python.Runtime { + + /// + /// Represents a generic Python sequence. The methods of this class are + /// equivalent to the Python "abstract sequence API". See + /// http://www.python.org/doc/current/api/sequence.html for details. + /// + + public class PySequence : PyObject, IEnumerable { + + protected PySequence(IntPtr ptr) : base(ptr) {} + + protected PySequence() : base() {} + + + /// + /// IsSequenceType Method + /// + /// + /// + /// Returns true if the given object implements the sequence protocol. + /// + + public static bool IsSequenceType(PyObject value) { + return Runtime.PySequence_Check(value.obj); + } + + + /// + /// GetSlice Method + /// + /// + /// + /// Return the slice of the sequence with the given indices. + /// + + public PyObject GetSlice(int i1, int i2) { + IntPtr op = Runtime.PySequence_GetSlice(obj, i1, i2); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(op); + } + + + /// + /// SetSlice Method + /// + /// + /// + /// Sets the slice of the sequence with the given indices. + /// + + public void SetSlice(int i1, int i2, PyObject v) { + int r = Runtime.PySequence_SetSlice(obj, i1, i2, v.obj); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// DelSlice Method + /// + /// + /// + /// Deletes the slice of the sequence with the given indices. + /// + + public void DelSlice(int i1, int i2) { + int r = Runtime.PySequence_DelSlice(obj, i1, i2); + if (r < 0) { + throw new PythonException(); + } + } + + + /// + /// Index Method + /// + /// + /// + /// Return the index of the given item in the sequence, or -1 if + /// the item does not appear in the sequence. + /// + + public int Index(PyObject item) { + int r = Runtime.PySequence_Index(obj, item.obj); + if (r < 0) { + Runtime.PyErr_Clear(); + return -1; + } + return r; + } + + + /// + /// Contains Method + /// + /// + /// + /// Return true if the sequence contains the given item. This method + /// throws a PythonException if an error occurs during the check. + /// + + public bool Contains(PyObject item) { + int r = Runtime.PySequence_Contains(obj, item.obj); + if (r < 0) { + throw new PythonException(); + } + return (r != 0); + } + + + /// + /// Concat Method + /// + /// + /// + /// Return the concatenation of the sequence object with the passed in + /// sequence object. + /// + + public PyObject Concat(PyObject other) { + IntPtr op = Runtime.PySequence_Concat(obj, other.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(op); + } + + + /// + /// Repeat Method + /// + /// + /// + /// Return the sequence object repeated N times. This is equivalent + /// to the Python expression "object * count". + /// + + public PyObject Repeat(int count) { + IntPtr op = Runtime.PySequence_Repeat(obj, count); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(op); + } + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return new PyIter(this); + } + + #endregion +} + +} diff --git a/src/runtime/pystring.cs b/src/runtime/pystring.cs new file mode 100644 index 000000000..818e124cd --- /dev/null +++ b/src/runtime/pystring.cs @@ -0,0 +1,85 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + /// + /// Represents a Python (ansi) string object. See the documentation at + /// http://www.python.org/doc/current/api/stringObjects.html for details. + /// 2011-01-29: ...Then why does the string constructor call PyUnicode_FromUnicode()??? + /// + + public class PyString : PySequence { + + /// + /// PyString Constructor + /// + /// + /// + /// Creates a new PyString from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyString(IntPtr ptr) : base(ptr) {} + + + /// + /// PyString Constructor + /// + /// + /// + /// Copy constructor - obtain a PyString from a generic PyObject. + /// An ArgumentException will be thrown if the given object is not + /// a Python string object. + /// + + public PyString(PyObject o) : base() { + if (!IsStringType(o)) { + throw new ArgumentException("object is not a string"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// PyString Constructor + /// + /// + /// + /// Creates a Python string from a managed string. + /// + + public PyString(string s) : base() { + obj = Runtime.PyUnicode_FromUnicode(s, s.Length); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// IsStringType Method + /// + /// + /// + /// Returns true if the given object is a Python string. + /// + + public static bool IsStringType(PyObject value) { + return Runtime.PyString_Check(value.obj); + } + + } + + +} diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs new file mode 100644 index 000000000..07326185f --- /dev/null +++ b/src/runtime/pythonengine.cs @@ -0,0 +1,355 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Threading; + +namespace Python.Runtime { + + /// + /// This class provides the public interface of the Python runtime. + /// + + public class PythonEngine { + + private static DelegateManager delegateManager; + private static bool initialized; + + #region Properties + + public static bool IsInitialized { + get { + return initialized; + } + } + + internal static DelegateManager DelegateManager { + get { + if (delegateManager == null) { + throw new InvalidOperationException("DelegateManager has not yet been initialized using Python.Runtime.PythonEngine.Initialize()."); + } + return delegateManager; + } + } + + public static string ProgramName { + get { + string result = Runtime.Py_GetProgramName(); + if (result == null) { + return ""; + } + return result; + } + set { + Runtime.Py_SetProgramName(value); + } + } + + public static string PythonHome { + get { + string result = Runtime.Py_GetPythonHome(); + if (result == null) { + return ""; + } + return result; + } + set { + Runtime.Py_SetPythonHome(value); + } + } + + public static string Version { + get { + return Runtime.Py_GetVersion(); + } + } + + public static string BuildInfo { + get { + return Runtime.Py_GetBuildInfo(); + } + } + + public static string Platform { + get { + return Runtime.Py_GetPlatform(); + } + } + + public static string Copyright { + get { + return Runtime.Py_GetCopyright(); + } + } + + public static int RunSimpleString(string code) { + return Runtime.PyRun_SimpleString(code); + } + + #endregion + + + /// + /// Initialize Method + /// + /// + /// + /// Initialize the Python runtime. It is safe to call this method + /// more than once, though initialization will only happen on the + /// first call. It is *not* necessary to hold the Python global + /// interpreter lock (GIL) to call this method. + /// + + public static void Initialize() { + if (!initialized) { + // Creating the delegateManager MUST happen before Runtime.Initialize + // is called. If it happens afterwards, DelegateManager's CodeGenerator + // throws an exception in its ctor. This exception is eaten somehow + // during an initial "import clr", and the world ends shortly thereafter. + // This is probably masking some bad mojo happening somewhere in Runtime.Initialize(). + delegateManager = new DelegateManager(); + Runtime.Initialize(); + initialized = true; + Exceptions.Clear(); + } + } + + + //==================================================================== + // A helper to perform initialization from the context of an active + // CPython interpreter process - this bootstraps the managed runtime + // when it is imported by the CLR extension module. + //==================================================================== + + public static void InitExt() { + Initialize(); + + // Trickery - when the import hook is installed into an already + // running Python, the standard import machinery is still in + // control for the duration of the import that caused bootstrap. + // + // That is problematic because the std machinery tries to get + // sub-names directly from the module __dict__ rather than going + // through our module object's getattr hook. This workaround is + // evil ;) We essentially climb up the stack looking for the + // import that caused the bootstrap to happen, then re-execute + // the import explicitly after our hook has been installed. By + // doing this, the original outer import should work correctly. + // + // Note that this is only needed during the execution of the + // first import that installs the CLR import hook. This hack + // still doesn't work if you use the interactive interpreter, + // since there is no line info to get the import line ;( + + string code = + + "import traceback\n" + + "for item in traceback.extract_stack():\n" + + " line = item[3]\n" + + " if line is not None:\n" + + " if line.startswith('import CLR') or \\\n" + + " line.startswith('import clr') or \\\n" + + " line.startswith('from clr') or \\\n" + + " line.startswith('from CLR'):\n" + + " exec line\n" + + " break\n"; + + PyObject r = PythonEngine.RunString(code); + if (r != null) { + r.Dispose(); + } + } + + + /// + /// Shutdown Method + /// + /// + /// + /// Shutdown and release resources held by the Python runtime. The + /// Python runtime can no longer be used in the current process + /// after calling the Shutdown method. + /// + + public static void Shutdown() { + if (initialized) { + Runtime.Shutdown(); + initialized = false; + } + } + + + /// + /// AcquireLock Method + /// + /// + /// + /// Acquire the Python global interpreter lock (GIL). Managed code + /// *must* call this method before using any objects or calling any + /// methods on objects in the Python.Runtime namespace. The only + /// exception is PythonEngine.Initialize, which may be called without + /// first calling AcquireLock. + /// + /// Each call to AcquireLock must be matched by a corresponding call + /// to ReleaseLock, passing the token obtained from AcquireLock. + /// + /// For more information, see the "Extending and Embedding" section + /// of the Python documentation on www.python.org. + /// + + public static IntPtr AcquireLock() { + return Runtime.PyGILState_Ensure(); + } + + + /// + /// ReleaseLock Method + /// + /// + /// + /// Release the Python global interpreter lock using a token obtained + /// from a previous call to AcquireLock. + /// + /// For more information, see the "Extending and Embedding" section + /// of the Python documentation on www.python.org. + /// + + public static void ReleaseLock(IntPtr gs) { + Runtime.PyGILState_Release(gs); + } + + + /// + /// BeginAllowThreads Method + /// + /// + /// + /// Release the Python global interpreter lock to allow other threads + /// to run. This is equivalent to the Py_BEGIN_ALLOW_THREADS macro + /// provided by the C Python API. + /// + /// For more information, see the "Extending and Embedding" section + /// of the Python documentation on www.python.org. + /// + + public static IntPtr BeginAllowThreads() { + return Runtime.PyEval_SaveThread(); + } + + + /// + /// EndAllowThreads Method + /// + /// + /// + /// Re-aquire the Python global interpreter lock for the current + /// thread. This is equivalent to the Py_END_ALLOW_THREADS macro + /// provided by the C Python API. + /// + /// For more information, see the "Extending and Embedding" section + /// of the Python documentation on www.python.org. + /// + + public static void EndAllowThreads(IntPtr ts) { + Runtime.PyEval_RestoreThread(ts); + } + + + + /// + /// ImportModule Method + /// + /// + /// + /// Given a fully-qualified module or package name, import the + /// module and return the resulting module object as a PyObject + /// or null if an exception is raised. + /// + + public static PyObject ImportModule(string name) { + IntPtr op = Runtime.PyImport_ImportModule(name); + if (op == IntPtr.Zero) { + return null; + } + return new PyObject(op); + } + + + /// + /// ReloadModule Method + /// + /// + /// + /// Given a PyObject representing a previously loaded module, reload + /// the module. + /// + + public static PyObject ReloadModule(PyObject module) { + IntPtr op = Runtime.PyImport_ReloadModule(module.Handle); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(op); + } + + + /// + /// ModuleFromString Method + /// + /// + /// + /// Given a string module name and a string containing Python code, + /// execute the code in and return a module of the given name. + /// + + public static PyObject ModuleFromString(string name, string code) { + IntPtr c = Runtime.Py_CompileString(code, "none", (IntPtr)257); + if (c == IntPtr.Zero) { + throw new PythonException(); + } + IntPtr m = Runtime.PyImport_ExecCodeModule(name, c); + if (m == IntPtr.Zero) { + throw new PythonException(); + } + return new PyObject(m); + } + + + /// + /// RunString Method + /// + /// + /// + /// Run a string containing Python code. Returns the result of + /// executing the code string as a PyObject instance, or null if + /// an exception was raised. + /// + + public static PyObject RunString(string code) { + IntPtr globals = Runtime.PyEval_GetGlobals(); + IntPtr locals = Runtime.PyDict_New(); + + IntPtr builtins = Runtime.PyEval_GetBuiltins(); + Runtime.PyDict_SetItemString(locals, "__builtins__", builtins); + + IntPtr flag = (IntPtr)257; /* Py_file_input */ + IntPtr result = Runtime.PyRun_String(code, flag, globals, locals); + Runtime.Decref(locals); + if (result == IntPtr.Zero) { + return null; + } + return new PyObject(result); + } + + + + } + + +} diff --git a/src/runtime/pythonexception.cs b/src/runtime/pythonexception.cs new file mode 100644 index 000000000..592e9ea37 --- /dev/null +++ b/src/runtime/pythonexception.cs @@ -0,0 +1,150 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + /// + /// Provides a managed interface to exceptions thrown by the Python + /// runtime. + /// + + public class PythonException : System.Exception { + + private IntPtr _pyType = IntPtr.Zero; + private IntPtr _pyValue = IntPtr.Zero; + private IntPtr _pyTB = IntPtr.Zero; + private string _tb = ""; + private string _message = ""; + private bool disposed = false; + + public PythonException() : base() + { + IntPtr gs = PythonEngine.AcquireLock(); + Runtime.PyErr_Fetch(ref _pyType, ref _pyValue, ref _pyTB); + Runtime.Incref(_pyType); + Runtime.Incref(_pyValue); + Runtime.Incref(_pyTB); + if ((_pyType != IntPtr.Zero) && (_pyValue != IntPtr.Zero)) + { + string type = new PyObject(_pyType).GetAttr("__name__").ToString(); + string message = Runtime.GetManagedString(_pyValue); + _message = type + " : " + message; + } + if (_pyTB != IntPtr.Zero) + { + PyObject tb_module = PythonEngine.ImportModule("traceback"); + _tb = tb_module.InvokeMethod("format_tb", new PyObject(_pyTB)).ToString(); + } + PythonEngine.ReleaseLock(gs); + } + + // Ensure that encapsulated Python objects are decref'ed appropriately + // when the managed exception wrapper is garbage-collected. + + ~PythonException() { + Dispose(); + } + + + /// + /// PyType Property + /// + /// + /// + /// Returns the exception type as a Python object. + /// + + public IntPtr PyType + { + get { return _pyType; } + } + + /// + /// PyValue Property + /// + /// + /// + /// Returns the exception value as a Python object. + /// + + public IntPtr PyValue + { + get { return _pyValue; } + } + + /// + /// Message Property + /// + /// + /// + /// A string representing the python exception message. + /// + + public override string Message + { + get { return _message; } + } + + /// + /// StackTrace Property + /// + /// + /// + /// A string representing the python exception stack trace. + /// + + public override string StackTrace + { + get { return _tb; } + } + + + /// + /// Dispose Method + /// + /// + /// + /// The Dispose method provides a way to explicitly release the + /// Python objects represented by a PythonException. + /// + + public void Dispose() { + if (!disposed) { + if (Runtime.Py_IsInitialized() > 0) { + IntPtr gs = PythonEngine.AcquireLock(); + Runtime.Decref(_pyType); + Runtime.Decref(_pyValue); + // XXX Do we ever get TraceBack? // + if (_pyTB != IntPtr.Zero) { + Runtime.Decref(_pyTB); + } + PythonEngine.ReleaseLock(gs); + } + GC.SuppressFinalize(this); + disposed = true; + } + } + + /// + /// Matches Method + /// + /// + /// + /// Returns true if the Python exception type represented by the + /// PythonException instance matches the given exception type. + /// + + public static bool Matches(IntPtr ob) { + return Runtime.PyErr_ExceptionMatches(ob) != 0; + } + + } +} diff --git a/src/runtime/pytuple.cs b/src/runtime/pytuple.cs new file mode 100644 index 000000000..cac41acf4 --- /dev/null +++ b/src/runtime/pytuple.cs @@ -0,0 +1,126 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Runtime { + + /// + /// Represents a Python tuple object. See the documentation at + /// http://www.python.org/doc/current/api/tupleObjects.html for details. + /// + + public class PyTuple : PySequence { + + /// + /// PyTuple Constructor + /// + /// + /// + /// Creates a new PyTuple from an existing object reference. Note + /// that the instance assumes ownership of the object reference. + /// The object reference is not checked for type-correctness. + /// + + public PyTuple(IntPtr ptr) : base(ptr) {} + + + /// + /// PyTuple Constructor + /// + /// + /// + /// Copy constructor - obtain a PyTuple from a generic PyObject. An + /// ArgumentException will be thrown if the given object is not a + /// Python tuple object. + /// + + public PyTuple(PyObject o) : base() { + if (!IsTupleType(o)) { + throw new ArgumentException("object is not a tuple"); + } + Runtime.Incref(o.obj); + obj = o.obj; + } + + + /// + /// PyTuple Constructor + /// + /// + /// + /// Creates a new empty PyTuple. + /// + + public PyTuple() : base() { + obj = Runtime.PyTuple_New(0); + if (obj == IntPtr.Zero) { + throw new PythonException(); + } + } + + + /// + /// PyTuple Constructor + /// + /// + /// + /// Creates a new PyTuple from an array of PyObject instances. + /// + + public PyTuple(PyObject[] items) : base() { + int count = items.Length; + obj = Runtime.PyTuple_New(count); + for (int i = 0; i < count; i++) { + IntPtr ptr = items[i].obj; + Runtime.Incref(ptr); + int r = Runtime.PyTuple_SetItem(obj, i, ptr); + if (r < 0) { + throw new PythonException(); + } + } + } + + + /// + /// IsTupleType Method + /// + /// + /// + /// Returns true if the given object is a Python tuple. + /// + + public static bool IsTupleType(PyObject value) { + return Runtime.PyTuple_Check(value.obj); + } + + + /// + /// AsTuple Method + /// + /// + /// + /// Convert a Python object to a Python tuple if possible, raising + /// a PythonException if the conversion is not possible. This is + /// equivalent to the Python expression "tuple(object)". + /// + + public static PyTuple AsTuple(PyObject value) { + IntPtr op = Runtime.PySequence_Tuple(value.obj); + if (op == IntPtr.Zero) { + throw new PythonException(); + } + return new PyTuple(op); + } + + + } + + +} diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs new file mode 100644 index 000000000..19aa2ca2d --- /dev/null +++ b/src/runtime/runtime.cs @@ -0,0 +1,1605 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; +using System.Security; +#if (UCS4) +using System.Text; +using Mono.Unix; +#endif + +namespace Python.Runtime { + + [SuppressUnmanagedCodeSecurityAttribute()] + + public class Runtime { + + /// + /// Encapsulates the low-level Python C API. Note that it is + /// the responsibility of the caller to have acquired the GIL + /// before calling any of these methods. + /// +#if (UCS4) + public const int UCS = 4; +#endif +#if (UCS2) + public const int UCS = 2; +#endif +#if ! (UCS2 || UCS4) +#error You must define either UCS2 or UCS4! +#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 +#endif + + internal static bool wrap_exceptions; + internal static bool is32bit; + + /// + /// Intitialize the runtime... + /// + internal static void Initialize() { + + is32bit = IntPtr.Size == 4; + + if (0 == Runtime.Py_IsInitialized()) { + Runtime.Py_Initialize(); + } + + // make sure threads are initialized even if python was initialized already + Runtime.PyEval_InitThreads(); + + IntPtr dict = Runtime.PyImport_GetModuleDict(); + IntPtr op = Runtime.PyDict_GetItemString(dict, "__builtin__"); + + PyBaseObjectType = Runtime.PyObject_GetAttrString(op, "object"); + + PyModuleType = Runtime.PyObject_Type(op); + PyNone = Runtime.PyObject_GetAttrString(op, "None"); + PyTrue = Runtime.PyObject_GetAttrString(op, "True"); + PyFalse = Runtime.PyObject_GetAttrString(op, "False"); + + PyBoolType = Runtime.PyObject_Type(PyTrue); + PyNoneType = Runtime.PyObject_Type(PyNone); + PyTypeType = Runtime.PyObject_Type(PyNoneType); + + op = Runtime.PyObject_GetAttrString(dict, "keys"); + PyMethodType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyString_FromString("string"); + PyStringType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyUnicode_FromString("unicode"); + PyUnicodeType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyTuple_New(0); + PyTupleType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyList_New(0); + PyListType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyDict_New(); + PyDictType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyInt_FromInt32(0); + PyIntType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyLong_FromLong(0); + PyLongType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + op = Runtime.PyFloat_FromDouble(0); + PyFloatType = Runtime.PyObject_Type(op); + Runtime.Decref(op); + + 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); + + IntPtr i = Runtime.PyInstance_New(c, IntPtr.Zero, IntPtr.Zero); + PyInstanceType = Runtime.PyObject_Type(i); + + Runtime.Decref(s); + Runtime.Decref(i); + Runtime.Decref(c); + Runtime.Decref(d); + + Error = new IntPtr(-1); + + // 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) + wrap_exceptions = false; +#else + IntPtr m = PyImport_ImportModule("exceptions"); + Exceptions.ErrorCheck(m); + op = Runtime.PyObject_GetAttrString(m, "Exception"); + Exceptions.ErrorCheck(op); + if (Runtime.PyObject_TYPE(op) == PyClassType) { + wrap_exceptions = true; + } + Runtime.Decref(op); + Runtime.Decref(m); +#endif + + // Initialize modules that depend on the runtime class. + AssemblyManager.Initialize(); + PyCLRMetaType = MetaType.Initialize(); + Exceptions.Initialize(); + ImportHook.Initialize(); + + // Need to add the runtime directory to sys.path so that we + // can find built-in assemblies like System.Data, et. al. + string rtdir = RuntimeEnvironment.GetRuntimeDirectory(); + IntPtr path = Runtime.PySys_GetObject("path"); + IntPtr item = Runtime.PyString_FromString(rtdir); + Runtime.PyList_Append(path, item); + Runtime.Decref(item); + AssemblyManager.UpdatePath(); + } + + internal static void Shutdown() { + AssemblyManager.Shutdown(); + Exceptions.Shutdown(); + ImportHook.Shutdown(); + Py_Finalize(); + } + + internal static IntPtr Py_single_input = (IntPtr)256; + internal static IntPtr Py_file_input = (IntPtr)257; + internal static IntPtr Py_eval_input = (IntPtr)258; + + internal static IntPtr PyBaseObjectType; + internal static IntPtr PyModuleType; + internal static IntPtr PyClassType; + internal static IntPtr PyInstanceType; + internal static IntPtr PyCLRMetaType; + internal static IntPtr PyMethodType; + + internal static IntPtr PyUnicodeType; + internal static IntPtr PyStringType; + internal static IntPtr PyTupleType; + internal static IntPtr PyListType; + internal static IntPtr PyDictType; + internal static IntPtr PyIntType; + internal static IntPtr PyLongType; + internal static IntPtr PyFloatType; + internal static IntPtr PyBoolType; + internal static IntPtr PyNoneType; + internal static IntPtr PyTypeType; + + internal static IntPtr PyTrue; + internal static IntPtr PyFalse; + internal static IntPtr PyNone; + internal static IntPtr Error; + + + + internal static IntPtr GetBoundArgTuple(IntPtr obj, IntPtr args) { + if (Runtime.PyObject_TYPE(args) != Runtime.PyTupleType) { + Exceptions.SetError(Exceptions.TypeError, "tuple expected"); + return IntPtr.Zero; + } + int size = Runtime.PyTuple_Size(args); + IntPtr items = Runtime.PyTuple_New(size + 1); + Runtime.PyTuple_SetItem(items, 0, obj); + Runtime.Incref(obj); + + for (int i = 0; i < size; i++) { + IntPtr item = Runtime.PyTuple_GetItem(args, i); + Runtime.Incref(item); + Runtime.PyTuple_SetItem(items, i + 1, item); + } + + return items; + } + + + internal static IntPtr ExtendTuple(IntPtr t, params IntPtr[] args) { + int size = Runtime.PyTuple_Size(t); + int add = args.Length; + IntPtr item; + + IntPtr items = Runtime.PyTuple_New(size + add); + for (int i = 0; i < size; i++) { + item = Runtime.PyTuple_GetItem(t, i); + Runtime.Incref(item); + Runtime.PyTuple_SetItem(items, i, item); + } + + for (int n = 0; n < add; n++) { + item = args[n]; + Runtime.Incref(item); + Runtime.PyTuple_SetItem(items, size + n, item); + } + + return items; + } + + internal static Type[] PythonArgsToTypeArray(IntPtr arg) { + return PythonArgsToTypeArray(arg, false); + } + + internal static Type[] PythonArgsToTypeArray(IntPtr arg, bool mangleObjects) { + // Given a PyObject * that is either a single type object or a + // tuple of (managed or unmanaged) type objects, return a Type[] + // containing the CLR Type objects that map to those types. + IntPtr args = arg; + bool free = false; + + if (!Runtime.PyTuple_Check(arg)) { + args = Runtime.PyTuple_New(1); + Runtime.Incref(arg); + Runtime.PyTuple_SetItem(args, 0, arg); + free = true; + } + + int n = Runtime.PyTuple_Size(args); + Type[] types = new Type[n]; + Type t = null; + + for (int i = 0; i < n; i++) { + IntPtr op = Runtime.PyTuple_GetItem(args, i); + if (mangleObjects && (!Runtime.PyType_Check(op))) { + op = Runtime.PyObject_TYPE(op); + } + ManagedType mt = ManagedType.GetManagedObject(op); + + if (mt is ClassBase) { + t = ((ClassBase)mt).type; + } + else if (mt is CLRObject) { + object inst = ((CLRObject)mt).inst; + if (inst is Type) { + t = inst as Type; + } + } + else { + t = Converter.GetTypeByAlias(op); + } + + if (t == null) { + types = null; + break; + } + types[i] = t; + } + if (free) { + Runtime.Decref(args); + } + return types; + } + + //=================================================================== + // Managed exports of the Python C API. Where appropriate, we do + // some optimization to avoid managed <--> unmanaged transitions + // (mostly for heavily used methods). + //=================================================================== + + internal unsafe static void Incref(IntPtr op) { +#if (Py_DEBUG) + Py_IncRef(op); + return; +#else + void *p = (void *)op; + if ((void *)0 != p) { + if (is32bit) { (*(int *)p)++; } + else { (*(long *)p)++; } + } +#endif + } + + internal unsafe static void Decref(IntPtr op) { + if (op == IntPtr.Zero) { + DebugUtil.Print("Decref(NULL)"); + } +#if (Py_DEBUG) + // Py_DecRef calls Python's Py_DECREF + Py_DecRef(op); + return; +#else + void* p = (void*) op; + if ((void*) 0 != p) { + if (is32bit) { --(*(int*) p); } + else { --(*(long*) p); } + if ((*(int*) p) == 0) { + // PyObject_HEAD: struct _typeobject *ob_type + void* t = is32bit ? (void*) (*((uint*) p + 1)) : + (void*) (*((ulong*) p + 1)); + // PyTypeObject: destructor tp_dealloc + void* f = is32bit ? (void*) (*((uint*) t + 6)) : + (void*) (*((ulong*) t + 6)); + if ((void*) 0 == f) { + return; + } + NativeCall.Impl.Void_Call_1(new IntPtr(f), op); + return; + } + } +#endif + } + +#if (Py_DEBUG) + // Py_IncRef and Py_DecRef are taking care of the extra payload + // in Py_DEBUG builds of Python like _Py_RefTotal + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + private unsafe static extern void + Py_IncRef(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + private unsafe static extern void + Py_DecRef(IntPtr ob); +#endif + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + Py_Initialize(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + Py_IsInitialized(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + Py_Finalize(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + Py_NewInterpreter(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + Py_EndInterpreter(IntPtr threadState); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyThreadState_New(IntPtr istate); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyThreadState_Get(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyThread_get_key_value(IntPtr key); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyThread_get_thread_ident(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyThread_set_key_value(IntPtr key, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyThreadState_Swap(IntPtr key); + + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyGILState_Ensure(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyGILState_Release(IntPtr gs); + + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyGILState_GetThisThreadState(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + public unsafe static extern int + Py_Main(int argc, string[] argv); + + [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 void + PyEval_AcquireLock(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyEval_ReleaseLock(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyEval_AcquireThread(IntPtr tstate); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyEval_ReleaseThread(IntPtr tstate); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyEval_SaveThread(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyEval_RestoreThread(IntPtr tstate); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyEval_GetBuiltins(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyEval_GetGlobals(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyEval_GetLocals(); + + + [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_GetVersion(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern string + Py_GetPlatform(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern string + Py_GetCopyright(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern string + Py_GetCompiler(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern string + Py_GetBuildInfo(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyRun_SimpleString(string code); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyRun_String(string code, IntPtr st, IntPtr globals, IntPtr locals); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + Py_CompileString(string code, string file, IntPtr tok); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + 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 + PyCFunction_NewEx(IntPtr ml, IntPtr self, IntPtr mod); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyCFunction_Call(IntPtr func, IntPtr args, IntPtr kw); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyClass_New(IntPtr bases, IntPtr dict, IntPtr name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyInstance_New(IntPtr cls, IntPtr args, IntPtr kw); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyInstance_NewRaw(IntPtr cls, IntPtr dict); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyMethod_New(IntPtr func, IntPtr self, IntPtr cls); + + + //==================================================================== + // Python abstract object API + //==================================================================== + + // A macro-like method to get the type of a Python object. This is + // designed to be lean and mean in IL & avoid managed <-> unmanaged + // transitions. Note that this does not incref the type object. + + internal unsafe static IntPtr + PyObject_TYPE(IntPtr op) { + void* p = (void*)op; + if ((void*)0 == p) { + return IntPtr.Zero; + } +#if (Py_DEBUG) + int n = 3; +#else + int n = 1; +#endif + if (is32bit) { + return new IntPtr((void*)(*((uint*)p + n))); + } + else { + return new IntPtr((void*)(*((ulong*)p + n))); + } + } + + // Managed version of the standard Python C API PyObject_Type call. + // This version avoids a managed <-> unmanaged transition. This one + // does incref the returned type object. + + internal unsafe static IntPtr + PyObject_Type(IntPtr op) { + IntPtr tp = PyObject_TYPE(op); + Runtime.Incref(tp); + return tp; + } + + internal static string PyObject_GetTypeName(IntPtr op) { + IntPtr pyType = Marshal.ReadIntPtr(op, ObjectOffset.ob_type); + IntPtr ppName = Marshal.ReadIntPtr(pyType, TypeOffset.tp_name); + return Marshal.PtrToStringAnsi(ppName); + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_HasAttrString(IntPtr pointer, string name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_GetAttrString(IntPtr pointer, string name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_SetAttrString(IntPtr pointer, string name, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_HasAttr(IntPtr pointer, IntPtr name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_GetAttr(IntPtr pointer, IntPtr name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_SetAttr(IntPtr pointer, IntPtr name, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_GetItem(IntPtr pointer, IntPtr key); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_SetItem(IntPtr pointer, IntPtr key, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_DelItem(IntPtr pointer, IntPtr key); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_GetIter(IntPtr op); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_Call(IntPtr pointer, IntPtr args, IntPtr kw); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_CallObject(IntPtr pointer, IntPtr args); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_Compare(IntPtr value1, IntPtr value2); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_IsInstance(IntPtr ob, IntPtr type); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_IsSubclass(IntPtr ob, IntPtr type); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyCallable_Check(IntPtr pointer); + + [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_Size(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_Hash(IntPtr op); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_Repr(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_Str(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + ExactSpelling = true, CharSet = CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_Unicode(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_Dir(IntPtr pointer); + + + //==================================================================== + // Python number API + //==================================================================== + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyNumber_Int(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyNumber_Long(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyNumber_Float(IntPtr ob); + + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern bool + PyNumber_Check(IntPtr ob); + + + internal static bool PyInt_Check(IntPtr ob) { + return PyObject_TypeCheck(ob, Runtime.PyIntType); + } + + 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) { + IntPtr v = new IntPtr(value); + return PyInt_FromLong(v); + } + + internal static IntPtr PyInt_FromInt64(long value) { + IntPtr v = new IntPtr(value); + return PyInt_FromLong(v); + } + + + [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(); + + + internal static bool PyLong_Check(IntPtr ob) { + return PyObject_TYPE(ob) == Runtime.PyLongType; + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyLong_FromLong(long value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyLong_FromUnsignedLong(uint value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyLong_FromDouble(double value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyLong_FromLongLong(long value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyLong_FromUnsignedLongLong(ulong value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyLong_FromString(string value, IntPtr end, int radix); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyLong_AsLong(IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern uint + PyLong_AsUnsignedLong(IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern long + PyLong_AsLongLong(IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern ulong + PyLong_AsUnsignedLongLong(IntPtr value); + + + internal static bool PyFloat_Check(IntPtr ob) { + return PyObject_TYPE(ob) == Runtime.PyFloatType; + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyFloat_FromDouble(double value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyFloat_FromString(IntPtr value, IntPtr junk); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern double + PyFloat_AsDouble(IntPtr ob); + + + //==================================================================== + // Python sequence API + //==================================================================== + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern bool + PySequence_Check(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PySequence_GetItem(IntPtr pointer, int index); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_SetItem(IntPtr pointer, int index, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_DelItem(IntPtr pointer, int index); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PySequence_GetSlice(IntPtr pointer, int i1, int i2); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_SetSlice(IntPtr pointer, int i1, int i2, IntPtr v); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_DelSlice(IntPtr pointer, int i1, int i2); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_Size(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_Contains(IntPtr pointer, IntPtr item); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PySequence_Concat(IntPtr pointer, IntPtr other); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PySequence_Repeat(IntPtr pointer, int count); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_Index(IntPtr pointer, IntPtr item); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySequence_Count(IntPtr pointer, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PySequence_Tuple(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PySequence_List(IntPtr pointer); + + + //==================================================================== + // Python string API + //==================================================================== + + internal static bool IsStringType(IntPtr op) { + IntPtr t = PyObject_TYPE(op); + return (t == PyStringType) || (t == PyUnicodeType); + } + + internal static bool PyString_Check(IntPtr ob) { + return PyObject_TYPE(ob) == Runtime.PyStringType; + } + + internal static IntPtr PyString_FromString(string value) { + return PyString_FromStringAndSize(value, value.Length); + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyString_FromStringAndSize(string value, int size); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + EntryPoint="PyString_AsString", + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyString_AS_STRING(IntPtr op); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyString_Size(IntPtr pointer); + + internal static bool PyUnicode_Check(IntPtr ob) { + return PyObject_TYPE(ob) == Runtime.PyUnicodeType; + } + +#if (UCS2) + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + EntryPoint="PyUnicodeUCS2_FromObject", + ExactSpelling=true, CharSet=CharSet.Unicode)] + internal unsafe static extern IntPtr + PyUnicode_FromObject(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + EntryPoint="PyUnicodeUCS2_FromEncodedObject", + 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="PyUnicodeUCS2_FromUnicode", + ExactSpelling=true, CharSet=CharSet.Unicode)] + internal unsafe static extern IntPtr + PyUnicode_FromUnicode(string s, int size); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + EntryPoint="PyUnicodeUCS2_GetSize", + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyUnicode_GetSize(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + EntryPoint="PyUnicodeUCS2_AsUnicode", + ExactSpelling=true)] + internal unsafe static extern char * + PyUnicode_AsUnicode(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + EntryPoint="PyUnicodeUCS2_AsUnicode", + ExactSpelling=true, CharSet=CharSet.Unicode)] + internal unsafe static extern IntPtr + PyUnicode_AS_UNICODE(IntPtr op); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + EntryPoint="PyUnicodeUCS2_FromOrdinal", + ExactSpelling=true, CharSet=CharSet.Unicode)] + internal unsafe static extern IntPtr + PyUnicode_FromOrdinal(int c); + + internal static IntPtr PyUnicode_FromString(string s) + { + return PyUnicode_FromUnicode(s, (s.Length)); + } + + internal unsafe static string GetManagedString(IntPtr op) + { + IntPtr type = PyObject_TYPE(op); + + if (type == Runtime.PyStringType) + { + return Marshal.PtrToStringAnsi( + PyString_AS_STRING(op), + Runtime.PyString_Size(op) + ); + } + + if (type == Runtime.PyUnicodeType) + { + char* p = Runtime.PyUnicode_AsUnicode(op); + int size = Runtime.PyUnicode_GetSize(op); + return new String(p, 0, size); + } + + return null; + } + +#endif +#if (UCS4) + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicodeUCS4_FromObject", + ExactSpelling = true, CharSet = CharSet.Unicode)] + internal unsafe static extern IntPtr + PyUnicode_FromObject(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicodeUCS4_FromEncodedObject", + 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 = "PyUnicodeUCS4_FromUnicode", + ExactSpelling = true)] + internal unsafe static extern IntPtr + PyUnicode_FromUnicode( + [MarshalAs (UnmanagedType.CustomMarshaler, + MarshalTypeRef=typeof(Utf32Marshaler))] + string s, int size); + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicodeUCS4_GetSize", + ExactSpelling = true, CharSet = CharSet.Ansi)] + internal unsafe static extern int + PyUnicode_GetSize(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicodeUCS4_AsUnicode", + ExactSpelling = true)] + internal unsafe static extern IntPtr + PyUnicode_AsUnicode(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicodeUCS4_AsUnicode", + ExactSpelling = true, CharSet = CharSet.Unicode)] + internal unsafe static extern IntPtr + PyUnicode_AS_UNICODE(IntPtr op); + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicodeUCS4_FromOrdinal", + ExactSpelling = true, CharSet = CharSet.Unicode)] + internal unsafe static extern IntPtr + PyUnicode_FromOrdinal(int c); + + internal static IntPtr PyUnicode_FromString(string s) + { + return PyUnicode_FromUnicode(s, (s.Length)); + } + + internal unsafe static string GetManagedString(IntPtr op) + { + IntPtr type = PyObject_TYPE(op); + + if (type == Runtime.PyStringType) + { + return Marshal.PtrToStringAnsi( + PyString_AS_STRING(op), + Runtime.PyString_Size(op) + ); + } + + if (type == Runtime.PyUnicodeType) + { + IntPtr p = Runtime.PyUnicode_AsUnicode(op); + return UnixMarshal.PtrToString(p, Encoding.UTF32); + } + + return null; + } +#endif + + //==================================================================== + // Python dictionary API + //==================================================================== + + internal static bool PyDict_Check(IntPtr ob) { + return PyObject_TYPE(ob) == Runtime.PyDictType; + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDict_New(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDictProxy_New(IntPtr dict); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDict_GetItem(IntPtr pointer, IntPtr key); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDict_GetItemString(IntPtr pointer, string key); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyDict_SetItem(IntPtr pointer, IntPtr key, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyDict_SetItemString(IntPtr pointer, string key, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + 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 + PyMapping_HasKey(IntPtr pointer, IntPtr key); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDict_Keys(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDict_Values(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDict_Items(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyDict_Copy(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyDict_Update(IntPtr pointer, IntPtr other); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyDict_Clear(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyDict_Size(IntPtr pointer); + + + //==================================================================== + // Python list API + //==================================================================== + + internal static bool PyList_Check(IntPtr ob) { + return PyObject_TYPE(ob) == Runtime.PyListType; + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyList_New(int size); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyList_AsTuple(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyList_GetItem(IntPtr pointer, int index); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyList_SetItem(IntPtr pointer, int index, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyList_Insert(IntPtr pointer, int index, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyList_Append(IntPtr pointer, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyList_Reverse(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyList_Sort(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyList_GetSlice(IntPtr pointer, int start, int end); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyList_SetSlice(IntPtr pointer, int start, int end, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyList_Size(IntPtr pointer); + + + //==================================================================== + // Python tuple API + //==================================================================== + + internal static bool PyTuple_Check(IntPtr ob) { + return PyObject_TYPE(ob) == Runtime.PyTupleType; + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyTuple_New(int size); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyTuple_GetItem(IntPtr pointer, int index); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyTuple_SetItem(IntPtr pointer, int index, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyTuple_GetSlice(IntPtr pointer, int start, int end); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyTuple_Size(IntPtr pointer); + + + //==================================================================== + // Python iterator API + //==================================================================== + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + ExactSpelling = true, CharSet = CharSet.Ansi)] + internal unsafe static extern bool + PyIter_Check(IntPtr pointer); + + [DllImport(Runtime.dll, CallingConvention = CallingConvention.Cdecl, + ExactSpelling = true, CharSet = CharSet.Ansi)] + internal unsafe static extern IntPtr + PyIter_Next(IntPtr pointer); + + //==================================================================== + // Python module API + //==================================================================== + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern string + PyModule_GetName(IntPtr module); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyModule_GetDict(IntPtr module); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern string + PyModule_GetFilename(IntPtr module); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyImport_Import(IntPtr name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyImport_ImportModule(string name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyImport_ReloadModule(IntPtr module); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyImport_AddModule(string name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyImport_GetModuleDict(); + + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PySys_SetArgv(int argc, IntPtr argv); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PySys_GetObject(string name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PySys_SetObject(string name, IntPtr ob); + + + //==================================================================== + // Python type object API + //==================================================================== + + internal static bool PyType_Check(IntPtr ob) { + return PyObject_TypeCheck(ob, Runtime.PyTypeType); + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern bool + PyType_IsSubtype(IntPtr t1, IntPtr t2); + + internal static bool PyObject_TypeCheck(IntPtr ob, IntPtr tp) { + IntPtr t = PyObject_TYPE(ob); + return (t == tp) || PyType_IsSubtype(t, tp); + } + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyType_GenericNew(IntPtr type, IntPtr args, IntPtr kw); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyType_GenericAlloc(IntPtr type, int n); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyType_Ready(IntPtr type); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + _PyType_Lookup(IntPtr type, IntPtr name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_GenericGetAttr(IntPtr obj, IntPtr name); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyObject_GenericSetAttr(IntPtr obj, IntPtr name, IntPtr value); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + _PyObject_GetDictPtr(IntPtr obj); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyObject_GC_New(IntPtr tp); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyObject_GC_Del(IntPtr tp); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyObject_GC_Track(IntPtr tp); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyObject_GC_UnTrack(IntPtr tp); + + + //==================================================================== + // Python memory API + //==================================================================== + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyMem_Malloc(int size); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyMem_Realloc(IntPtr ptr, int size); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyMem_Free(IntPtr ptr); + + + //==================================================================== + // Python exception API + //==================================================================== + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_SetString(IntPtr ob, string message); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_SetObject(IntPtr ob, IntPtr message); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyErr_SetFromErrno(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_SetNone(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyErr_ExceptionMatches(IntPtr exception); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyErr_GivenExceptionMatches(IntPtr ob, IntPtr val); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_NormalizeException(IntPtr ob, IntPtr val, IntPtr tb); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern int + PyErr_Occurred(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_Fetch(ref IntPtr ob, ref IntPtr val, ref IntPtr tb); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_Restore(IntPtr ob, IntPtr val, IntPtr tb); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_Clear(); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern void + PyErr_Print(); + + + //==================================================================== + // Miscellaneous + //==================================================================== + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyMethod_Self(IntPtr ob); + + [DllImport(Runtime.dll, CallingConvention=CallingConvention.Cdecl, + ExactSpelling=true, CharSet=CharSet.Ansi)] + internal unsafe static extern IntPtr + PyMethod_Function(IntPtr ob); + + } + + +} diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs new file mode 100644 index 000000000..41b845737 --- /dev/null +++ b/src/runtime/typemanager.cs @@ -0,0 +1,452 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Runtime.InteropServices; +using System.Reflection.Emit; +using System.Collections.Generic; +using System.Collections; +using System.Reflection; +using System.Threading; + +namespace Python.Runtime { + + //======================================================================= + // The TypeManager class is responsible for building binary-compatible + // Python type objects that are implemented in managed code. + //======================================================================= + + internal class TypeManager { + + static BindingFlags tbFlags; + static Dictionary cache; + static int obSize; + + static TypeManager() { + tbFlags = BindingFlags.Public | BindingFlags.Static; + obSize = 5 * IntPtr.Size; + cache = new Dictionary(128); + } + + + //==================================================================== + // Given a managed Type derived from ExtensionType, get the handle to + // a Python type object that delegates its implementation to the Type + // object. These Python type instances are used to implement internal + // descriptor and utility types like ModuleObject, PropertyObject, etc. + //==================================================================== + + internal static IntPtr GetTypeHandle(Type type) { + // Note that these types are cached with a refcount of 1, so they + // effectively exist until the CPython runtime is finalized. + IntPtr handle = IntPtr.Zero; + cache.TryGetValue(type, out handle); + if (handle != IntPtr.Zero) { + return handle; + } + handle = CreateType(type); + cache[type] = handle; + return handle; + } + + + //==================================================================== + // Get the handle of a Python type that reflects the given CLR type. + // The given ManagedType instance is a managed object that implements + // the appropriate semantics in Python for the reflected managed type. + //==================================================================== + + internal static IntPtr GetTypeHandle(ManagedType obj, Type type) { + IntPtr handle = IntPtr.Zero; + cache.TryGetValue(type, out handle); + if (handle != IntPtr.Zero) { + return handle; + } + handle = CreateType(obj, type); + cache[type] = handle; + return handle; + } + + + //==================================================================== + // The following CreateType implementations do the necessary work to + // create Python types to represent managed extension types, reflected + // types, subclasses of reflected types and the managed metatype. The + // dance is slightly different for each kind of type due to different + // behavior needed and the desire to have the existing Python runtime + // do as much of the allocation and initialization work as possible. + //==================================================================== + + internal static IntPtr CreateType(Type impl) { + + IntPtr type = AllocateTypeObject(impl.Name); + + // Set tp_basicsize to the size of our managed instance objects. + Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); + + IntPtr offset = (IntPtr)ObjectOffset.ob_dict; + Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); + + InitializeSlots(type, impl); + + int flags = TypeFlags.Default | TypeFlags.Managed | + TypeFlags.HeapType | TypeFlags.HaveGC; + Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + + Runtime.PyType_Ready(type); + + IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); + IntPtr mod = Runtime.PyString_FromString("CLR"); + Runtime.PyDict_SetItemString(dict, "__module__", mod); + + InitMethods(type, impl); + + return type; + } + + + internal static IntPtr CreateType(ManagedType impl, Type clrType) { + // Cleanup the type name to get rid of funny nested type names. + string name = "CLR." + clrType.FullName; + int i = name.LastIndexOf('+'); + if (i > -1) { + name = name.Substring(i + 1); + } + i = name.LastIndexOf('.'); + if (i > -1) { + name = name.Substring(i + 1); + } + + IntPtr base_ = IntPtr.Zero; + // XXX Hack, use a different base class for System.Exception + // Python 2.5+ allows new style class exceptions but they *must* + // subclass BaseException (or better Exception). +#if (PYTHON25 || PYTHON26 || PYTHON27) + if (clrType == typeof(System.Exception)) { + base_ = Exceptions.Exception; + Runtime.Incref(base_); + } else +#endif + if (clrType.BaseType != null) { + ClassBase bc = ClassManager.GetClass(clrType.BaseType); + base_ = bc.pyHandle; + } + + IntPtr type = AllocateTypeObject(name); + + Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType); + Runtime.Incref(Runtime.PyCLRMetaType); + + Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); + Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); + + IntPtr offset = (IntPtr)ObjectOffset.ob_dict; + Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); + + InitializeSlots(type, impl.GetType()); + + if (base_ != IntPtr.Zero) { + Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); + Runtime.Incref(base_); + } + + int flags = TypeFlags.Default; + flags |= TypeFlags.Managed; + flags |= TypeFlags.HeapType; + flags |= TypeFlags.BaseType; + flags |= TypeFlags.HaveGC; + Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + + // Leverage followup initialization from the Python runtime. Note + // that the type of the new type must PyType_Type at the time we + // call this, else PyType_Ready will skip some slot initialization. + + Runtime.PyType_Ready(type); + + IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); + string mn = clrType.Namespace != null ? clrType.Namespace : ""; + IntPtr mod = Runtime.PyString_FromString(mn); + Runtime.PyDict_SetItemString(dict, "__module__", mod); + + // Hide the gchandle of the implementation in a magic type slot. + GCHandle gc = GCHandle.Alloc(impl); + Marshal.WriteIntPtr(type, TypeOffset.magic(), (IntPtr)gc); + + // Set the handle attributes on the implementing instance. + impl.tpHandle = Runtime.PyCLRMetaType; + impl.gcHandle = gc; + impl.pyHandle = type; + + //DebugUtil.DumpType(type); + + return type; + } + + internal static IntPtr CreateSubType(IntPtr args) { + + IntPtr py_name = Runtime.PyTuple_GetItem(args, 0); + IntPtr bases = Runtime.PyTuple_GetItem(args, 1); + IntPtr dict = Runtime.PyTuple_GetItem(args, 2); + IntPtr base_ = Runtime.PyTuple_GetItem(bases, 0); + + string name = Runtime.GetManagedString(py_name); + IntPtr type = AllocateTypeObject(name); + + Marshal.WriteIntPtr(type,TypeOffset.ob_type,Runtime.PyCLRMetaType); + Runtime.Incref(Runtime.PyCLRMetaType); + + Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); + Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); + + IntPtr offset = (IntPtr)ObjectOffset.ob_dict; + Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); + + IntPtr dc = Runtime.PyDict_Copy(dict); + Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc); + + Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); + Runtime.Incref(base_); + + int flags = TypeFlags.Default; + flags |= TypeFlags.Managed; + flags |= TypeFlags.HeapType; + flags |= TypeFlags.BaseType; + flags |= TypeFlags.Subclass; + flags |= TypeFlags.HaveGC; + Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + + CopySlot(base_, type, TypeOffset.tp_traverse); + CopySlot(base_, type, TypeOffset.tp_clear); + CopySlot(base_, type, TypeOffset.tp_is_gc); + + Runtime.PyType_Ready(type); + + + IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); + IntPtr mod = Runtime.PyString_FromString("CLR"); + Runtime.PyDict_SetItemString(tp_dict, "__module__", mod); + + // for now, move up hidden handle... + IntPtr gc = Marshal.ReadIntPtr(base_, TypeOffset.magic()); + Marshal.WriteIntPtr(type, TypeOffset.magic(), gc); + + return type; + } + + + internal static IntPtr CreateMetaType(Type impl) { + + // The managed metatype is functionally little different than the + // standard Python metatype (PyType_Type). It overrides certain of + // the standard type slots, and has to subclass PyType_Type for + // certain functions in the C runtime to work correctly with it. + + IntPtr type = AllocateTypeObject("CLR Metatype"); + IntPtr py_type = Runtime.PyTypeType; + + Marshal.WriteIntPtr(type, TypeOffset.tp_base, py_type); + Runtime.Incref(py_type); + + // Copy gc and other type slots from the base Python metatype. + + CopySlot(py_type, type, TypeOffset.tp_basicsize); + CopySlot(py_type, type, TypeOffset.tp_itemsize); + + CopySlot(py_type, type, TypeOffset.tp_dictoffset); + CopySlot(py_type, type, TypeOffset.tp_weaklistoffset); + + CopySlot(py_type, type, TypeOffset.tp_traverse); + CopySlot(py_type, type, TypeOffset.tp_clear); + CopySlot(py_type, type, TypeOffset.tp_is_gc); + + // Override type slots with those of the managed implementation. + + InitializeSlots(type, impl); + + int flags = TypeFlags.Default; + flags |= TypeFlags.Managed; + flags |= TypeFlags.HeapType; + flags |= TypeFlags.HaveGC; + Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + + Runtime.PyType_Ready(type); + + IntPtr dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); + IntPtr mod = Runtime.PyString_FromString("CLR"); + Runtime.PyDict_SetItemString(dict, "__module__", mod); + + //DebugUtil.DumpType(type); + + return type; + } + + + internal static IntPtr BasicSubType(string name, IntPtr base_, + Type impl) { + + // Utility to create a subtype of a std Python type, but with + // a managed type able to override implementation + + IntPtr type = AllocateTypeObject(name); + //Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize); + //Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero); + + //IntPtr offset = (IntPtr)ObjectOffset.ob_dict; + //Marshal.WriteIntPtr(type, TypeOffset.tp_dictoffset, offset); + + //IntPtr dc = Runtime.PyDict_Copy(dict); + //Marshal.WriteIntPtr(type, TypeOffset.tp_dict, dc); + + Marshal.WriteIntPtr(type, TypeOffset.tp_base, base_); + Runtime.Incref(base_); + + int flags = TypeFlags.Default; + flags |= TypeFlags.Managed; + flags |= TypeFlags.HeapType; + flags |= TypeFlags.HaveGC; + Marshal.WriteIntPtr(type, TypeOffset.tp_flags, (IntPtr)flags); + + CopySlot(base_, type, TypeOffset.tp_traverse); + CopySlot(base_, type, TypeOffset.tp_clear); + CopySlot(base_, type, TypeOffset.tp_is_gc); + + InitializeSlots(type, impl); + + Runtime.PyType_Ready(type); + + IntPtr tp_dict = Marshal.ReadIntPtr(type, TypeOffset.tp_dict); + IntPtr mod = Runtime.PyString_FromString("CLR"); + Runtime.PyDict_SetItemString(tp_dict, "__module__", mod); + + return type; + } + + + //==================================================================== + // Utility method to allocate a type object & do basic initialization. + //==================================================================== + + internal static IntPtr AllocateTypeObject(string name) { + IntPtr type = Runtime.PyType_GenericAlloc(Runtime.PyTypeType, 0); + + // Cheat a little: we'll set tp_name to the internal char * of + // the Python version of the type name - otherwise we'd have to + // allocate the tp_name and would have no way to free it. + + IntPtr temp = Runtime.PyString_FromString(name); + IntPtr raw = Runtime.PyString_AS_STRING(temp); + Marshal.WriteIntPtr(type, TypeOffset.tp_name, raw); + Marshal.WriteIntPtr(type, TypeOffset.name, temp); + + long ptr = type.ToInt64(); // 64-bit safe + + temp = new IntPtr(ptr + TypeOffset.nb_add); + Marshal.WriteIntPtr(type, TypeOffset.tp_as_number, temp); + + temp = new IntPtr(ptr + TypeOffset.sq_length); + Marshal.WriteIntPtr(type, TypeOffset.tp_as_sequence, temp); + + temp = new IntPtr(ptr + TypeOffset.mp_length); + Marshal.WriteIntPtr(type, TypeOffset.tp_as_mapping, temp); + + temp = new IntPtr(ptr + TypeOffset.bf_getreadbuffer); + Marshal.WriteIntPtr(type, TypeOffset.tp_as_buffer, temp); + + return type; + } + + + //==================================================================== + // Given a newly allocated Python type object and a managed Type that + // provides the implementation for the type, connect the type slots of + // the Python object to the managed methods of the implementing Type. + //==================================================================== + + internal static void InitializeSlots(IntPtr type, Type impl) { + Hashtable seen = new Hashtable(8); + Type offsetType = typeof(TypeOffset); + + while (impl != null) { + MethodInfo[] methods = impl.GetMethods(tbFlags); + for (int i = 0; i < methods.Length; i++) { + MethodInfo method = methods[i]; + string name = method.Name; + if (! (name.StartsWith("tp_") || + name.StartsWith("nb_") || + name.StartsWith("sq_") || + name.StartsWith("mp_") || + name.StartsWith("bf_") + ) ) { + continue; + } + + if (seen[name] != null) { + continue; + } + + FieldInfo fi = offsetType.GetField(name); + int offset = (int)fi.GetValue(offsetType); + + IntPtr slot = Interop.GetThunk(method); + Marshal.WriteIntPtr(type, offset, slot); + + seen[name] = 1; + } + + impl = impl.BaseType; + } + + } + + + //==================================================================== + // Given a newly allocated Python type object and a managed Type that + // implements it, initialize any methods defined by the Type that need + // to appear in the Python type __dict__ (based on custom attribute). + //==================================================================== + + private static void InitMethods(IntPtr pytype, Type type) { + IntPtr dict = Marshal.ReadIntPtr(pytype, TypeOffset.tp_dict); + Type marker = typeof(PythonMethodAttribute); + + BindingFlags flags = BindingFlags.Public | BindingFlags.Static; + + while (type != null) { + MethodInfo[] methods = type.GetMethods(flags); + for (int i = 0; i < methods.Length; i++) { + MethodInfo method = methods[i]; + object[] attrs = method.GetCustomAttributes(marker, false); + if (attrs.Length > 0) { + string method_name = method.Name; + MethodInfo[] mi = new MethodInfo[1]; + mi[0] = method; + MethodObject m = new TypeMethod(method_name, mi); + Runtime.PyDict_SetItemString(dict, method_name, + m.pyHandle); + } + } + type = type.BaseType; + } + } + + + //==================================================================== + // Utility method to copy slots from a given type to another type. + //==================================================================== + + internal static void CopySlot(IntPtr from, IntPtr to, int offset) { + IntPtr fp = Marshal.ReadIntPtr(from, offset); + Marshal.WriteIntPtr(to, offset, fp); + } + + + } + + +} diff --git a/src/runtime/typemethod.cs b/src/runtime/typemethod.cs new file mode 100644 index 000000000..ab95f28ed --- /dev/null +++ b/src/runtime/typemethod.cs @@ -0,0 +1,54 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using System.Reflection; + +namespace Python.Runtime { + + //======================================================================== + // Implements a Python type that provides access to CLR object methods. + //======================================================================== + + internal class TypeMethod : MethodObject { + + public TypeMethod(string name, MethodInfo[] info) : + base(name, info) {} + + public TypeMethod(string name, MethodInfo[] info, bool allow_threads) : + base(name, info, allow_threads) { } + + public override IntPtr Invoke(IntPtr ob, IntPtr args, IntPtr kw) { + MethodInfo mi = this.info[0]; + Object[] arglist = new Object[3]; + arglist[0] = ob; + arglist[1] = args; + arglist[2] = kw; + + try { + Object inst = null; + if (ob != IntPtr.Zero) { + inst = GetManagedObject(ob); + } + return (IntPtr)mi.Invoke(inst, BindingFlags.Default, null, arglist, + null); + } + catch (Exception e) { + Exceptions.SetError(e); + return IntPtr.Zero; + } + } + + + + } + + +} diff --git a/src/runtime/x64/clrmodule-platform.il b/src/runtime/x64/clrmodule-platform.il new file mode 100644 index 000000000..d04f74603 --- /dev/null +++ b/src/runtime/x64/clrmodule-platform.il @@ -0,0 +1,11 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +.vtfixup [1] int64 fromunmanaged at VT_01 +.data VT_01 = int64(0) diff --git a/src/runtime/x86/clrmodule-platform.il b/src/runtime/x86/clrmodule-platform.il new file mode 100644 index 000000000..aeac29658 --- /dev/null +++ b/src/runtime/x86/clrmodule-platform.il @@ -0,0 +1,11 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +.vtfixup [1] int32 fromunmanaged at VT_01 +.data VT_01 = int32(0) diff --git a/src/testing/Python.Test.csproj b/src/testing/Python.Test.csproj new file mode 100644 index 000000000..b0c41a866 --- /dev/null +++ b/src/testing/Python.Test.csproj @@ -0,0 +1,147 @@ + + + + Debug + AnyCPU + {6F401A34-273B-450F-9A4C-13550BE0767B} + Library + false + Python.Test + Python.Test + OnBuildSuccess + v4.0 + + ..\..\ + $(SolutionDir) + + + 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\ + DEBUG;TRACE + 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 + + + + + + + + + + + + + + + + + + + + + + + + 3.5 + + + + + + {097B4AC0-74E9-4C58-BCF8-C69746EC8271} + Python.Runtime + + + + + + + + $(SolutionDir) + + + + + diff --git a/src/testing/Python.Test.mdp b/src/testing/Python.Test.mdp new file mode 100644 index 000000000..e8ab5d5cf --- /dev/null +++ b/src/testing/Python.Test.mdp @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/testing/arraytest.cs b/src/testing/arraytest.cs new file mode 100644 index 000000000..8c29e8f75 --- /dev/null +++ b/src/testing/arraytest.cs @@ -0,0 +1,331 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; + +namespace Python.Test { + + //======================================================================== + // Supports units tests for indexer access. + //======================================================================== + + public class PublicArrayTest { + + public int[] items; + + public PublicArrayTest() { + items = new int[5] {0, 1, 2, 3, 4}; + } + + } + + + public class ProtectedArrayTest { + + protected int[] items; + + public ProtectedArrayTest() { + items = new int[5] {0, 1, 2, 3, 4}; + } + + } + + + public class InternalArrayTest { + + internal int[] items; + + public InternalArrayTest() { + items = new int[5] {0, 1, 2, 3, 4}; + } + + } + + + public class PrivateArrayTest { + + private int[] items; + + public PrivateArrayTest() { + items = new int[5] {0, 1, 2, 3, 4}; + } + + } + + + public class BooleanArrayTest { + + public bool[] items; + + public BooleanArrayTest() { + items = new bool[5] {true, false, true, false, true}; + } + + } + + + public class ByteArrayTest { + + public byte[] items; + + public ByteArrayTest() { + items = new byte[5] {0, 1, 2, 3, 4}; + } + + } + + + public class SByteArrayTest { + + public sbyte[] items; + + public SByteArrayTest() { + items = new sbyte[5] {0, 1, 2, 3, 4}; + } + + } + + + public class CharArrayTest { + + public char[] items; + + public CharArrayTest() { + items = new char[5] {'a', 'b', 'c', 'd', 'e'}; + } + + } + + + public class Int16ArrayTest { + + public short[] items; + + public Int16ArrayTest() { + items = new short[5] {0, 1, 2, 3, 4}; + } + + } + + + public class Int32ArrayTest { + + public int[] items; + + public Int32ArrayTest() { + items = new int[5] {0, 1, 2, 3, 4}; + } + + } + + + public class Int64ArrayTest { + + public long[] items; + + public Int64ArrayTest() { + items = new long[5] {0, 1, 2, 3, 4}; + } + + } + + + public class UInt16ArrayTest { + + public ushort[] items; + + public UInt16ArrayTest() { + items = new ushort[5] {0, 1, 2, 3, 4}; + } + + } + + + public class UInt32ArrayTest { + + public uint[] items; + + public UInt32ArrayTest() { + items = new uint[5] {0, 1, 2, 3, 4}; + } + + } + + + public class UInt64ArrayTest { + + public ulong[] items; + + public UInt64ArrayTest() { + items = new ulong[5] {0, 1, 2, 3, 4}; + } + + } + + + public class SingleArrayTest { + + public float[] items; + + public SingleArrayTest() { + items = new float[5] {0.0F, 1.0F, 2.0F, 3.0F, 4.0F}; + } + + } + + + public class DoubleArrayTest { + + public double[] items; + + public DoubleArrayTest() { + items = new double[5] {0.0, 1.0, 2.0, 3.0, 4.0}; + } + + } + + + public class DecimalArrayTest { + + public decimal[] items; + + public DecimalArrayTest() { + items = new decimal[5] {0, 1, 2, 3, 4}; + } + + } + + + public class StringArrayTest { + + public string[] items; + + public StringArrayTest() { + items = new string[5] {"0", "1", "2", "3", "4"}; + } + + } + + public class EnumArrayTest { + + public ShortEnum[] items; + + public EnumArrayTest() { + items = new ShortEnum[5] + { ShortEnum.Zero, + ShortEnum.One, + ShortEnum.Two, + ShortEnum.Three, + ShortEnum.Four}; + } + + } + + + public class NullArrayTest { + + public object[] items; + public object[] empty; + + public NullArrayTest() { + items = new object[5] {null, null, null, null, null}; + empty = new object[0] {}; + } + + } + + + public class ObjectArrayTest { + + public object[] items; + + public ObjectArrayTest() { + items = new object[5]; + items[0] = new Spam("0"); + items[1] = new Spam("1"); + items[2] = new Spam("2"); + items[3] = new Spam("3"); + items[4] = new Spam("4"); + } + + } + + + public class InterfaceArrayTest { + + public ISpam[] items; + + public InterfaceArrayTest() { + items = new ISpam[5]; + items[0] = new Spam("0"); + items[1] = new Spam("1"); + items[2] = new Spam("2"); + items[3] = new Spam("3"); + items[4] = new Spam("4"); + } + + } + + + public class TypedArrayTest { + + public Spam[] items; + + public TypedArrayTest() { + items = new Spam[5]; + items[0] = new Spam("0"); + items[1] = new Spam("1"); + items[2] = new Spam("2"); + items[3] = new Spam("3"); + items[4] = new Spam("4"); + } + + } + + + public class MultiDimensionalArrayTest { + + public int[,] items; + + public MultiDimensionalArrayTest() { + items = new int[5, 5] { + {0, 1, 2, 3, 4}, + {5, 6, 7, 8, 9}, + {10, 11, 12, 13, 14}, + {15, 16, 17, 18, 19}, + {20, 21, 22, 23, 24} + }; + + } + + } + + + public class ArrayConversionTest { + + public static Spam[] EchoRange(Spam[] items) { + return items; + } + + public static Spam[,] EchoRangeMD(Spam[,] items) { + return items; + } + + public static Spam[][] EchoRangeAA(Spam[][] items) { + return items; + } + + } + + + + +} + diff --git a/src/testing/classtest.cs b/src/testing/classtest.cs new file mode 100644 index 000000000..86239c9c5 --- /dev/null +++ b/src/testing/classtest.cs @@ -0,0 +1,72 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; + +namespace Python.Test { + + //======================================================================== + // Supports CLR class unit tests. + //======================================================================== + + public class ClassTest { + + public static ArrayList GetArrayList() { + ArrayList list = new ArrayList(); + for (int i = 0; i < 10; i++) { + list.Add(i); + } + return list; + } + + public static Hashtable GetHashtable() { + Hashtable dict = new Hashtable(); + dict.Add("one", 1); + dict.Add("two", 2); + dict.Add("three", 3); + dict.Add("four", 4); + dict.Add("five", 5); + return dict; + } + + public static IEnumerator GetEnumerator() { + string temp = "test string"; + return temp.GetEnumerator(); + } + + + } + + + public class ClassCtorTest1 { + public string value; + + public ClassCtorTest1() { + value = "default"; + } + + } + + public class ClassCtorTest2 { + public string value; + + public ClassCtorTest2(string v) { + value = v; + } + + } + + internal class InternalClass { + + + } + + +} diff --git a/pythonnet/src/testing/constructortests.cs b/src/testing/constructortests.cs old mode 100755 new mode 100644 similarity index 59% rename from pythonnet/src/testing/constructortests.cs rename to src/testing/constructortests.cs index d1fc1bc52..59181c3af --- a/pythonnet/src/testing/constructortests.cs +++ b/src/testing/constructortests.cs @@ -1,17 +1,14 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// +// ========================================================================== // 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.Windows.Forms; using System.IO; namespace Python.Test { @@ -22,44 +19,44 @@ namespace Python.Test { public class EnumConstructorTest { - public TypeCode value; + public TypeCode value; - public EnumConstructorTest(TypeCode v) { - this.value = v; - } + public EnumConstructorTest(TypeCode v) { + this.value = v; + } } public class FlagsConstructorTest { - public FileAccess value; + public FileAccess value; - public FlagsConstructorTest(FileAccess v) { - this.value = v; - } + public FlagsConstructorTest(FileAccess v) { + this.value = v; + } } public class StructConstructorTest { - public Guid value; + public Guid value; - public StructConstructorTest(Guid v) { - this.value = v; - } + public StructConstructorTest(Guid v) { + this.value = v; + } } public class SubclassConstructorTest { - public Control value; + public Exception value; - public SubclassConstructorTest(Control v) { - this.value = v; - } + public SubclassConstructorTest(Exception v) { + this.value = v; + } } diff --git a/src/testing/conversiontest.cs b/src/testing/conversiontest.cs new file mode 100644 index 000000000..9024b6f51 --- /dev/null +++ b/src/testing/conversiontest.cs @@ -0,0 +1,68 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + + +namespace Python.Test { + + //======================================================================== + // Supports units tests for field access. + //======================================================================== + + public class ConversionTest { + + public ConversionTest() { + EnumField = ShortEnum.Zero; + SpamField = new Spam("spam"); + StringField = "spam"; + } + + public bool BooleanField = false; + public byte ByteField = 0; + public sbyte SByteField = 0; + public char CharField = 'A'; + public short Int16Field = 0; + public int Int32Field = 0; + public long Int64Field = 0; + public ushort UInt16Field = 0; + public uint UInt32Field = 0; + public ulong UInt64Field = 0; + public float SingleField = 0.0F; + public double DoubleField = 0.0; + public decimal DecimalField = 0; + public string StringField; + public ShortEnum EnumField; + public object ObjectField = null; + public ISpam SpamField; + + public byte[] ByteArrayField; + public sbyte[] SByteArrayField; + + } + + + public interface ISpam { + string GetValue(); + } + + public class Spam : ISpam { + string value; + + public Spam(string value) { + this.value = value; + } + + public string GetValue() { + return value; + + } + } + +} diff --git a/src/testing/delegatetest.cs b/src/testing/delegatetest.cs new file mode 100644 index 000000000..0b8e135cd --- /dev/null +++ b/src/testing/delegatetest.cs @@ -0,0 +1,65 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Test { + + //======================================================================== + // Supports CLR class unit tests. + //======================================================================== + + public delegate void PublicDelegate(); + internal delegate void InternalDelegate(); + + public delegate DelegateTest ObjectDelegate(); + public delegate string StringDelegate(); + public delegate bool BoolDelegate(); + + + public class DelegateTest { + + public delegate void PublicDelegate(); + protected delegate void ProtectedDelegate(); + internal delegate void InternalDelegate(); + private delegate void PrivateDelegate(); + + public StringDelegate stringDelegate; + public ObjectDelegate objectDelegate; + public BoolDelegate boolDelegate; + + public DelegateTest() { + + } + + public string SayHello() { + return "hello"; + } + + public static string StaticSayHello() { + return "hello"; + } + + public string CallStringDelegate(StringDelegate d) { + return d(); + } + + public DelegateTest CallObjectDelegate(ObjectDelegate d) { + return d(); + } + + public bool CallBoolDelegate(BoolDelegate d) { + return d(); + } + + + } + + +} diff --git a/src/testing/doctest.cs b/src/testing/doctest.cs new file mode 100644 index 000000000..00fa2a904 --- /dev/null +++ b/src/testing/doctest.cs @@ -0,0 +1,61 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using Python.Runtime; + +namespace Python.Test { + + //======================================================================== + // Supports units tests for exposing docstrings from C# to Python + //======================================================================== + + // Classes with a constructor have their docstring set to the ctor signature. + // Test if a class has an explicit doc string it gets set correctly. + [DocStringAttribute("DocWithCtorTest Class")] + public class DocWithCtorTest { + + public DocWithCtorTest() { + } + + [DocStringAttribute("DocWithCtorTest TestMethod")] + public void TestMethod() { + } + + [DocStringAttribute("DocWithCtorTest StaticTestMethod")] + public static void StaticTestMethod() { + } + + } + + public class DocWithCtorNoDocTest + { + public DocWithCtorNoDocTest(bool x) { + } + + public void TestMethod(double a, int b) { + } + + public static void StaticTestMethod(double a, int b) { + } + } + + [DocStringAttribute("DocWithoutCtorTest Class")] + public class DocWithoutCtorTest { + + [DocStringAttribute("DocWithoutCtorTest TestMethod")] + public void TestMethod() { + } + + [DocStringAttribute("DocWithoutCtorTest StaticTestMethod")] + public static void StaticTestMethod() { + } + + } + +} diff --git a/pythonnet/src/testing/enumtest.cs b/src/testing/enumtest.cs old mode 100755 new mode 100644 similarity index 50% rename from pythonnet/src/testing/enumtest.cs rename to src/testing/enumtest.cs index 76b161b88..eeabe8984 --- a/pythonnet/src/testing/enumtest.cs +++ b/src/testing/enumtest.cs @@ -1,13 +1,11 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// +// ========================================================================== // 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; @@ -18,76 +16,86 @@ namespace Python.Test { //======================================================================== public enum ByteEnum : byte { - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five } public enum SByteEnum : sbyte { - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five } public enum ShortEnum : short { - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five } public enum UShortEnum : ushort { - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five } public enum IntEnum : int{ - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five } public enum UIntEnum : uint { - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five } public enum LongEnum : long { - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five } public enum ULongEnum : ulong { - Zero, - One, - Two, - Three, - Four, - Five + Zero, + One, + Two, + Three, + Four, + Five + } + + [FlagsAttribute] + public enum FlagsEnum { + Zero, + One, + Two, + Three, + Four, + Five } } diff --git a/src/testing/eventtest.cs b/src/testing/eventtest.cs new file mode 100644 index 000000000..c7f90da86 --- /dev/null +++ b/src/testing/eventtest.cs @@ -0,0 +1,113 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Test { + + //======================================================================== + // Supports CLR event unit tests. + //======================================================================== + + public delegate void TestEventHandler(object sender, TestEventArgs e); + + + public class EventTest { + + public static event TestEventHandler PublicStaticEvent; + + protected static event TestEventHandler ProtectedStaticEvent; + + internal static event TestEventHandler InternalStaticEvent; + + private static event TestEventHandler PrivateStaticEvent; + + public event TestEventHandler PublicEvent; + + protected event TestEventHandler ProtectedEvent; + + internal event TestEventHandler InternalEvent; + + private event TestEventHandler PrivateEvent; + + + public static int s_value; + public int value; + + public EventTest () { + this.value = 0; + } + + static EventTest () { + s_value = 0; + } + + + public void OnPublicEvent(TestEventArgs e) { + if (PublicEvent != null) { + PublicEvent(this, e); + } + } + + + public void OnProtectedEvent(TestEventArgs e) { + if (ProtectedEvent != null) { + ProtectedEvent(this, e); + } + } + + + public static void OnPublicStaticEvent(TestEventArgs e) { + if (PublicStaticEvent != null) { + PublicStaticEvent(null, e); + } + } + + + protected static void OnProtectedStaticEvent(TestEventArgs e) { + if (ProtectedStaticEvent != null) { + ProtectedStaticEvent(null, e); + } + } + + + public void GenericHandler(object sender, TestEventArgs e) { + this.value = e.value; + } + + public static void StaticHandler(object sender, TestEventArgs e) { + s_value = e.value; + } + + public static void ShutUpCompiler() { + // Quiet compiler warnings. + EventTest e = new EventTest(); + TestEventHandler f = new TestEventHandler(e.GenericHandler); + ProtectedStaticEvent += f; + InternalStaticEvent += f; + PrivateStaticEvent += f; + e.ProtectedEvent += f; + e.InternalEvent += f; + e.PrivateEvent += f; + } + + } + + + public class TestEventArgs : EventArgs { + public int value; + + public TestEventArgs(int v) { + this.value = v; + } + + } + + +} diff --git a/src/testing/exceptiontest.cs b/src/testing/exceptiontest.cs new file mode 100644 index 000000000..291c7ed58 --- /dev/null +++ b/src/testing/exceptiontest.cs @@ -0,0 +1,94 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + + +namespace Python.Test { + + //======================================================================== + // Supports CLR Exception unit tests. + //======================================================================== + + public class ExceptionTest { + + public int ThrowProperty { + get { + throw new OverflowException("error"); + } + set { + throw new OverflowException("error"); + } + } + + public static Exception GetBaseException() { + return new Exception("error"); + } + + public static OverflowException GetExplicitException() { + return new OverflowException("error"); + } + + public static Exception GetWidenedException() { + return new OverflowException("error"); + } + + public static ExtendedException GetExtendedException() { + return new ExtendedException("error"); + } + + + public static bool SetBaseException(Exception e) { + return typeof(Exception).IsInstanceOfType(e); + } + + public static bool SetExplicitException(OverflowException e) { + return typeof(OverflowException).IsInstanceOfType(e); + } + + public static bool SetWidenedException(Exception e) { + return typeof(Exception).IsInstanceOfType(e); + } + + public static bool ThrowException() { + throw new OverflowException("error"); + } + } + + + public class ExtendedException : OverflowException { + + public ExtendedException() : base() {} + public ExtendedException(string m) : base(m) {} + + public string extra = "extra"; + + public string ExtraProperty { + get { + return extra; + } + set { + extra = value; + } + } + + public string GetExtraInfo() { + return extra; + } + + + } + + + +} + + + + diff --git a/src/testing/fieldtest.cs b/src/testing/fieldtest.cs new file mode 100644 index 000000000..1f345f423 --- /dev/null +++ b/src/testing/fieldtest.cs @@ -0,0 +1,67 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + + +namespace Python.Test { + + //======================================================================== + // Supports units tests for field access. + //======================================================================== + + public class FieldTest { + + public FieldTest() { + EnumField = ShortEnum.Zero; + SpamField = new Spam("spam"); + StringField = "spam"; + } + + public void Shutup() { + int i = PrivateStaticField; + int j = PrivateField; + } + + public static readonly int ReadOnlyStaticField = 0; + protected static int ProtectedStaticField = 0; + internal static int InternalStaticField = 0; + private static int PrivateStaticField = 0; + public static int PublicStaticField = 0; + + public const int ConstField = 0; + public readonly int ReadOnlyField = 0; + internal int InternalField = 0; + protected int ProtectedField = 0; + private int PrivateField = 0; + public int PublicField = 0; + + public bool BooleanField = false; + public byte ByteField = 0; + public sbyte SByteField = 0; + public char CharField = 'A'; + public short Int16Field = 0; + public int Int32Field = 0; + public long Int64Field = 0; + public ushort UInt16Field = 0; + public uint UInt32Field = 0; + public ulong UInt64Field = 0; + public float SingleField = 0.0F; + public double DoubleField = 0.0; + public decimal DecimalField = 0; + public string StringField; + public ShortEnum EnumField; + public FlagsEnum FlagsField; + public object ObjectField; + public ISpam SpamField; + + } + + +} diff --git a/src/testing/generictest.cs b/src/testing/generictest.cs new file mode 100644 index 000000000..c8f12ab2b --- /dev/null +++ b/src/testing/generictest.cs @@ -0,0 +1,123 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; + +namespace Python.Test { + + //======================================================================== + // Supports CLR generics unit tests. + //======================================================================== + + public class GenericWrapper { + public T value; + + public GenericWrapper(T value) { + this.value = value; + } + } + + public class GenericTypeDefinition { + public T value1; + public U value2; + + public GenericTypeDefinition(T arg1, U arg2) { + this.value1 = arg1; + this.value2 = arg2; + } + } + + public class DerivedFromOpenGeneric : + GenericTypeDefinition { + + public W value3; + + public DerivedFromOpenGeneric(int arg1, V arg2, W arg3) : + base(arg1, arg2) { + this.value3 = arg3; + } + } + + + public class GenericNameTest1 { + public static int value = 0; + } + + public class GenericNameTest1 { + public static int value = 1; + } + + public class GenericNameTest1 { + public static int value = 2; + } + + public class GenericNameTest2 { + public static int value = 1; + } + + public class GenericNameTest2 { + public static int value = 2; + } + + + public class GenericMethodTest { + + public GenericMethodTest() {} + + public int Overloaded() { + return 1; + } + + public T Overloaded(T arg) { + return arg; + } + + public Q Overloaded(Q arg) { + return arg; + } + + public U Overloaded(Q arg1, U arg2) { + return arg2; + } + + public string Overloaded(int arg1, int arg2, string arg3) { + return arg3; + } + + } + + public class GenericStaticMethodTest { + + public GenericStaticMethodTest() {} + + public static int Overloaded() { + return 1; + } + + public static T Overloaded(T arg) { + return arg; + } + + public static Q Overloaded(Q arg) { + return arg; + } + + public static U Overloaded(Q arg1, U arg2) { + return arg2; + } + + public static string Overloaded(int arg1, int arg2, string arg3) { + return arg3; + } + + } + + +} diff --git a/pythonnet/src/testing/globaltest.cs b/src/testing/globaltest.cs old mode 100755 new mode 100644 similarity index 81% rename from pythonnet/src/testing/globaltest.cs rename to src/testing/globaltest.cs index 441747233..70e8ba901 --- a/pythonnet/src/testing/globaltest.cs +++ b/src/testing/globaltest.cs @@ -1,13 +1,11 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// +// ========================================================================== // 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; diff --git a/src/testing/indexertest.cs b/src/testing/indexertest.cs new file mode 100644 index 000000000..fa4a8c8e2 --- /dev/null +++ b/src/testing/indexertest.cs @@ -0,0 +1,354 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; + +namespace Python.Test { + + //======================================================================== + // Supports units tests for indexer access. + //======================================================================== + + public class IndexerBase { + + protected Hashtable t; + + protected IndexerBase() { + t = new Hashtable(); + } + + protected string GetValue(object index) { + if (index == null) { + return null; + } + object value = t[index]; + if (value != null) { + return (string)value; + } + return null; + } + + } + + + public class PublicIndexerTest : IndexerBase { + + public PublicIndexerTest() : base () {} + + public string this [int index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class ProtectedIndexerTest : IndexerBase { + + public ProtectedIndexerTest() : base () {} + + protected string this [int index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class InternalIndexerTest : IndexerBase { + + public InternalIndexerTest() : base () {} + + internal string this [int index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class PrivateIndexerTest : IndexerBase { + + public PrivateIndexerTest() : base () {} + + private string this [int index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class BooleanIndexerTest : IndexerBase { + + public BooleanIndexerTest() : base() {} + + public string this [bool index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class ByteIndexerTest : IndexerBase { + + public ByteIndexerTest() : base() {} + + public string this [byte index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class SByteIndexerTest : IndexerBase { + + public SByteIndexerTest() : base() {} + + public string this [sbyte index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class CharIndexerTest : IndexerBase { + + public CharIndexerTest() : base() {} + + public string this [char index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class Int16IndexerTest : IndexerBase { + + public Int16IndexerTest() : base() {} + + public string this [short index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class Int32IndexerTest : IndexerBase { + + public Int32IndexerTest() : base() {} + + public string this [int index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class Int64IndexerTest : IndexerBase { + + public Int64IndexerTest() : base() {} + + public string this [long index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class UInt16IndexerTest : IndexerBase { + + public UInt16IndexerTest() : base() {} + + public string this [ushort index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class UInt32IndexerTest : IndexerBase { + + public UInt32IndexerTest() : base() {} + + public string this [uint index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class UInt64IndexerTest : IndexerBase { + + public UInt64IndexerTest() : base() {} + + public string this [ulong index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class SingleIndexerTest : IndexerBase { + + public SingleIndexerTest() : base() {} + + public string this [float index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class DoubleIndexerTest : IndexerBase { + + public DoubleIndexerTest() : base() {} + + public string this [double index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class DecimalIndexerTest : IndexerBase { + + public DecimalIndexerTest() : base() {} + + public string this [decimal index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class StringIndexerTest : IndexerBase { + + public StringIndexerTest() : base() {} + + public string this [string index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class EnumIndexerTest : IndexerBase { + + public EnumIndexerTest() : base() {} + + public string this [ShortEnum index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class ObjectIndexerTest : IndexerBase { + + public ObjectIndexerTest() : base() {} + + public string this [object index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class InterfaceIndexerTest : IndexerBase { + + public InterfaceIndexerTest() : base() {} + + public string this [ISpam index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class TypedIndexerTest : IndexerBase { + + public TypedIndexerTest() : base() {} + + public string this [Spam index] { + get { return GetValue(index); } + set { t[index] = value; } + } + + } + + + public class MultiArgIndexerTest : IndexerBase { + + public MultiArgIndexerTest() : base() {} + + public string this [int index1, int index2] { + get { + string key = index1.ToString() + index2.ToString(); + object value = t[key]; + if (value != null) { + return (string)value; + } + return null; + } + set { + string key = index1.ToString() + index2.ToString(); + t[key] = value; + } + } + + } + + + public class MultiTypeIndexerTest : IndexerBase { + + public MultiTypeIndexerTest() : base() {} + + public string this [int i1, string i2, ISpam i3] { + get { + string key = i1.ToString() + i2.ToString() + + i3.GetHashCode().ToString(); + object value = t[key]; + if (value != null) { + return (string)value; + } + return null; + } + set { + string key = i1.ToString() + i2.ToString() + + i3.GetHashCode().ToString(); + t[key] = value; + } + } + + } + + + + + +} diff --git a/pythonnet/src/testing/interfacetest.cs b/src/testing/interfacetest.cs old mode 100755 new mode 100644 similarity index 57% rename from pythonnet/src/testing/interfacetest.cs rename to src/testing/interfacetest.cs index 93bf1dba2..99bb3fbba --- a/pythonnet/src/testing/interfacetest.cs +++ b/src/testing/interfacetest.cs @@ -1,13 +1,11 @@ -// Copyright (c) 2001, 2002 Zope Corporation and Contributors. -// -// All Rights Reserved. -// +// ========================================================================== // 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; @@ -24,36 +22,36 @@ internal interface IInternalInterface {} public interface ISayHello1 { - string SayHello(); + string SayHello(); } public interface ISayHello2 { - string SayHello(); + string SayHello(); } public class InterfaceTest : ISayHello1, ISayHello2{ - public InterfaceTest() {} + public InterfaceTest() {} - public string HelloProperty { - get { return "hello"; } - } + public string HelloProperty { + get { return "hello"; } + } - string ISayHello1.SayHello() { - return "hello 1"; - } + string ISayHello1.SayHello() { + return "hello 1"; + } - string ISayHello2.SayHello() { - return "hello 2"; - } + string ISayHello2.SayHello() { + return "hello 2"; + } - public interface IPublic {} + public interface IPublic {} - protected interface IProtected {} + protected interface IProtected {} - internal interface IInternal {} + internal interface IInternal {} - private interface IPrivate {} + private interface IPrivate {} } diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs new file mode 100644 index 000000000..086aa58d5 --- /dev/null +++ b/src/testing/methodtest.cs @@ -0,0 +1,511 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.IO; +using System.Collections.Generic; + +namespace Python.Test { + + //======================================================================== + // Supports units tests for method access. + //======================================================================== + + public class MethodTest { + + public MethodTest() {} + + public string PublicMethod() { + return "public"; + } + + public static string PublicStaticMethod() { + return "public static"; + } + + protected string ProtectedMethod() { + return "protected"; + } + + protected static string ProtectedStaticMethod() { + return "protected static"; + } + + internal string InternalMethod() { + return "internal"; + } + + internal static string InternalStaticMethod() { + return "internal static"; + } + + private string PrivateMethod() { + return "private"; + } + + private static string PrivateStaticMethod() { + return "private static"; + } + + + //=================================================================== + // Methods to support specific argument conversion unit tests + //=================================================================== + + public TypeCode TestEnumConversion(TypeCode v) { + return v; + } + + public FileAccess TestFlagsConversion(FileAccess v) { + return v; + } + + public Guid TestStructConversion(Guid v) { + return v; + } + + public Exception TestSubclassConversion(Exception v) { + return v; + } + + public Type[] TestNullArrayConversion(Type [] v) { + return v; + } + + public static string[] TestStringParamsArg(params string[] args) { + return args; + } + + public static object[] TestObjectParamsArg(params object[] args) { + return args; + } + + public static int[] TestValueParamsArg(params int[] args) { + return args; + } + + public static int[] TestOneArgWithParams(string s, params int[] args) { + return args; + } + + public static int[] TestTwoArgWithParams(string s, string x, + params int[] args) { + return args; + } + + public static int[] TestOverloadedParams(string v, params int[] args) { + return args; + } + + public static int[] TestOverloadedParams(int v, int[] args) { + return args; + } + + public static bool TestStringOutParams (string s, out string s1) { + s1 = "output string"; + return true; + } + + public static bool TestStringRefParams (string s, ref string s1) { + s1 = "output string"; + return true; + } + + public static bool TestValueOutParams (string s, out int i1) { + i1 = 42; + return true; + } + + public static bool TestValueRefParams (string s, ref int i1) { + i1 = 42; + return true; + } + + public static bool TestObjectOutParams (object o, out object o1) { + o1 = new System.Exception("test"); + return true; + } + + public static bool TestObjectRefParams (object o, ref object o1) { + o1 = new System.Exception("test"); + return true; + } + + public static bool TestStructOutParams (object o, out Guid o1) { + o1 = Guid.NewGuid(); + return true; + } + + public static bool TestStructRefParams (object o, ref Guid o1) { + o1 = Guid.NewGuid(); + return true; + } + + public static void TestVoidSingleOutParam (out int i) { + i = 42; + } + + public static void TestVoidSingleRefParam (ref int i) { + i = 42; + } + + + + // overload selection test support + + public static bool Overloaded(bool v) { + return v; + } + + public static byte Overloaded(byte v) { + return v; + } + + public static sbyte Overloaded(sbyte v) { + return v; + } + + public static char Overloaded(char v) { + return v; + } + + public static short Overloaded(short v) { + return v; + } + + public static int Overloaded(int v) { + return v; + } + + public static long Overloaded(long v) { + return v; + } + + public static ushort Overloaded(ushort v) { + return v; + } + + public static uint Overloaded(uint v) { + return v; + } + + public static ulong Overloaded(ulong v) { + return v; + } + + public static float Overloaded(float v) { + return v; + } + + public static double Overloaded(double v) { + return v; + } + + public static decimal Overloaded(decimal v) { + return v; + } + + public static string Overloaded(string v) { + return v; + } + + public static ShortEnum Overloaded(ShortEnum v) { + return v; + } + + public static object Overloaded(object v) { + return v; + } + + public static InterfaceTest Overloaded(InterfaceTest v) { + return v; + } + + public static ISayHello1 Overloaded(ISayHello1 v) { + return v; + } + + public static bool[] Overloaded(bool[] v) { + return v; + } + + public static byte[] Overloaded(byte[] v) { + return v; + } + + public static sbyte[] Overloaded(sbyte[] v) { + return v; + } + + public static char[] Overloaded(char[] v) { + return v; + } + + public static short[] Overloaded(short[] v) { + return v; + } + + public static int[] Overloaded(int[] v) { + return v; + } + + public static long[] Overloaded(long[] v) { + return v; + } + + public static ushort[] Overloaded(ushort[] v) { + return v; + } + + public static uint[] Overloaded(uint[] v) { + return v; + } + + public static ulong[] Overloaded(ulong[] v) { + return v; + } + + public static float[] Overloaded(float[] v) { + return v; + } + + public static double[] Overloaded(double[] v) { + return v; + } + + public static decimal[] Overloaded(decimal[] v) { + return v; + } + + public static string[] Overloaded(string[] v) { + return v; + } + + public static ShortEnum[] Overloaded(ShortEnum[] v) { + return v; + } + + public static object[] Overloaded(object[] v) { + return v; + } + + public static InterfaceTest[] Overloaded(InterfaceTest[] v){ + return v; + } + + public static ISayHello1[] Overloaded(ISayHello1[] v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper Overloaded( + GenericWrapper v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + return v; + } + + public static GenericWrapper[] Overloaded( + GenericWrapper[] v) { + + return v; + } + + public static int Overloaded(string s, int i, object[] o) { + return o.Length; + } + + public static int Overloaded(string s, int i) { + return i; + } + + public static int Overloaded(int i, string s) { + return i; + } + + } + + + public class MethodTestSub : MethodTest { + + public MethodTestSub() : base() {} + + public string PublicMethod(string echo) { + return echo; + } + + } + + +} diff --git a/src/testing/propertytest.cs b/src/testing/propertytest.cs new file mode 100644 index 000000000..687571d29 --- /dev/null +++ b/src/testing/propertytest.cs @@ -0,0 +1,79 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; + +namespace Python.Test { + + //======================================================================== + // Supports units tests for property access. + //======================================================================== + + public class PropertyTest { + + public PropertyTest() {} + + int _public_property = 0; + public int PublicProperty { + get { return _public_property; } + set { _public_property = value; } + } + + static int _public_static_property = 0; + public static int PublicStaticProperty { + get { return _public_static_property; } + set { _public_static_property = value; } + } + + int _protected_property = 0; + protected int ProtectedProperty { + get { return _protected_property; } + set { _protected_property = value; } + } + + static int _protected_static_property = 0; + protected static int ProtectedStaticProperty { + get { return _protected_static_property; } + set { _protected_static_property = value; } + } + + int _internal_property = 0; + internal int InternalProperty { + get { return _internal_property; } + set { _internal_property = value; } + } + + static int _internal_static_property = 0; + internal static int InternalStaticProperty { + get { return _internal_static_property; } + set { _internal_static_property = value; } + } + + int _private_property = 0; + private int PrivateProperty { + get { return _private_property; } + set { _private_property = value; } + } + + static int _private_static_property = 0; + private static int PrivateStaticProperty { + get { return _private_static_property; } + set { _private_static_property = value; } + } + + ShortEnum _enum_property = ShortEnum.Zero; + + public ShortEnum EnumProperty { + get { return _enum_property; } + set { _enum_property = value; } + } + + } + +} diff --git a/src/testing/threadtest.cs b/src/testing/threadtest.cs new file mode 100644 index 000000000..caad9fcf4 --- /dev/null +++ b/src/testing/threadtest.cs @@ -0,0 +1,85 @@ +// ========================================================================== +// This software is subject to the provisions of the Zope Public License, +// Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +// FOR A PARTICULAR PURPOSE. +// ========================================================================== + +using System; +using System.Collections; +using Python.Runtime; + +namespace Python.Test { + + //======================================================================== + // Supports CLR threading / reentrancy unit tests. + //======================================================================== + + public class ThreadTest { + + private static PyObject module; + + private static string testmod = + "import CLR\n" + + "from CLR.Python.Test import ThreadTest\n" + + "\n" + + "def echostring(value):\n" + + " return value\n" + + "\n" + + "def echostring2(value):\n" + + " return ThreadTest.CallEchoString(value)\n" + + "\n"; + + + // This method calls back into the CPython runtime - tests + // call this from Python to check that we don't hang on + // nested transitions from managed to Python code and back. + + public static string CallEchoString(string arg) { + IntPtr gs = PythonEngine.AcquireLock(); + try { + if (module == null) { + module = PythonEngine.ModuleFromString("tt", testmod); + } + PyObject func = module.GetAttr("echostring"); + PyString parg = new PyString(arg); + PyObject temp = func.Invoke(parg); + string result = (string)temp.AsManagedObject(typeof(String)); + func.Dispose(); + parg.Dispose(); + temp.Dispose(); + return result; + } + finally { + PythonEngine.ReleaseLock(gs); + } + } + + public static string CallEchoString2(string arg) { + IntPtr gs = PythonEngine.AcquireLock(); + try { + if (module == null) { + module = PythonEngine.ModuleFromString("tt", testmod); + } + + PyObject func = module.GetAttr("echostring2"); + PyString parg = new PyString(arg); + PyObject temp = func.Invoke(parg); + string result = (string)temp.AsManagedObject(typeof(String)); + func.Dispose(); + parg.Dispose(); + temp.Dispose(); + return result; + } + finally { + PythonEngine.ReleaseLock(gs); + } + } + + + } + + +} diff --git a/src/tests/PyImportTest/__init__.py b/src/tests/PyImportTest/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/tests/PyImportTest/test/__init__.py b/src/tests/PyImportTest/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/tests/PyImportTest/test/one.py b/src/tests/PyImportTest/test/one.py new file mode 100644 index 000000000..e69de29bb diff --git a/pythonnet/src/tests/leaktest.py b/src/tests/leaktest.py old mode 100755 new mode 100644 similarity index 94% rename from pythonnet/src/tests/leaktest.py rename to src/tests/leaktest.py index e41a456be..95f3873a2 --- a/pythonnet/src/tests/leaktest.py +++ b/src/tests/leaktest.py @@ -1,15 +1,13 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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.System as System +import System import gc class LeakTest: @@ -69,19 +67,19 @@ def testModules(self): if i == 10: self.start_test() - __import__('CLR') - __import__('CLR.System') - __import__('CLR.System.IO') - __import__('CLR.System.Net') - __import__('CLR.System.Xml') + __import__('clr') + __import__('System') + __import__('System.IO') + __import__('System.Net') + __import__('System.Xml') self.end_test() def testClasses(self): - from CLR.System.Collections import Hashtable - from CLR.Python.Test import StringDelegate - from CLR.System import Int32 + from System.Collections import Hashtable + from Python.Test import StringDelegate + from System import Int32 self.notify("Running class leak check...") @@ -105,7 +103,7 @@ def testClasses(self): def testEnumerations(self): - from CLR.Python import Test + from Python import Test self.notify("Running enum leak check...") @@ -141,7 +139,7 @@ def testEnumerations(self): def testEvents(self): - from CLR.Python.Test import EventTest, TestEventArgs + from Python.Test import EventTest, TestEventArgs self.notify("Running event leak check...") @@ -219,8 +217,8 @@ def handler(sender, args, dict=dict): def testDelegates(self): - from CLR.Python.Test import DelegateTest, StringDelegate - from CLR import System + from Python.Test import DelegateTest, StringDelegate + import System self.notify("Running delegate leak check...") diff --git a/pythonnet/src/tests/profile.py b/src/tests/profile.py old mode 100755 new mode 100644 similarity index 52% rename from pythonnet/src/tests/profile.py rename to src/tests/profile.py index b182da21d..cc5e48ac9 --- a/pythonnet/src/tests/profile.py +++ b/src/tests/profile.py @@ -1,3 +1,12 @@ +# =========================================================================== +# 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. +# =========================================================================== + """Run all of the unit tests for this package over and over, in order to provide for better profiling.""" diff --git a/src/tests/runtests.py b/src/tests/runtests.py new file mode 100644 index 000000000..452b701f8 --- /dev/null +++ b/src/tests/runtests.py @@ -0,0 +1,74 @@ +# =========================================================================== +# 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. +# =========================================================================== + +"""Run all of the unit tests for this package.""" + +import os +import sys +import unittest +import warnfilter +warnfilter.addClrWarnfilter() + +try: + import System +except ImportError: + print "Load clr import hook" + import clr + +test_modules = ( + 'test_module', # Passes on its own, but not here if + # other test modules that import System.Windows.Forms + # run first. They must not do module level import/AddReference() + # of the System.Windows.Forms namespace. + 'test_event', + 'test_constructors', + 'test_enum', + 'test_method', + + 'test_exceptions', + 'test_compat', + 'test_generic', + 'test_conversion', + 'test_class', + 'test_interface', + 'test_field', + 'test_property', + 'test_indexer', + 'test_delegate', + 'test_array', + 'test_thread' +) + +def removePyc(): + path = os.path.dirname(os.path.abspath(__file__)) + for name in test_modules: + pyc = os.path.join(path, "%s.pyc" % name) + if os.path.isfile(pyc): + os.unlink(pyc) + +def main(verbosity=1): + + removePyc() + + suite = unittest.TestSuite() + + for name in test_modules: + module = __import__(name) + suite.addTests((module.test_suite(),)) + + result = unittest.TextTestRunner(verbosity=verbosity).run(suite) + if not result.wasSuccessful(): + raise Exception("Tests failed") + +if __name__ == '__main__': + main(1) + if '--pause' in sys.argv: + print "Press enter to continue" + raw_input() + diff --git a/pythonnet/src/tests/stress.py b/src/tests/stress.py old mode 100755 new mode 100644 similarity index 93% rename from pythonnet/src/tests/stress.py rename to src/tests/stress.py index b0258f775..d0716022a --- a/pythonnet/src/tests/stress.py +++ b/src/tests/stress.py @@ -1,13 +1,11 @@ -# Copyright (c) 2005 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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. +# =========================================================================== """ Run all of the unit tests for this package multiple times in a highly diff --git a/pythonnet/src/tests/stresstest.py b/src/tests/stresstest.py old mode 100755 new mode 100644 similarity index 58% rename from pythonnet/src/tests/stresstest.py rename to src/tests/stresstest.py index afb419fbd..58b448c78 --- a/pythonnet/src/tests/stresstest.py +++ b/src/tests/stresstest.py @@ -1,3 +1,12 @@ +# =========================================================================== +# 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. +# =========================================================================== + """Basic stress test.""" def main(): diff --git a/pythonnet/src/tests/test_array.py b/src/tests/test_array.py old mode 100755 new mode 100644 similarity index 50% rename from pythonnet/src/tests/test_array.py rename to src/tests/test_array.py index 1625ae346..3a2259e45 --- a/pythonnet/src/tests/test_array.py +++ b/src/tests/test_array.py @@ -1,16 +1,15 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types -import CLR.Python.Test as Test +import Python.Test as Test +import System class ArrayTests(unittest.TestCase): @@ -21,22 +20,22 @@ def testPublicArray(self): object = Test.PublicArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) items[0] = 8 - self.failUnless(items[0] == 8) + self.assertTrue(items[0] == 8) items[4] = 9 - self.failUnless(items[4] == 9) + self.assertTrue(items[4] == 9) items[-4] = 0 - self.failUnless(items[-4] == 0) + self.assertTrue(items[-4] == 0) items[-1] = 4 - self.failUnless(items[-1] == 4) + self.assertTrue(items[-1] == 4) def testProtectedArray(self): @@ -44,22 +43,22 @@ def testProtectedArray(self): object = Test.ProtectedArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) items[0] = 8 - self.failUnless(items[0] == 8) + self.assertTrue(items[0] == 8) items[4] = 9 - self.failUnless(items[4] == 9) + self.assertTrue(items[4] == 9) items[-4] = 0 - self.failUnless(items[-4] == 0) + self.assertTrue(items[-4] == 0) items[-1] = 4 - self.failUnless(items[-1] == 4) + self.assertTrue(items[-1] == 4) def testInternalArray(self): @@ -69,7 +68,7 @@ def test(): object = Test.InternalArrayTest() items = object.items - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testPrivateArray(self): @@ -79,7 +78,7 @@ def test(): object = Test.PrivateArrayTest() items = object.items - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testArrayBoundsChecking(self): @@ -88,41 +87,41 @@ def testArrayBoundsChecking(self): object = Test.Int32ArrayTest() items = object.items - self.failUnless(items[0] == 0) - self.failUnless(items[1] == 1) - self.failUnless(items[2] == 2) - self.failUnless(items[3] == 3) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[1] == 1) + self.assertTrue(items[2] == 2) + self.assertTrue(items[3] == 3) + self.assertTrue(items[4] == 4) - self.failUnless(items[-5] == 0) - self.failUnless(items[-4] == 1) - self.failUnless(items[-3] == 2) - self.failUnless(items[-2] == 3) - self.failUnless(items[-1] == 4) + self.assertTrue(items[-5] == 0) + self.assertTrue(items[-4] == 1) + self.assertTrue(items[-3] == 2) + self.assertTrue(items[-2] == 3) + self.assertTrue(items[-1] == 4) def test(): object = Test.Int32ArrayTest() object.items[5] - self.failUnlessRaises(IndexError, test) + self.assertRaises(IndexError, test) def test(): object = Test.Int32ArrayTest() object.items[5] = 0 - self.failUnlessRaises(IndexError, test) + self.assertRaises(IndexError, test) def test(): object = Test.Int32ArrayTest() items[-6] - self.failUnlessRaises(IndexError, test) + self.assertRaises(IndexError, test) def test(): object = Test.Int32ArrayTest() items[-6] = 0 - self.failUnlessRaises(IndexError, test) + self.assertRaises(IndexError, test) def testArrayContains(self): @@ -131,15 +130,16 @@ def testArrayContains(self): object = Test.Int32ArrayTest() items = object.items - self.failUnless(0 in items) - self.failUnless(1 in items) - self.failUnless(2 in items) - self.failUnless(3 in items) - self.failUnless(4 in items) + self.assertTrue(0 in items) + self.assertTrue(1 in items) + self.assertTrue(2 in items) + self.assertTrue(3 in items) + self.assertTrue(4 in items) - self.failIf(5 in items) - self.failIf(-1 in items) - self.failIf(None in items) + self.assertFalse(5 in items) # "H:\Python27\Lib\unittest\case.py", line 592, in deprecated_func, + self.assertFalse(-1 in items) #TypeError: int() argument must be a string or a number, not 'NoneType' + self.assertFalse(None in items) # which threw ^ here which is a little odd. + # But when run from runtests.py. Not when this module ran by itself. def testBooleanArray(self): @@ -147,31 +147,31 @@ def testBooleanArray(self): object = Test.BooleanArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == True) - self.failUnless(items[1] == False) - self.failUnless(items[2] == True) - self.failUnless(items[3] == False) - self.failUnless(items[4] == True) + self.assertTrue(items[0] == True) + self.assertTrue(items[1] == False) + self.assertTrue(items[2] == True) + self.assertTrue(items[3] == False) + self.assertTrue(items[4] == True) items[0] = False - self.failUnless(items[0] == False) + self.assertTrue(items[0] == False) items[0] = True - self.failUnless(items[0] == True) + self.assertTrue(items[0] == True) def test(): object = Test.ByteArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.ByteArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testByteArray(self): @@ -179,49 +179,49 @@ def testByteArray(self): object = Test.ByteArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 255 min = 0 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.ByteArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.ByteArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.ByteArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.ByteArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testSByteArray(self): @@ -229,49 +229,49 @@ def testSByteArray(self): object = Test.SByteArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 127 min = -128 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.SByteArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.SByteArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.SByteArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.SByteArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testCharArray(self): @@ -279,37 +279,37 @@ def testCharArray(self): object = Test.CharArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 'a') - self.failUnless(items[4] == 'e') + self.assertTrue(items[0] == 'a') + self.assertTrue(items[4] == 'e') max = unichr(65535) min = unichr(0) items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.CharArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.CharArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInt16Array(self): @@ -317,49 +317,49 @@ def testInt16Array(self): object = Test.Int16ArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 32767 min = -32768 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.Int16ArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.Int16ArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.Int16ArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.Int16ArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInt32Array(self): @@ -367,49 +367,49 @@ def testInt32Array(self): object = Test.Int32ArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 2147483647 min = -2147483648 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.Int32ArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.Int32ArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.Int32ArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.Int32ArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInt64Array(self): @@ -417,49 +417,49 @@ def testInt64Array(self): object = Test.Int64ArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 9223372036854775807L min = -9223372036854775808L items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.Int64ArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.Int64ArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.Int64ArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.Int64ArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testUInt16Array(self): @@ -467,49 +467,49 @@ def testUInt16Array(self): object = Test.UInt16ArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 65535 min = 0 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.UInt16ArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.UInt16ArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.UInt16ArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.UInt16ArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testUInt32Array(self): @@ -517,49 +517,49 @@ def testUInt32Array(self): object = Test.UInt32ArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 4294967295L min = 0 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.UInt32ArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.UInt32ArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.UInt32ArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.UInt32ArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testUInt64Array(self): @@ -567,49 +567,49 @@ def testUInt64Array(self): object = Test.UInt64ArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0) - self.failUnless(items[4] == 4) + self.assertTrue(items[0] == 0) + self.assertTrue(items[4] == 4) max = 18446744073709551615L min = 0 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.UInt64ArrayTest() object.items[0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.UInt64ArrayTest() object.items[0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.UInt64ArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.UInt64ArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testSingleArray(self): @@ -617,37 +617,37 @@ def testSingleArray(self): object = Test.SingleArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0.0) - self.failUnless(items[4] == 4.0) + self.assertTrue(items[0] == 0.0) + self.assertTrue(items[4] == 4.0) max = 3.402823e38 min = -3.402823e38 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.SingleArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.SingleArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testDoubleArray(self): @@ -655,37 +655,37 @@ def testDoubleArray(self): object = Test.DoubleArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == 0.0) - self.failUnless(items[4] == 4.0) + self.assertTrue(items[0] == 0.0) + self.assertTrue(items[4] == 4.0) max = 1.7976931348623157e308 min = -1.7976931348623157e308 items[0] = max - self.failUnless(items[0] == max) + self.assertTrue(items[0] == max) items[0] = min - self.failUnless(items[0] == min) + self.assertTrue(items[0] == min) items[-4] = max - self.failUnless(items[-4] == max) + self.assertTrue(items[-4] == max) items[-1] = min - self.failUnless(items[-1] == min) + self.assertTrue(items[-1] == min) def test(): object = Test.DoubleArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.DoubleArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testDecimalArray(self): @@ -693,38 +693,38 @@ def testDecimalArray(self): object = Test.DecimalArrayTest() items = object.items - from CLR.System import Decimal + from System import Decimal max_d = Decimal.Parse("79228162514264337593543950335") min_d = Decimal.Parse("-79228162514264337593543950335") - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == Decimal(0)) - self.failUnless(items[4] == Decimal(4)) + self.assertTrue(items[0] == Decimal(0)) + self.assertTrue(items[4] == Decimal(4)) items[0] = max_d - self.failUnless(items[0] == max_d) + self.assertTrue(items[0] == max_d) items[0] = min_d - self.failUnless(items[0] == min_d) + self.assertTrue(items[0] == min_d) items[-4] = max_d - self.failUnless(items[-4] == max_d) + self.assertTrue(items[-4] == max_d) items[-1] = min_d - self.failUnless(items[-1] == min_d) + self.assertTrue(items[-1] == min_d) def test(): object = Test.DecimalArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.DecimalArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testStringArray(self): @@ -732,118 +732,118 @@ def testStringArray(self): object = Test.StringArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == '0') - self.failUnless(items[4] == '4') + self.assertTrue(items[0] == '0') + self.assertTrue(items[4] == '4') items[0] = "spam" - self.failUnless(items[0] == "spam") + self.assertTrue(items[0] == "spam") items[0] = "eggs" - self.failUnless(items[0] == "eggs") + self.assertTrue(items[0] == "eggs") items[-4] = "spam" - self.failUnless(items[-4] == "spam") + self.assertTrue(items[-4] == "spam") items[-1] = "eggs" - self.failUnless(items[-1] == "eggs") + self.assertTrue(items[-1] == "eggs") def test(): object = Test.StringArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.Int64ArrayTest() object[0] = 0 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testEnumArray(self): """Test enum arrays.""" - from CLR.Python.Test import ShortEnum + from Python.Test import ShortEnum object = Test.EnumArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == ShortEnum.Zero) - self.failUnless(items[4] == ShortEnum.Four) + self.assertTrue(items[0] == ShortEnum.Zero) + self.assertTrue(items[4] == ShortEnum.Four) items[0] = ShortEnum.Four - self.failUnless(items[0] == ShortEnum.Four) + self.assertTrue(items[0] == ShortEnum.Four) items[0] = ShortEnum.Zero - self.failUnless(items[0] == ShortEnum.Zero) + self.assertTrue(items[0] == ShortEnum.Zero) items[-4] = ShortEnum.Four - self.failUnless(items[-4] == ShortEnum.Four) + self.assertTrue(items[-4] == ShortEnum.Four) items[-1] = ShortEnum.Zero - self.failUnless(items[-1] == ShortEnum.Zero) + self.assertTrue(items[-1] == ShortEnum.Zero) def test(): object = Test.EnumArrayTest() object.items[0] = 99 - self.failUnlessRaises(ValueError, test) + self.assertRaises(ValueError, test) def test(): object = Test.EnumArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.EnumArrayTest() object[0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testObjectArray(self): """Test object arrays.""" - from CLR.Python.Test import Spam + from Python.Test import Spam object = Test.ObjectArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0].GetValue() == "0") - self.failUnless(items[4].GetValue() == "4") + self.assertTrue(items[0].GetValue() == "0") + self.assertTrue(items[4].GetValue() == "4") items[0] = Spam("4") - self.failUnless(items[0].GetValue() == "4") + self.assertTrue(items[0].GetValue() == "4") items[0] = Spam("0") - self.failUnless(items[0].GetValue() == "0") + self.assertTrue(items[0].GetValue() == "0") items[-4] = Spam("4") - self.failUnless(items[-4].GetValue() == "4") + self.assertTrue(items[-4].GetValue() == "4") items[-1] = Spam("0") - self.failUnless(items[-1].GetValue() == "0") + self.assertTrue(items[-1].GetValue() == "0") items[0] = 99 - self.failUnless(items[0] == 99) + self.assertTrue(items[0] == 99) items[0] = None - self.failUnless(items[0] == None) + self.assertTrue(items[0] == None) def test(): object = Test.ObjectArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.ObjectArrayTest() object.items["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testNullArray(self): @@ -851,121 +851,121 @@ def testNullArray(self): object = Test.NullArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0] == None) - self.failUnless(items[4] == None) + self.assertTrue(items[0] == None) + self.assertTrue(items[4] == None) items[0] = "spam" - self.failUnless(items[0] == "spam") + self.assertTrue(items[0] == "spam") items[0] = None - self.failUnless(items[0] == None) + self.assertTrue(items[0] == None) items[-4] = "spam" - self.failUnless(items[-4] == "spam") + self.assertTrue(items[-4] == "spam") items[-1] = None - self.failUnless(items[-1] == None) + self.assertTrue(items[-1] == None) empty = object.empty - self.failUnless(len(empty) == 0) + self.assertTrue(len(empty) == 0) def test(): object = Test.NullArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInterfaceArray(self): """Test interface arrays.""" - from CLR.Python.Test import Spam + from Python.Test import Spam object = Test.InterfaceArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0].GetValue() == "0") - self.failUnless(items[4].GetValue() == "4") + self.assertTrue(items[0].GetValue() == "0") + self.assertTrue(items[4].GetValue() == "4") items[0] = Spam("4") - self.failUnless(items[0].GetValue() == "4") + self.assertTrue(items[0].GetValue() == "4") items[0] = Spam("0") - self.failUnless(items[0].GetValue() == "0") + self.assertTrue(items[0].GetValue() == "0") items[-4] = Spam("4") - self.failUnless(items[-4].GetValue() == "4") + self.assertTrue(items[-4].GetValue() == "4") items[-1] = Spam("0") - self.failUnless(items[-1].GetValue() == "0") + self.assertTrue(items[-1].GetValue() == "0") items[0] = None - self.failUnless(items[0] == None) + self.assertTrue(items[0] == None) def test(): object = Test.InterfaceArrayTest() object.items[0] = 99 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.InterfaceArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.InterfaceArrayTest() object.items["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testTypedArray(self): """Test typed arrays.""" - from CLR.Python.Test import Spam + from Python.Test import Spam object = Test.TypedArrayTest() items = object.items - self.failUnless(len(items) == 5) + self.assertTrue(len(items) == 5) - self.failUnless(items[0].GetValue() == "0") - self.failUnless(items[4].GetValue() == "4") + self.assertTrue(items[0].GetValue() == "0") + self.assertTrue(items[4].GetValue() == "4") items[0] = Spam("4") - self.failUnless(items[0].GetValue() == "4") + self.assertTrue(items[0].GetValue() == "4") items[0] = Spam("0") - self.failUnless(items[0].GetValue() == "0") + self.assertTrue(items[0].GetValue() == "0") items[-4] = Spam("4") - self.failUnless(items[-4].GetValue() == "4") + self.assertTrue(items[-4].GetValue() == "4") items[-1] = Spam("0") - self.failUnless(items[-1].GetValue() == "0") + self.assertTrue(items[-1].GetValue() == "0") items[0] = None - self.failUnless(items[0] == None) + self.assertTrue(items[0] == None) def test(): object = Test.TypedArrayTest() object.items[0] = 99 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.TypedArrayTest() v = object.items["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.TypedArrayTest() object.items["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testMultiDimensionalArray(self): @@ -973,72 +973,72 @@ def testMultiDimensionalArray(self): object = Test.MultiDimensionalArrayTest() items = object.items - self.failUnless(len(items) == 25) + self.assertTrue(len(items) == 25) - self.failUnless(items[0, 0] == 0) - self.failUnless(items[0, 1] == 1) - self.failUnless(items[0, 2] == 2) - self.failUnless(items[0, 3] == 3) - self.failUnless(items[0, 4] == 4) - self.failUnless(items[1, 0] == 5) - self.failUnless(items[1, 1] == 6) - self.failUnless(items[1, 2] == 7) - self.failUnless(items[1, 3] == 8) - self.failUnless(items[1, 4] == 9) - self.failUnless(items[2, 0] == 10) - self.failUnless(items[2, 1] == 11) - self.failUnless(items[2, 2] == 12) - self.failUnless(items[2, 3] == 13) - self.failUnless(items[2, 4] == 14) - self.failUnless(items[3, 0] == 15) - self.failUnless(items[3, 1] == 16) - self.failUnless(items[3, 2] == 17) - self.failUnless(items[3, 3] == 18) - self.failUnless(items[3, 4] == 19) - self.failUnless(items[4, 0] == 20) - self.failUnless(items[4, 1] == 21) - self.failUnless(items[4, 2] == 22) - self.failUnless(items[4, 3] == 23) - self.failUnless(items[4, 4] == 24) + self.assertTrue(items[0, 0] == 0) + self.assertTrue(items[0, 1] == 1) + self.assertTrue(items[0, 2] == 2) + self.assertTrue(items[0, 3] == 3) + self.assertTrue(items[0, 4] == 4) + self.assertTrue(items[1, 0] == 5) + self.assertTrue(items[1, 1] == 6) + self.assertTrue(items[1, 2] == 7) + self.assertTrue(items[1, 3] == 8) + self.assertTrue(items[1, 4] == 9) + self.assertTrue(items[2, 0] == 10) + self.assertTrue(items[2, 1] == 11) + self.assertTrue(items[2, 2] == 12) + self.assertTrue(items[2, 3] == 13) + self.assertTrue(items[2, 4] == 14) + self.assertTrue(items[3, 0] == 15) + self.assertTrue(items[3, 1] == 16) + self.assertTrue(items[3, 2] == 17) + self.assertTrue(items[3, 3] == 18) + self.assertTrue(items[3, 4] == 19) + self.assertTrue(items[4, 0] == 20) + self.assertTrue(items[4, 1] == 21) + self.assertTrue(items[4, 2] == 22) + self.assertTrue(items[4, 3] == 23) + self.assertTrue(items[4, 4] == 24) max = 2147483647 min = -2147483648 items[0, 0] = max - self.failUnless(items[0, 0] == max) + self.assertTrue(items[0, 0] == max) items[0, 0] = min - self.failUnless(items[0, 0] == min) + self.assertTrue(items[0, 0] == min) items[-4, 0] = max - self.failUnless(items[-4, 0] == max) + self.assertTrue(items[-4, 0] == max) items[-1, -1] = min - self.failUnless(items[-1, -1] == min) + self.assertTrue(items[-1, -1] == min) def test(): object = Test.MultiDimensionalArrayTest() object.items[0, 0] = max + 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.MultiDimensionalArrayTest() object.items[0, 0] = min - 1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = Test.MultiDimensionalArrayTest() v = object.items["wrong", 0] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.MultiDimensionalArrayTest() object[0, 0] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testArrayIteration(self): @@ -1046,12 +1046,12 @@ def testArrayIteration(self): items = Test.Int32ArrayTest().items for i in items: - self.failUnless((i > -1) and (i < 5)) + self.assertTrue((i > -1) and (i < 5)) items = Test.NullArrayTest().items for i in items: - self.failUnless(i == None) + self.assertTrue(i == None) empty = Test.NullArrayTest().empty @@ -1061,8 +1061,8 @@ def testArrayIteration(self): def testTupleArrayConversion(self): """Test conversion of tuples to array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam items = [] for i in range(10): @@ -1070,14 +1070,14 @@ def testTupleArrayConversion(self): items = tuple(items) result = ArrayConversionTest.EchoRange(items) - self.failUnless(result[0].__class__ == Spam) - self.failUnless(len(result) == 10) + self.assertTrue(result[0].__class__ == Spam) + self.assertTrue(len(result) == 10) def testTupleNestedArrayConversion(self): """Test conversion of tuples to array-of-array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam items = [] for i in range(10): @@ -1089,29 +1089,29 @@ def testTupleNestedArrayConversion(self): result = ArrayConversionTest.EchoRangeAA(items) - self.failUnless(len(result) == 10) - self.failUnless(len(result[0]) == 10) - self.failUnless(result[0][0].__class__ == Spam) + self.assertTrue(len(result) == 10) + self.assertTrue(len(result[0]) == 10) + self.assertTrue(result[0][0].__class__ == Spam) def testListArrayConversion(self): """Test conversion of lists to array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam items = [] for i in range(10): items.append(Spam(str(i))) result = ArrayConversionTest.EchoRange(items) - self.failUnless(result[0].__class__ == Spam) - self.failUnless(len(result) == 10) + self.assertTrue(result[0].__class__ == Spam) + self.assertTrue(len(result) == 10) def testListNestedArrayConversion(self): """Test conversion of lists to array-of-array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam items = [] for i in range(10): @@ -1122,15 +1122,15 @@ def testListNestedArrayConversion(self): result = ArrayConversionTest.EchoRangeAA(items) - self.failUnless(len(result) == 10) - self.failUnless(len(result[0]) == 10) - self.failUnless(result[0][0].__class__ == Spam) + self.assertTrue(len(result) == 10) + self.assertTrue(len(result[0]) == 10) + self.assertTrue(result[0][0].__class__ == Spam) def testSequenceArrayConversion(self): """Test conversion of sequence-like objects to array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam from UserList import UserList items = UserList() @@ -1138,14 +1138,14 @@ def testSequenceArrayConversion(self): items.append(Spam(str(i))) result = ArrayConversionTest.EchoRange(items) - self.failUnless(result[0].__class__ == Spam) - self.failUnless(len(result) == 10) + self.assertTrue(result[0].__class__ == Spam) + self.assertTrue(len(result) == 10) def testSequenceNestedArrayConversion(self): """Test conversion of sequences to array-of-array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam from UserList import UserList items = UserList() @@ -1157,15 +1157,15 @@ def testSequenceNestedArrayConversion(self): result = ArrayConversionTest.EchoRangeAA(items) - self.failUnless(len(result) == 10) - self.failUnless(len(result[0]) == 10) - self.failUnless(result[0][0].__class__ == Spam) + self.assertTrue(len(result) == 10) + self.assertTrue(len(result[0]) == 10) + self.assertTrue(result[0][0].__class__ == Spam) def testTupleArrayConversionTypeChecking(self): """Test error handling for tuple conversion to array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam # This should work, because null / None is a valid value in an # array of reference types. @@ -1178,9 +1178,9 @@ def testTupleArrayConversionTypeChecking(self): result = ArrayConversionTest.EchoRange(items) - self.failUnless(result[0].__class__ == Spam) - self.failUnless(result[1] == None) - self.failUnless(len(result) == 10) + self.assertTrue(result[0].__class__ == Spam) + self.assertTrue(result[1] == None) + self.assertTrue(len(result) == 10) def test(items = items): temp = list(items) @@ -1188,7 +1188,7 @@ def test(items = items): result = ArrayConversionTest.EchoRange(tuple(temp)) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(items = items): temp = list(items) @@ -1196,13 +1196,13 @@ def test(items = items): result = ArrayConversionTest.EchoRange(tuple(temp)) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testListArrayConversionTypeChecking(self): """Test error handling for list conversion to array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam # This should work, because null / None is a valid value in an # array of reference types. @@ -1214,27 +1214,27 @@ def testListArrayConversionTypeChecking(self): result = ArrayConversionTest.EchoRange(items) - self.failUnless(result[0].__class__ == Spam) - self.failUnless(result[1] == None) - self.failUnless(len(result) == 10) + self.assertTrue(result[0].__class__ == Spam) + self.assertTrue(result[1] == None) + self.assertTrue(len(result) == 10) def test(items = items): items[1] = 1 result = ArrayConversionTest.EchoRange(items) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(items = items): items[1] = "spam" result = ArrayConversionTest.EchoRange(items) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testSequenceArrayConversionTypeChecking(self): """Test error handling for sequence conversion to array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam + from Python.Test import ArrayConversionTest + from Python.Test import Spam from UserList import UserList # This should work, because null / None is a valid value in an @@ -1247,28 +1247,28 @@ def testSequenceArrayConversionTypeChecking(self): result = ArrayConversionTest.EchoRange(items) - self.failUnless(result[0].__class__ == Spam) - self.failUnless(result[1] == None) - self.failUnless(len(result) == 10) + self.assertTrue(result[0].__class__ == Spam) + self.assertTrue(result[1] == None) + self.assertTrue(len(result) == 10) def test(items = items): items[1] = 1 result = ArrayConversionTest.EchoRange(items) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(items = items): items[1] = "spam" result = ArrayConversionTest.EchoRange(items) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testMDArrayConversion(self): """Test passing of multi-dimensional array arguments.""" - from CLR.Python.Test import ArrayConversionTest - from CLR.Python.Test import Spam - from CLR.System import Array + from Python.Test import ArrayConversionTest + from Python.Test import Spam + from System import Array # Currently, the runtime does not support automagic conversion of # Python sequences to true multi-dimensional arrays (though it @@ -1284,9 +1284,9 @@ def testMDArrayConversion(self): result = ArrayConversionTest.EchoRangeMD(items) - self.failUnless(len(result) == 25) - self.failUnless(result[0, 0].__class__ == Spam) - self.failUnless(result[0, 0].__class__ == Spam) + self.assertTrue(len(result) == 25) + self.assertTrue(result[0, 0].__class__ == Spam) + self.assertTrue(result[0, 0].__class__ == Spam) def testBoxedValueTypeMutationResult(self): @@ -1298,8 +1298,8 @@ def testBoxedValueTypeMutationResult(self): # to accidentally write code like the following which is not really # mutating value types in-place but changing boxed copies. - from CLR.System.Drawing import Point - from CLR.System import Array + from System.Drawing import Point + from System import Array items = Array.CreateInstance(Point, 5) @@ -1308,23 +1308,156 @@ def testBoxedValueTypeMutationResult(self): for i in range(5): # Boxed items, so settr will not change the array member. - self.failUnless(items[i].X == i) - self.failUnless(items[i].Y == i) + self.assertTrue(items[i].X == i) + self.assertTrue(items[i].Y == i) items[i].X = i + 1 items[i].Y = i + 1 - self.failUnless(items[i].X == i) - self.failUnless(items[i].Y == i) + self.assertTrue(items[i].X == i) + self.assertTrue(items[i].Y == i) for i in range(5): # Demonstrates the workaround that will change the members. - self.failUnless(items[i].X == i) - self.failUnless(items[i].Y == i) + self.assertTrue(items[i].X == i) + self.assertTrue(items[i].Y == i) item = items[i] item.X = i + 1 item.Y = i + 1 items[i] = item - self.failUnless(items[i].X == i + 1) - self.failUnless(items[i].Y == i + 1) + self.assertTrue(items[i].X == i + 1) + self.assertTrue(items[i].Y == i + 1) + + + def testSpecialArrayCreation(self): + """Test using the Array[] syntax for creating arrays.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from System import Array + inst = InterfaceTest() + + value = Array[System.Boolean]([True, True]) + self.assertTrue(value[0] == True) + self.assertTrue(value[1] == True) + self.assertTrue(value.Length == 2) + + value = Array[bool]([True, True]) + self.assertTrue(value[0] == True) + self.assertTrue(value[1] == True) + self.assertTrue(value.Length == 2) + + value = Array[System.Byte]([0, 255]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 255) + self.assertTrue(value.Length == 2) + + value = Array[System.SByte]([0, 127]) + self.assertTrue(value[0] == 0) + 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') + self.assertTrue(value.Length == 2) + + value = Array[System.Char]([0, 65535]) + self.assertTrue(value[0] == unichr(0)) + self.assertTrue(value[1] == unichr(65535)) + self.assertTrue(value.Length == 2) + + value = Array[System.Int16]([0, 32767]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 32767) + self.assertTrue(value.Length == 2) + + value = Array[System.Int32]([0, 2147483647]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 2147483647) + self.assertTrue(value.Length == 2) + + value = Array[int]([0, 2147483647]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 2147483647) + self.assertTrue(value.Length == 2) + + value = Array[System.Int64]([0, 9223372036854775807L]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 9223372036854775807L) + 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) + + value = Array[System.UInt16]([0, 65000]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 65000) + self.assertTrue(value.Length == 2) + + value = Array[System.UInt32]([0, 4294967295L]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 4294967295L) + self.assertTrue(value.Length == 2) + + value = Array[System.UInt64]([0, 18446744073709551615L]) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 18446744073709551615L) + self.assertTrue(value.Length == 2) + + value = Array[System.Single]([0.0, 3.402823e38]) + self.assertTrue(value[0] == 0.0) + self.assertTrue(value[1] == 3.402823e38) + self.assertTrue(value.Length == 2) + + value = Array[System.Double]([0.0, 1.7976931348623157e308]) + self.assertTrue(value[0] == 0.0) + self.assertTrue(value[1] == 1.7976931348623157e308) + self.assertTrue(value.Length == 2) + + value = Array[float]([0.0, 1.7976931348623157e308]) + self.assertTrue(value[0] == 0.0) + self.assertTrue(value[1] == 1.7976931348623157e308) + self.assertTrue(value.Length == 2) + + value = Array[System.Decimal]([System.Decimal.Zero,System.Decimal.One]) + self.assertTrue(value[0] == System.Decimal.Zero) + self.assertTrue(value[1] == System.Decimal.One) + self.assertTrue(value.Length == 2) + + value = Array[System.String](["one", "two"]) + self.assertTrue(value[0] == "one") + self.assertTrue(value[1] == "two") + self.assertTrue(value.Length == 2) + + value = Array[str](["one", "two"]) + self.assertTrue(value[0] == "one") + self.assertTrue(value[1] == "two") + self.assertTrue(value.Length == 2) + + value = Array[ShortEnum]([ShortEnum.Zero, ShortEnum.One]) + self.assertTrue(value[0] == ShortEnum.Zero) + self.assertTrue(value[1] == ShortEnum.One) + self.assertTrue(value.Length == 2) + + value = Array[System.Object]([inst, inst]) + self.assertTrue(value[0].__class__ == inst.__class__) + self.assertTrue(value[1].__class__ == inst.__class__) + self.assertTrue(value.Length == 2) + + value = Array[InterfaceTest]([inst, inst]) + self.assertTrue(value[0].__class__ == inst.__class__) + self.assertTrue(value[1].__class__ == inst.__class__) + self.assertTrue(value.Length == 2) + + value = Array[ISayHello1]([inst, inst]) + self.assertTrue(value[0].__class__ == inst.__class__) + self.assertTrue(value[1].__class__ == inst.__class__) + self.assertTrue(value.Length == 2) + + inst = System.Exception("badness") + value = Array[System.Exception]([inst, inst]) + self.assertTrue(value[0].__class__ == inst.__class__) + self.assertTrue(value[1].__class__ == inst.__class__) + self.assertTrue(value.Length == 2) def testArrayAbuse(self): @@ -1335,44 +1468,44 @@ def testArrayAbuse(self): def test(): del _class.__getitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): del object.__getitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): del _class.__setitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): del object.__setitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): Test.PublicArrayTest.__getitem__(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): Test.PublicArrayTest.__setitem__(0, 0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): desc = Test.PublicArrayTest.__dict__['__getitem__'] desc(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): desc = Test.PublicArrayTest.__dict__['__setitem__'] desc(0, 0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) @@ -1383,6 +1516,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/pythonnet/src/tests/test_class.py b/src/tests/test_class.py old mode 100755 new mode 100644 similarity index 65% rename from pythonnet/src/tests/test_class.py rename to src/tests/test_class.py index 38ab0b495..b87587586 --- a/pythonnet/src/tests/test_class.py +++ b/src/tests/test_class.py @@ -1,19 +1,16 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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. - -from CLR.System.Collections import Hashtable -from CLR.Python.Test import ClassTest +# =========================================================================== +from System.Collections import Hashtable +from Python.Test import ClassTest import sys, os, string, unittest, types -import CLR.Python.Test as Test -import CLR.System as System +import Python.Test as Test +import System class ClassTests(unittest.TestCase): @@ -33,43 +30,43 @@ def testBasicValueType(self): def testClassStandardAttrs(self): """Test standard class attributes.""" - self.failUnless(ClassTest.__name__ == 'ClassTest') - self.failUnless(ClassTest.__module__ == 'CLR.Python.Test') - self.failUnless(type(ClassTest.__dict__) == types.DictProxyType) - self.failUnless(len(ClassTest.__doc__) > 0) + self.assertTrue(ClassTest.__name__ == 'ClassTest') + self.assertTrue(ClassTest.__module__ == 'Python.Test') + self.assertTrue(type(ClassTest.__dict__) == types.DictProxyType) + self.assertTrue(len(ClassTest.__doc__) > 0) def testClassDocstrings(self): """Test standard class docstring generation""" value = 'Void .ctor()' - self.failUnless(ClassTest.__doc__ == value) + self.assertTrue(ClassTest.__doc__ == value) def testClassDefaultStr(self): """Test the default __str__ implementation for managed objects.""" s = System.String("this is a test") - self.failUnless(str(s) == "this is a test") + self.assertTrue(str(s) == "this is a test") def testClassDefaultRepr(self): """Test the default __repr__ implementation for managed objects.""" s = System.String("this is a test") - self.failUnless(repr(s).startswith(" -1) and (item < 10)) + self.assertTrue((item > -1) and (item < 10)) dict = Test.ClassTest.GetHashtable() for item in dict: cname = item.__class__.__name__ - self.failUnless(cname.endswith('DictionaryEntry')) + self.assertTrue(cname.endswith('DictionaryEntry')) def testIEnumeratorIteration(self): @@ -176,7 +172,7 @@ def testIEnumeratorIteration(self): chars = Test.ClassTest.GetEnumerator() for item in chars: - self.failUnless(item in 'test string') + self.assertTrue(item in 'test string') @@ -195,11 +191,11 @@ def __getitem__(self, key): table['two'] = 'two' table['three'] = 'three' - self.failUnless(table['one'] == 'my one') - self.failUnless(table['two'] == 'my two') - self.failUnless(table['three'] == 'my three') + self.assertTrue(table['one'] == 'my one') + self.assertTrue(table['two'] == 'my two') + self.assertTrue(table['three'] == 'my three') - self.failUnless(table.Count == 3) + self.assertTrue(table.Count == 3) def testOverrideSetItem(self): @@ -216,11 +212,11 @@ def __setitem__(self, key, value): table['two'] = 'two' table['three'] = 'three' - self.failUnless(table['one'] == 'my one') - self.failUnless(table['two'] == 'my two') - self.failUnless(table['three'] == 'my three') + self.assertTrue(table['one'] == 'my one') + self.assertTrue(table['two'] == 'my two') + self.assertTrue(table['three'] == 'my three') - self.failUnless(table.Count == 3) + self.assertTrue(table.Count == 3) @@ -241,6 +237,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/src/tests/test_compat.py b/src/tests/test_compat.py new file mode 100644 index 000000000..7bb80d488 --- /dev/null +++ b/src/tests/test_compat.py @@ -0,0 +1,272 @@ +# =========================================================================== +# 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 sys, os, string, unittest, types + + +class CompatibilityTests(unittest.TestCase): + """ + Backward-compatibility tests for deprecated features. + """ + + def isCLRModule(self, object): + return type(object).__name__ == 'ModuleObject' + + def isCLRRootModule(self, object): + return type(object).__name__ == 'CLRModule' + + def isCLRClass(self, object): + return type(object).__name__ == 'CLR Metatype' # for now + + # Tests for old-style CLR-prefixed module naming. + + def testSimpleImport(self): + """Test simple import.""" + import CLR + self.assertTrue(self.isCLRRootModule(CLR)) + self.assertTrue(CLR.__name__ == 'clr') + + import sys + self.assertTrue(type(sys) == types.ModuleType) + self.assertTrue(sys.__name__ == 'sys') + + import httplib + self.assertTrue(type(httplib) == types.ModuleType) + self.assertTrue(httplib.__name__ == 'httplib') + + + def testSimpleImportWithAlias(self): + """Test simple import with aliasing.""" + import CLR as myCLR + self.assertTrue(self.isCLRRootModule(myCLR)) + self.assertTrue(myCLR.__name__ == 'clr') + + import sys as mySys + 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') + + + def testDottedNameImport(self): + """Test dotted-name import.""" + import CLR.System + self.assertTrue(self.isCLRModule(CLR.System)) + self.assertTrue(CLR.System.__name__ == 'System') + + import System + self.assertTrue(self.isCLRModule(System)) + self.assertTrue(System.__name__ == 'System') + + self.assertTrue(System is CLR.System) + + import xml.dom + self.assertTrue(type(xml.dom) == types.ModuleType) + self.assertTrue(xml.dom.__name__ == 'xml.dom') + + + def testDottedNameImportWithAlias(self): + """Test dotted-name import with aliasing.""" + import CLR.System as myCLRSystem + self.assertTrue(self.isCLRModule(myCLRSystem)) + self.assertTrue(myCLRSystem.__name__ == 'System') + + import System as mySystem + self.assertTrue(self.isCLRModule(mySystem)) + self.assertTrue(mySystem.__name__ == 'System') + + self.assertTrue(mySystem is myCLRSystem) + + import xml.dom as myDom + self.assertTrue(type(myDom) == types.ModuleType) + self.assertTrue(myDom.__name__ == 'xml.dom') + + + def testSimpleImportFrom(self): + """Test simple 'import from'.""" + from CLR import System + self.assertTrue(self.isCLRModule(System)) + self.assertTrue(System.__name__ == 'System') + + from xml import dom + self.assertTrue(type(dom) == types.ModuleType) + self.assertTrue(dom.__name__ == 'xml.dom') + + + def testSimpleImportFromWithAlias(self): + """Test simple 'import from' with aliasing.""" + from CLR import System as mySystem + self.assertTrue(self.isCLRModule(mySystem)) + self.assertTrue(mySystem.__name__ == 'System') + + from xml import dom as myDom + self.assertTrue(type(myDom) == types.ModuleType) + self.assertTrue(myDom.__name__ == 'xml.dom') + + + def testDottedNameImportFrom(self): + """Test dotted-name 'import from'.""" + from CLR.System import Xml + self.assertTrue(self.isCLRModule(Xml)) + self.assertTrue(Xml.__name__ == 'System.Xml') + + from CLR.System.Xml import XmlDocument + self.assertTrue(self.isCLRClass(XmlDocument)) + self.assertTrue(XmlDocument.__name__ == 'XmlDocument') + + from xml.dom import pulldom + self.assertTrue(type(pulldom) == types.ModuleType) + self.assertTrue(pulldom.__name__ == 'xml.dom.pulldom') + + from xml.dom.pulldom import PullDOM + self.assertTrue(type(PullDOM) == types.ClassType) + self.assertTrue(PullDOM.__name__ == 'PullDOM') + + + def testDottedNameImportFromWithAlias(self): + """Test dotted-name 'import from' with aliasing.""" + from CLR.System import Xml as myXml + self.assertTrue(self.isCLRModule(myXml)) + self.assertTrue(myXml.__name__ == 'System.Xml') + + from CLR.System.Xml import XmlDocument as myXmlDocument + self.assertTrue(self.isCLRClass(myXmlDocument)) + self.assertTrue(myXmlDocument.__name__ == 'XmlDocument') + + from xml.dom import pulldom as myPulldom + self.assertTrue(type(myPulldom) == types.ModuleType) + self.assertTrue(myPulldom.__name__ == 'xml.dom.pulldom') + + from xml.dom.pulldom import PullDOM as myPullDOM + self.assertTrue(type(myPullDOM) == types.ClassType) + self.assertTrue(myPullDOM.__name__ == 'PullDOM') + + + def testFromModuleImportStar(self): + """Test from module import * behavior.""" + import clr + clr.AddReference("System.Management") + + count = len(locals().keys()) + m = __import__('CLR.System.Management', globals(), locals(), ['*']) + self.assertTrue(m.__name__ == 'System.Management') + self.assertTrue(self.isCLRModule(m)) + self.assertTrue(len(locals().keys()) > count + 1) + + m2 = __import__('System.Management', globals(), locals(), ['*']) + self.assertTrue(m2.__name__ == 'System.Management') + self.assertTrue(self.isCLRModule(m2)) + self.assertTrue(len(locals().keys()) > count + 1) + + self.assertTrue(m is m2) + + def testExplicitAssemblyLoad(self): + """Test explicit assembly loading using standard CLR tools.""" + from CLR.System.Reflection import Assembly + from CLR import System + import sys + + assembly = Assembly.LoadWithPartialName('System.Data') + self.assertTrue(assembly != None) + + import CLR.System.Data + self.assertTrue(sys.modules.has_key('System.Data')) + + assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') + self.assertTrue(assembly == None) + + + def testImplicitLoadAlreadyValidNamespace(self): + """Test implicit assembly load over an already valid namespace.""" + # In this case, the mscorlib assembly (loaded by default) defines + # a number of types in the System namespace. There is also a System + # assembly, which is _not_ loaded by default, which also contains + # types in the System namespace. The desired behavior is for the + # Python runtime to "do the right thing", allowing types from both + # assemblies to be found in the CLR.System module implicitly. + import CLR.System + self.assertTrue(self.isCLRClass(CLR.System.UriBuilder)) + + + def testImportNonExistantModule(self): + """Test import failure for a non-existant module.""" + def test(): + import System.SpamSpamSpam + + def testclr(): + import CLR.System.SpamSpamSpam + + self.assertRaises(ImportError, test) + self.assertRaises(ImportError, testclr) + + def testLookupNoNamespaceType(self): + """Test lookup of types without a qualified namespace.""" + import CLR.Python.Test + import CLR + self.assertTrue(self.isCLRClass(CLR.NoNamespaceType)) + + + def testModuleLookupRecursion(self): + """Test for recursive lookup handling.""" + def test1(): + from CLR import CLR + + self.assertRaises(ImportError, test1) + + def test2(): + import CLR + x = CLR.CLR + + self.assertRaises(AttributeError, test2) + + + def testModuleGetAttr(self): + """Test module getattr behavior.""" + import CLR.System as System + + int_type = System.Int32 + self.assertTrue(self.isCLRClass(int_type)) + + module = System.Xml + self.assertTrue(self.isCLRModule(module)) + + def test(): + spam = System.Spam + + self.assertRaises(AttributeError, test) + + def test(): + spam = getattr(System, 1) + + self.assertRaises(TypeError, test) + + def test000MultipleImports(self): + # import CLR did raise a Seg Fault once + # test if the Exceptions.warn() method still causes it + for n in range(100): + import CLR + + +def test_suite(): + return unittest.makeSuite(CompatibilityTests) + +def main(): + unittest.TextTestRunner().run(test_suite()) + +if __name__ == '__main__': + try: + import System + except ImportError: + print "Load clr import hook" + import clr + + main() + diff --git a/pythonnet/src/tests/test_constructors.py b/src/tests/test_constructors.py old mode 100755 new mode 100644 similarity index 60% rename from pythonnet/src/tests/test_constructors.py rename to src/tests/test_constructors.py index d2b73df50..4486e50bd --- a/pythonnet/src/tests/test_constructors.py +++ b/src/tests/test_constructors.py @@ -1,17 +1,17 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types -import CLR.Python.Test as Test -import CLR.System as System +import clr +clr.AddReference("Python.Test") +import Python.Test as Test +import System class ConstructorTests(unittest.TestCase): @@ -19,42 +19,44 @@ class ConstructorTests(unittest.TestCase): def testEnumConstructor(self): """Test enum constructor args""" - from Test import EnumConstructorTest + from System import TypeCode + from Python.Test import EnumConstructorTest ob = EnumConstructorTest(TypeCode.Int32) - self.failUnless(ob.value == TypeCode.Int32) + self.assertTrue(ob.value == TypeCode.Int32) def testFlagsConstructor(self): """Test flags constructor args""" - from Test import FlagsConstructorTest + from Python.Test import FlagsConstructorTest from System.IO import FileAccess flags = FileAccess.Read | FileAccess.Write ob = FlagsConstructorTest(flags) - self.failUnless(ob.value == flags) + self.assertTrue(ob.value == flags) def testStructConstructor(self): """Test struct constructor args""" - from Test import StructConstructorTest + from System import Guid + from Python.Test import StructConstructorTest guid = Guid.NewGuid() ob = StructConstructorTest(guid) - self.failUnless(ob.value == guid) + self.assertTrue(ob.value == guid) def testSubclassConstructor(self): """Test subclass constructor args""" - from Test import SubclassConstructorTest - from System.Windows.Forms import Form, Control + from Python.Test import SubclassConstructorTest - class sub(Form): + class sub(System.Exception): pass - form = sub() - ob = SubclassConstructorTest(form) - self.failUnless(isinstance(ob.value, Control)) + instance = sub() + ob = SubclassConstructorTest(instance) + print ob + self.assertTrue(isinstance(ob.value, System.Exception)) @@ -65,6 +67,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/pythonnet/src/tests/test_conversion.py b/src/tests/test_conversion.py old mode 100755 new mode 100644 similarity index 51% rename from pythonnet/src/tests/test_conversion.py rename to src/tests/test_conversion.py index 01a11d6ec..8408f6fe3 --- a/pythonnet/src/tests/test_conversion.py +++ b/src/tests/test_conversion.py @@ -1,17 +1,15 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types -from CLR.Python.Test import ConversionTest -from CLR import System +from Python.Test import ConversionTest +import System class ConversionTests(unittest.TestCase): @@ -20,726 +18,726 @@ class ConversionTests(unittest.TestCase): def testBoolConversion(self): """Test bool conversion.""" object = ConversionTest() - self.failUnless(object.BooleanField == False) - self.failUnless(object.BooleanField is False) - self.failUnless(object.BooleanField == 0) + self.assertTrue(object.BooleanField == False) + self.assertTrue(object.BooleanField is False) + self.assertTrue(object.BooleanField == 0) object.BooleanField = True - self.failUnless(object.BooleanField == True) - self.failUnless(object.BooleanField is True) - self.failUnless(object.BooleanField == 1) + self.assertTrue(object.BooleanField == True) + self.assertTrue(object.BooleanField is True) + self.assertTrue(object.BooleanField == 1) object.BooleanField = False - self.failUnless(object.BooleanField == False) - self.failUnless(object.BooleanField is False) - self.failUnless(object.BooleanField == 0) + self.assertTrue(object.BooleanField == False) + self.assertTrue(object.BooleanField is False) + self.assertTrue(object.BooleanField == 0) object.BooleanField = 1 - self.failUnless(object.BooleanField == True) - self.failUnless(object.BooleanField is True) - self.failUnless(object.BooleanField == 1) + self.assertTrue(object.BooleanField == True) + self.assertTrue(object.BooleanField is True) + self.assertTrue(object.BooleanField == 1) object.BooleanField = 0 - self.failUnless(object.BooleanField == False) - self.failUnless(object.BooleanField is False) - self.failUnless(object.BooleanField == 0) + self.assertTrue(object.BooleanField == False) + self.assertTrue(object.BooleanField is False) + self.assertTrue(object.BooleanField == 0) object.BooleanField = System.Boolean(None) - self.failUnless(object.BooleanField == False) - self.failUnless(object.BooleanField is False) - self.failUnless(object.BooleanField == 0) + self.assertTrue(object.BooleanField == False) + self.assertTrue(object.BooleanField is False) + self.assertTrue(object.BooleanField == 0) object.BooleanField = System.Boolean('') - self.failUnless(object.BooleanField == False) - self.failUnless(object.BooleanField is False) - self.failUnless(object.BooleanField == 0) + self.assertTrue(object.BooleanField == False) + self.assertTrue(object.BooleanField is False) + self.assertTrue(object.BooleanField == 0) object.BooleanField = System.Boolean(0) - self.failUnless(object.BooleanField == False) - self.failUnless(object.BooleanField is False) - self.failUnless(object.BooleanField == 0) + self.assertTrue(object.BooleanField == False) + self.assertTrue(object.BooleanField is False) + self.assertTrue(object.BooleanField == 0) object.BooleanField = System.Boolean(1) - self.failUnless(object.BooleanField == True) - self.failUnless(object.BooleanField is True) - self.failUnless(object.BooleanField == 1) + self.assertTrue(object.BooleanField == True) + self.assertTrue(object.BooleanField is True) + self.assertTrue(object.BooleanField == 1) object.BooleanField = System.Boolean('a') - self.failUnless(object.BooleanField == True) - self.failUnless(object.BooleanField is True) - self.failUnless(object.BooleanField == 1) + self.assertTrue(object.BooleanField == True) + self.assertTrue(object.BooleanField is True) + self.assertTrue(object.BooleanField == 1) def testSByteConversion(self): """Test sbyte conversion.""" - self.failUnless(System.SByte.MaxValue == 127) - self.failUnless(System.SByte.MinValue == -128) + self.assertTrue(System.SByte.MaxValue == 127) + self.assertTrue(System.SByte.MinValue == -128) object = ConversionTest() - self.failUnless(object.SByteField == 0) + self.assertTrue(object.SByteField == 0) object.SByteField = 127 - self.failUnless(object.SByteField == 127) + self.assertTrue(object.SByteField == 127) object.SByteField = -128 - self.failUnless(object.SByteField == -128) + self.assertTrue(object.SByteField == -128) object.SByteField = System.SByte(127) - self.failUnless(object.SByteField == 127) + self.assertTrue(object.SByteField == 127) object.SByteField = System.SByte(-128) - self.failUnless(object.SByteField == -128) + self.assertTrue(object.SByteField == -128) def test(): ConversionTest().SByteField = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().SByteField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().SByteField = 128 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().SByteField = -129 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.SByte(128) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.SByte(-129) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testByteConversion(self): """Test byte conversion.""" - self.failUnless(System.Byte.MaxValue == 255) - self.failUnless(System.Byte.MinValue == 0) + self.assertTrue(System.Byte.MaxValue == 255) + self.assertTrue(System.Byte.MinValue == 0) object = ConversionTest() - self.failUnless(object.ByteField == 0) + self.assertTrue(object.ByteField == 0) object.ByteField = 255 - self.failUnless(object.ByteField == 255) + self.assertTrue(object.ByteField == 255) object.ByteField = 0 - self.failUnless(object.ByteField == 0) + self.assertTrue(object.ByteField == 0) object.ByteField = System.Byte(255) - self.failUnless(object.ByteField == 255) + self.assertTrue(object.ByteField == 255) object.ByteField = System.Byte(0) - self.failUnless(object.ByteField == 0) + self.assertTrue(object.ByteField == 0) def test(): ConversionTest().ByteField = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().ByteField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().ByteField = 256 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().ByteField = -1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Byte(256) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Byte(-1) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testCharConversion(self): """Test char conversion.""" - self.failUnless(System.Char.MaxValue == unichr(65535)) - self.failUnless(System.Char.MinValue == unichr(0)) + self.assertTrue(System.Char.MaxValue == unichr(65535)) + self.assertTrue(System.Char.MinValue == unichr(0)) object = ConversionTest() - self.failUnless(object.CharField == u'A') + self.assertTrue(object.CharField == u'A') object.CharField = 'B' - self.failUnless(object.CharField == u'B') + self.assertTrue(object.CharField == u'B') object.CharField = u'B' - self.failUnless(object.CharField == u'B') + self.assertTrue(object.CharField == u'B') object.CharField = 67 - self.failUnless(object.CharField == u'C') + self.assertTrue(object.CharField == u'C') def test(): ConversionTest().CharField = 65536 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().CharField = -1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().CharField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInt16Conversion(self): """Test int16 conversion.""" - self.failUnless(System.Int16.MaxValue == 32767) - self.failUnless(System.Int16.MinValue == -32768) + self.assertTrue(System.Int16.MaxValue == 32767) + self.assertTrue(System.Int16.MinValue == -32768) object = ConversionTest() - self.failUnless(object.Int16Field == 0) + self.assertTrue(object.Int16Field == 0) object.Int16Field = 32767 - self.failUnless(object.Int16Field == 32767) + self.assertTrue(object.Int16Field == 32767) object.Int16Field = -32768 - self.failUnless(object.Int16Field == -32768) + self.assertTrue(object.Int16Field == -32768) object.Int16Field = System.Int16(32767) - self.failUnless(object.Int16Field == 32767) + self.assertTrue(object.Int16Field == 32767) object.Int16Field = System.Int16(-32768) - self.failUnless(object.Int16Field == -32768) + self.assertTrue(object.Int16Field == -32768) def test(): ConversionTest().Int16Field = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().Int16Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().Int16Field = 32768 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().Int16Field = -32769 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Int16(32768) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Int16(-32769) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testInt32Conversion(self): """Test int32 conversion.""" - self.failUnless(System.Int32.MaxValue == 2147483647) - self.failUnless(System.Int32.MinValue == -2147483648) + self.assertTrue(System.Int32.MaxValue == 2147483647) + self.assertTrue(System.Int32.MinValue == -2147483648) object = ConversionTest() - self.failUnless(object.Int32Field == 0) + self.assertTrue(object.Int32Field == 0) object.Int32Field = 2147483647 - self.failUnless(object.Int32Field == 2147483647) + self.assertTrue(object.Int32Field == 2147483647) object.Int32Field = -2147483648 - self.failUnless(object.Int32Field == -2147483648) + self.assertTrue(object.Int32Field == -2147483648) object.Int32Field = System.Int32(2147483647) - self.failUnless(object.Int32Field == 2147483647) + self.assertTrue(object.Int32Field == 2147483647) object.Int32Field = System.Int32(-2147483648) - self.failUnless(object.Int32Field == -2147483648) + self.assertTrue(object.Int32Field == -2147483648) def test(): ConversionTest().Int32Field = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().Int32Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().Int32Field = 2147483648 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().Int32Field = -2147483649 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Int32(2147483648) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Int32(-2147483649) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testInt64Conversion(self): """Test int64 conversion.""" - self.failUnless(System.Int64.MaxValue == 9223372036854775807L) - self.failUnless(System.Int64.MinValue == -9223372036854775808L) + self.assertTrue(System.Int64.MaxValue == 9223372036854775807L) + self.assertTrue(System.Int64.MinValue == -9223372036854775808L) object = ConversionTest() - self.failUnless(object.Int64Field == 0) + self.assertTrue(object.Int64Field == 0) object.Int64Field = 9223372036854775807L - self.failUnless(object.Int64Field == 9223372036854775807L) + self.assertTrue(object.Int64Field == 9223372036854775807L) object.Int64Field = -9223372036854775808L - self.failUnless(object.Int64Field == -9223372036854775808L) + self.assertTrue(object.Int64Field == -9223372036854775808L) object.Int64Field = System.Int64(9223372036854775807L) - self.failUnless(object.Int64Field == 9223372036854775807L) + self.assertTrue(object.Int64Field == 9223372036854775807L) object.Int64Field = System.Int64(-9223372036854775808L) - self.failUnless(object.Int64Field == -9223372036854775808L) + self.assertTrue(object.Int64Field == -9223372036854775808L) def test(): ConversionTest().Int64Field = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().Int64Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().Int64Field = 9223372036854775808L - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().Int64Field = -9223372036854775809L - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Int64(9223372036854775808L) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Int64(-9223372036854775809L) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testUInt16Conversion(self): """Test uint16 conversion.""" - self.failUnless(System.UInt16.MaxValue == 65535) - self.failUnless(System.UInt16.MinValue == 0) + self.assertTrue(System.UInt16.MaxValue == 65535) + self.assertTrue(System.UInt16.MinValue == 0) object = ConversionTest() - self.failUnless(object.UInt16Field == 0) + self.assertTrue(object.UInt16Field == 0) object.UInt16Field = 65535 - self.failUnless(object.UInt16Field == 65535) + self.assertTrue(object.UInt16Field == 65535) object.UInt16Field = -0 - self.failUnless(object.UInt16Field == 0) + self.assertTrue(object.UInt16Field == 0) object.UInt16Field = System.UInt16(65535) - self.failUnless(object.UInt16Field == 65535) + self.assertTrue(object.UInt16Field == 65535) object.UInt16Field = System.UInt16(0) - self.failUnless(object.UInt16Field == 0) + self.assertTrue(object.UInt16Field == 0) def test(): ConversionTest().UInt16Field = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().UInt16Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().UInt16Field = 65536 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().UInt16Field = -1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.UInt16(65536) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.UInt16(-1) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testUInt32Conversion(self): """Test uint32 conversion.""" - self.failUnless(System.UInt32.MaxValue == 4294967295L) - self.failUnless(System.UInt32.MinValue == 0) + self.assertTrue(System.UInt32.MaxValue == 4294967295L) + self.assertTrue(System.UInt32.MinValue == 0) object = ConversionTest() - self.failUnless(object.UInt32Field == 0) + self.assertTrue(object.UInt32Field == 0) object.UInt32Field = 4294967295L - self.failUnless(object.UInt32Field == 4294967295L) + self.assertTrue(object.UInt32Field == 4294967295L) object.UInt32Field = -0 - self.failUnless(object.UInt32Field == 0) + self.assertTrue(object.UInt32Field == 0) object.UInt32Field = System.UInt32(4294967295L) - self.failUnless(object.UInt32Field == 4294967295L) + self.assertTrue(object.UInt32Field == 4294967295L) object.UInt32Field = System.UInt32(0) - self.failUnless(object.UInt32Field == 0) + self.assertTrue(object.UInt32Field == 0) def test(): ConversionTest().UInt32Field = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().UInt32Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().UInt32Field = 4294967296L - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().UInt32Field = -1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.UInt32(4294967296L) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.UInt32(-1) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testUInt64Conversion(self): """Test uint64 conversion.""" - self.failUnless(System.UInt64.MaxValue == 18446744073709551615L) - self.failUnless(System.UInt64.MinValue == 0) + self.assertTrue(System.UInt64.MaxValue == 18446744073709551615L) + self.assertTrue(System.UInt64.MinValue == 0) object = ConversionTest() - self.failUnless(object.UInt64Field == 0) + self.assertTrue(object.UInt64Field == 0) object.UInt64Field = 18446744073709551615L - self.failUnless(object.UInt64Field == 18446744073709551615L) + self.assertTrue(object.UInt64Field == 18446744073709551615L) object.UInt64Field = -0 - self.failUnless(object.UInt64Field == 0) + self.assertTrue(object.UInt64Field == 0) object.UInt64Field = System.UInt64(18446744073709551615L) - self.failUnless(object.UInt64Field == 18446744073709551615L) + self.assertTrue(object.UInt64Field == 18446744073709551615L) object.UInt64Field = System.UInt64(0) - self.failUnless(object.UInt64Field == 0) + self.assertTrue(object.UInt64Field == 0) def test(): ConversionTest().UInt64Field = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().UInt64Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().UInt64Field = 18446744073709551616L - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().UInt64Field = -1 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.UInt64(18446744073709551616L) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.UInt64(-1) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testSingleConversion(self): """Test single conversion.""" - self.failUnless(System.Single.MaxValue == 3.402823e38) - self.failUnless(System.Single.MinValue == -3.402823e38) + self.assertTrue(System.Single.MaxValue == 3.402823e38) + self.assertTrue(System.Single.MinValue == -3.402823e38) object = ConversionTest() - self.failUnless(object.SingleField == 0.0) + self.assertTrue(object.SingleField == 0.0) object.SingleField = 3.402823e38 - self.failUnless(object.SingleField == 3.402823e38) + self.assertTrue(object.SingleField == 3.402823e38) object.SingleField = -3.402823e38 - self.failUnless(object.SingleField == -3.402823e38) + self.assertTrue(object.SingleField == -3.402823e38) object.SingleField = System.Single(3.402823e38) - self.failUnless(object.SingleField == 3.402823e38) + self.assertTrue(object.SingleField == 3.402823e38) object.SingleField = System.Single(-3.402823e38) - self.failUnless(object.SingleField == -3.402823e38) + self.assertTrue(object.SingleField == -3.402823e38) def test(): ConversionTest().SingleField = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().SingleField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().SingleField = 3.402824e38 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().SingleField = -3.402824e38 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Single(3.402824e38) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Single(-3.402824e38) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testDoubleConversion(self): """Test double conversion.""" - self.failUnless(System.Double.MaxValue == 1.7976931348623157e308) - self.failUnless(System.Double.MinValue == -1.7976931348623157e308) + self.assertTrue(System.Double.MaxValue == 1.7976931348623157e308) + self.assertTrue(System.Double.MinValue == -1.7976931348623157e308) object = ConversionTest() - self.failUnless(object.DoubleField == 0.0) + self.assertTrue(object.DoubleField == 0.0) object.DoubleField = 1.7976931348623157e308 - self.failUnless(object.DoubleField == 1.7976931348623157e308) + self.assertTrue(object.DoubleField == 1.7976931348623157e308) object.DoubleField = -1.7976931348623157e308 - self.failUnless(object.DoubleField == -1.7976931348623157e308) + self.assertTrue(object.DoubleField == -1.7976931348623157e308) object.DoubleField = System.Double(1.7976931348623157e308) - self.failUnless(object.DoubleField == 1.7976931348623157e308) + self.assertTrue(object.DoubleField == 1.7976931348623157e308) object.DoubleField = System.Double(-1.7976931348623157e308) - self.failUnless(object.DoubleField == -1.7976931348623157e308) + self.assertTrue(object.DoubleField == -1.7976931348623157e308) def test(): ConversionTest().DoubleField = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().DoubleField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().DoubleField = 1.7976931348623159e308 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): ConversionTest().DoubleField = -1.7976931348623159e308 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Double(1.7976931348623159e308) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): value = System.Double(-1.7976931348623159e308) - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def testDecimalConversion(self): """Test decimal conversion.""" - from CLR.System import Decimal + from System import Decimal max_d = Decimal.Parse("79228162514264337593543950335") min_d = Decimal.Parse("-79228162514264337593543950335") - self.failUnless(Decimal.ToInt64(Decimal(10)) == 10L) + self.assertTrue(Decimal.ToInt64(Decimal(10)) == 10L) object = ConversionTest() - self.failUnless(object.DecimalField == Decimal(0)) + self.assertTrue(object.DecimalField == Decimal(0)) object.DecimalField = Decimal(10) - self.failUnless(object.DecimalField == Decimal(10)) + self.assertTrue(object.DecimalField == Decimal(10)) object.DecimalField = Decimal.One - self.failUnless(object.DecimalField == Decimal.One) + self.assertTrue(object.DecimalField == Decimal.One) object.DecimalField = Decimal.Zero - self.failUnless(object.DecimalField == Decimal.Zero) + self.assertTrue(object.DecimalField == Decimal.Zero) object.DecimalField = max_d - self.failUnless(object.DecimalField == max_d) + self.assertTrue(object.DecimalField == max_d) object.DecimalField = min_d - self.failUnless(object.DecimalField == min_d) + self.assertTrue(object.DecimalField == min_d) def test(): ConversionTest().DecimalField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().DecimalField = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().DecimalField = 1 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testStringConversion(self): """Test string / unicode conversion.""" object = ConversionTest() - self.failUnless(object.StringField == "spam") - self.failUnless(object.StringField == u"spam") + self.assertTrue(object.StringField == "spam") + self.assertTrue(object.StringField == u"spam") object.StringField = "eggs" - self.failUnless(object.StringField == "eggs") - self.failUnless(object.StringField == u"eggs") + self.assertTrue(object.StringField == "eggs") + self.assertTrue(object.StringField == u"eggs") object.StringField = u"spam" - self.failUnless(object.StringField == "spam") - self.failUnless(object.StringField == u"spam") + self.assertTrue(object.StringField == "spam") + self.assertTrue(object.StringField == u"spam") object.StringField = u'\uffff\uffff' - self.failUnless(object.StringField == u'\uffff\uffff') + self.assertTrue(object.StringField == u'\uffff\uffff') object.StringField = System.String("spam") - self.failUnless(object.StringField == "spam") - self.failUnless(object.StringField == u"spam") + self.assertTrue(object.StringField == "spam") + self.assertTrue(object.StringField == u"spam") object.StringField = System.String(u'\uffff\uffff') - self.failUnless(object.StringField == u'\uffff\uffff') + self.assertTrue(object.StringField == u'\uffff\uffff') object.StringField = None - self.failUnless(object.StringField == None) + self.assertTrue(object.StringField == None) def test(): ConversionTest().StringField = 1 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInterfaceConversion(self): """Test interface conversion.""" - from CLR.Python.Test import Spam, ISpam + from Python.Test import Spam, ISpam object = ConversionTest() - self.failUnless(ISpam(object.SpamField).GetValue() == "spam") - self.failUnless(object.SpamField.GetValue() == "spam") + self.assertTrue(ISpam(object.SpamField).GetValue() == "spam") + self.assertTrue(object.SpamField.GetValue() == "spam") object.SpamField = Spam("eggs") - self.failUnless(ISpam(object.SpamField).GetValue() == "eggs") - self.failUnless(object.SpamField.GetValue() == "eggs") + self.assertTrue(ISpam(object.SpamField).GetValue() == "eggs") + self.assertTrue(object.SpamField.GetValue() == "eggs") # need to test spam subclass here. object.SpamField = None - self.failUnless(object.SpamField == None) + self.assertTrue(object.SpamField == None) def test(): object = ConversionTest() object.SpamField = System.String("bad") - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = ConversionTest() object.SpamField = System.Int32(1) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testObjectConversion(self): """Test object conversion.""" - from CLR.Python.Test import Spam + from Python.Test import Spam object = ConversionTest() - self.failUnless(object.ObjectField == None) + self.assertTrue(object.ObjectField == None) object.ObjectField = Spam("eggs") - self.failUnless(object.ObjectField.__class__.__name__ == "Spam") - self.failUnless(object.ObjectField.GetValue() == "eggs") + self.assertTrue(object.ObjectField.__class__.__name__ == "Spam") + self.assertTrue(object.ObjectField.GetValue() == "eggs") object.ObjectField = None - self.failUnless(object.ObjectField == None) + self.assertTrue(object.ObjectField == None) object.ObjectField = System.String("spam") - self.failUnless(object.ObjectField == "spam") + self.assertTrue(object.ObjectField == "spam") object.ObjectField = System.Int32(1) - self.failUnless(object.ObjectField == 1) + self.assertTrue(object.ObjectField == 1) # need to test subclass here @@ -747,50 +745,50 @@ def test(): object = ConversionTest() object.ObjectField = self - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testEnumConversion(self): """Test enum conversion.""" - from CLR.Python.Test import ShortEnum + from Python.Test import ShortEnum object = ConversionTest() - self.failUnless(object.EnumField == ShortEnum.Zero) + self.assertTrue(object.EnumField == ShortEnum.Zero) object.EnumField = ShortEnum.One - self.failUnless(object.EnumField == ShortEnum.One) + self.assertTrue(object.EnumField == ShortEnum.One) object.EnumField = 0 - self.failUnless(object.EnumField == ShortEnum.Zero) - self.failUnless(object.EnumField == 0) + self.assertTrue(object.EnumField == ShortEnum.Zero) + self.assertTrue(object.EnumField == 0) object.EnumField = 1 - self.failUnless(object.EnumField == ShortEnum.One) - self.failUnless(object.EnumField == 1) + self.assertTrue(object.EnumField == ShortEnum.One) + self.assertTrue(object.EnumField == 1) def test(): object = ConversionTest() object.EnumField = 10 - self.failUnlessRaises(ValueError, test) + self.assertRaises(ValueError, test) def test(): object = ConversionTest() object.EnumField = 255 - self.failUnlessRaises(ValueError, test) + self.assertRaises(ValueError, test) def test(): object = ConversionTest() object.EnumField = 1000000 - self.failUnlessRaises(OverflowError, test) + self.assertRaises(OverflowError, test) def test(): object = ConversionTest() object.EnumField = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testNullConversion(self): @@ -798,63 +796,63 @@ def testNullConversion(self): object = ConversionTest() object.StringField = None - self.failUnless(object.StringField == None) + self.assertTrue(object.StringField == None) object.ObjectField = None - self.failUnless(object.ObjectField == None) + self.assertTrue(object.ObjectField == None) object.SpamField = None - self.failUnless(object.SpamField == None) + self.assertTrue(object.SpamField == None) # Primitive types and enums should not be set to null. def test(): ConversionTest().Int32Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): ConversionTest().EnumField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testByteArrayConversion(self): """Test byte array conversion.""" object = ConversionTest() - self.failUnless(object.ByteArrayField == None) + self.assertTrue(object.ByteArrayField == None) object.ByteArrayField = [0, 1, 2 , 3, 4] array = object.ByteArrayField - self.failUnless(len(array) == 5) - self.failUnless(array[0] == 0) - self.failUnless(array[4] == 4) + self.assertTrue(len(array) == 5) + self.assertTrue(array[0] == 0) + self.assertTrue(array[4] == 4) value = "testing" object.ByteArrayField = value array = object.ByteArrayField for i in range(len(value)): - self.failUnless(array[i] == ord(value[i])) + self.assertTrue(array[i] == ord(value[i])) def testSByteArrayConversion(self): """Test sbyte array conversion.""" object = ConversionTest() - self.failUnless(object.SByteArrayField == None) + self.assertTrue(object.SByteArrayField == None) object.SByteArrayField = [0, 1, 2 , 3, 4] array = object.SByteArrayField - self.failUnless(len(array) == 5) - self.failUnless(array[0] == 0) - self.failUnless(array[4] == 4) + self.assertTrue(len(array) == 5) + self.assertTrue(array[0] == 0) + self.assertTrue(array[4] == 4) value = "testing" object.SByteArrayField = value array = object.SByteArrayField for i in range(len(value)): - self.failUnless(array[i] == ord(value[i])) + self.assertTrue(array[i] == ord(value[i])) @@ -871,6 +869,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/pythonnet/src/tests/test_delegate.py b/src/tests/test_delegate.py old mode 100755 new mode 100644 similarity index 57% rename from pythonnet/src/tests/test_delegate.py rename to src/tests/test_delegate.py index a24cabffc..21c53ea3f --- a/pythonnet/src/tests/test_delegate.py +++ b/src/tests/test_delegate.py @@ -1,19 +1,20 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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') -from CLR.Python.Test import DelegateTest, PublicDelegate -from CLR.Python.Test import StringDelegate, ObjectDelegate +from Python.Test import DelegateTest, PublicDelegate +from Python.Test import StringDelegate, ObjectDelegate +from Python.Test import BoolDelegate import sys, os, string, unittest, types -import CLR.Python.Test as Test -import CLR.System as System +import Python.Test as Test +import System class DelegateTests(unittest.TestCase): @@ -21,47 +22,47 @@ class DelegateTests(unittest.TestCase): def testDelegateStandardAttrs(self): """Test standard delegate attributes.""" - self.failUnless(PublicDelegate.__name__ == 'PublicDelegate') - self.failUnless(PublicDelegate.__module__ == 'CLR.Python.Test') - self.failUnless(type(PublicDelegate.__dict__) == types.DictProxyType) - self.failUnless(PublicDelegate.__doc__ == None) + self.assertTrue(PublicDelegate.__name__ == 'PublicDelegate') + self.assertTrue(PublicDelegate.__module__ == 'Python.Test') + self.assertTrue(type(PublicDelegate.__dict__) == types.DictProxyType) + self.assertTrue(PublicDelegate.__doc__ == None) def testGlobalDelegateVisibility(self): """Test visibility of module-level delegates.""" - from CLR.Python.Test import PublicDelegate + from Python.Test import PublicDelegate - self.failUnless(PublicDelegate.__name__ == 'PublicDelegate') - self.failUnless(Test.PublicDelegate.__name__ == 'PublicDelegate') + self.assertTrue(PublicDelegate.__name__ == 'PublicDelegate') + self.assertTrue(Test.PublicDelegate.__name__ == 'PublicDelegate') def test(): - from CLR.Python.Test import InternalDelegate + from Python.Test import InternalDelegate - self.failUnlessRaises(ImportError, test) + self.assertRaises(ImportError, test) def test(): i = Test.InternalDelegate - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testNestedDelegateVisibility(self): """Test visibility of nested delegates.""" ob = DelegateTest.PublicDelegate - self.failUnless(ob.__name__ == 'PublicDelegate') + self.assertTrue(ob.__name__ == 'PublicDelegate') ob = DelegateTest.ProtectedDelegate - self.failUnless(ob.__name__ == 'ProtectedDelegate') + self.assertTrue(ob.__name__ == 'ProtectedDelegate') def test(): ob = DelegateTest.InternalDelegate - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): ob = DelegateTest.PrivateDelegate - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testDelegateFromFunction(self): @@ -73,12 +74,12 @@ def sayhello(): d = StringDelegate(sayhello) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateFromMethod(self): @@ -92,12 +93,12 @@ def sayhello(self): d = StringDelegate(inst.sayhello) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateFromUnboundMethod(self): @@ -111,7 +112,7 @@ def test(): d = StringDelegate(Hello.sayhello) d() - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testDelegateFromStaticMethod(self): @@ -125,23 +126,23 @@ def sayhello(): d = StringDelegate(Hello.sayhello) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") inst = Hello() d = StringDelegate(inst.sayhello) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateFromClassMethod(self): @@ -155,23 +156,23 @@ def sayhello(self): d = StringDelegate(Hello.sayhello) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") inst = Hello() d = StringDelegate(inst.sayhello) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateFromCallable(self): @@ -185,12 +186,12 @@ def __call__(self): d = StringDelegate(inst) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateFromManagedInstanceMethod(self): @@ -198,12 +199,12 @@ def testDelegateFromManagedInstanceMethod(self): ob = DelegateTest() d = StringDelegate(ob.SayHello) - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateFromManagedStaticMethod(self): @@ -211,12 +212,12 @@ def testDelegateFromManagedStaticMethod(self): d = StringDelegate(DelegateTest.StaticSayHello) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d) == "hello") - self.failUnless(d() == "hello") + self.assertTrue(ob.CallStringDelegate(d) == "hello") + self.assertTrue(d() == "hello") ob.stringDelegate = d - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateFromDelegate(self): @@ -229,12 +230,12 @@ def sayhello(): d2 = StringDelegate(d1) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(d2) == "hello") - self.failUnless(d2() == "hello") + self.assertTrue(ob.CallStringDelegate(d2) == "hello") + self.assertTrue(d2() == "hello") ob.stringDelegate = d2 - self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello") - self.failUnless(ob.stringDelegate() == "hello") + self.assertTrue(ob.CallStringDelegate(ob.stringDelegate) == "hello") + self.assertTrue(ob.stringDelegate() == "hello") def testDelegateWithInvalidArgs(self): @@ -242,17 +243,17 @@ def testDelegateWithInvalidArgs(self): def test(): d = StringDelegate(None) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): d = StringDelegate("spam") - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): d = StringDelegate(1) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testMulticastDelegate(self): @@ -273,11 +274,11 @@ def count(self): md = System.Delegate.Combine(d1, d2) ob = DelegateTest() - self.failUnless(ob.CallStringDelegate(md) == "ok") - self.failUnless(inst.value == 2) + self.assertTrue(ob.CallStringDelegate(md) == "ok") + self.assertTrue(inst.value == 2) - self.failUnless(md() == "ok") - self.failUnless(inst.value == 4) + self.assertTrue(md() == "ok") + self.assertTrue(inst.value == 4) def testSubclassDelegateFails(self): @@ -286,7 +287,7 @@ def test(): class Boom(PublicDelegate): pass - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testDelegateEquality(self): @@ -298,9 +299,24 @@ def sayhello(): d = StringDelegate(sayhello) ob = DelegateTest() ob.stringDelegate = d - self.failUnless(ob.stringDelegate == d) + self.assertTrue(ob.stringDelegate == d) + def testBoolDelegate(self): + """Test boolean delegate.""" + + def always_so_negative(): + return 0 + + d = BoolDelegate(always_so_negative) + ob = DelegateTest() + ob.CallBoolDelegate(d) + + + self.assertTrue(not d()) + + self.assertTrue(not ob.CallBoolDelegate(d)) + # test async delegates # test multicast delegates @@ -320,6 +336,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/src/tests/test_docstring.py b/src/tests/test_docstring.py new file mode 100644 index 000000000..0d0e49f77 --- /dev/null +++ b/src/tests/test_docstring.py @@ -0,0 +1,46 @@ +# =========================================================================== +# 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 unittest +import clr +clr.AddReference('Python.Test') + +from Python.Test import DocWithCtorTest, DocWithoutCtorTest, DocWithCtorNoDocTest + + +class DocStringTests(unittest.TestCase): + """Test doc strings support.""" + + def testDocWithCtor(self): + self.assertEqual(DocWithCtorTest.__doc__, 'DocWithCtorTest Class') + self.assertEqual(DocWithCtorTest.TestMethod.__doc__, 'DocWithCtorTest TestMethod') + self.assertEqual(DocWithCtorTest.StaticTestMethod.__doc__, 'DocWithCtorTest StaticTestMethod') + + + def testDocWithCtorNoDoc(self): + self.assertEqual(DocWithCtorNoDocTest.__doc__, 'Void .ctor(Boolean)') + self.assertEqual(DocWithCtorNoDocTest.TestMethod.__doc__, 'Void TestMethod(Double, Int32)') + self.assertEqual(DocWithCtorNoDocTest.StaticTestMethod.__doc__, 'Void StaticTestMethod(Double, Int32)') + + + def testDocWithoutCtor(self): + self.assertEqual(DocWithoutCtorTest.__doc__, 'DocWithoutCtorTest Class') + self.assertEqual(DocWithoutCtorTest.TestMethod.__doc__, 'DocWithoutCtorTest TestMethod') + self.assertEqual(DocWithoutCtorTest.StaticTestMethod.__doc__, 'DocWithoutCtorTest StaticTestMethod') + + +def test_suite(): + return unittest.makeSuite(DocStringTests) + + +def main(): + unittest.TextTestRunner().run(test_suite()) + + +if __name__ == '__main__': + main() diff --git a/pythonnet/src/tests/test_engine.py b/src/tests/test_engine.py old mode 100755 new mode 100644 similarity index 75% rename from pythonnet/src/tests/test_engine.py rename to src/tests/test_engine.py index 6cd31c5e7..0e5277072 --- a/pythonnet/src/tests/test_engine.py +++ b/src/tests/test_engine.py @@ -1,17 +1,16 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types, CLR -from CLR.Python.Runtime import PythonEngine +import sys, os, string, unittest, types +from Python.Runtime import PythonEngine +# XXX This test module isn't used! class EngineTests(unittest.TestCase): """Test PythonEngine embedding APIs.""" @@ -26,7 +25,7 @@ def testImportModule(self): """Test module import.""" m = PythonEngine.ImportModule("sys") n = m.GetAttr("__name__") - self.failUnless(n.AsManagedObject(CLR.System.String) == "sys") + self.assertTrue(n.AsManagedObject(System.String) == "sys") def testRunString(self): @@ -35,11 +34,11 @@ def testRunString(self): code = "import sys; sys.singleline_worked = 1" PythonEngine.RunString(code) - self.failUnless(sys.singleline_worked == 1) + self.assertTrue(sys.singleline_worked == 1) code = "import sys\nsys.multiline_worked = 1" PythonEngine.RunString(code) - self.failUnless(sys.multiline_worked == 1) + self.assertTrue(sys.multiline_worked == 1) PythonEngine.ReleaseLock() @@ -51,6 +50,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/src/tests/test_enum.py b/src/tests/test_enum.py new file mode 100644 index 000000000..98db3f3c6 --- /dev/null +++ b/src/tests/test_enum.py @@ -0,0 +1,168 @@ +# =========================================================================== +# 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 sys, os, string, unittest, types +from System import DayOfWeek +from Python import Test + + +class EnumTests(unittest.TestCase): + """Test CLR enum support.""" + + 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(DayOfWeek.__doc__ == None) + + + def testEnumGetMember(self): + """Test access to enum members.""" + self.assertTrue(DayOfWeek.Sunday == 0) + self.assertTrue(DayOfWeek.Monday == 1) + self.assertTrue(DayOfWeek.Tuesday == 2) + self.assertTrue(DayOfWeek.Wednesday == 3) + self.assertTrue(DayOfWeek.Thursday == 4) + self.assertTrue(DayOfWeek.Friday == 5) + self.assertTrue(DayOfWeek.Saturday == 6) + + + def testByteEnum(self): + """Test byte enum.""" + self.assertTrue(Test.ByteEnum.Zero == 0) + self.assertTrue(Test.ByteEnum.One == 1) + self.assertTrue(Test.ByteEnum.Two == 2) + + + def testSByteEnum(self): + """Test sbyte enum.""" + self.assertTrue(Test.SByteEnum.Zero == 0) + self.assertTrue(Test.SByteEnum.One == 1) + self.assertTrue(Test.SByteEnum.Two == 2) + + + def testShortEnum(self): + """Test short enum.""" + self.assertTrue(Test.ShortEnum.Zero == 0) + self.assertTrue(Test.ShortEnum.One == 1) + self.assertTrue(Test.ShortEnum.Two == 2) + + + def testUShortEnum(self): + """Test ushort enum.""" + self.assertTrue(Test.UShortEnum.Zero == 0) + self.assertTrue(Test.UShortEnum.One == 1) + self.assertTrue(Test.UShortEnum.Two == 2) + + + def testIntEnum(self): + """Test int enum.""" + self.assertTrue(Test.IntEnum.Zero == 0) + self.assertTrue(Test.IntEnum.One == 1) + self.assertTrue(Test.IntEnum.Two == 2) + + + def testUIntEnum(self): + """Test uint enum.""" + self.assertTrue(Test.UIntEnum.Zero == 0L) + self.assertTrue(Test.UIntEnum.One == 1L) + self.assertTrue(Test.UIntEnum.Two == 2L) + + + def testLongEnum(self): + """Test long enum.""" + self.assertTrue(Test.LongEnum.Zero == 0L) + self.assertTrue(Test.LongEnum.One == 1L) + self.assertTrue(Test.LongEnum.Two == 2L) + + + def testULongEnum(self): + """Test ulong enum.""" + self.assertTrue(Test.ULongEnum.Zero == 0L) + self.assertTrue(Test.ULongEnum.One == 1L) + self.assertTrue(Test.ULongEnum.Two == 2L) + + + def testInstantiateEnumFails(self): + """Test that instantiation of an enum class fails.""" + def test(): + ob = DayOfWeek() + + self.assertRaises(TypeError, test) + + + def testSubclassEnumFails(self): + """Test that subclassing of an enumeration fails.""" + def test(): + class Boom(DayOfWeek): + pass + + self.assertRaises(TypeError, test) + + + def testEnumSetMemberFails(self): + """Test that setattr operations on enumerations fail.""" + def test(): + DayOfWeek.Sunday = 13 + + self.assertRaises(TypeError, test) + + def test(): + del DayOfWeek.Sunday + + self.assertRaises(TypeError, test) + + + def testEnumWithFlagsAttrConversion(self): + """Test enumeration conversion with FlagsAttribute set.""" + # This works because the FlagsField enum has FlagsAttribute. + Test.FieldTest().FlagsField = 99 + + # This should fail because our test enum doesn't have it. + def test(): + Test.FieldTest().EnumField = 99 + + self.assertRaises(ValueError, test) + + + def testEnumConversion(self): + """Test enumeration conversion.""" + object = Test.FieldTest() + self.assertTrue(object.EnumField == 0) + + object.EnumField = Test.ShortEnum.One + self.assertTrue(object.EnumField == 1) + + def test(): + Test.FieldTest().EnumField = 20 + + self.assertRaises(ValueError, test) + + def test(): + Test.FieldTest().EnumField = 100000 + + self.assertRaises(OverflowError, test) + + def test(): + Test.FieldTest().EnumField = "str" + + self.assertRaises(TypeError, test) + + + +def test_suite(): + return unittest.makeSuite(EnumTests) + +def main(): + unittest.TextTestRunner().run(test_suite()) + +if __name__ == '__main__': + main() + diff --git a/pythonnet/src/tests/test_event.py b/src/tests/test_event.py old mode 100755 new mode 100644 similarity index 75% rename from pythonnet/src/tests/test_event.py rename to src/tests/test_event.py index 8bf976adc..614828a77 --- a/pythonnet/src/tests/test_event.py +++ b/src/tests/test_event.py @@ -1,17 +1,17 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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') import sys, os, string, unittest, types -from CLR.Python.Test import EventTest, TestEventHandler -from CLR.Python.Test import TestEventArgs +from Python.Test import EventTest, TestEventHandler +from Python.Test import TestEventArgs class EventTests(unittest.TestCase): @@ -22,12 +22,12 @@ def testPublicInstanceEvent(self): object = EventTest() handler = GenericHandler() - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.PublicEvent += handler.handler object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.PublicEvent -= handler.handler @@ -35,12 +35,12 @@ def testPublicInstanceEvent(self): def testPublicStaticEvent(self): """Test public static events.""" handler = GenericHandler() - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) EventTest.PublicStaticEvent += handler.handler EventTest.OnPublicStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testProtectedInstanceEvent(self): @@ -48,12 +48,12 @@ def testProtectedInstanceEvent(self): object = EventTest() handler = GenericHandler() - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.ProtectedEvent += handler.handler object.OnProtectedEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.ProtectedEvent -= handler.handler @@ -63,12 +63,12 @@ def testProtectedStaticEvent(self): object = EventTest handler = GenericHandler() - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) EventTest.ProtectedStaticEvent += handler.handler EventTest.OnProtectedStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) EventTest.ProtectedStaticEvent -= handler.handler @@ -79,17 +79,17 @@ def testInternalEvents(self): def test(): f = EventTest().InternalEvent - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = EventTest().InternalStaticEvent - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = EventTest.InternalStaticEvent - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testPrivateEvents(self): @@ -98,17 +98,17 @@ def testPrivateEvents(self): def test(): f = EventTest().PrivateEvent - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = EventTest().PrivateStaticEvent - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = EventTest.PrivateStaticEvent - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testMulticastEvent(self): @@ -125,15 +125,15 @@ def testMulticastEvent(self): object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler1.value == 10) - self.failUnless(handler2.value == 10) - self.failUnless(handler3.value == 10) + self.assertTrue(handler1.value == 10) + self.assertTrue(handler2.value == 10) + self.assertTrue(handler3.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler1.value == 20) - self.failUnless(handler2.value == 20) - self.failUnless(handler3.value == 20) + self.assertTrue(handler1.value == 20) + self.assertTrue(handler2.value == 20) + self.assertTrue(handler3.value == 20) object.PublicEvent -= handler1.handler object.PublicEvent -= handler2.handler @@ -146,16 +146,16 @@ def testInstanceMethodHandler(self): handler = GenericHandler() object.PublicEvent += handler.handler - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.PublicEvent -= handler.handler - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testVarArgsInstanceMethodHandler(self): @@ -164,16 +164,16 @@ def testVarArgsInstanceMethodHandler(self): handler = VariableArgsHandler() object.PublicEvent += handler.handler - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.PublicEvent -= handler.handler - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testCallableObjectHandler(self): @@ -182,16 +182,16 @@ def testCallableObjectHandler(self): handler = CallableHandler() object.PublicEvent += handler - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.PublicEvent -= handler - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testVarArgsCallableHandler(self): @@ -200,16 +200,16 @@ def testVarArgsCallableHandler(self): handler = VarCallableHandler() object.PublicEvent += handler - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.PublicEvent -= handler - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testStaticMethodHandler(self): @@ -219,16 +219,16 @@ def testStaticMethodHandler(self): StaticMethodHandler.value = None object.PublicEvent += handler.handler - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.PublicEvent -= handler.handler - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testClassMethodHandler(self): @@ -238,16 +238,16 @@ def testClassMethodHandler(self): ClassMethodHandler.value = None object.PublicEvent += handler.handler - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.PublicEvent -= handler.handler - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testManagedInstanceMethodHandler(self): @@ -255,16 +255,16 @@ def testManagedInstanceMethodHandler(self): object = EventTest() object.PublicEvent += object.GenericHandler - self.failUnless(object.value == 0) + self.assertTrue(object.value == 0) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(object.value == 10) + self.assertTrue(object.value == 10) object.PublicEvent -= object.GenericHandler - self.failUnless(object.value == 10) + self.assertTrue(object.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(object.value == 10) + self.assertTrue(object.value == 10) def testManagedStaticMethodHandler(self): @@ -273,16 +273,16 @@ def testManagedStaticMethodHandler(self): EventTest.s_value = 0 object.PublicEvent += object.StaticHandler - self.failUnless(EventTest.s_value == 0) + self.assertTrue(EventTest.s_value == 0) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(EventTest.s_value == 10) + self.assertTrue(EventTest.s_value == 10) object.PublicEvent -= object.StaticHandler - self.failUnless(EventTest.s_value == 10) + self.assertTrue(EventTest.s_value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(EventTest.s_value == 10) + self.assertTrue(EventTest.s_value == 10) def testUnboundMethodHandler(self): @@ -307,16 +307,16 @@ def handler(sender, args, dict=dict): dict['value'] = args.value object.PublicEvent += handler - self.failUnless(dict['value'] == None) + self.assertTrue(dict['value'] == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(dict['value'] == 10) + self.assertTrue(dict['value'] == 10) object.PublicEvent -= handler - self.failUnless(dict['value'] == 10) + self.assertTrue(dict['value'] == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(dict['value'] == 10) + self.assertTrue(dict['value'] == 10) def testAddNonCallableHandler(self): @@ -326,13 +326,13 @@ def test(): object = EventTest() object.PublicEvent += 10 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = EventTest() object.PublicEvent += "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): @@ -342,7 +342,7 @@ class spam: object = EventTest() object.PublicEvent += spam() - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testRemoveMultipleHandlers(self): @@ -357,17 +357,17 @@ def testRemoveMultipleHandlers(self): object.PublicEvent += h2 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 20) + self.assertTrue(handler.value == 20) object.PublicEvent -= h1 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) object.PublicEvent -= h2 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) # try again, removing in a different order. @@ -381,17 +381,17 @@ def testRemoveMultipleHandlers(self): object.PublicEvent += h2 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 20) + self.assertTrue(handler.value == 20) object.PublicEvent -= h2 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) object.PublicEvent -= h1 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) def testRemoveMultipleStaticHandlers(self): @@ -406,17 +406,17 @@ def testRemoveMultipleStaticHandlers(self): object.PublicStaticEvent += h2 object.OnPublicStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 20) + self.assertTrue(handler.value == 20) object.PublicStaticEvent -= h1 object.OnPublicStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) object.PublicStaticEvent -= h2 object.OnPublicStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) # try again, removing in a different order. @@ -430,17 +430,17 @@ def testRemoveMultipleStaticHandlers(self): object.PublicStaticEvent += h2 object.OnPublicStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 20) + self.assertTrue(handler.value == 20) object.PublicStaticEvent -= h2 object.OnPublicStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) object.PublicStaticEvent -= h1 object.OnPublicStaticEvent(TestEventArgs(10)) - self.failUnless(handler.value == 30) + self.assertTrue(handler.value == 30) def testRandomMultipleHandlers(self): @@ -460,8 +460,8 @@ def testRandomMultipleHandlers(self): handlers.append(method) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 300) - self.failUnless(handler2.value == 20) + self.assertTrue(handler.value == 300) + self.assertTrue(handler2.value == 20) handler.value = 0 handler2.value = 0 @@ -471,24 +471,24 @@ def testRandomMultipleHandlers(self): object.PublicEvent -= item handler.value = 0 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == (len(handlers) * 10)) - self.failUnless(handler2.value == ((i + 1) * 20)) + self.assertTrue(handler.value == (len(handlers) * 10)) + self.assertTrue(handler2.value == ((i + 1) * 20)) handler2.value = 0 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler2.value == 20) + self.assertTrue(handler2.value == 20) object.PublicEvent -= handler2.handler handler2.value = 0 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler2.value == 10) + self.assertTrue(handler2.value == 10) object.PublicEvent -= handler2.handler handler2.value = 0 object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler2.value == 0) + self.assertTrue(handler2.value == 0) def testRemoveInternalCallHandler(self): @@ -501,12 +501,6 @@ def h(sender, args): object.PublicEvent += h object.PublicEvent -= h - from CLR.System.Windows.Forms import Form - f = Form() - f.Click += h - f.Click -= h - f.Dispose() - def testRemoveUnknownHandler(self): """Test removing an event handler that was never added.""" @@ -516,7 +510,7 @@ def test(): object.PublicEvent -= handler.handler - self.failUnlessRaises(ValueError, test) + self.assertRaises(ValueError, test) def testHandlerCallbackFailure(self): @@ -533,7 +527,7 @@ def test(): object.PublicEvent += handler.handler object.OnPublicEvent(TestEventArgs(10)) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) object.PublicEvent -= handler.handler @@ -548,7 +542,7 @@ def test(): object.PublicEvent += handler.handler object.OnPublicEvent(TestEventArgs(10)) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) object.PublicEvent -= handler.handler @@ -563,12 +557,12 @@ def testIncorrectInvokation(self): def test(): object.OnPublicEvent() - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object.OnPublicEvent(32) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) object.PublicEvent -= handler.handler @@ -580,16 +574,16 @@ def testExplicitCLSEventRegistration(self): delegate = TestEventHandler(handler.handler) object.add_PublicEvent(delegate) - self.failUnless(handler.value == None) + self.assertTrue(handler.value == None) object.OnPublicEvent(TestEventArgs(10)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.remove_PublicEvent(delegate) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) object.OnPublicEvent(TestEventArgs(20)) - self.failUnless(handler.value == 10) + self.assertTrue(handler.value == 10) def testImplicitCLSEventRegistration(self): @@ -600,7 +594,7 @@ def test(): handler = GenericHandler() object.add_PublicEvent(handler.handler) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testEventDescriptorAbuse(self): @@ -609,35 +603,35 @@ def testEventDescriptorAbuse(self): def test(): del EventTest.PublicEvent - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del EventTest.__dict__['PublicEvent'] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) desc = EventTest.__dict__['PublicEvent'] def test(): desc.__get__(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): desc.__set__(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = EventTest() object.PublicEvent = 0 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): EventTest.PublicStaticEvent = 0 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) @@ -718,6 +712,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/pythonnet/src/tests/test_exceptions.py b/src/tests/test_exceptions.py old mode 100755 new mode 100644 similarity index 60% rename from pythonnet/src/tests/test_exceptions.py rename to src/tests/test_exceptions.py index 90b004cd2..de6dd01e5 --- a/pythonnet/src/tests/test_exceptions.py +++ b/src/tests/test_exceptions.py @@ -1,16 +1,14 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types -from CLR import System +import System # 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 @@ -22,173 +20,173 @@ class ExceptionTests(unittest.TestCase): def testUnifiedExceptionSemantics(self): """Test unified exception semantics.""" - from CLR.System import Exception, Object + from System import Exception, Object import exceptions e = Exception('Something bad happened') - self.failUnless(isinstance(e, exceptions.Exception)) - self.failUnless(isinstance(e, Exception)) + self.assertTrue(isinstance(e, exceptions.Exception)) + self.assertTrue(isinstance(e, Exception)) def testStandardExceptionAttributes(self): """Test accessing standard exception attributes.""" - from CLR.System import OverflowException - from CLR.Python.Test import ExceptionTest + from System import OverflowException + from Python.Test import ExceptionTest e = ExceptionTest.GetExplicitException() - self.failUnless(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, OverflowException)) - self.failUnless(e.Message == 'error') + self.assertTrue(e.Message == 'error') e.Source = 'Test Suite' - self.failUnless(e.Source == 'Test Suite') + self.assertTrue(e.Source == 'Test Suite') v = e.ToString() - self.failUnless(len(v) > 0) + self.assertTrue(len(v) > 0) def testExtendedExceptionAttributes(self): """Test accessing extended exception attributes.""" - from CLR.Python.Test import ExceptionTest, ExtendedException - from CLR.System import Exception, OverflowException + from Python.Test import ExceptionTest, ExtendedException + from System import Exception, OverflowException import exceptions e = ExceptionTest.GetExtendedException() - self.failUnless(isinstance(e, ExtendedException)) - self.failUnless(isinstance(e, OverflowException)) - self.failUnless(isinstance(e, Exception)) + self.assertTrue(isinstance(e, ExtendedException)) + self.assertTrue(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, Exception)) - self.failUnless(e.Message == 'error') + self.assertTrue(e.Message == 'error') e.Source = 'Test Suite' - self.failUnless(e.Source == 'Test Suite') + self.assertTrue(e.Source == 'Test Suite') v = e.ToString() - self.failUnless(len(v) > 0) + self.assertTrue(len(v) > 0) - self.failUnless(e.ExtraProperty == 'extra') + self.assertTrue(e.ExtraProperty == 'extra') e.ExtraProperty = 'changed' - self.failUnless(e.ExtraProperty == 'changed') + self.assertTrue(e.ExtraProperty == 'changed') - self.failUnless(e.GetExtraInfo() == 'changed') + self.assertTrue(e.GetExtraInfo() == 'changed') def testRaiseClassException(self): """Test class exception propagation.""" - from CLR.System import NullReferenceException + from System import NullReferenceException def test(): raise NullReferenceException - self.failUnlessRaises(NullReferenceException, test) + self.assertRaises(NullReferenceException, test) try: raise NullReferenceException except: type, value, tb = sys.exc_info() - self.failUnless(type is NullReferenceException) - self.failUnless(isinstance(value, NullReferenceException)) + self.assertTrue(type is NullReferenceException) + self.assertTrue(isinstance(value, NullReferenceException)) def testRaiseClassExceptionWithValue(self): """Test class exception propagation with associated value.""" - from CLR.System import NullReferenceException + from System import NullReferenceException def test(): raise NullReferenceException, 'Aiiieee!' - self.failUnlessRaises(NullReferenceException, test) + self.assertRaises(NullReferenceException, test) try: raise NullReferenceException('Aiiieee!') except: type, value, tb = sys.exc_info() - self.failUnless(type is NullReferenceException) - self.failUnless(isinstance(value, NullReferenceException)) - self.failUnless(value.Message == 'Aiiieee!') + self.assertTrue(type is NullReferenceException) + self.assertTrue(isinstance(value, NullReferenceException)) + self.assertTrue(value.Message == 'Aiiieee!') def testRaiseInstanceException(self): """Test instance exception propagation.""" - from CLR.System import NullReferenceException + from System import NullReferenceException def test(): raise NullReferenceException() - self.failUnlessRaises(NullReferenceException, test) + self.assertRaises(NullReferenceException, test) try: raise NullReferenceException() except: type, value, tb = sys.exc_info() - self.failUnless(type is NullReferenceException) - self.failUnless(isinstance(value, NullReferenceException)) - self.failUnless(len(value.Message) > 0) + self.assertTrue(type is NullReferenceException) + self.assertTrue(isinstance(value, NullReferenceException)) + self.assertTrue(len(value.Message) > 0) def testRaiseInstanceExceptionWithArgs(self): """Test instance exception propagation with args.""" - from CLR.System import NullReferenceException + from System import NullReferenceException def test(): raise NullReferenceException("Aiieeee!") - self.failUnlessRaises(NullReferenceException, test) + self.assertRaises(NullReferenceException, test) try: raise NullReferenceException('Aiiieee!') except: type, value, tb = sys.exc_info() - self.failUnless(type is NullReferenceException) - self.failUnless(isinstance(value, NullReferenceException)) - self.failUnless(value.Message == 'Aiiieee!') + self.assertTrue(type is NullReferenceException) + self.assertTrue(isinstance(value, NullReferenceException)) + self.assertTrue(value.Message == 'Aiiieee!') def testManagedExceptionPropagation(self): """Test propagation of exceptions raised in managed code.""" - from CLR.System import Decimal, OverflowException + from System import Decimal, OverflowException def test(): l = Decimal.ToInt64(Decimal.MaxValue) - self.failUnlessRaises(OverflowException, test) + self.assertRaises(OverflowException, test) def testManagedExceptionConversion(self): """Test conversion of managed exceptions.""" - from CLR.System import Exception, OverflowException - from CLR.Python.Test import ExceptionTest + from System import Exception, OverflowException + from Python.Test import ExceptionTest e = ExceptionTest.GetBaseException() - self.failUnless(isinstance(e, Exception)) + self.assertTrue(isinstance(e, Exception)) e = ExceptionTest.GetExplicitException() - self.failUnless(isinstance(e, OverflowException)) - self.failUnless(isinstance(e, Exception)) + self.assertTrue(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, Exception)) e = ExceptionTest.GetWidenedException() - self.failUnless(isinstance(e, OverflowException)) - self.failUnless(isinstance(e, Exception)) + self.assertTrue(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, Exception)) v = ExceptionTest.SetBaseException(Exception('error')) - self.failUnless(v) + self.assertTrue(v) v = ExceptionTest.SetExplicitException(OverflowException('error')) - self.failUnless(v) + self.assertTrue(v) v = ExceptionTest.SetWidenedException(OverflowException('error')) - self.failUnless(v) + self.assertTrue(v) def testCatchExceptionFromManagedMethod(self): """Test catching an exception from a managed method.""" - from CLR.Python.Test import ExceptionTest - from CLR.System import OverflowException + from Python.Test import ExceptionTest + from System import OverflowException try: ExceptionTest().ThrowException() except OverflowException, e: - self.failUnless(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, OverflowException)) return raise SystemError('failed to catch exception from managed method') @@ -196,19 +194,19 @@ def testCatchExceptionFromManagedMethod(self): def testCatchExceptionFromManagedProperty(self): """Test catching an exception from a managed property.""" - from CLR.Python.Test import ExceptionTest - from CLR.System import OverflowException + from Python.Test import ExceptionTest + from System import OverflowException try: v = ExceptionTest().ThrowProperty except OverflowException, e: - self.failUnless(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, OverflowException)) return try: ExceptionTest().ThrowProperty = 1 except OverflowException, e: - self.failUnless(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, OverflowException)) return raise SystemError('failed to catch exception from managed property') @@ -216,7 +214,7 @@ def testCatchExceptionFromManagedProperty(self): def testCatchExceptionManagedClass(self): """Test catching the managed class of an exception.""" - from CLR.System import OverflowException + from System import OverflowException try: raise OverflowException('overflow') @@ -228,7 +226,7 @@ def testCatchExceptionManagedClass(self): def testCatchExceptionPythonClass(self): """Test catching the python class of an exception.""" - from CLR.System import OverflowException + from System import OverflowException from exceptions import Exception try: @@ -241,7 +239,7 @@ def testCatchExceptionPythonClass(self): def testCatchExceptionBaseClass(self): """Test catching the base of an exception.""" - from CLR.System import OverflowException, ArithmeticException + from System import OverflowException, ArithmeticException try: raise OverflowException('overflow') @@ -253,7 +251,7 @@ def testCatchExceptionBaseClass(self): def testCatchExceptionNestedBaseClass(self): """Test catching the nested base of an exception.""" - from CLR.System import OverflowException, SystemException + from System import OverflowException, SystemException try: raise OverflowException('overflow') @@ -265,17 +263,17 @@ def testCatchExceptionNestedBaseClass(self): def testCatchExceptionWithAssignment(self): """Test catching an exception with assignment.""" - from CLR.System import OverflowException + from System import OverflowException try: raise OverflowException('overflow') except OverflowException, e: - self.failUnless(isinstance(e, OverflowException)) + self.assertTrue(isinstance(e, OverflowException)) def testCatchExceptionUnqualified(self): """Test catching an unqualified exception.""" - from CLR.System import OverflowException + from System import OverflowException try: raise OverflowException('overflow') @@ -287,28 +285,44 @@ def testCatchExceptionUnqualified(self): def testApparentModuleOfException(self): """Test the apparent module of an exception.""" - from CLR.System import Exception, OverflowException + from System import Exception, OverflowException - self.failUnless(Exception.__module__ == 'CLR.System') - self.failUnless(OverflowException.__module__ == 'CLR.System') + self.assertTrue(Exception.__module__ == 'System') + self.assertTrue(OverflowException.__module__ == 'System') def testStrOfException(self): """Test the str() representation of an exception.""" - from CLR.System import NullReferenceException - from CLR.System import Convert, FormatException - + from System import NullReferenceException + from System import Convert, FormatException e = NullReferenceException('') - self.failUnless(str(e) == '') + self.assertEqual(str(e), '') e = NullReferenceException('Something bad happened') - self.failUnless(str(e).startswith('Something bad happened')) + self.assertTrue(str(e).startswith('Something bad happened')) try: Convert.ToDateTime('this will fail') except FormatException, e: - self.failUnless(str(e).find('at System.DateTime.Parse') > -1) - + msg = unicode(e).encode("utf8") # fix for international installation + self.assertTrue(msg.find('System.Convert.ToDateTime') > -1, msg) + + + def testPythonCompatOfManagedExceptions(self): + """Test if managed exceptions are compatible with Python's implementation + """ + from System import OverflowException + msg = "A simple message" + + e = OverflowException(msg) + self.assertEqual(e.message, msg) + self.assertTrue(isinstance(e.message, unicode)) # ??? + self.assertEqual(str(e), msg) + self.assertEqual(unicode(e), msg) + + self.assertEqual(e.args, (msg,)) + self.assertTrue(isinstance(e.args, tuple)) + self.assertEqual(repr(e), "OverflowException('A simple message',)") def testExceptionIsInstanceOfSystemObject(self): """Test behavior of isinstance(, System.Object).""" @@ -322,11 +336,11 @@ 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. - from CLR.System import OverflowException - from CLR.System import Object + from System import OverflowException + from System import Object o = OverflowException('error') - self.failIf(isinstance(o, Object)) + self.assertFalse(isinstance(o, Object)) @@ -337,5 +351,4 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/pythonnet/src/tests/test_field.py b/src/tests/test_field.py old mode 100755 new mode 100644 similarity index 57% rename from pythonnet/src/tests/test_field.py rename to src/tests/test_field.py index c3c9aa976..e266f65d1 --- a/pythonnet/src/tests/test_field.py +++ b/src/tests/test_field.py @@ -1,18 +1,16 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types -from CLR.Python.Test import FieldTest -from CLR.Python.Test import ShortEnum -from CLR import System +from Python.Test import FieldTest +from Python.Test import ShortEnum +import System class FieldTests(unittest.TestCase): @@ -21,146 +19,146 @@ class FieldTests(unittest.TestCase): def testPublicInstanceField(self): """Test public instance fields.""" object = FieldTest(); - self.failUnless(object.PublicField == 0) + self.assertTrue(object.PublicField == 0) object.PublicField = 1 - self.failUnless(object.PublicField == 1) + self.assertTrue(object.PublicField == 1) def test(): del FieldTest().PublicField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testPublicStaticField(self): """Test public static fields.""" object = FieldTest(); - self.failUnless(FieldTest.PublicStaticField == 0) + self.assertTrue(FieldTest.PublicStaticField == 0) FieldTest.PublicStaticField = 1 - self.failUnless(FieldTest.PublicStaticField == 1) + self.assertTrue(FieldTest.PublicStaticField == 1) - self.failUnless(object.PublicStaticField == 1) + self.assertTrue(object.PublicStaticField == 1) object.PublicStaticField = 0 - self.failUnless(object.PublicStaticField == 0) + self.assertTrue(object.PublicStaticField == 0) def test(): del FieldTest.PublicStaticField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del FieldTest().PublicStaticField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testProtectedInstanceField(self): """Test protected instance fields.""" object = FieldTest(); - self.failUnless(object.ProtectedField == 0) + self.assertTrue(object.ProtectedField == 0) object.ProtectedField = 1 - self.failUnless(object.ProtectedField == 1) + self.assertTrue(object.ProtectedField == 1) def test(): del FieldTest().ProtectedField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testProtectedStaticField(self): """Test protected static fields.""" object = FieldTest(); - self.failUnless(FieldTest.ProtectedStaticField == 0) + self.assertTrue(FieldTest.ProtectedStaticField == 0) FieldTest.ProtectedStaticField = 1 - self.failUnless(FieldTest.ProtectedStaticField == 1) + self.assertTrue(FieldTest.ProtectedStaticField == 1) - self.failUnless(object.ProtectedStaticField == 1) + self.assertTrue(object.ProtectedStaticField == 1) object.ProtectedStaticField = 0 - self.failUnless(object.ProtectedStaticField == 0) + self.assertTrue(object.ProtectedStaticField == 0) def test(): del FieldTest.ProtectedStaticField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del FieldTest().ProtectedStaticField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testReadOnlyInstanceField(self): """Test readonly instance fields.""" - self.failUnless(FieldTest().ReadOnlyField == 0) + self.assertTrue(FieldTest().ReadOnlyField == 0) def test(): FieldTest().ReadOnlyField = 1 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del FieldTest().ReadOnlyField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testReadOnlyStaticField(self): """Test readonly static fields.""" object = FieldTest(); - self.failUnless(FieldTest.ReadOnlyStaticField == 0) - self.failUnless(object.ReadOnlyStaticField == 0) + self.assertTrue(FieldTest.ReadOnlyStaticField == 0) + self.assertTrue(object.ReadOnlyStaticField == 0) def test(): FieldTest.ReadOnlyStaticField = 1 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): FieldTest().ReadOnlyStaticField = 1 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del FieldTest.ReadOnlyStaticField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del FieldTest().ReadOnlyStaticField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testConstantField(self): """Test const fields.""" object = FieldTest(); - self.failUnless(FieldTest.ConstField == 0) - self.failUnless(object.ConstField == 0) + self.assertTrue(FieldTest.ConstField == 0) + self.assertTrue(object.ConstField == 0) def test(): FieldTest().ConstField = 1 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): FieldTest.ConstField = 1 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del FieldTest().ConstField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del FieldTest.ConstField - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInternalField(self): @@ -169,17 +167,17 @@ def testInternalField(self): def test(): f = FieldTest().InternalField - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = FieldTest().InternalStaticField - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = FieldTest.InternalStaticField - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testPrivateField(self): @@ -188,17 +186,17 @@ def testPrivateField(self): def test(): f = FieldTest().PrivateField - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = FieldTest().PrivateStaticField - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = FieldTest.PrivateStaticField - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testFieldDescriptorGetSet(self): @@ -210,19 +208,19 @@ def testFieldDescriptorGetSet(self): object = FieldTest() - self.failUnless(FieldTest.PublicStaticField == 0) - self.failUnless(object.PublicStaticField == 0) + self.assertTrue(FieldTest.PublicStaticField == 0) + self.assertTrue(object.PublicStaticField == 0) descriptor = FieldTest.__dict__['PublicStaticField'] - self.failUnless(type(descriptor) != types.IntType) + self.assertTrue(type(descriptor) != types.IntType) object.PublicStaticField = 0 descriptor = FieldTest.__dict__['PublicStaticField'] - self.failUnless(type(descriptor) != types.IntType) + self.assertTrue(type(descriptor) != types.IntType) FieldTest.PublicStaticField = 0 descriptor = FieldTest.__dict__['PublicStaticField'] - self.failUnless(type(descriptor) != types.IntType) + self.assertTrue(type(descriptor) != types.IntType) def testFieldDescriptorWrongType(self): @@ -230,7 +228,7 @@ def testFieldDescriptorWrongType(self): def test(): FieldTest().PublicField = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testFieldDescriptorAbuse(self): @@ -240,192 +238,192 @@ def testFieldDescriptorAbuse(self): def test(): desc.__get__(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): desc.__set__(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testBooleanField(self): """Test boolean fields.""" # change this to true / false later for Python 2.3? object = FieldTest() - self.failUnless(object.BooleanField == False) + self.assertTrue(object.BooleanField == False) object.BooleanField = True - self.failUnless(object.BooleanField == True) + self.assertTrue(object.BooleanField == True) object.BooleanField = False - self.failUnless(object.BooleanField == False) + self.assertTrue(object.BooleanField == False) object.BooleanField = 1 - self.failUnless(object.BooleanField == True) + self.assertTrue(object.BooleanField == True) object.BooleanField = 0 - self.failUnless(object.BooleanField == False) + self.assertTrue(object.BooleanField == False) def testSByteField(self): """Test sbyte fields.""" object = FieldTest() - self.failUnless(object.SByteField == 0) + self.assertTrue(object.SByteField == 0) object.SByteField = 1 - self.failUnless(object.SByteField == 1) + self.assertTrue(object.SByteField == 1) def testByteField(self): """Test byte fields.""" object = FieldTest() - self.failUnless(object.ByteField == 0) + self.assertTrue(object.ByteField == 0) object.ByteField = 1 - self.failUnless(object.ByteField == 1) + self.assertTrue(object.ByteField == 1) def testCharField(self): """Test char fields.""" object = FieldTest() - self.failUnless(object.CharField == u'A') - self.failUnless(object.CharField == 'A') + self.assertTrue(object.CharField == u'A') + self.assertTrue(object.CharField == 'A') object.CharField = 'B' - self.failUnless(object.CharField == u'B') - self.failUnless(object.CharField == 'B') + self.assertTrue(object.CharField == u'B') + self.assertTrue(object.CharField == 'B') object.CharField = u'C' - self.failUnless(object.CharField == u'C') - self.failUnless(object.CharField == 'C') + self.assertTrue(object.CharField == u'C') + self.assertTrue(object.CharField == 'C') def testInt16Field(self): """Test int16 fields.""" object = FieldTest() - self.failUnless(object.Int16Field == 0) + self.assertTrue(object.Int16Field == 0) object.Int16Field = 1 - self.failUnless(object.Int16Field == 1) + self.assertTrue(object.Int16Field == 1) def testInt32Field(self): """Test int32 fields.""" object = FieldTest() - self.failUnless(object.Int32Field == 0) + self.assertTrue(object.Int32Field == 0) object.Int32Field = 1 - self.failUnless(object.Int32Field == 1) + self.assertTrue(object.Int32Field == 1) def testInt64Field(self): """Test int64 fields.""" object = FieldTest() - self.failUnless(object.Int64Field == 0) + self.assertTrue(object.Int64Field == 0) object.Int64Field = 1 - self.failUnless(object.Int64Field == 1) + self.assertTrue(object.Int64Field == 1) def testUInt16Field(self): """Test uint16 fields.""" object = FieldTest() - self.failUnless(object.UInt16Field == 0) + self.assertTrue(object.UInt16Field == 0) object.UInt16Field = 1 - self.failUnless(object.UInt16Field == 1) + self.assertTrue(object.UInt16Field == 1) def testUInt32Field(self): """Test uint32 fields.""" object = FieldTest() - self.failUnless(object.UInt32Field == 0) + self.assertTrue(object.UInt32Field == 0) object.UInt32Field = 1 - self.failUnless(object.UInt32Field == 1) + self.assertTrue(object.UInt32Field == 1) def testUInt64Field(self): """Test uint64 fields.""" object = FieldTest() - self.failUnless(object.UInt64Field == 0) + self.assertTrue(object.UInt64Field == 0) object.UInt64Field = 1 - self.failUnless(object.UInt64Field == 1) + self.assertTrue(object.UInt64Field == 1) def testSingleField(self): """Test single fields.""" object = FieldTest() - self.failUnless(object.SingleField == 0.0) + self.assertTrue(object.SingleField == 0.0) object.SingleField = 1.1 - self.failUnless(object.SingleField == 1.1) + self.assertTrue(object.SingleField == 1.1) def testDoubleField(self): """Test double fields.""" object = FieldTest() - self.failUnless(object.DoubleField == 0.0) + self.assertTrue(object.DoubleField == 0.0) object.DoubleField = 1.1 - self.failUnless(object.DoubleField == 1.1) + self.assertTrue(object.DoubleField == 1.1) def testDecimalField(self): """Test decimal fields.""" object = FieldTest() - self.failUnless(object.DecimalField == System.Decimal(0)) + self.assertTrue(object.DecimalField == System.Decimal(0)) object.DecimalField = System.Decimal(1) - self.failUnless(object.DecimalField == System.Decimal(1)) + self.assertTrue(object.DecimalField == System.Decimal(1)) def testStringField(self): """Test string fields.""" object = FieldTest() - self.failUnless(object.StringField == "spam") + self.assertTrue(object.StringField == "spam") object.StringField = "eggs" - self.failUnless(object.StringField == "eggs") + self.assertTrue(object.StringField == "eggs") def testInterfaceField(self): """Test interface fields.""" - from CLR.Python.Test import Spam, ISpam + from Python.Test import Spam, ISpam object = FieldTest() - self.failUnless(ISpam(object.SpamField).GetValue() == "spam") - self.failUnless(object.SpamField.GetValue() == "spam") + self.assertTrue(ISpam(object.SpamField).GetValue() == "spam") + self.assertTrue(object.SpamField.GetValue() == "spam") object.SpamField = Spam("eggs") - self.failUnless(ISpam(object.SpamField).GetValue() == "eggs") - self.failUnless(object.SpamField.GetValue() == "eggs") + self.assertTrue(ISpam(object.SpamField).GetValue() == "eggs") + self.assertTrue(object.SpamField.GetValue() == "eggs") def testObjectField(self): """Test object fields.""" object = FieldTest() - self.failUnless(object.ObjectField == None) + self.assertTrue(object.ObjectField == None) object.ObjectField = System.String("spam") - self.failUnless(object.ObjectField == "spam") + self.assertTrue(object.ObjectField == "spam") object.ObjectField = System.Int32(1) - self.failUnless(object.ObjectField == 1) + self.assertTrue(object.ObjectField == 1) object.ObjectField = None - self.failUnless(object.ObjectField == None) + self.assertTrue(object.ObjectField == None) def testEnumField(self): """Test enum fields.""" object = FieldTest() - self.failUnless(object.EnumField == ShortEnum.Zero) + self.assertTrue(object.EnumField == ShortEnum.Zero) object.EnumField = ShortEnum.One - self.failUnless(object.EnumField == ShortEnum.One) + self.assertTrue(object.EnumField == ShortEnum.One) def testNullableField(self): @@ -433,25 +431,25 @@ def testNullableField(self): object = FieldTest() object.StringField = None - self.failUnless(object.StringField == None) + self.assertTrue(object.StringField == None) object.ObjectField = None - self.failUnless(object.ObjectField == None) + self.assertTrue(object.ObjectField == None) object.SpamField = None - self.failUnless(object.SpamField == None) + self.assertTrue(object.SpamField == None) # Primitive types and enums should not be set to null. def test(): FieldTest().Int32Field = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): FieldTest().EnumField = None - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) @@ -462,6 +460,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/src/tests/test_generic.py b/src/tests/test_generic.py new file mode 100644 index 000000000..256bca29a --- /dev/null +++ b/src/tests/test_generic.py @@ -0,0 +1,748 @@ +# =========================================================================== +# 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') + +from System.Collections.Generic import Dictionary, List +import sys, os, string, unittest, types +import Python.Test as Test +import System + +class GenericTests(unittest.TestCase): + """Test CLR generics support.""" + + def testPythonTypeAliasing(self): + """Test python type alias support with generics.""" + dict = Dictionary[str, str]() + self.assertEquals(dict.Count, 0) + dict.Add("one", "one") + self.assertTrue(dict["one"] == "one") + + dict = Dictionary[System.String, System.String]() + self.assertEquals(dict.Count, 0) + dict.Add("one", "one") + self.assertTrue(dict["one"] == "one") + + dict = Dictionary[int, int]() + self.assertEquals(dict.Count, 0) + dict.Add(1, 1) + self.assertTrue(dict[1] == 1) + + dict = Dictionary[System.Int32, System.Int32]() + self.assertEquals(dict.Count, 0) + dict.Add(1, 1) + self.assertTrue(dict[1] == 1) + + dict = Dictionary[long, long]() + self.assertEquals(dict.Count, 0) + dict.Add(1L, 1L) + self.assertTrue(dict[1L] == 1L) + + dict = Dictionary[System.Int64, System.Int64]() + self.assertEquals(dict.Count, 0) + dict.Add(1L, 1L) + self.assertTrue(dict[1L] == 1L) + + dict = Dictionary[float, float]() + self.assertEquals(dict.Count, 0) + dict.Add(1.5, 1.5) + self.assertTrue(dict[1.5] == 1.5) + + dict = Dictionary[System.Double, System.Double]() + self.assertEquals(dict.Count, 0) + dict.Add(1.5, 1.5) + self.assertTrue(dict[1.5] == 1.5) + + dict = Dictionary[bool, bool]() + self.assertEquals(dict.Count, 0) + dict.Add(True, False) + self.assertTrue(dict[True] == False) + + dict = Dictionary[System.Boolean, System.Boolean]() + self.assertEquals(dict.Count, 0) + dict.Add(True, False) + self.assertTrue(dict[True] == False) + + def testGenericReferenceType(self): + """Test usage of generic reference type definitions.""" + from Python.Test import GenericTypeDefinition + inst = GenericTypeDefinition[System.String, System.Int32]("one", 2) + self.assertTrue(inst.value1 == "one") + self.assertTrue(inst.value2 == 2) + + def testGenericValueType(self): + """Test usage of generic value type definitions.""" + inst = System.Nullable[System.Int32](10) + self.assertTrue(inst.HasValue) + self.assertTrue(inst.Value == 10) + + def testGenericInterface(self): + pass + + def testGenericDelegate(self): + pass + + def testOpenGenericType(self): + """ + Test behavior of reflected open constructed generic types. + """ + from Python.Test import DerivedFromOpenGeneric + + OpenGenericType = DerivedFromOpenGeneric.__bases__[0] + def test(): + inst = OpenGenericType() + + self.assertRaises(TypeError, test) + + def test(): + type = OpenGenericType[System.String] + + self.assertRaises(TypeError, test) + + def testDerivedFromOpenGenericType(self): + """ + Test a generic type derived from an open generic type. + """ + from Python.Test import DerivedFromOpenGeneric + + type = DerivedFromOpenGeneric[System.String, System.String] + inst = type(1, 'two', 'three') + + self.assertTrue(inst.value1 == 1) + self.assertTrue(inst.value2 == 'two') + self.assertTrue(inst.value3 == 'three') + + def testGenericTypeNameResolution(self): + """ + Test the ability to disambiguate generic type names. + """ + from Python.Test import GenericNameTest1, GenericNameTest2 + + # If both a non-generic and generic type exist for a name, the + # unadorned name always resolves to the non-generic type. + _class = GenericNameTest1 + self.assertTrue(_class().value == 0) + self.assertTrue(_class.value == 0) + + # If no non-generic type exists for a name, the unadorned name + # cannot be instantiated. It can only be used to bind a generic. + + def test(): + inst = GenericNameTest2() + + self.assertRaises(TypeError, test) + + _class = GenericNameTest2[int] + self.assertTrue(_class().value == 1) + self.assertTrue(_class.value == 1) + + _class = GenericNameTest2[int, int] + self.assertTrue(_class().value == 2) + self.assertTrue(_class.value == 2) + + def _testGenericWrapperByType(self, ptype, value, test_type=0): + from Python.Test import GenericWrapper + import System + + inst = GenericWrapper[ptype](value) + self.assertTrue(inst.value == value) + + atype = System.Array[ptype] + items = atype([value, value, value]) + inst = GenericWrapper[atype](items) + self.assertTrue(len(inst.value) == 3) + self.assertTrue(inst.value[0] == value) + self.assertTrue(inst.value[1] == value) + + def testGenericTypeBinding(self): + """ + Test argument conversion / binding for generic methods. + """ + from Python.Test import InterfaceTest, ISayHello1, ShortEnum + import System + + self._testGenericWrapperByType(System.Boolean, True) + self._testGenericWrapperByType(bool, True) + self._testGenericWrapperByType(System.Byte, 255) + self._testGenericWrapperByType(System.SByte, 127) + self._testGenericWrapperByType(System.Char, 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.UInt16, 65000) + self._testGenericWrapperByType(System.UInt32, 4294967295L) + self._testGenericWrapperByType(System.UInt64, 18446744073709551615L) + self._testGenericWrapperByType(System.Single, 3.402823e38) + self._testGenericWrapperByType(System.Double, 1.7976931348623157e308) + self._testGenericWrapperByType(float, 1.7976931348623157e308) + self._testGenericWrapperByType(System.Decimal, System.Decimal.One) + self._testGenericWrapperByType(System.String, "test") + self._testGenericWrapperByType(unicode, "test") + self._testGenericWrapperByType(str, "test") + self._testGenericWrapperByType(ShortEnum, ShortEnum.Zero) + self._testGenericWrapperByType(System.Object, InterfaceTest()) + self._testGenericWrapperByType(InterfaceTest, InterfaceTest()) + self._testGenericWrapperByType(ISayHello1, InterfaceTest()) + + def _testGenericMethodByType(self, ptype, value, test_type=0): + from Python.Test import GenericMethodTest, GenericStaticMethodTest + import System + + itype = GenericMethodTest[System.Type] + stype = GenericStaticMethodTest[System.Type] + + # Explicit selection (static method) + result = stype.Overloaded[ptype](value) + if test_type: self.assertTrue(result.__class__ == value.__class__) + else: self.assertTrue(result == value) + + # Type inference (static method) + result = stype.Overloaded(value) + self.assertTrue(result == value) + if test_type: self.assertTrue(result.__class__ == value.__class__) + else: self.assertTrue(result == value) + + # Explicit selection (instance method) + result = itype().Overloaded[ptype](value) + self.assertTrue(result == value) + if test_type: self.assertTrue(result.__class__ == value.__class__) + else: self.assertTrue(result == value) + + # Type inference (instance method) + result = itype().Overloaded(value) + self.assertTrue(result == value) + if test_type: self.assertTrue(result.__class__ == value.__class__) + else: self.assertTrue(result == value) + + atype = System.Array[ptype] + items = atype([value, value, value]) + + # Explicit selection (static method) + result = stype.Overloaded[atype](items) + if test_type: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0].__class__ == value.__class__) + self.assertTrue(result[1].__class__ == value.__class__) + else: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0] == value) + self.assertTrue(result[1] == value) + + # Type inference (static method) + result = stype.Overloaded(items) + if test_type: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0].__class__ == value.__class__) + self.assertTrue(result[1].__class__ == value.__class__) + else: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0] == value) + self.assertTrue(result[1] == value) + + # Explicit selection (instance method) + result = itype().Overloaded[atype](items) + if test_type: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0].__class__ == value.__class__) + self.assertTrue(result[1].__class__ == value.__class__) + else: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0] == value) + self.assertTrue(result[1] == value) + + # Type inference (instance method) + result = itype().Overloaded(items) + if test_type: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0].__class__ == value.__class__) + self.assertTrue(result[1].__class__ == value.__class__) + else: + self.assertTrue(len(result) == 3) + self.assertTrue(result[0] == value) + self.assertTrue(result[1] == value) + + def testGenericMethodBinding(self): + from Python.Test import GenericMethodTest, GenericStaticMethodTest + from System import InvalidOperationException + + # Can invoke a static member on a closed generic type. + value = GenericStaticMethodTest[str].Overloaded() + self.assertTrue(value == 1) + + def test(): + # Cannot invoke a static member on an open type. + GenericStaticMethodTest.Overloaded() + + self.assertRaises(InvalidOperationException, test) + + # Can invoke an instance member on a closed generic type. + value = GenericMethodTest[str]().Overloaded() + self.assertTrue(value == 1) + + def test(): + # Cannot invoke an instance member on an open type, + # because the open type cannot be instantiated. + GenericMethodTest().Overloaded() + + self.assertRaises(TypeError, test) + + def testGenericMethodTypeHandling(self): + """ + Test argument conversion / binding for generic methods. + """ + from Python.Test import InterfaceTest, ISayHello1, ShortEnum + import System + + # XXX BUG: The value doesn't fit into Int64 and PythonNet doesn't + # recognize it as UInt64 for unknown reasons. +## self._testGenericMethodByType(System.UInt64, 18446744073709551615L) + self._testGenericMethodByType(System.Boolean, True) + self._testGenericMethodByType(bool, True) + self._testGenericMethodByType(System.Byte, 255) + self._testGenericMethodByType(System.SByte, 127) + self._testGenericMethodByType(System.Char, 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) + 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) + self._testGenericMethodByType(System.Decimal, System.Decimal.One) + self._testGenericMethodByType(System.String, "test") + self._testGenericMethodByType(unicode, "test") + self._testGenericMethodByType(str, "test") + self._testGenericMethodByType(ShortEnum, ShortEnum.Zero) + self._testGenericMethodByType(System.Object, InterfaceTest()) + self._testGenericMethodByType(InterfaceTest, InterfaceTest(), 1) + self._testGenericMethodByType(ISayHello1, InterfaceTest(), 1) + + + def testGenericMethodOverloadSelection(self): + """ + Test explicit overload selection with generic methods. + """ + from Python.Test import GenericMethodTest, GenericStaticMethodTest + type = GenericStaticMethodTest[str] + inst = GenericMethodTest[str]() + + # public static int Overloaded() + value = type.Overloaded() + self.assertTrue(value == 1) + + # public int Overloaded() + value = inst.Overloaded() + self.assertTrue(value == 1) + + # public static T Overloaded(T arg) (inferred) + value = type.Overloaded("test") + self.assertTrue(value == "test") + + # public T Overloaded(T arg) (inferred) + value = inst.Overloaded("test") + self.assertTrue(value == "test") + + # public static T Overloaded(T arg) (explicit) + value = type.Overloaded[str]("test") + self.assertTrue(value == "test") + + # public T Overloaded(T arg) (explicit) + value = inst.Overloaded[str]("test") + self.assertTrue(value == "test") + + # public static Q Overloaded(Q arg) + value = type.Overloaded[float](2.2) + self.assertTrue(value == 2.2) + + # public Q Overloaded(Q arg) + value = inst.Overloaded[float](2.2) + self.assertTrue(value == 2.2) + + # public static Q Overloaded(Q arg) + value = type.Overloaded[bool](True) + self.assertTrue(value == True) + + # public Q Overloaded(Q arg) + value = inst.Overloaded[bool](True) + self.assertTrue(value == True) + + # public static U Overloaded(Q arg1, U arg2) + value = type.Overloaded[bool, str](True, "true") + self.assertTrue(value == "true") + + # public U Overloaded(Q arg1, U arg2) + value = inst.Overloaded[bool, str](True, "true") + self.assertTrue(value == "true") + + # public static U Overloaded(Q arg1, U arg2) + value = type.Overloaded[str, bool]("true", True) + self.assertTrue(value == True) + + # public U Overloaded(Q arg1, U arg2) + value = inst.Overloaded[str, bool]("true", True) + self.assertTrue(value == True) + + # public static string Overloaded(int arg1, int arg2, string arg3) + value = type.Overloaded[str](123, 456, "success") + self.assertTrue(value == "success") + + # public string Overloaded(int arg1, int arg2, string arg3) + value = inst.Overloaded[str](123, 456, "success") + self.assertTrue(value == "success") + + def test(): + value = type.Overloaded[str, bool, int]("true", True, 1) + self.assertRaises(TypeError, test) + + def test(): + value = inst.Overloaded[str, bool, int]("true", True, 1) + + self.assertRaises(TypeError, test) + + def testMethodOverloadSelectionWithGenericTypes(self): + """Check method overload selection using generic types.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from Python.Test import MethodTest, GenericWrapper + inst = InterfaceTest() + + vtype = GenericWrapper[System.Boolean] + input = vtype(True) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == True) + + vtype = GenericWrapper[bool] + input = vtype(True) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == True) + + vtype = GenericWrapper[System.Byte] + input = vtype(255) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 255) + + vtype = GenericWrapper[System.SByte] + input = vtype(127) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 127) + + vtype = GenericWrapper[System.Char] + input = vtype(u'A') + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == u'A') + + vtype = GenericWrapper[System.Char] + input = vtype(65535) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == unichr(65535)) + + vtype = GenericWrapper[System.Int16] + input = vtype(32767) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 32767) + + vtype = GenericWrapper[System.Int32] + input = vtype(2147483647) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 2147483647) + + vtype = GenericWrapper[int] + input = vtype(2147483647) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 2147483647) + + vtype = GenericWrapper[System.Int64] + input = vtype(9223372036854775807L) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 9223372036854775807L) + + vtype = GenericWrapper[long] + input = vtype(9223372036854775807L) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 9223372036854775807L) + + vtype = GenericWrapper[System.UInt16] + input = vtype(65000) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 65000) + + vtype = GenericWrapper[System.UInt32] + input = vtype(4294967295L) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 4294967295L) + + vtype = GenericWrapper[System.UInt64] + input = vtype(18446744073709551615L) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 18446744073709551615L) + + vtype = GenericWrapper[System.Single] + input = vtype(3.402823e38) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 3.402823e38) + + vtype = GenericWrapper[System.Double] + input = vtype(1.7976931348623157e308) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 1.7976931348623157e308) + + vtype = GenericWrapper[float] + input = vtype(1.7976931348623157e308) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == 1.7976931348623157e308) + + vtype = GenericWrapper[System.Decimal] + input = vtype(System.Decimal.One) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == System.Decimal.One) + + vtype = GenericWrapper[System.String] + input = vtype("spam") + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == "spam") + + vtype = GenericWrapper[str] + input = vtype("spam") + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == "spam") + + vtype = GenericWrapper[ShortEnum] + input = vtype(ShortEnum.Zero) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value == ShortEnum.Zero) + + vtype = GenericWrapper[System.Object] + input = vtype(inst) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value.__class__ == inst.__class__) + + vtype = GenericWrapper[InterfaceTest] + input = vtype(inst) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value.__class__ == inst.__class__) + + vtype = GenericWrapper[ISayHello1] + input = vtype(inst) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value.value.__class__ == inst.__class__) + + vtype = System.Array[GenericWrapper[int]] + input = vtype([GenericWrapper[int](0), GenericWrapper[int](1)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 0) + self.assertTrue(value[1].value == 1) + + def testOverloadSelectionWithArraysOfGenericTypes(self): + """Check overload selection using arrays of generic types.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from Python.Test import MethodTest, GenericWrapper + inst = InterfaceTest() + + gtype = GenericWrapper[System.Boolean] + vtype = System.Array[gtype] + input = vtype([gtype(True),gtype(True)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == True) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[bool] + vtype = System.Array[gtype] + input = vtype([gtype(True), gtype(True)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == True) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Byte] + vtype = System.Array[gtype] + input = vtype([gtype(255), gtype(255)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 255) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.SByte] + vtype = System.Array[gtype] + input = vtype([gtype(127), gtype(127)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 127) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Char] + vtype = System.Array[gtype] + input = vtype([gtype(u'A'), gtype(u'A')]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == u'A') + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Char] + vtype = System.Array[gtype] + input = vtype([gtype(65535), gtype(65535)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == unichr(65535)) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Int16] + vtype = System.Array[gtype] + input = vtype([gtype(32767),gtype(32767)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 32767) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Int32] + vtype = System.Array[gtype] + input = vtype([gtype(2147483647), gtype(2147483647)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 2147483647) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[int] + vtype = System.Array[gtype] + input = vtype([gtype(2147483647), gtype(2147483647)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 2147483647) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Int64] + vtype = System.Array[gtype] + input = vtype([gtype(9223372036854775807L), + gtype(9223372036854775807L)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 9223372036854775807L) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[long] + vtype = System.Array[gtype] + input = vtype([gtype(9223372036854775807L), + gtype(9223372036854775807L)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 9223372036854775807L) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.UInt16] + vtype = System.Array[gtype] + input = vtype([gtype(65000), gtype(65000)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 65000) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.UInt32] + vtype = System.Array[gtype] + input = vtype([gtype(4294967295L), gtype(4294967295L)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 4294967295L) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.UInt64] + vtype = System.Array[gtype] + input = vtype([gtype(18446744073709551615L), + gtype(18446744073709551615L)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 18446744073709551615L) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Single] + vtype = System.Array[gtype] + input = vtype([gtype(3.402823e38), gtype(3.402823e38)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 3.402823e38) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Double] + vtype = System.Array[gtype] + input = vtype([gtype(1.7976931348623157e308), + gtype(1.7976931348623157e308)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 1.7976931348623157e308) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[float] + vtype = System.Array[gtype] + input = vtype([gtype(1.7976931348623157e308), + gtype(1.7976931348623157e308)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == 1.7976931348623157e308) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Decimal] + vtype = System.Array[gtype] + input = vtype([gtype(System.Decimal.One), + gtype(System.Decimal.One)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == System.Decimal.One) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.String] + vtype = System.Array[gtype] + input = vtype([gtype("spam"), gtype("spam")]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == "spam") + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[str] + vtype = System.Array[gtype] + input = vtype([gtype("spam"), gtype("spam")]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == "spam") + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[ShortEnum] + vtype = System.Array[gtype] + input = vtype([gtype(ShortEnum.Zero), gtype(ShortEnum.Zero)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value == ShortEnum.Zero) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[System.Object] + vtype = System.Array[gtype] + input = vtype([gtype(inst), gtype(inst)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value.__class__ == inst.__class__) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[InterfaceTest] + vtype = System.Array[gtype] + input = vtype([gtype(inst), gtype(inst)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value.__class__ == inst.__class__) + self.assertTrue(value.Length == 2) + + gtype = GenericWrapper[ISayHello1] + vtype = System.Array[gtype] + input = vtype([gtype(inst), gtype(inst)]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].value.__class__ == inst.__class__) + self.assertTrue(value.Length == 2) + + def testGenericOverloadSelectionMagicNameOnly(self): + """Test using only __overloads__ to select on type & sig""" + # XXX NotImplemented + pass + + def testNestedGenericClass(self): + """Check nested generic classes.""" + # XXX NotImplemented + pass + + + +def test_suite(): + return unittest.makeSuite(GenericTests) + +def main(): + unittest.TextTestRunner().run(test_suite()) + +if __name__ == '__main__': + main() + + diff --git a/pythonnet/src/tests/test_indexer.py b/src/tests/test_indexer.py old mode 100755 new mode 100644 similarity index 63% rename from pythonnet/src/tests/test_indexer.py rename to src/tests/test_indexer.py index 976793e12..2b1d4e100 --- a/pythonnet/src/tests/test_indexer.py +++ b/src/tests/test_indexer.py @@ -1,16 +1,14 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types -import CLR.Python.Test as Test +import Python.Test as Test class IndexerTests(unittest.TestCase): @@ -21,12 +19,12 @@ def testPublicIndexer(self): object = Test.PublicIndexerTest() object[0] = "zero" - self.failUnless(object[0] == "zero") + self.assertTrue(object[0] == "zero") object[1] = "one" - self.failUnless(object[1] == "one") + self.assertTrue(object[1] == "one") - self.failUnless(object[10] == None) + self.assertTrue(object[10] == None) def testProtectedIndexer(self): @@ -34,12 +32,12 @@ def testProtectedIndexer(self): object = Test.ProtectedIndexerTest() object[0] = "zero" - self.failUnless(object[0] == "zero") + self.assertTrue(object[0] == "zero") object[1] = "one" - self.failUnless(object[1] == "one") + self.assertTrue(object[1] == "one") - self.failUnless(object[10] == None) + self.assertTrue(object[10] == None) def testInternalIndexer(self): @@ -49,17 +47,17 @@ def testInternalIndexer(self): def test(): object[0] = "zero" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): Test.InternalIndexerTest.__getitem__(object, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object.__getitem__(0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testPrivateIndexer(self): @@ -69,37 +67,37 @@ def testPrivateIndexer(self): def test(): object[0] = "zero" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): Test.PrivateIndexerTest.__getitem__(object, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object.__getitem__(0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testBooleanIndexer(self): """Test boolean indexers.""" object = Test.BooleanIndexerTest() - self.failUnless(object[True] == None) - self.failUnless(object[1] == None) + self.assertTrue(object[True] == None) + self.assertTrue(object[1] == None) object[0] = "false" - self.failUnless(object[0] == "false") + self.assertTrue(object[0] == "false") object[1] = "true" - self.failUnless(object[1] == "true") + self.assertTrue(object[1] == "true") object[False] = "false" - self.failUnless(object[False] == "false") + self.assertTrue(object[False] == "false") object[True] = "true" - self.failUnless(object[True] == "true") + self.assertTrue(object[True] == "true") def testByteIndexer(self): @@ -108,25 +106,25 @@ def testByteIndexer(self): max = 255 min = 0 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.ByteIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.ByteIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testSByteIndexer(self): @@ -135,25 +133,25 @@ def testSByteIndexer(self): max = 127 min = -128 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.SByteIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.SByteIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testCharIndexer(self): @@ -162,25 +160,25 @@ def testCharIndexer(self): max = unichr(65535) min = unichr(0) - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = "max" - self.failUnless(object[max] == "max") + self.assertTrue(object[max] == "max") object[min] = "min" - self.failUnless(object[min] == "min") + self.assertTrue(object[min] == "min") def test(): object = Test.CharIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.CharIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInt16Indexer(self): @@ -189,25 +187,25 @@ def testInt16Indexer(self): max = 32767 min = -32768 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.Int16IndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.Int16IndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInt32Indexer(self): @@ -216,25 +214,25 @@ def testInt32Indexer(self): max = 2147483647 min = -2147483648 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.Int32IndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.Int32IndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInt64Indexer(self): @@ -243,25 +241,25 @@ def testInt64Indexer(self): max = 9223372036854775807L min = -9223372036854775808L - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.Int64IndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.Int64IndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testUInt16Indexer(self): @@ -270,25 +268,25 @@ def testUInt16Indexer(self): max = 65535 min = 0 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.UInt16IndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.UInt16IndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testUInt32Indexer(self): @@ -297,25 +295,25 @@ def testUInt32Indexer(self): max = 4294967295L min = 0 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.UInt32IndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.UInt32IndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testUInt64Indexer(self): @@ -324,25 +322,25 @@ def testUInt64Indexer(self): max = 18446744073709551615L min = 0 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = str(max) - self.failUnless(object[max] == str(max)) + self.assertTrue(object[max] == str(max)) object[min] = str(min) - self.failUnless(object[min] == str(min)) + self.assertTrue(object[min] == str(min)) def test(): object = Test.UInt64IndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.UInt64IndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testSingleIndexer(self): @@ -351,25 +349,25 @@ def testSingleIndexer(self): max = 3.402823e38 min = -3.402823e38 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = "max" - self.failUnless(object[max] == "max") + self.assertTrue(object[max] == "max") object[min] = "min" - self.failUnless(object[min] == "min") + self.assertTrue(object[min] == "min") def test(): object = Test.SingleIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.SingleIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testDoubleIndexer(self): @@ -378,86 +376,86 @@ def testDoubleIndexer(self): max = 1.7976931348623157e308 min = -1.7976931348623157e308 - self.failUnless(object[max] == None) + self.assertTrue(object[max] == None) object[max] = "max" - self.failUnless(object[max] == "max") + self.assertTrue(object[max] == "max") object[min] = "min" - self.failUnless(object[min] == "min") + self.assertTrue(object[min] == "min") def test(): object = Test.DoubleIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.DoubleIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testDecimalIndexer(self): """Test Decimal indexers.""" object = Test.DecimalIndexerTest() - from CLR.System import Decimal + from System import Decimal max_d = Decimal.Parse("79228162514264337593543950335") min_d = Decimal.Parse("-79228162514264337593543950335") - self.failUnless(object[max_d] == None) + self.assertTrue(object[max_d] == None) object[max_d] = "max" - self.failUnless(object[max_d] == "max") + self.assertTrue(object[max_d] == "max") object[min_d] = "min" - self.failUnless(object[min_d] == "min") + self.assertTrue(object[min_d] == "min") def test(): object = Test.DecimalIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.DecimalIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testStringIndexer(self): """Test String indexers.""" object = Test.StringIndexerTest() - self.failUnless(object["spam"] == None) - self.failUnless(object[u"spam"] == None) + self.assertTrue(object["spam"] == None) + self.assertTrue(object[u"spam"] == None) object["spam"] = "spam" - self.failUnless(object["spam"] == "spam") - self.failUnless(object["spam"] == u"spam") - self.failUnless(object[u"spam"] == "spam") - self.failUnless(object[u"spam"] == u"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") object[u"eggs"] = u"eggs" - self.failUnless(object["eggs"] == "eggs") - self.failUnless(object["eggs"] == u"eggs") - self.failUnless(object[u"eggs"] == "eggs") - self.failUnless(object[u"eggs"] == 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") def test(): object = Test.StringIndexerTest() object[1] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.StringIndexerTest() object[1] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testEnumIndexer(self): @@ -466,53 +464,53 @@ def testEnumIndexer(self): key = Test.ShortEnum.One - self.failUnless(object[key] == None) + self.assertTrue(object[key] == None) object[key] = "spam" - self.failUnless(object[key] == "spam") + self.assertTrue(object[key] == "spam") object[key] = "eggs" - self.failUnless(object[key] == "eggs") + self.assertTrue(object[key] == "eggs") object[1] = "spam" - self.failUnless(object[1] == "spam") + self.assertTrue(object[1] == "spam") def test(): object = Test.EnumIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.EnumIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testObjectIndexer(self): """Test object indexers.""" object = Test.ObjectIndexerTest() - from CLR.Python.Test import Spam + from Python.Test import Spam spam = Spam("spam") - self.failUnless(object[spam] == None) - self.failUnless(object["spam"] == None) - self.failUnless(object[1] == None) - self.failUnless(object[None] == None) + self.assertTrue(object[spam] == None) + self.assertTrue(object["spam"] == None) + self.assertTrue(object[1] == None) + self.assertTrue(object[None] == None) object[spam] = "spam" - self.failUnless(object[spam] == "spam") + self.assertTrue(object[spam] == "spam") object["spam"] = "eggs" - self.failUnless(object["spam"] == "eggs") + self.assertTrue(object["spam"] == "eggs") object[1] = "one" - self.failUnless(object[1] == "one") + self.assertTrue(object[1] == "one") object[1L] = "long" - self.failUnless(object[1L] == "long") + self.assertTrue(object[1L] == "long") def test(): class eggs: @@ -521,63 +519,63 @@ class eggs: object = Test.ObjectIndexerTest() object[key] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInterfaceIndexer(self): """Test interface indexers.""" object = Test.InterfaceIndexerTest() - from CLR.Python.Test import Spam + from Python.Test import Spam spam = Spam("spam") - self.failUnless(object[spam] == None) + self.assertTrue(object[spam] == None) object[spam] = "spam" - self.failUnless(object[spam] == "spam") + self.assertTrue(object[spam] == "spam") object[spam] = "eggs" - self.failUnless(object[spam] == "eggs") + self.assertTrue(object[spam] == "eggs") def test(): object = Test.InterfaceIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.InterfaceIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testTypedIndexer(self): """Test typed indexers.""" object = Test.TypedIndexerTest() - from CLR.Python.Test import Spam + from Python.Test import Spam spam = Spam("spam") - self.failUnless(object[spam] == None) + self.assertTrue(object[spam] == None) object[spam] = "spam" - self.failUnless(object[spam] == "spam") + self.assertTrue(object[spam] == "spam") object[spam] = "eggs" - self.failUnless(object[spam] == "eggs") + self.assertTrue(object[spam] == "eggs") def test(): object = Test.TypedIndexerTest() object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.TypedIndexerTest() object["wrong"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testMultiArgIndexer(self): @@ -585,24 +583,24 @@ def testMultiArgIndexer(self): object = Test.MultiArgIndexerTest() object[0, 1] = "zero one" - self.failUnless(object[0, 1] == "zero one") + self.assertTrue(object[0, 1] == "zero one") object[1, 9] = "one nine" - self.failUnless(object[1, 9] == "one nine") + self.assertTrue(object[1, 9] == "one nine") - self.failUnless(object[10, 50] == None) + self.assertTrue(object[10, 50] == None) def test(): object = Test.MultiArgIndexerTest() v = object[0, "one"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.MultiArgIndexerTest() object[0, "one"] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testMultiTypeIndexer(self): @@ -611,22 +609,22 @@ def testMultiTypeIndexer(self): spam = Test.Spam("spam") object[0, "one", spam] = "zero one spam" - self.failUnless(object[0, "one", spam] == "zero one spam") + self.assertTrue(object[0, "one", spam] == "zero one spam") object[1, "nine", spam] = "one nine spam" - self.failUnless(object[1, "nine", spam] == "one nine spam") + self.assertTrue(object[1, "nine", spam] == "one nine spam") def test(): object = Test.MultiTypeIndexerTest() v = object[0, 1, spam] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.MultiTypeIndexerTest() object[0, 1, spam] = "wrong" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testIndexerWrongKeyType(self): @@ -636,13 +634,13 @@ def test(): object = Test.PublicIndexerTest() v = object["wrong"] - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): object = Test.PublicIndexerTest() object["wrong"] = "spam" - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testIndexerWrongValueType(self): @@ -652,7 +650,7 @@ def test(): object = Test.PublicIndexerTest() object[1] = 9993.9 - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testUnboundIndexer(self): @@ -660,12 +658,12 @@ def testUnboundIndexer(self): object = Test.PublicIndexerTest() Test.PublicIndexerTest.__setitem__(object, 0, "zero") - self.failUnless(object[0] == "zero") + self.assertTrue(object[0] == "zero") Test.PublicIndexerTest.__setitem__(object, 1, "one") - self.failUnless(object[1] == "one") + self.assertTrue(object[1] == "one") - self.failUnless(object[10] == None) + self.assertTrue(object[10] == None) def testIndexerAbuse(self): @@ -676,22 +674,22 @@ def testIndexerAbuse(self): def test(): del _class.__getitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): del object.__getitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): del _class.__setitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): del object.__setitem__ - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) @@ -702,6 +700,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/src/tests/test_interface.py b/src/tests/test_interface.py new file mode 100644 index 000000000..1e9c0ad96 --- /dev/null +++ b/src/tests/test_interface.py @@ -0,0 +1,89 @@ +# =========================================================================== +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# =========================================================================== + +from Python.Test import InterfaceTest +import sys, os, string, unittest, types +import Python.Test as Test +import System + +class InterfaceTests(unittest.TestCase): + """Test CLR interface support.""" + + def testInterfaceStandardAttrs(self): + """Test standard class attributes.""" + 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) + + + def testGlobalInterfaceVisibility(self): + """Test visibility of module-level interfaces.""" + from Python.Test import IPublicInterface + self.assertTrue(IPublicInterface.__name__ == 'IPublicInterface') + + def test(): + from Python.Test import IInternalInterface + + self.assertRaises(ImportError, test) + + def test(): + i = Test.IInternalInterface + + self.assertRaises(AttributeError, test) + + + def testNestedInterfaceVisibility(self): + """Test visibility of nested interfaces.""" + ob = InterfaceTest.IPublic + self.assertTrue(ob.__name__ == 'IPublic') + + ob = InterfaceTest.IProtected + self.assertTrue(ob.__name__ == 'IProtected') + + def test(): + ob = InterfaceTest.IInternal + + self.assertRaises(AttributeError, test) + + def test(): + ob = InterfaceTest.IPrivate + + self.assertRaises(AttributeError, test) + + + def testExplicitCastToInterface(self): + """Test explicit cast to an interface.""" + ob = InterfaceTest() + self.assertTrue(type(ob).__name__ == 'InterfaceTest') + self.assertTrue(hasattr(ob, 'HelloProperty')) + + i1 = Test.ISayHello1(ob) + self.assertTrue(type(i1).__name__ == 'ISayHello1') + self.assertTrue(hasattr(i1, 'SayHello')) + self.assertTrue(i1.SayHello() == 'hello 1') + self.assertFalse(hasattr(i1, 'HelloProperty')) + + i2 = Test.ISayHello2(ob) + self.assertTrue(type(i2).__name__ == 'ISayHello2') + self.assertTrue(i2.SayHello() == 'hello 2') + self.assertTrue(hasattr(i2, 'SayHello')) + self.assertFalse(hasattr(i2, 'HelloProperty')) + + + +def test_suite(): + return unittest.makeSuite(InterfaceTests) + +def main(): + unittest.TextTestRunner().run(test_suite()) + +if __name__ == '__main__': + main() + diff --git a/src/tests/test_method.py b/src/tests/test_method.py new file mode 100644 index 000000000..03a23cf84 --- /dev/null +++ b/src/tests/test_method.py @@ -0,0 +1,775 @@ +# =========================================================================== +# 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 sys, os, string, unittest, types +import clr +clr.AddReference("Python.Test") + +from Python.Test import MethodTest, MethodTestSub +import System + +class MethodTests(unittest.TestCase): + """Test CLR method support.""" + + def testInstanceMethodDescriptor(self): + """Test instance method descriptor behavior.""" + def test(): + MethodTest().PublicMethod = 0 + + self.assertRaises(AttributeError, test) + + def test(): + MethodTest.PublicMethod = 0 + + self.assertRaises(AttributeError, test) + + def test(): + del MethodTest().PublicMethod + + self.assertRaises(AttributeError, test) + + def test(): + del MethodTest.PublicMethod + + self.assertRaises(AttributeError, test) + + + def testStaticMethodDescriptor(self): + """Test static method descriptor behavior.""" + def test(): + MethodTest().PublicStaticMethod = 0 + + self.assertRaises(AttributeError, test) + + def test(): + MethodTest.PublicStaticMethod = 0 + + self.assertRaises(AttributeError, test) + + def test(): + del MethodTest().PublicStaticMethod + + self.assertRaises(AttributeError, test) + + def test(): + del MethodTest.PublicStaticMethod + + self.assertRaises(AttributeError, test) + + + def testPublicInstanceMethod(self): + """Test public instance method visibility.""" + object = MethodTest(); + self.assertTrue(object.PublicMethod() == "public") + + + def testPublicStaticMethod(self): + """Test public static method visibility.""" + object = MethodTest(); + self.assertTrue(MethodTest.PublicStaticMethod() == "public static") + self.assertTrue(object.PublicStaticMethod() == "public static") + + + def testProtectedInstanceMethod(self): + """Test protected instance method visibility.""" + object = MethodTest(); + self.assertTrue(object.ProtectedMethod() == "protected") + + + def testProtectedStaticMethod(self): + """Test protected static method visibility.""" + object = MethodTest(); + result = "protected static" + self.assertTrue(MethodTest.ProtectedStaticMethod() == result) + self.assertTrue(object.ProtectedStaticMethod() == result) + + + def testInternalMethod(self): + """Test internal method visibility.""" + def test(): + f = MethodTest().InternalMethod + + self.assertRaises(AttributeError, test) + + def test(): + f = MethodTest.InternalMethod + + self.assertRaises(AttributeError, test) + + def test(): + f = MethodTest().InternalStaticMethod + + self.assertRaises(AttributeError, test) + + def test(): + f = MethodTest.InternalStaticMethod + + self.assertRaises(AttributeError, test) + + + def testPrivateMethod(self): + """Test private method visibility.""" + def test(): + f = MethodTest().PrivateMethod + + self.assertRaises(AttributeError, test) + + def test(): + f = MethodTest.PrivateMethod + + self.assertRaises(AttributeError, test) + + def test(): + f = MethodTest().PrivateStaticMethod + + self.assertRaises(AttributeError, test) + + def test(): + f = MethodTest.PrivateStaticMethod + + self.assertRaises(AttributeError, test) + + + def testUnboundManagedMethodCall(self): + """Test calling unbound managed methods.""" + + object = MethodTest() + self.assertTrue(MethodTest.PublicMethod(object) == "public") + + def test(): + MethodTest.PublicMethod() + + self.assertRaises(TypeError, test) + + + object = MethodTestSub(); + self.assertTrue(MethodTestSub.PublicMethod(object) == "public") + self.assertTrue(MethodTestSub.PublicMethod(object, "echo") == "echo") + + def test(): + MethodTestSub.PublicMethod("echo") + + self.assertRaises(TypeError, test) + + + def testOverloadedMethodInheritance(self): + """Test that overloads are inherited properly.""" + + object = MethodTest() + self.assertTrue(object.PublicMethod() == "public") + + def test(): + object = MethodTest() + object.PublicMethod("echo") + + self.assertRaises(TypeError, test) + + + object = MethodTestSub(); + self.assertTrue(object.PublicMethod() == "public") + + self.assertTrue(object.PublicMethod("echo") == "echo") + + + def testMethodDescriptorAbuse(self): + """Test method descriptor abuse.""" + desc = MethodTest.__dict__['PublicMethod'] + + def test(): + desc.__get__(0, 0) + + self.assertRaises(TypeError, test) + + def test(): + desc.__set__(0, 0) + + self.assertRaises(AttributeError, test) + + + def testMethodDocstrings(self): + """Test standard method docstring generation""" + method = MethodTest.GetType + value = 'System.Type GetType()' + self.assertTrue(method.__doc__ == value) + + + #====================================================================== + # Tests of specific argument and result conversion scenarios + #====================================================================== + + def testMethodCallEnumConversion(self): + """Test enum conversion in method call.""" + from System import TypeCode + + object = MethodTest() + r = object.TestEnumConversion(TypeCode.Int32) + self.assertTrue(r == TypeCode.Int32) + + + def testMethodCallFlagsConversion(self): + """Test flags conversion in method call.""" + from System.IO import FileAccess + + object = MethodTest() + flags = FileAccess.Read | FileAccess.Write + r = object.TestFlagsConversion(flags) + self.assertTrue(r == flags) + + + def testMethodCallStructConversion(self): + """Test struct conversion in method call.""" + from System import Guid + + object = MethodTest() + guid = Guid.NewGuid() + temp = guid.ToString() + r = object.TestStructConversion(guid) + self.assertTrue(r.ToString() == temp) + + + def testSubclassInstanceConversion(self): + """Test subclass instance conversion in method call.""" + class sub(System.Exception): + pass + + object = MethodTest() + instance = sub() + result = object.TestSubclassConversion(instance) + self.assertTrue(isinstance(result, System.Exception)) + + + def testNullArrayConversion(self): + """Test null array conversion in method call.""" + from System import Type + + object = MethodTest() + r = object.TestNullArrayConversion(None) + self.assertTrue(r == None) + + + def testStringParamsArgs(self): + """Test use of string params.""" + result = MethodTest.TestStringParamsArg('one', 'two', 'three') + self.assertEqual(result.Length, 3) + self.assertEqual(len(result), 3, result) + self.assertTrue(result[0] == 'one') + self.assertTrue(result[1] == 'two') + self.assertTrue(result[2] == 'three') + + result = MethodTest.TestStringParamsArg(['one', 'two', 'three']) + self.assertTrue(len(result) == 3) + self.assertTrue(result[0] == 'one') + self.assertTrue(result[1] == 'two') + self.assertTrue(result[2] == 'three') + + + def testObjectParamsArgs(self): + """Test use of object params.""" + result = MethodTest.TestObjectParamsArg('one', 'two', 'three') + self.assertEqual(len(result), 3, result) + self.assertTrue(result[0] == 'one') + self.assertTrue(result[1] == 'two') + self.assertTrue(result[2] == 'three') + + result = MethodTest.TestObjectParamsArg(['one', 'two', 'three']) + self.assertEqual(len(result), 3, result) + self.assertTrue(result[0] == 'one') + self.assertTrue(result[1] == 'two') + self.assertTrue(result[2] == 'three') + + + def testValueParamsArgs(self): + """Test use of value type params.""" + result = MethodTest.TestValueParamsArg(1, 2, 3) + self.assertEqual(len(result), 3) + self.assertTrue(result[0] == 1) + self.assertTrue(result[1] == 2) + self.assertTrue(result[2] == 3) + + result = MethodTest.TestValueParamsArg([1, 2, 3]) + self.assertEqual(len(result), 3) + self.assertTrue(result[0] == 1) + self.assertTrue(result[1] == 2) + self.assertTrue(result[2] == 3) + + + def testStringOutParams(self): + """Test use of string out-parameters.""" + result = MethodTest.TestStringOutParams("hi", "there") + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + result = MethodTest.TestStringOutParams("hi", None) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + + def testStringRefParams(self): + """Test use of string byref parameters.""" + result = MethodTest.TestStringRefParams("hi", "there") + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + result = MethodTest.TestStringRefParams("hi", None) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + + def testValueOutParams(self): + """Test use of value type out-parameters.""" + result = MethodTest.TestValueOutParams("hi", 1) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == 42) + + def test(): + MethodTest.TestValueOutParams("hi", None) + + # None cannot be converted to a value type like int, long, etc. + self.assertRaises(TypeError, test) + + + def testValueRefParams(self): + """Test use of value type byref parameters.""" + result = MethodTest.TestValueRefParams("hi", 1) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == 42) + + def test(): + MethodTest.TestValueRefParams("hi", None) + + # None cannot be converted to a value type like int, long, etc. + self.assertRaises(TypeError, test) + + + def testObjectOutParams(self): + """Test use of object out-parameters.""" + result = MethodTest.TestObjectOutParams("hi", MethodTest()) + self.assertTrue(type(result) == type(())) + self.assertTrue(len(result) == 2) + self.assertTrue(result[0] == True) + self.assertTrue(isinstance(result[1], System.Exception)) + + result = MethodTest.TestObjectOutParams("hi", None) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(isinstance(result[1], System.Exception)) + + + def testObjectRefParams(self): + """Test use of object byref parameters.""" + result = MethodTest.TestObjectRefParams("hi", MethodTest()) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(isinstance(result[1], System.Exception)) + + result = MethodTest.TestObjectRefParams("hi", None) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(isinstance(result[1], System.Exception)) + + + def testStructOutParams(self): + """Test use of struct out-parameters.""" + result = MethodTest.TestStructOutParams("hi",System.Guid.NewGuid()) + self.assertTrue(type(result) == type(())) + self.assertEqual(len(result), 2) + self.assertTrue(result[0] == True) + self.assertTrue(isinstance(result[1], System.Guid)) + + def test(): + MethodTest.TestValueRefParams("hi", None) + + # None cannot be converted to a value type like a struct + self.assertRaises(TypeError, test) + + + def testStructRefParams(self): + """Test use of struct byref parameters.""" + result = MethodTest.TestStructRefParams("hi",System.Guid.NewGuid()) + self.assertTrue(type(result) == type(())) + self.assertTrue(len(result) == 2) + self.assertTrue(result[0] == True) + self.assertTrue(isinstance(result[1], System.Guid)) + + def test(): + MethodTest.TestValueRefParams("hi", None) + + # None cannot be converted to a value type like a struct + self.assertRaises(TypeError, test) + + + def testVoidSingleOutParam(self): + """Test void method with single out-parameter.""" + result = MethodTest.TestVoidSingleOutParam(9) + self.assertTrue(result == 42) + + def test(): + MethodTest.TestVoidSingleOutParam(None) + + # None cannot be converted to a value type + self.assertRaises(TypeError, test) + + + def testVoidSingleRefParam(self): + """Test void method with single ref-parameter.""" + result = MethodTest.TestVoidSingleRefParam(9) + self.assertTrue(result == 42) + + def test(): + MethodTest.TestVoidSingleRefParam(None) + + # None cannot be converted to a value type + self.assertRaises(TypeError, test) + + + def testExplicitSelectionWithOutModifier(self): + """Check explicit overload selection with out modifiers.""" + refstr = System.String("").GetType().MakeByRefType() + result = MethodTest.TestStringOutParams.__overloads__[str, refstr]( + "hi", "there" + ) + self.assertTrue(type(result) == type(())) + self.assertTrue(len(result) == 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + result = MethodTest.TestStringOutParams.__overloads__[str, refstr]( + "hi", None + ) + self.assertTrue(type(result) == type(())) + self.assertTrue(len(result) == 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + + def testExplicitSelectionWithRefModifier(self): + """Check explicit overload selection with ref modifiers.""" + refstr = System.String("").GetType().MakeByRefType() + result = MethodTest.TestStringRefParams.__overloads__[str, refstr]( + "hi", "there" + ) + self.assertTrue(type(result) == type(())) + self.assertTrue(len(result) == 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + result = MethodTest.TestStringRefParams.__overloads__[str, refstr]( + "hi", None + ) + self.assertTrue(type(result) == type(())) + self.assertTrue(len(result) == 2) + self.assertTrue(result[0] == True) + self.assertTrue(result[1] == "output string") + + + def testExplicitOverloadSelection(self): + """Check explicit overload selection using [] syntax.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from System import Array + inst = InterfaceTest() + + value =MethodTest.Overloaded.__overloads__[System.Boolean](True) + self.assertTrue(value == True) + + value = MethodTest.Overloaded.__overloads__[bool](True) + self.assertTrue(value == True) + + value = MethodTest.Overloaded.__overloads__[System.Byte](255) + self.assertTrue(value == 255) + + 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](65535) + self.assertTrue(value == unichr(65535)) + + value = MethodTest.Overloaded.__overloads__[System.Int16](32767) + self.assertTrue(value == 32767) + + value = MethodTest.Overloaded.__overloads__[System.Int32](2147483647) + self.assertTrue(value == 2147483647) + + value = MethodTest.Overloaded.__overloads__[int](2147483647) + self.assertTrue(value == 2147483647) + + value = MethodTest.Overloaded.__overloads__[System.Int64]( + 9223372036854775807L + ) + self.assertTrue(value == 9223372036854775807L) + + value = MethodTest.Overloaded.__overloads__[long]( + 9223372036854775807L + ) + self.assertTrue(value == 9223372036854775807L) + + 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.UInt64]( + 18446744073709551615L + ) + self.assertTrue(value == 18446744073709551615L) + + value = MethodTest.Overloaded.__overloads__[System.Single](3.402823e38) + self.assertTrue(value == 3.402823e38) + + value = MethodTest.Overloaded.__overloads__[System.Double]( + 1.7976931348623157e308 + ) + self.assertTrue(value == 1.7976931348623157e308) + + value = MethodTest.Overloaded.__overloads__[float]( + 1.7976931348623157e308 + ) + self.assertTrue(value == 1.7976931348623157e308) + + value = MethodTest.Overloaded.__overloads__[System.Decimal]( + System.Decimal.One + ) + self.assertTrue(value == System.Decimal.One) + + value = MethodTest.Overloaded.__overloads__[System.String]("spam") + self.assertTrue(value == "spam") + + value = MethodTest.Overloaded.__overloads__[str]("spam") + self.assertTrue(value == "spam") + + value = MethodTest.Overloaded.__overloads__[ShortEnum](ShortEnum.Zero) + self.assertTrue(value == ShortEnum.Zero) + + value = MethodTest.Overloaded.__overloads__[System.Object](inst) + self.assertTrue(value.__class__ == inst.__class__) + + value = MethodTest.Overloaded.__overloads__[InterfaceTest](inst) + self.assertTrue(value.__class__ == inst.__class__) + + value = MethodTest.Overloaded.__overloads__[ISayHello1](inst) + self.assertTrue(value.__class__ == inst.__class__) + + atype = Array[System.Object] + value = MethodTest.Overloaded.__overloads__[str, int, atype]( + "one", 1, atype([1, 2, 3]) + ) + self.assertTrue(value == 3) + + value = MethodTest.Overloaded.__overloads__[str, int]("one", 1) + self.assertTrue(value == 1) + + value = MethodTest.Overloaded.__overloads__[int, str](1, "one") + self.assertTrue(value == 1) + + + def testOverloadSelectionWithArrayTypes(self): + """Check overload selection using array types.""" + from Python.Test import ISayHello1, InterfaceTest, ShortEnum + from System import Array + inst = InterfaceTest() + + vtype = Array[System.Boolean] + input = vtype([True, True]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == True) + self.assertTrue(value[1] == True) + + vtype = Array[bool] + input = vtype([True, True]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == True) + self.assertTrue(value[1] == True) + + vtype = Array[System.Byte] + input = vtype([0, 255]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 255) + + vtype = Array[System.SByte] + input = vtype([0, 127]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 127) + + vtype = Array[System.Char] + input = vtype([u'A', u'Z']) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == u'A') + self.assertTrue(value[1] == u'Z') + + vtype = Array[System.Char] + input = vtype([0, 65535]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == unichr(0)) + self.assertTrue(value[1] == unichr(65535)) + + vtype = Array[System.Int16] + input = vtype([0, 32767]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 32767) + + vtype = Array[System.Int32] + input = vtype([0, 2147483647]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 2147483647) + + vtype = Array[int] + input = vtype([0, 2147483647]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 2147483647) + + vtype = Array[System.Int64] + input = vtype([0, 9223372036854775807L]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 9223372036854775807L) + + vtype = Array[long] + input = vtype([0, 9223372036854775807L]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 9223372036854775807L) + + vtype = Array[System.UInt16] + input = vtype([0, 65000]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 65000) + + vtype = Array[System.UInt32] + input = vtype([0, 4294967295L]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 4294967295L) + + vtype = Array[System.UInt64] + input = vtype([0, 18446744073709551615L]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0) + self.assertTrue(value[1] == 18446744073709551615L) + + vtype = Array[System.Single] + input = vtype([0.0, 3.402823e38]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0.0) + self.assertTrue(value[1] == 3.402823e38) + + vtype = Array[System.Double] + input = vtype([0.0, 1.7976931348623157e308]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0.0) + self.assertTrue(value[1] == 1.7976931348623157e308) + + vtype = Array[float] + input = vtype([0.0, 1.7976931348623157e308]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == 0.0) + self.assertTrue(value[1] == 1.7976931348623157e308) + + vtype = Array[System.Decimal] + input = vtype([System.Decimal.Zero, System.Decimal.One]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == System.Decimal.Zero) + self.assertTrue(value[1] == System.Decimal.One) + + vtype = Array[System.String] + input = vtype(["one", "two"]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == "one") + self.assertTrue(value[1] == "two") + + vtype = Array[str] + input = vtype(["one", "two"]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == "one") + self.assertTrue(value[1] == "two") + + vtype = Array[ShortEnum] + input = vtype([ShortEnum.Zero, ShortEnum.One]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0] == ShortEnum.Zero) + self.assertTrue(value[1] == ShortEnum.One) + + vtype = Array[System.Object] + input = vtype([inst, inst]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].__class__ == inst.__class__) + self.assertTrue(value[1].__class__ == inst.__class__) + + vtype = Array[InterfaceTest] + input = vtype([inst, inst]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].__class__ == inst.__class__) + self.assertTrue(value[1].__class__ == inst.__class__) + + vtype = Array[ISayHello1] + input = vtype([inst, inst]) + value = MethodTest.Overloaded.__overloads__[vtype](input) + self.assertTrue(value[0].__class__ == inst.__class__) + self.assertTrue(value[1].__class__ == inst.__class__) + + + def testExplicitOverloadSelectionFailure(self): + """Check that overload selection fails correctly.""" + + def test(): + value = MethodTest.Overloaded.__overloads__[System.Type](True) + + self.assertRaises(TypeError, test) + + def test(): + value = MethodTest.Overloaded.__overloads__[int, int](1, 1) + + self.assertRaises(TypeError, test) + + def test(): + value = MethodTest.Overloaded.__overloads__[str, int, int]( + "", 1, 1 + ) + + self.assertRaises(TypeError, test) + + def test(): + value = MethodTest.Overloaded.__overloads__[int, long](1) + + self.assertRaises(TypeError, test) + + + +def test_suite(): + return unittest.makeSuite(MethodTests) + +def main(): + unittest.TextTestRunner().run(test_suite()) + +if __name__ == '__main__': + main() + diff --git a/src/tests/test_module.py b/src/tests/test_module.py new file mode 100644 index 000000000..62ea78311 --- /dev/null +++ b/src/tests/test_module.py @@ -0,0 +1,368 @@ +# =========================================================================== +# This software is subject to the provisions of the Zope Public License, +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS +# FOR A PARTICULAR PURPOSE. +# =========================================================================== +import clr +clr.AddReference('Python.Test') +clr.AddReference('System.Data') + +# testImplicitAssemblyLoad() passes on deprecation warning; perfect! # +##clr.AddReference('System.Windows.Forms') +import sys, os, string, unittest, types, warnings + + +class ModuleTests(unittest.TestCase): + """Test CLR modules and the CLR import hook.""" + + def isCLRModule(self, object): + return type(object).__name__ == 'ModuleObject' + + def isCLRRootModule(self, object): + return type(object).__name__ == 'CLRModule' + + def isCLRClass(self, object): + return type(object).__name__ == 'CLR Metatype' # for now + + def testAAAImportHookWorks(self): + """Test that the import hook works correctly both using the + included runtime and an external runtime. This must be + the first test run in the unit tests!""" + + from System import String + + def test000importClr(self): + import clr + self.assertTrue(self.isCLRRootModule(clr)) + + def testPreloadVar(self): + import clr + self.assertTrue(clr.getPreload() is False, clr.getPreload()) + clr.setPreload(False) + self.assertTrue(clr.getPreload() is False, clr.getPreload()) + try: + clr.setPreload(True) + self.assertTrue(clr.getPreload() is True, clr.getPreload()) + clr.setPreload(0) + self.assertTrue(clr.getPreload() is False, clr.getPreload()) + clr.setPreload(1) + self.assertTrue(clr.getPreload() is True, clr.getPreload()) + + import System.Configuration + content = dir(System.Configuration) + self.assertTrue(len(content) > 10, content) + finally: + clr.setPreload(False) + + def testModuleInterface(self): + """Test the interface exposed by CLR module objects.""" + import System + self.assertEquals(type(System.__dict__), type({})) + self.assertEquals(System.__name__, 'System') + self.assertEquals(System.__file__, None) + self.assertEquals(System.__doc__, None) + self.assertTrue(self.isCLRClass(System.String)) + self.assertTrue(self.isCLRClass(System.Int32)) + + + def testSimpleImport(self): + """Test simple import.""" + import System + self.assertTrue(self.isCLRModule(System)) + self.assertTrue(System.__name__ == 'System') + + import sys + self.assertTrue(type(sys) == types.ModuleType) + self.assertTrue(sys.__name__ == 'sys') + + import httplib + self.assertTrue(type(httplib) == types.ModuleType) + self.assertTrue(httplib.__name__ == 'httplib') + + + def testSimpleImportWithAlias(self): + """Test simple import with aliasing.""" + import System as mySystem + self.assertTrue(self.isCLRModule(mySystem)) + self.assertTrue(mySystem.__name__ == 'System') + + import sys as mySys + 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') + + + def testDottedNameImport(self): + """Test dotted-name import.""" + import System.Reflection + self.assertTrue(self.isCLRModule(System.Reflection)) + self.assertTrue(System.Reflection.__name__ == 'System.Reflection') + + import xml.dom + self.assertTrue(type(xml.dom) == types.ModuleType) + self.assertTrue(xml.dom.__name__ == 'xml.dom') + + + def testMultipleDottedNameImport(self): + """Test an import bug with multiple dotted imports.""" + import System.Data + self.assertTrue(self.isCLRModule(System.Data)) + self.assertTrue(System.Data.__name__ == 'System.Data') + import System.Data + self.assertTrue(self.isCLRModule(System.Data)) + self.assertTrue(System.Data.__name__ == 'System.Data') + + + def testDottedNameImportWithAlias(self): + """Test dotted-name import with aliasing.""" + import System.Reflection as SysRef + self.assertTrue(self.isCLRModule(SysRef)) + self.assertTrue(SysRef.__name__ == 'System.Reflection') + + import xml.dom as myDom + self.assertTrue(type(myDom) == types.ModuleType) + self.assertTrue(myDom.__name__ == 'xml.dom') + + + def testSimpleImportFrom(self): + """Test simple 'import from'.""" + from System import Reflection + self.assertTrue(self.isCLRModule(Reflection)) + self.assertTrue(Reflection.__name__ == 'System.Reflection') + + from xml import dom + self.assertTrue(type(dom) == types.ModuleType) + self.assertTrue(dom.__name__ == 'xml.dom') + + + def testSimpleImportFromWithAlias(self): + """Test simple 'import from' with aliasing.""" + from System import Collections as Coll + self.assertTrue(self.isCLRModule(Coll)) + self.assertTrue(Coll.__name__ == 'System.Collections') + + from xml import dom as myDom + self.assertTrue(type(myDom) == types.ModuleType) + self.assertTrue(myDom.__name__ == 'xml.dom') + + + def testDottedNameImportFrom(self): + """Test dotted-name 'import from'.""" + from System.Collections import Specialized + self.assertTrue(self.isCLRModule(Specialized)) + self.assertTrue( + Specialized.__name__ == 'System.Collections.Specialized' + ) + + from System.Collections.Specialized import StringCollection + self.assertTrue(self.isCLRClass(StringCollection)) + self.assertTrue(StringCollection.__name__ == 'StringCollection') + + from xml.dom import pulldom + self.assertTrue(type(pulldom) == types.ModuleType) + self.assertTrue(pulldom.__name__ == 'xml.dom.pulldom') + + from xml.dom.pulldom import PullDOM + self.assertTrue(type(PullDOM) == types.ClassType) + self.assertTrue(PullDOM.__name__ == 'PullDOM') + + + def testDottedNameImportFromWithAlias(self): + """Test dotted-name 'import from' with aliasing.""" + from System.Collections import Specialized as Spec + self.assertTrue(self.isCLRModule(Spec)) + self.assertTrue(Spec.__name__ == 'System.Collections.Specialized') + + from System.Collections.Specialized import StringCollection as SC + self.assertTrue(self.isCLRClass(SC)) + self.assertTrue(SC.__name__ == 'StringCollection') + + from xml.dom import pulldom as myPulldom + self.assertTrue(type(myPulldom) == types.ModuleType) + self.assertTrue(myPulldom.__name__ == 'xml.dom.pulldom') + + from xml.dom.pulldom import PullDOM as myPullDOM + self.assertTrue(type(myPullDOM) == types.ClassType) + self.assertTrue(myPullDOM.__name__ == 'PullDOM') + + + def testFromModuleImportStar(self): + """Test from module import * behavior.""" + count = len(locals().keys()) + m = __import__('System.Xml', globals(), locals(), ['*']) + self.assertTrue(m.__name__ == 'System.Xml') + self.assertTrue(self.isCLRModule(m)) + self.assertTrue(len(locals().keys()) > count + 1) + + + def testImplicitAssemblyLoad(self): + """Test implicit assembly loading via import.""" + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + + # should trigger a DeprecationWarning as Microsoft.Build hasn't + # been added as a reference yet (and should exist for mono) + import Microsoft.Build + + self.assertEqual(len(w), 1) + self.assertTrue(isinstance(w[0].message, DeprecationWarning)) + + with warnings.catch_warnings(record=True) as w: + clr.AddReference("System.Windows.Forms") + import System.Windows.Forms as Forms + self.assertTrue(self.isCLRModule(Forms)) + self.assertTrue(Forms.__name__ == 'System.Windows.Forms') + from System.Windows.Forms import Form + self.assertTrue(self.isCLRClass(Form)) + self.assertTrue(Form.__name__ == 'Form') + self.assertEqual(len(w), 0) + + + def testExplicitAssemblyLoad(self): + """Test explicit assembly loading using standard CLR tools.""" + from System.Reflection import Assembly + import System, sys + + assembly = Assembly.LoadWithPartialName('System.Data') + self.assertTrue(assembly != None) + + import System.Data + self.assertTrue(sys.modules.has_key('System.Data')) + + assembly = Assembly.LoadWithPartialName('SpamSpamSpamSpamEggsAndSpam') + self.assertTrue(assembly == None) + + + def testImplicitLoadAlreadyValidNamespace(self): + """Test implicit assembly load over an already valid namespace.""" + # In this case, the mscorlib assembly (loaded by default) defines + # a number of types in the System namespace. There is also a System + # assembly, which is _not_ loaded by default, which also contains + # types in the System namespace. The desired behavior is for the + # Python runtime to "do the right thing", allowing types from both + # assemblies to be found in the System module implicitly. + import System + self.assertTrue(self.isCLRClass(System.UriBuilder)) + + + def testImportNonExistantModule(self): + """Test import failure for a non-existant module.""" + def test(): + import System.SpamSpamSpam + + self.assertTrue(ImportError, test) + + + def testLookupNoNamespaceType(self): + """Test lookup of types without a qualified namespace.""" + import Python.Test + import clr + self.assertTrue(self.isCLRClass(clr.NoNamespaceType)) + + + def testModuleLookupRecursion(self): + """Test for recursive lookup handling.""" + def test1(): + from System import System + + self.assertTrue(ImportError, test1) + + def test2(): + import System + x = System.System + + self.assertTrue(AttributeError, test2) + + + def testModuleGetAttr(self): + """Test module getattr behavior.""" + import System + + int_type = System.Int32 + self.assertTrue(self.isCLRClass(int_type)) + + module = System.Xml + self.assertTrue(self.isCLRModule(module)) + + def test(): + spam = System.Spam + + self.assertTrue(AttributeError, test) + + def test(): + spam = getattr(System, 1) + + self.assertTrue(TypeError, test) + + + def testModuleAttrAbuse(self): + """Test handling of attempts to set module attributes.""" + + # It would be safer to use a dict-proxy as the __dict__ for CLR + # modules, but as of Python 2.3 some parts of the CPython runtime + # like dir() will fail if a module dict is not a real dictionary. + + def test(): + import System + System.__dict__['foo'] = 0 + return 1 + + self.assertTrue(test()) + + + def testModuleTypeAbuse(self): + """Test handling of attempts to break the module type.""" + import System + mtype = type(System) + + def test(): + mtype.__getattribute__(0, 'spam') + + self.assertTrue(TypeError, test) + + def test(): + mtype.__setattr__(0, 'spam', 1) + + self.assertTrue(TypeError, test) + + def test(): + mtype.__repr__(0) + + self.assertTrue(TypeError, test) + + 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]) + + def test_ClrAddReference(self): + from clr import AddReference + from System.IO import FileNotFoundException + for name in ("System", "Python.Runtime"): + assy = AddReference(name) + assyName = assy.GetName().Name + self.assertEqual(assyName, name) + + self.assertRaises(FileNotFoundException, + AddReference, "somethingtotallysilly") + + +def test_suite(): + return unittest.makeSuite(ModuleTests) + +def main(): + unittest.TextTestRunner().run(test_suite()) + +if __name__ == '__main__': + main() + diff --git a/pythonnet/src/tests/test_property.py b/src/tests/test_property.py old mode 100755 new mode 100644 similarity index 66% rename from pythonnet/src/tests/test_property.py rename to src/tests/test_property.py index 27b5e76ab..851ff8af0 --- a/pythonnet/src/tests/test_property.py +++ b/src/tests/test_property.py @@ -1,16 +1,14 @@ -# Copyright (c) 2001, 2002 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types -from CLR.Python.Test import PropertyTest +from Python.Test import PropertyTest class PropertyTests(unittest.TestCase): @@ -20,74 +18,74 @@ def testPublicInstanceProperty(self): """Test public instance properties.""" object = PropertyTest(); - self.failUnless(object.PublicProperty == 0) + self.assertTrue(object.PublicProperty == 0) object.PublicProperty = 1 - self.failUnless(object.PublicProperty == 1) + self.assertTrue(object.PublicProperty == 1) def test(): del PropertyTest().PublicProperty - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testPublicStaticProperty(self): """Test public static properties.""" object = PropertyTest(); - self.failUnless(PropertyTest.PublicStaticProperty == 0) + self.assertTrue(PropertyTest.PublicStaticProperty == 0) PropertyTest.PublicStaticProperty = 1 - self.failUnless(PropertyTest.PublicStaticProperty == 1) + self.assertTrue(PropertyTest.PublicStaticProperty == 1) - self.failUnless(object.PublicStaticProperty == 1) + self.assertTrue(object.PublicStaticProperty == 1) object.PublicStaticProperty = 0 - self.failUnless(object.PublicStaticProperty == 0) + self.assertTrue(object.PublicStaticProperty == 0) def test(): del PropertyTest.PublicStaticProperty - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del PropertyTest().PublicStaticProperty - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testProtectedInstanceProperty(self): """Test protected instance properties.""" object = PropertyTest(); - self.failUnless(object.ProtectedProperty == 0) + self.assertTrue(object.ProtectedProperty == 0) object.ProtectedProperty = 1 - self.failUnless(object.ProtectedProperty == 1) + self.assertTrue(object.ProtectedProperty == 1) def test(): del PropertyTest().ProtectedProperty - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testProtectedStaticProperty(self): """Test protected static properties.""" object = PropertyTest(); - self.failUnless(PropertyTest.ProtectedStaticProperty == 0) + self.assertTrue(PropertyTest.ProtectedStaticProperty == 0) PropertyTest.ProtectedStaticProperty = 1 - self.failUnless(PropertyTest.ProtectedStaticProperty == 1) + self.assertTrue(PropertyTest.ProtectedStaticProperty == 1) - self.failUnless(object.ProtectedStaticProperty == 1) + self.assertTrue(object.ProtectedStaticProperty == 1) object.ProtectedStaticProperty = 0 - self.failUnless(object.ProtectedStaticProperty == 0) + self.assertTrue(object.ProtectedStaticProperty == 0) def test(): del PropertyTest.ProtectedStaticProperty - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): del PropertyTest().ProtectedStaticProperty - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInternalProperty(self): @@ -96,17 +94,17 @@ def testInternalProperty(self): def test(): f = PropertyTest().InternalProperty - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = PropertyTest().InternalStaticProperty - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = PropertyTest.InternalStaticProperty - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testPrivateProperty(self): @@ -115,17 +113,17 @@ def testPrivateProperty(self): def test(): f = PropertyTest().PrivateProperty - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = PropertyTest().PrivateStaticProperty - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def test(): f = PropertyTest.PrivateStaticProperty - self.failUnlessRaises(AttributeError, test) + self.assertRaises(AttributeError, test) def testPropertyDescriptorGetSet(self): @@ -137,19 +135,19 @@ def testPropertyDescriptorGetSet(self): object = PropertyTest() - self.failUnless(PropertyTest.PublicStaticProperty == 0) - self.failUnless(object.PublicStaticProperty == 0) + self.assertTrue(PropertyTest.PublicStaticProperty == 0) + self.assertTrue(object.PublicStaticProperty == 0) descriptor = PropertyTest.__dict__['PublicStaticProperty'] - self.failUnless(type(descriptor) != types.IntType) + self.assertTrue(type(descriptor) != types.IntType) object.PublicStaticProperty = 0 descriptor = PropertyTest.__dict__['PublicStaticProperty'] - self.failUnless(type(descriptor) != types.IntType) + self.assertTrue(type(descriptor) != types.IntType) PropertyTest.PublicStaticProperty = 0 descriptor = PropertyTest.__dict__['PublicStaticProperty'] - self.failUnless(type(descriptor) != types.IntType) + self.assertTrue(type(descriptor) != types.IntType) def testPropertyDescriptorWrongType(self): @@ -158,7 +156,7 @@ def test(): object = PropertyTest() object.PublicProperty = "spam" - self.failUnlessRaises(TypeError, test) + self.assertTrue(TypeError, test) def testPropertyDescriptorAbuse(self): @@ -168,12 +166,12 @@ def testPropertyDescriptorAbuse(self): def test(): desc.__get__(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def test(): desc.__set__(0, 0) - self.failUnlessRaises(TypeError, test) + self.assertRaises(TypeError, test) def testInterfaceProperty(self): @@ -181,10 +179,10 @@ def testInterfaceProperty(self): that an IsAbstract check was inappropriate and prevented use of properties when only the interface is known.""" - from CLR.System.Collections import Hashtable, ICollection + from System.Collections import Hashtable, ICollection mapping = Hashtable() coll = ICollection(mapping) - self.failUnless(coll.Count == 0) + self.assertTrue(coll.Count == 0) @@ -195,6 +193,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/pythonnet/src/tests/test_thread.py b/src/tests/test_thread.py old mode 100755 new mode 100644 similarity index 88% rename from pythonnet/src/tests/test_thread.py rename to src/tests/test_thread.py index 7822cc5a5..171efa3bb --- a/pythonnet/src/tests/test_thread.py +++ b/src/tests/test_thread.py @@ -1,16 +1,14 @@ -# Copyright (c) 2005 Zope Corporation and Contributors. -# -# All Rights Reserved. -# +# =========================================================================== # 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 sys, os, string, unittest, types, thread -from CLR.Python.Test import ThreadTest +from Python.Test import ThreadTest def dprint(msg): @@ -25,7 +23,7 @@ def testSimpleCallbackToPython(self): """Test a call to managed code that then calls back into Python.""" dprint("thread %s SimpleCallBack" % thread.get_ident()) result = ThreadTest.CallEchoString("spam") - self.failUnless(result == "spam") + self.assertTrue(result == "spam") dprint("thread %s SimpleCallBack ret" % thread.get_ident()) @@ -34,7 +32,7 @@ def testDoubleCallbackToPython(self): that then calls managed code that then calls Python again.""" dprint("thread %s DoubleCallBack" % thread.get_ident()) result = ThreadTest.CallEchoString2("spam") - self.failUnless(result == "spam") + self.assertTrue(result == "spam") dprint("thread %s DoubleCallBack ret" % thread.get_ident()) @@ -42,7 +40,7 @@ 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 - from CLR.System import String + from System import String done = [] def run_thread(): @@ -78,6 +76,5 @@ def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': - testcase.setup() main() diff --git a/src/tests/warnfilter.py b/src/tests/warnfilter.py new file mode 100644 index 000000000..b7a947cb9 --- /dev/null +++ b/src/tests/warnfilter.py @@ -0,0 +1,19 @@ +# =========================================================================== +# 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. +# =========================================================================== + +"""Warnfilter +""" + +from warnings import filterwarnings +from warnings import resetwarnings + +def addClrWarnfilter(action="ignore", append=False): + msgs = ["^The CLR module is deprecated.*", "^Importing from the CLR\.\* namespace.*"] + for msg in msgs: + filterwarnings(action, msg, category=DeprecationWarning, append=append) diff --git a/tools/nuget/nuget.exe b/tools/nuget/nuget.exe new file mode 100644 index 000000000..9cba6edbf Binary files /dev/null and b/tools/nuget/nuget.exe differ