Initial revision
This commit is contained in:
Родитель
748f8e2c78
Коммит
614c4b07ff
|
@ -0,0 +1 @@
|
|||
A D/CVSROOT////
|
|
@ -0,0 +1,210 @@
|
|||
<html>
|
||||
<head>
|
||||
|
||||
<title>Python for .NET</title>
|
||||
|
||||
<style type="text/css"><!--
|
||||
|
||||
body {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
background: #ffffff;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
p {
|
||||
font: 8pt/16pt georgia;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font: bold 14pt;
|
||||
color: #000044;
|
||||
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: bold 14pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: bold 12pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
a:link {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
text-decoration: underline;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace;
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
}
|
||||
|
||||
li {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
font: bold 14pt;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
.menu ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
//--></style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table width="98%" border="0" cellspacing="4">
|
||||
|
||||
<tr>
|
||||
<!--
|
||||
<td align="left" valign="top" width="20%" class="menu">
|
||||
|
||||
<h1>Python for .NET</h1>
|
||||
|
||||
|
||||
</td>
|
||||
-->
|
||||
|
||||
<td align="left" valign="top">
|
||||
|
||||
<h1>Python for .NET</h1>
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that this package does <em>not</em> 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
|
||||
<a href="http://www.ironpython.com">IronPython</a> project, which is in
|
||||
active development.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Python for .NET is currently compatible with Python releases 2.3 and greater.
|
||||
To subscribe to the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
Python for .NET mailing list
|
||||
</a> or read the
|
||||
<a href="http://mail.python.org/pipermail/pythondotnet/">
|
||||
online archives
|
||||
</a> of the list, see the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
mailing list information
|
||||
</a> page. You can also send questions or comments to me at
|
||||
<a href="mailto:brian.lloyd@revolution.com">brian.lloyd@revolution.com</a>
|
||||
or use the
|
||||
<a href="http://sourceforge.net/tracker/?group_id=162464">
|
||||
Python for .NET issue tracker</a> to report issues.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
My <a href="http://brianlloyd.blogspot.com">blog site</a> is also
|
||||
(sometimes) a good source for more information on Python for .NET ;)
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>The <a href="./readme.html">README</a>
|
||||
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.
|
||||
</li>
|
||||
|
||||
<li>Checkout the
|
||||
<a href="http://cvs.sourceforge.net/viewcvs.py/pythonnet">PythonNet</a>
|
||||
code
|
||||
from CVS. See the <a href="http://sourceforge.net/cvs/?group_id=162464">
|
||||
instructions on Source Forge</a> for details.
|
||||
</li>
|
||||
|
||||
<li><strong>Python 2.4 Releases</strong>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.4-clr1.1.exe">
|
||||
pythonnet-1.0-rc2-py2.4-clr1.1.exe
|
||||
</a>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.4-clr1.1-src.tgz">
|
||||
pythonnet-1.0-rc2-py2.4-clr1.1-src.tgz
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><strong>Python 2.3 Releases</strong>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.3-clr1.1.exe">
|
||||
pythonnet-1.0-rc2-py2.3-clr1.1.exe
|
||||
</a>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.3-clr1.1-src.tgz">
|
||||
pythonnet-1.0-rc2-py2.3-clr1.1-src.tgz
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,61 @@
|
|||
Zope Public License (ZPL) Version 2.0
|
||||
-----------------------------------------------
|
||||
|
||||
This software is Copyright (c) Zope Corporation (tm) and
|
||||
Contributors. All rights reserved.
|
||||
|
||||
This license has been certified as open source. It has also
|
||||
been designated as GPL compatible by the Free Software
|
||||
Foundation (FSF).
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions in source code must retain the above
|
||||
copyright notice, this list of conditions, and the following
|
||||
disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions, and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
3. The name Zope Corporation (tm) must not be used to
|
||||
endorse or promote products derived from this software
|
||||
without prior written permission from Zope Corporation.
|
||||
|
||||
4. The right to distribute this software or to use it for
|
||||
any purpose does not give you the right to use Servicemarks
|
||||
(sm) or Trademarks (tm) of Zope Corporation. Use of them is
|
||||
covered in a separate agreement (see
|
||||
http://www.zope.com/Marks).
|
||||
|
||||
5. If any files are modified, you must cause the modified
|
||||
files to carry prominent notices stating that you changed
|
||||
the files and the date of any change.
|
||||
|
||||
Disclaimer
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
|
||||
AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
|
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -0,0 +1,870 @@
|
|||
<html>
|
||||
<head>
|
||||
|
||||
<title>Python for .NET</title>
|
||||
|
||||
<style type="text/css"><!--
|
||||
|
||||
body {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
background: #ffffff;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
p {
|
||||
font: 8pt/16pt georgia;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font: bold 14pt;
|
||||
color: #000044;
|
||||
/*
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
*/
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: bold 14pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: bold 12pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
a:link {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
text-decoration: underline;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace;
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
}
|
||||
|
||||
li {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
font: bold 14pt;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
.menu ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
//--></style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table width="98%" border="0" cellspacing="4">
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top" width="20%" class="menu">
|
||||
|
||||
<h1>Python for .NET</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#getting_started">Getting Started</a></li>
|
||||
<li><a href="#importing">Importing Modules</a></li>
|
||||
<li><a href="#classes">Using Classes</a></li>
|
||||
<li><a href="#fields">Fields and Properties</a></li>
|
||||
<li><a href="#indexers">Using Indexers</a></li>
|
||||
<li><a href="#methods">Using Methods</a></li>
|
||||
<li><a href="#delegates">Delegates and Events</a></li>
|
||||
<li><a href="#exceptions">Exception Handling</a></li>
|
||||
<li><a href="#arrays">Using Arrays</a></li>
|
||||
<li><a href="#collections">Using Collections</a></li>
|
||||
<li><a href="#com">COM Components</a></li>
|
||||
<li><a href="#types">Type Conversion</a></li>
|
||||
<li><a href="#assemblies">Using Assemblies</a></li>
|
||||
<li><a href="#embedding">Embedding Python</a></li>
|
||||
<li><a href="#license">License</a></li>
|
||||
</ul>
|
||||
|
||||
</td>
|
||||
|
||||
<td align="left" valign="top">
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that this package does <em>not</em> 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
|
||||
<a href="http://www.ironpython.com">IronPython</a> project, which is in
|
||||
active development.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Python for .NET is currently compatible with Python releases 2.3 and greater.
|
||||
Current releases are available at the
|
||||
<a href="http://pythonnet.sourceforge.net/">
|
||||
Python for .NET website
|
||||
</a>. To subscribe to the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
Python for .NET mailing list
|
||||
</a> or read the
|
||||
<a href="http://mail.python.org/pipermail/pythondotnet/">
|
||||
online archives
|
||||
</a> of the list, see the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
mailing list information
|
||||
</a> page.
|
||||
</p>
|
||||
|
||||
<a name="#installation"></a>
|
||||
|
||||
<h2>Installation</h2>
|
||||
|
||||
<p>
|
||||
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
|
||||
<a href="http://pythonnet.sourceforge.net/">
|
||||
Python for .NET website
|
||||
</a>. 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Running on Linux/Mono:</strong> preliminary testing shows that
|
||||
PythonNet will run under <a href="http://www.go-mono.com">Mono</a>, 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
ln -s /usr/lib/libpython2.4.so ./python24.so
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="getting_started"></a>
|
||||
|
||||
<h2>Getting Started</h2>
|
||||
|
||||
<p>
|
||||
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#").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A good way to start is to run <strong>python.exe</strong> 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.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="importing"></a>
|
||||
|
||||
<h2>Importing Modules</h2>
|
||||
|
||||
<p>
|
||||
Python for .NET allows CLR namespaces to be treated essentially as
|
||||
Python packages. The top-level package is named <code>CLR</code>, and
|
||||
acts as the root for accessing all CLR namespaces:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import String
|
||||
import CLR.System as System
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
# This will implicitly load the System.Windows.Forms assembly
|
||||
|
||||
from CLR.System.Windows.Forms import Form
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <code>sys.path</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To load assemblies with names that do not correspond with a namespace,
|
||||
you can use the standard mechanisms provided by the CLR:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Reflection import Assembly
|
||||
|
||||
a = Assembly.LoadWithPartialName("SomeAssembly")
|
||||
|
||||
# now we can import namespaces defined in that assembly
|
||||
|
||||
from CLR.SomeNamespace import Something
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <code>dir()</code> 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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It also means that <code>from somemodule import *</code> 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 ;)
|
||||
</p>
|
||||
|
||||
|
||||
<a name="classes"></a>
|
||||
|
||||
<h2>Using Classes</h2>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Drawing import Point
|
||||
|
||||
p = Point(5, 5)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You can also subclass managed classes in Python. See the
|
||||
<code>helloform.py</code> file in the <code>/demo</code> directory of the
|
||||
distribution for a simple Windows Forms example that demonstrates
|
||||
subclassing a managed class.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="fields"></a>
|
||||
|
||||
<h2>Fields And Properties</h2>
|
||||
|
||||
<p>
|
||||
You can get and set fields and properties of CLR objects just as if
|
||||
they were regular attributes:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import Environment
|
||||
|
||||
name = Environment.MachineName
|
||||
Environment.ExitCode = 1
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="indexers"></a>
|
||||
|
||||
<h2>Using Indexers</h2>
|
||||
|
||||
<p>
|
||||
If a managed object implements one or more indexers, you can call
|
||||
the indexer using standard Python indexing syntax:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Collections import Hashtable
|
||||
|
||||
table = Hashtable()
|
||||
table["key 1"] = "value 1"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Overloaded indexers are supported, using the same notation one
|
||||
would use in C#:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
items[0, 2]
|
||||
|
||||
items[0, 2, 3]
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="methods"></a>
|
||||
|
||||
<h2>Using Methods</h2>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import Environment
|
||||
|
||||
drives = Environment.GetLogicalDrives()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
It is also possible to call managed methods <code>unbound</code> (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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>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.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 <code>help</code> method to inspect
|
||||
a managed class:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import Environment
|
||||
|
||||
print Environment.GetFolderPath.__doc__
|
||||
|
||||
help(Environment)
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="delegates"></a>
|
||||
|
||||
<h2>Delegates And Events</h2>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
|
||||
<p>
|
||||
Multicast delegates can be implemented by adding more callable objects
|
||||
to a delegate instance:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
d += self.method1
|
||||
d += self.method2
|
||||
d()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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
|
||||
<code>+=</code> and <code>-=</code> operators in a way very similar to
|
||||
the C# idiom:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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(...)
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="exceptions"></a>
|
||||
|
||||
<h2>Exception Handling</h2>
|
||||
|
||||
<p>
|
||||
You can raise and catch managed exceptions just the same as you would
|
||||
pure-Python exceptions:
|
||||
<pre>
|
||||
from CLR.System import NullReferenceException
|
||||
|
||||
try:
|
||||
raise NullReferenceException("aiieee!")
|
||||
except NullReferenceException, e:
|
||||
print e.Message
|
||||
print e.Source
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
|
||||
<a name="arrays"></a>
|
||||
|
||||
<h2>Using Arrays</h2>
|
||||
|
||||
<p>
|
||||
Managed arrays support the standard Python sequence protocols:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Multidimensional arrays support indexing using the same notation one
|
||||
would use in C#:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
items[0, 2]
|
||||
|
||||
items[0, 2, 3]
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="collections"></a>
|
||||
|
||||
<h2>Using Collections</h2>
|
||||
|
||||
<p>
|
||||
Managed arrays and managed objects that implement the IEnumerable
|
||||
interface can be iterated over using the standard iteration Python
|
||||
idioms:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
domain = System.AppDomain.CurrentDomain
|
||||
|
||||
for item in domain.GetAssemblies():
|
||||
name = item.GetName()
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="com"></a>
|
||||
|
||||
<h2>Using COM Components</h2>
|
||||
|
||||
<p>
|
||||
Using Microsoft-provided tools such as <strong>aximp.exe</strong> and
|
||||
<strong>tlbimp.exe</strong>, 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.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<a name="types"></a>
|
||||
|
||||
<h2>Type Conversion</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Types that do not have a logical equivalent in Python are exposed as
|
||||
instances of managed classes or structs (System.Decimal is an example).
|
||||
</p>
|
||||
<p>
|
||||
The .NET architecture makes a distinction between <code>value types</code>
|
||||
and <code>reference types</code>. Reference types are allocated on the heap,
|
||||
and value types are allocated either on the stack or in-line within an
|
||||
object.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A process called <code>boxing</code> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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".
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here is a simple example that demonstrates an issue. If you are an
|
||||
experienced C# programmer, you might write the following code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
items = CLR.System.Array.CreateInstance(Point, 3)
|
||||
for i in range(3):
|
||||
items[i] = Point(0, 0)
|
||||
|
||||
items[0].X = 1 # won't work!!
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
While the spelling of <code>items[0].X = 1</code> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 <code>items[0]</code> itself doesn't change is that
|
||||
when you say <code>items[0]</code>, that getitem operation creates a Python
|
||||
object that holds a reference to the object at <code>items[0]</code> via a
|
||||
GCHandle. That causes a ValueType (like Point) to be boxed, so the following
|
||||
setattr (<code>.X = 1</code>) <em>changes the state of the boxed value, not
|
||||
the original unboxed value</em>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <code>lost
|
||||
update</code> problems (generally because an implicit boxing happened that
|
||||
was not taken into account in the code).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="assemblies"></a>
|
||||
|
||||
<h2>Using Assemblies</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It <em>is</em> possible to load a specific version of an assembly if you
|
||||
need to using code similar to the following:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Reflection import Assembly, AssemblyName
|
||||
|
||||
name = AssemblyName(...) # set required version, etc.
|
||||
assembly = Assembly.Load(name)
|
||||
|
||||
# now import namespaces from the loaded assembly
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You <em>can</em> still use particular versions of objects in this case - you
|
||||
just have to do more work to get the right versions of objects:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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)
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
|
||||
<a name="embedding"></a>
|
||||
|
||||
<h2>Embedding Python</h2>
|
||||
|
||||
<p>
|
||||
<strong>Note:</strong> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Python runtime assembly defines a number of public classes that
|
||||
provide a subset of the functionality provided by the Python C API.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At a very high level, to embed Python in your application you
|
||||
will need to:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Reference Python.Runtime.dll in your build environment</li>
|
||||
<li>Call PythonEngine.Intialize() to initialize Python</li>
|
||||
<li>Call PythonEngine.ImportModule(name) to import a module</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Important Note for embedders:</strong> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 <code>PythonEngine.AcquireLock</code>
|
||||
method. The only exception to this rule is the
|
||||
<code>PythonEngine.Initialize</code> method, which may be called at startup
|
||||
without having acquired the GIL.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When finished using Python APIs, managed code must call a corresponding
|
||||
<code>PythonEngine.ReleaseLock</code> to release the GIL and allow other
|
||||
threads to use Python.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The AcquireLock and ReleaseLock methods are thin wrappers over the
|
||||
unmanaged <code>PyGILState_Ensure</code> and <code>PyGILState_Release</code>
|
||||
functions from the Python API, and the documentation for those APIs applies
|
||||
to the managed versions.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="license" />
|
||||
|
||||
<h2>License</h2>
|
||||
|
||||
<p>
|
||||
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
|
||||
<a href="http://pythonnet.sourceforge.net/license.txt">
|
||||
ZPL online
|
||||
</a>. Some distributions of this package include a copy of the C Python
|
||||
dlls and standard library, which are covered by the
|
||||
<a href="http://www.python.org/license.html">
|
||||
Python license
|
||||
</a>.
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,63 @@
|
|||
# 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
|
||||
|
||||
|
||||
class HelloApp(WinForms.Form):
|
||||
"""A simple hello world app that demonstrates the essentials of
|
||||
winforms programming and event-based programming in Python."""
|
||||
|
||||
def __init__(self):
|
||||
self.Text = "Hello World From Python"
|
||||
self.AutoScaleBaseSize = Size(5, 13)
|
||||
self.ClientSize = Size(392, 117);
|
||||
h = WinForms.SystemInformation.CaptionHeight
|
||||
self.MinimumSize = Size(392, (117 + h))
|
||||
|
||||
# Create the button
|
||||
self.button = WinForms.Button()
|
||||
self.button.Location = Point(256, 64)
|
||||
self.button.Size = Size(120, 40)
|
||||
self.button.TabIndex = 2
|
||||
self.button.Text = "Click Me!"
|
||||
|
||||
# Register the event handler
|
||||
self.button.Click += self.button_Click
|
||||
|
||||
# Create the text box
|
||||
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)
|
||||
|
||||
# Add the controls to the form
|
||||
self.AcceptButton = self.button
|
||||
self.Controls.Add(self.button);
|
||||
self.Controls.Add(self.textbox);
|
||||
|
||||
def button_Click(self, sender, args):
|
||||
"""Button click event handler"""
|
||||
WinForms.MessageBox.Show("Please do not press this button again.")
|
||||
|
||||
def run(self):
|
||||
WinForms.Application.Run(self)
|
||||
|
||||
|
||||
def main():
|
||||
HelloApp().run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
# 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
|
||||
|
||||
|
||||
class Splitter(WinForms.Form):
|
||||
"""A WinForms example transcribed to Python from the MSDN article:
|
||||
'Creating a Multipane User Interface with Windows Forms'."""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
# Create an instance of each control being used.
|
||||
self.components = System.ComponentModel.Container()
|
||||
self.treeView1 = WinForms.TreeView()
|
||||
self.listView1 = WinForms.ListView()
|
||||
self.richTextBox1 = WinForms.RichTextBox()
|
||||
self.splitter1 = WinForms.Splitter()
|
||||
self.splitter2 = WinForms.Splitter()
|
||||
self.panel1 = WinForms.Panel()
|
||||
|
||||
|
||||
# Set properties of TreeView control.
|
||||
self.treeView1.Dock = WinForms.DockStyle.Left
|
||||
self.treeView1.Width = self.ClientSize.Width / 3
|
||||
self.treeView1.TabIndex = 0
|
||||
self.treeView1.Nodes.Add("TreeView")
|
||||
|
||||
# Set properties of ListView control.
|
||||
self.listView1.Dock = WinForms.DockStyle.Top
|
||||
self.listView1.Height = self.ClientSize.Height * 2 / 3
|
||||
self.listView1.TabIndex = 0
|
||||
self.listView1.Items.Add("ListView")
|
||||
|
||||
# Set properties of RichTextBox control.
|
||||
self.richTextBox1.Dock = WinForms.DockStyle.Fill
|
||||
self.richTextBox1.TabIndex = 2
|
||||
self.richTextBox1.Text = "richTextBox1"
|
||||
|
||||
# Set properties of Panel's Splitter control.
|
||||
self.splitter2.Dock = WinForms.DockStyle.Top
|
||||
|
||||
# Width is irrelevant if splitter is docked to Top.
|
||||
self.splitter2.Height = 3
|
||||
|
||||
# Use a different color to distinguish the two splitters.
|
||||
self.splitter2.BackColor = Color.Blue
|
||||
self.splitter2.TabIndex = 1
|
||||
|
||||
# Set TabStop to false for ease of use when negotiating UI.
|
||||
self.splitter2.TabStop = 0
|
||||
|
||||
# Set properties of Form's Splitter control.
|
||||
self.splitter1.Location = System.Drawing.Point(121, 0)
|
||||
self.splitter1.Size = System.Drawing.Size(3, 273)
|
||||
self.splitter1.BackColor = Color.Red
|
||||
self.splitter1.TabIndex = 1
|
||||
|
||||
# Set TabStop to false for ease of use when negotiating UI.
|
||||
self.splitter1.TabStop = 0
|
||||
|
||||
# Add the appropriate controls to the Panel.
|
||||
for item in (self.richTextBox1, self.splitter2, self.listView1):
|
||||
self.panel1.Controls.Add(item)
|
||||
|
||||
# Set properties of Panel control.
|
||||
self.panel1.Dock = WinForms.DockStyle.Fill
|
||||
self.panel1.TabIndex = 2
|
||||
|
||||
# Add the rest of the controls to the form.
|
||||
for item in (self.panel1, self.splitter1, self.treeView1):
|
||||
self.Controls.Add(item)
|
||||
|
||||
self.Text = "Intricate UI Example"
|
||||
|
||||
def Dispose(self):
|
||||
self.components.Dispose()
|
||||
WinForms.Form.Dispose(self)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
app = Splitter()
|
||||
WinForms.Application.Run(app)
|
||||
app.Dispose()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
# 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
|
||||
|
||||
|
||||
class Wordpad(WinForms.Form):
|
||||
"""A simple example winforms application similar to wordpad."""
|
||||
|
||||
def __init__(self):
|
||||
self.filename = ''
|
||||
self.word_wrap = 1
|
||||
self.doctype = 1
|
||||
self.InitializeComponent()
|
||||
self.NewDocument()
|
||||
|
||||
def InitializeComponent(self):
|
||||
"""Initialize form components."""
|
||||
self.components = System.ComponentModel.Container()
|
||||
|
||||
self.openFileDialog = WinForms.OpenFileDialog()
|
||||
self.saveFileDialog = WinForms.SaveFileDialog()
|
||||
|
||||
self.mainMenu = WinForms.MainMenu()
|
||||
|
||||
self.fileMenu = WinForms.MenuItem()
|
||||
self.menuFileNew = WinForms.MenuItem()
|
||||
self.menuFileOpen = WinForms.MenuItem()
|
||||
self.menuFileSave = WinForms.MenuItem()
|
||||
self.menuFileSaveAs = WinForms.MenuItem()
|
||||
self.menuFileSep_1 = WinForms.MenuItem()
|
||||
self.menuFileExit = WinForms.MenuItem()
|
||||
|
||||
self.editMenu = WinForms.MenuItem()
|
||||
self.menuEditUndo = WinForms.MenuItem()
|
||||
self.menuEditRedo = WinForms.MenuItem()
|
||||
self.menuEditSep_1 = WinForms.MenuItem()
|
||||
self.menuEditCut = WinForms.MenuItem()
|
||||
self.menuEditCopy = WinForms.MenuItem()
|
||||
self.menuEditPaste = WinForms.MenuItem()
|
||||
self.menuEditSep_2 = WinForms.MenuItem()
|
||||
self.menuEditSelectAll = WinForms.MenuItem()
|
||||
|
||||
self.formatMenu = WinForms.MenuItem()
|
||||
self.menuFormatFont = WinForms.MenuItem()
|
||||
self.menuFormatWordWrap = WinForms.MenuItem()
|
||||
|
||||
self.aboutMenu = WinForms.MenuItem()
|
||||
self.menuHelpAbout = WinForms.MenuItem()
|
||||
|
||||
|
||||
self.richTextBox = WinForms.RichTextBox()
|
||||
self.statusBarPanel1 = WinForms.StatusBarPanel()
|
||||
self.statusBar = WinForms.StatusBar()
|
||||
self.fontDialog = WinForms.FontDialog()
|
||||
self.statusBarPanel1.BeginInit()
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# File Menu
|
||||
# ===================================================================
|
||||
|
||||
self.menuFileNew.Text = "&New"
|
||||
self.menuFileNew.Shortcut = WinForms.Shortcut.CtrlN
|
||||
self.menuFileNew.ShowShortcut = False
|
||||
self.menuFileNew.Index = 0
|
||||
self.menuFileNew.Click += self.OnClickFileNew
|
||||
|
||||
self.menuFileOpen.Text = "&Open"
|
||||
self.menuFileOpen.Shortcut = WinForms.Shortcut.CtrlO
|
||||
self.menuFileOpen.ShowShortcut = False
|
||||
self.menuFileOpen.Index = 1
|
||||
self.menuFileOpen.Click += self.OnClickFileOpen
|
||||
|
||||
self.menuFileSave.Text = "&Save"
|
||||
self.menuFileSave.Shortcut = WinForms.Shortcut.CtrlS
|
||||
self.menuFileSave.ShowShortcut = False
|
||||
self.menuFileSave.Index = 2
|
||||
self.menuFileSave.Click += self.OnClickFileSave
|
||||
|
||||
self.menuFileSaveAs.Text = "Save &As"
|
||||
self.menuFileSaveAs.Index = 3
|
||||
self.menuFileSaveAs.Click += self.OnClickFileSaveAs
|
||||
|
||||
self.menuFileSep_1.Text = "-"
|
||||
self.menuFileSep_1.Index = 4
|
||||
|
||||
self.menuFileExit.Text = "E&xit"
|
||||
self.menuFileExit.Shortcut = WinForms.Shortcut.AltF4
|
||||
self.menuFileExit.ShowShortcut = False
|
||||
self.menuFileExit.Index = 5
|
||||
self.menuFileExit.Click += self.OnClickFileExit
|
||||
|
||||
self.fileMenu.Text = "&File"
|
||||
self.fileMenu.Index = 0
|
||||
|
||||
items = (self.menuFileNew, self.menuFileOpen,
|
||||
self.menuFileSave, self.menuFileSaveAs,
|
||||
self.menuFileSep_1, self.menuFileExit)
|
||||
|
||||
self.fileMenu.MenuItems.AddRange(items)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Edit menu
|
||||
# ===================================================================
|
||||
|
||||
self.menuEditUndo.Text = "&Undo"
|
||||
self.menuEditUndo.Shortcut = WinForms.Shortcut.CtrlZ
|
||||
self.menuEditUndo.Index = 0
|
||||
self.menuEditUndo.Click += self.OnClickEditUndo
|
||||
|
||||
self.menuEditRedo.Text = "&Redo"
|
||||
self.menuEditRedo.Shortcut = WinForms.Shortcut.CtrlY
|
||||
self.menuEditRedo.Index = 1
|
||||
self.menuEditRedo.Click += self.OnClickEditRedo
|
||||
|
||||
self.menuEditSep_1.Text = "-"
|
||||
self.menuEditSep_1.Index = 2
|
||||
|
||||
self.menuEditCut.Text = "Cut"
|
||||
self.menuEditCut.Shortcut = WinForms.Shortcut.CtrlX
|
||||
self.menuEditCut.Index = 3
|
||||
self.menuEditCut.Click += self.OnClickEditCut
|
||||
|
||||
self.menuEditCopy.Text = "Copy"
|
||||
self.menuEditCopy.Shortcut = WinForms.Shortcut.CtrlC
|
||||
self.menuEditCopy.Index = 4
|
||||
self.menuEditCopy.Click += self.OnClickEditCopy
|
||||
|
||||
self.menuEditPaste.Text = "Paste"
|
||||
self.menuEditPaste.Shortcut = WinForms.Shortcut.CtrlV
|
||||
self.menuEditPaste.Index = 5
|
||||
self.menuEditPaste.Click += self.OnClickEditPaste
|
||||
|
||||
self.menuEditSelectAll.Text = "Select All"
|
||||
self.menuEditSelectAll.Shortcut = WinForms.Shortcut.CtrlA
|
||||
self.menuEditSelectAll.Index = 7
|
||||
self.menuEditSelectAll.Click += self.OnClickEditSelectAll
|
||||
|
||||
self.menuEditSep_2.Text = "-"
|
||||
self.menuEditSep_2.Index = 6
|
||||
|
||||
self.editMenu.Text = "&Edit"
|
||||
self.editMenu.Index = 1
|
||||
|
||||
items = (self.menuEditUndo, self.menuEditRedo,
|
||||
self.menuEditSep_1, self.menuEditCut,
|
||||
self.menuEditCopy, self.menuEditPaste,
|
||||
self.menuEditSep_2, self.menuEditSelectAll)
|
||||
|
||||
self.editMenu.MenuItems.AddRange(items)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# Format Menu
|
||||
# ===================================================================
|
||||
|
||||
self.menuFormatWordWrap.Text = "Word Wrap"
|
||||
self.menuFormatWordWrap.Checked = self.word_wrap
|
||||
self.menuFormatWordWrap.Index = 1
|
||||
self.menuFormatWordWrap.Click += self.OnClickFormatWordWrap
|
||||
|
||||
self.menuFormatFont.Text = "Fo&nt"
|
||||
self.menuFormatFont.Index = 0
|
||||
self.menuFormatFont.Click += self.OnClickFormatFont
|
||||
|
||||
self.formatMenu.Text = "F&ormat"
|
||||
self.formatMenu.Index = 2
|
||||
|
||||
items = (self.menuFormatWordWrap, self.menuFormatFont)
|
||||
|
||||
self.formatMenu.MenuItems.AddRange(items)
|
||||
|
||||
|
||||
# ===================================================================
|
||||
# About menu
|
||||
# ===================================================================
|
||||
|
||||
self.menuHelpAbout.Text = "&About"
|
||||
self.menuHelpAbout.Index = 0
|
||||
self.menuHelpAbout.Click += self.OnClickHelpAbout
|
||||
|
||||
self.aboutMenu.Text = "&Help"
|
||||
self.aboutMenu.Index = 3
|
||||
self.aboutMenu.MenuItems.Add(self.menuHelpAbout)
|
||||
|
||||
self.statusBarPanel1.Dock = WinForms.DockStyle.Fill
|
||||
self.statusBarPanel1.Text = "Ready"
|
||||
self.statusBarPanel1.Width = 755
|
||||
|
||||
self.richTextBox.Dock = WinForms.DockStyle.Fill
|
||||
self.richTextBox.Size = System.Drawing.Size(795, 485)
|
||||
self.richTextBox.TabIndex = 0
|
||||
self.richTextBox.AutoSize = 1
|
||||
self.richTextBox.ScrollBars = WinForms.RichTextBoxScrollBars.ForcedBoth
|
||||
self.richTextBox.Font = System.Drawing.Font("Tahoma", 10)
|
||||
self.richTextBox.AcceptsTab = 1
|
||||
self.richTextBox.Location = System.Drawing.Point(0, 0)
|
||||
|
||||
|
||||
self.statusBar.BackColor = System.Drawing.SystemColors.Control
|
||||
self.statusBar.Location = System.Drawing.Point(0, 518)
|
||||
self.statusBar.Size = System.Drawing.Size(775, 19)
|
||||
self.statusBar.TabIndex = 1
|
||||
self.statusBar.ShowPanels = True
|
||||
self.statusBar.Panels.Add(self.statusBarPanel1)
|
||||
|
||||
|
||||
items = (self.fileMenu, self.editMenu, self.formatMenu, self.aboutMenu)
|
||||
self.mainMenu.MenuItems.AddRange(items)
|
||||
|
||||
|
||||
self.openFileDialog.Filter = "Text documents|*.txt|RTF document|*.rtf"
|
||||
self.openFileDialog.Title = "Open document"
|
||||
|
||||
self.saveFileDialog.Filter = "Text Documents|*.txt|" \
|
||||
"Rich Text Format|*.rtf"
|
||||
self.saveFileDialog.Title = "Save document"
|
||||
self.saveFileDialog.FileName = "Untitled"
|
||||
|
||||
|
||||
self.AutoScaleBaseSize = System.Drawing.Size(5, 13)
|
||||
self.ClientSize = System.Drawing.Size(775, 537)
|
||||
self.Menu = self.mainMenu
|
||||
self.Text = "Python Wordpad"
|
||||
|
||||
self.Controls.Add(self.statusBar)
|
||||
self.Controls.Add(self.richTextBox)
|
||||
self.statusBarPanel1.EndInit()
|
||||
|
||||
def Dispose(self):
|
||||
self.components.Dispose()
|
||||
WinForms.Form.Dispose(self)
|
||||
|
||||
|
||||
def OnClickFileNew(self, sender, args):
|
||||
self.SaveChangesDialog()
|
||||
self.NewDocument()
|
||||
|
||||
def OnClickFileOpen(self, sender, args):
|
||||
self.SaveChangesDialog()
|
||||
self.OpenDocument()
|
||||
|
||||
def OnClickFileSave(self, sender, args):
|
||||
self.SaveDocument()
|
||||
|
||||
def OnClickFileSaveAs(self, sender, args):
|
||||
self.filename = ''
|
||||
self.SaveDocument()
|
||||
|
||||
def OnClickFileExit(self, sender, args):
|
||||
self.SaveChangesDialog()
|
||||
self.Close()
|
||||
|
||||
|
||||
def OnClickEditUndo(self, sender, args):
|
||||
self.richTextBox.Undo()
|
||||
|
||||
def OnClickEditRedo(self, sender, args):
|
||||
self.richTextBox.Redo()
|
||||
|
||||
def OnClickEditCut(self, sender, args):
|
||||
self.richTextBox.Cut()
|
||||
|
||||
def OnClickEditCopy(self, sender, args):
|
||||
self.richTextBox.Copy()
|
||||
|
||||
def OnClickEditPaste(self, sender, args):
|
||||
self.richTextBox.Paste()
|
||||
|
||||
def OnClickEditSelectAll(self, sender, args):
|
||||
self.richTextBox.SelectAll()
|
||||
|
||||
|
||||
def OnClickFormatWordWrap(self, sender, args):
|
||||
value = not self.word_wrap
|
||||
self.richTextBox.WordWrap = value
|
||||
self.menuFormatWordWrap.Checked = value
|
||||
self.word_wrap = value
|
||||
|
||||
def OnClickFormatFont(self, sender, args):
|
||||
if self.fontDialog.ShowDialog() == WinForms.DialogResult.OK:
|
||||
self.richTextBox.SelectionFont = self.fontDialog.Font
|
||||
|
||||
def OnClickHelpAbout(self, sender, args):
|
||||
AboutForm().ShowDialog(self)
|
||||
|
||||
|
||||
def NewDocument(self):
|
||||
self.doctype = 1
|
||||
self.richTextBox.Rtf = ''
|
||||
self.richTextBox.Text = ''
|
||||
self.Text = 'Python Wordpad - (New Document)'
|
||||
self.filename = ''
|
||||
|
||||
def OpenDocument(self):
|
||||
if self.openFileDialog.ShowDialog() != WinForms.DialogResult.OK:
|
||||
return
|
||||
|
||||
filename = self.openFileDialog.FileName
|
||||
|
||||
stream = File.OpenRead(filename)
|
||||
|
||||
buff = System.Array.CreateInstance(System.Byte, 1024)
|
||||
data = []
|
||||
read = -1
|
||||
|
||||
while (read != 0):
|
||||
buff.Initialize()
|
||||
read = stream.Read(buff, 0, 1024)
|
||||
temp = Encoding.ASCII.GetString(buff, 0, 1024)
|
||||
data.append(temp)
|
||||
|
||||
data = ''.join(data)
|
||||
stream.Close()
|
||||
|
||||
filename = self.filename = filename.lower()
|
||||
|
||||
if filename.endswith('.rtf'):
|
||||
self.richTextBox.Rtf = data
|
||||
self.doctype = 2
|
||||
else:
|
||||
self.richTextBox.Text = data
|
||||
self.doctype = 1
|
||||
|
||||
self.Text = 'Python Wordpad - %s' % filename
|
||||
self.richTextBox.Select(0, 0)
|
||||
|
||||
def SaveDocument(self):
|
||||
filename = self.filename
|
||||
|
||||
if not filename:
|
||||
if self.saveFileDialog.ShowDialog() != WinForms.DialogResult.OK:
|
||||
return
|
||||
filename = self.saveFileDialog.FileName
|
||||
|
||||
filename = self.filename = filename.lower()
|
||||
self.Text = 'Python Wordpad - %s' % filename
|
||||
|
||||
self.richTextBox.Select(0, 0)
|
||||
|
||||
stream = File.OpenWrite(filename)
|
||||
|
||||
if filename.endswith('.rtf'):
|
||||
data = self.richTextBox.Rtf
|
||||
else:
|
||||
data = self.richTextBox.Text
|
||||
|
||||
data = System.Text.Encoding.ASCII.GetBytes(System.String(data))
|
||||
|
||||
stream.Write(data, 0, data.Length)
|
||||
stream.Close()
|
||||
|
||||
def SaveChangesDialog(self):
|
||||
if self.richTextBox.Modified:
|
||||
if WinForms.MessageBox.Show(
|
||||
"Save changes?", "Word Pad",
|
||||
WinForms.MessageBoxButtons.OK |
|
||||
WinForms.MessageBoxButtons.YesNo
|
||||
) == WinForms.DialogResult.Yes:
|
||||
self.SaveDocument()
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
class AboutForm(WinForms.Form):
|
||||
|
||||
def __init__(self):
|
||||
self.InitializeComponent()
|
||||
|
||||
def InitializeComponent(self):
|
||||
"""Initialize form components."""
|
||||
self.Text = "Python Wordpad"
|
||||
self.components = System.ComponentModel.Container()
|
||||
|
||||
self.btnClose = WinForms.Button()
|
||||
self.label1 = WinForms.Label()
|
||||
self.SuspendLayout()
|
||||
|
||||
self.btnClose.Location = System.Drawing.Point(360, 181)
|
||||
self.btnClose.Name = "bnClose"
|
||||
self.btnClose.TabIndex = 1
|
||||
self.btnClose.Text = "&Close"
|
||||
self.btnClose.Click += self.OnClickClose
|
||||
|
||||
self.label1.Location = System.Drawing.Point(20, 20)
|
||||
self.label1.Name = "label1"
|
||||
self.label1.Size = System.Drawing.Size(296, 140)
|
||||
self.label1.TabIndex = 2
|
||||
self.label1.Text = "Python Wordpad - an example winforms " \
|
||||
"application using Python for .NET"
|
||||
|
||||
self.AutoScaleBaseSize = System.Drawing.Size(5, 13)
|
||||
self.ClientSize = System.Drawing.Size(300, 150)
|
||||
|
||||
self.Controls.AddRange((self.label1, self.btnClose))
|
||||
|
||||
self.FormBorderStyle = WinForms.FormBorderStyle.FixedDialog
|
||||
self.MaximizeBox = 0
|
||||
self.MinimizeBox = 0
|
||||
self.Name = "AboutForm"
|
||||
self.ShowInTaskbar = False
|
||||
self.StartPosition = WinForms.FormStartPosition.CenterScreen
|
||||
self.Text = "About"
|
||||
self.ResumeLayout(0)
|
||||
|
||||
def OnClickClose(self, sender, args):
|
||||
self.Close()
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
app = Wordpad()
|
||||
WinForms.Application.Run(app)
|
||||
app.Dispose()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -0,0 +1,297 @@
|
|||
PythonNet Changes
|
||||
-----------------
|
||||
|
||||
PythonNet 1.0 release candidate 2
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Changed some uses of Finalize as a static method name that confused the
|
||||
Mono compiler and people reading the code. Note that this may be a
|
||||
breaking change if anyone was calling PythonEngine.Finalize(). If so,
|
||||
you should now use PythonEngine.Shutdown().
|
||||
|
||||
- Tweaked assembly lookup to ensure that assemblies can be found in the
|
||||
current working directory, even after changing directories using things
|
||||
like os.chdir() from Python.
|
||||
|
||||
- Fixed some incorrect finalizers (thanks to Greg Chapman for the report)
|
||||
that may have caused some threading oddities.
|
||||
|
||||
- Tweaked support for out and ref parameters. If a method has a return
|
||||
type of void and a single ref or out parameter, that parameter will be
|
||||
returned as the result of the method. This matches the current behavior
|
||||
of IronPython and makes it more likely that code can be moved between
|
||||
Python for .NET and IP in the future.
|
||||
|
||||
- Refactored part of the assembly manager to remove a potential case of
|
||||
thread-deadlock in multi-threaded applications.
|
||||
|
||||
- Added a __str__ method to managed exceptions that returns the Message
|
||||
attribute of the exception and the StackTrace (if available).
|
||||
|
||||
|
||||
PythonNet 1.0 release candidate 1
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Implemented a workaround for the fact that exceptions cannot be new-style
|
||||
classes in the CPython interpreter. Managed exceptions can now be raised
|
||||
and caught naturally from Python (hooray!)
|
||||
|
||||
- Implemented support for invoking methods with out and ref parameters.
|
||||
Because there is no real equivalent to these in Python, methods that
|
||||
have out or ref parameters will return a tuple. The tuple will contain
|
||||
the result of the method as its first item, followed by out parameter
|
||||
values in the order of their declaration in the method signature.
|
||||
|
||||
- Fixed a refcount problem that caused a crash when CLR was imported in
|
||||
an existing installed Python interpreter.
|
||||
|
||||
- Added an automatic conversion from Python strings to byte[]. This makes
|
||||
it easier to pass byte[] data to managed methods (or set properties,
|
||||
etc.) as a Python string without having to write explicit conversion
|
||||
code. Also works for sbyte arrays. Note that byte and sbyte arrays
|
||||
returned from managed methods or obtained from properties or fields
|
||||
do *not* get converted to Python strings - they remain instances of
|
||||
Byte[] or SByte[].
|
||||
|
||||
- Added conversion of generic Python sequences to object arrays when
|
||||
appropriate (thanks to Mackenzie Straight for the patch).
|
||||
|
||||
- Added a bit of cautionary documentation for embedders, focused on
|
||||
correct handling of the Python global interpreter lock from managed
|
||||
code for code that calls into Python.
|
||||
|
||||
- PyObject.FromManagedObject now correctly returns the Python None object
|
||||
if the input is a null reference. Also added a new AsManagedObject
|
||||
method to PyObject, making it easier to convert a Python-wrapped managed
|
||||
object to the real managed object.
|
||||
|
||||
- Created a simple installer for windows platforms.
|
||||
|
||||
|
||||
PythonNet 1.0 beta 5
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Refactored and fixed threading and global interpreter lock handling,
|
||||
which was badly broken before. Also added a number of threading and
|
||||
GIL-handling tests.
|
||||
|
||||
- Related to the GIL fixes, added a note to embedders in the README
|
||||
about using the AcquireLock and ReleaseLock methods of the PythonEngine
|
||||
class to manage the GIL.
|
||||
|
||||
- Fixed a problem in Single <--> float conversion for cultures that use
|
||||
different decimal symbols than Python.
|
||||
|
||||
- Added a new ReloadModule method to the PythonEngine class that hooks
|
||||
Python module reloading (PyImport_ReloadModule).
|
||||
|
||||
- Added a new StringAsModule method to the PythonEngine class that can
|
||||
create a module from a managed string of code.
|
||||
|
||||
- Added a default __str__ implementation for Python wrappers of managed
|
||||
objects that calls the ToString method of the managed object.
|
||||
|
||||
|
||||
PythonNet 1.0 beta 4
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Fixed a problem that made it impossible to override "special" methods
|
||||
like __getitem__ in subclasses of managed classes. Now the tests all
|
||||
pass, and there is much rejoicing.
|
||||
|
||||
- Managed classes reflected to Python now have an __doc__ attribute that
|
||||
contains a listing of the class constructor signatures.
|
||||
|
||||
- Fixed a problem that prevented passing null (None) for array arguments.
|
||||
|
||||
- Added a number of new argument conversion tests. Thanks to Laurent
|
||||
Caumont for giving Python for .NET a good workout with managed DirectX.
|
||||
|
||||
- Updated the bundled C Python runtime and libraries to Python 2.4. The
|
||||
current release is known to also run with Python 2.3. It is known
|
||||
*not* to work with older versions due to changes in CPython type
|
||||
object structure.
|
||||
|
||||
- Mostly fixed the differences in the way that import works depending
|
||||
on whether you are using the bundled interpreter or an existing Python
|
||||
interpreter. The hack I used makes import work uniformly for imports
|
||||
done in Python modules. Unfortunately, there is still a limitation
|
||||
when using the interpreter interactively: you need to do 'import CLR'
|
||||
first before importing any sub-names when running with an existing
|
||||
Python interpreter.
|
||||
|
||||
The reason is that the first import of 'CLR' installs the CLR import
|
||||
hook, but for an existing interpreter the standard importer is still
|
||||
in control for the duration of that first import, so sub-names won't
|
||||
be found until the next import, which will use the now-installed hook.
|
||||
|
||||
- Added support to directly iterate over objects that support IEnumerator
|
||||
(as well as IEnumerable). Thanks to Greg Chapman for prodding me ;)
|
||||
|
||||
- Added a section to the README dealing with rebuilding Python for .NET
|
||||
against other CPython versions.
|
||||
|
||||
- Fixed a problem with accessing properties when only the interface for
|
||||
an object is known. For example, ICollection(ob).Count failed because
|
||||
Python for .NET mistakenly decided that Count was abstract.
|
||||
|
||||
- Fixed some problems with how COM-based objects are exposed and how
|
||||
members of inherited interfaces are exposed. Thanks to Bruce Dodson
|
||||
for patches on this.
|
||||
|
||||
- Changed the Runtime class to use a const string to target the
|
||||
appropriate CPython dll in DllImport attributes. Now you only
|
||||
have to change one line to target a new Python version.
|
||||
|
||||
|
||||
PythonNet 1.0 beta 3
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- A dumb bug that could cause a crash on startup on some platforms was
|
||||
fixed. Decided to update the beta for this, as a number of people
|
||||
were running into the problem.
|
||||
|
||||
|
||||
PythonNet 1.0 beta 2
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Exceptions raised as a result of getting or setting properties were
|
||||
not very helpful (target invokation exception). This has been changed
|
||||
to pass through the inner exception the way that methods do, which is
|
||||
much more likely to be the real exception that caused the problem.
|
||||
|
||||
- Events were refactored as the implementation was based on some bad
|
||||
assumptions. As a result, subscription and unsubscription now works
|
||||
correctly. A change from beta 1 is that event objects are no longer
|
||||
directly callable - this was not appropriate, since the internal
|
||||
implementation of an event is private and cant work reliably. Instead,
|
||||
you should the appropriate OnSomeEvent method published by a class
|
||||
to fire an event.
|
||||
|
||||
- The distribution did not include the key file, making it a pain for
|
||||
people to build from source. Added the key file to the distribution
|
||||
buildout for beta 2.
|
||||
|
||||
- Assemblies can now be found and loaded if they are on the PYTHONPATH.
|
||||
Previously only the appbase and the GAC were checked. The system now
|
||||
checks PYTHONPATH first, then the appbase, then the GAC.
|
||||
|
||||
- Fixed a bug in constructor invokation during object instantiation.
|
||||
|
||||
|
||||
PythonNet 1.0 beta 1
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Added the baseline of the managed embedding API. Some of the details
|
||||
are still subject to change based on some real-world use and feedback.
|
||||
|
||||
The embedding API is based on the PyObject class, along with a number
|
||||
of specific PyDict, PyList, (etc.) classes that expose the respective
|
||||
interfaces of the built-in Python types. The basic structure and usage
|
||||
is intended be familar to anyone who has used Python / C++ wrapper
|
||||
libraries like CXX or Boost.
|
||||
|
||||
- Started integrating NUnit2 to support unit tests for the embedding
|
||||
layer - still need to add the embedding tests (many already exist,
|
||||
but were written for an older version of NUnit).
|
||||
|
||||
- Added Python iteration protocol support for arrays and managed objects
|
||||
that implement IEnumerable. This means that you can now use the Python
|
||||
idiom 'for item in object:' on any array or IEnumerable object.
|
||||
|
||||
- Added automatic conversion from Python sequence types to managed array
|
||||
types. This means, for example, that you can now call a managed method
|
||||
like AddRange that expects an array with any Python object that supports
|
||||
the Python sequence protocol, provided the items of the sequence are
|
||||
convertible to the item type of the managed array.
|
||||
|
||||
- Added new demo scripts, mostly more substantial winforms examples.
|
||||
|
||||
- Finished the unit tests for event support, and fixed lots of problems
|
||||
with events and delegates as a result. This is one of the trickier
|
||||
parts of the integration layer, and there is good coverage of these
|
||||
in the unit tests now.
|
||||
|
||||
- Did a fair amount of profiling with an eval version of ANTS (which is
|
||||
quite nice, BTW) and made a few changes as a result.
|
||||
|
||||
- Type management was refactored, fixing the issue that caused segfaults
|
||||
when GC was enabled. Unit tests, stress tests and demo apps now all run
|
||||
nicely with Python GC enabled. There are one or two things left to fix,
|
||||
but the fixes should not have any user impact.
|
||||
|
||||
- Changed to base PythonNet on Python 2.3.2. This is considered the most
|
||||
stable release, and a good 25 - 30% faster as well.
|
||||
|
||||
- Added a new 'CLR.dll' that acts as an extension module that allows an
|
||||
existing unmodified Python 2.3 installation to simply 'import CLR' to
|
||||
bootstrap the managed integration layer.
|
||||
|
||||
- A bug was causing managed methods to only expose overloads declared in
|
||||
a particular class, hiding inherited overloads of the same name. Fixed
|
||||
the bug and added some unit tests.
|
||||
|
||||
- Added a virtual '__doc__' attribute to managed methods that contains
|
||||
the signature of the method. This also means that the Python 'help'
|
||||
function now provides signature info when used on a managed class.
|
||||
|
||||
- Calling managed methods and events 'unbound' (passing the instance as
|
||||
the first argument) now works. There is a caveat for methods - if a
|
||||
class declares both static and instance methods with the same name,
|
||||
it is not possible to call that instance method unbound (the static
|
||||
method will always be called).
|
||||
|
||||
- Overload selection for overloaded methods is now much better and uses
|
||||
a method resolution algorithm similar to that used by Jython.
|
||||
|
||||
- Changed the managed python.exe wrapper to run as an STA thread, which
|
||||
seems to be more compatible with winforms apps. This needs a better
|
||||
solution long-term. One possibility would be a command line switch
|
||||
so that -sta or -mta could control the python.exe apartment state.
|
||||
|
||||
- Added support for the Python boolean type (True, False). Bool values
|
||||
now appear as True or False to Python.
|
||||
|
||||
|
||||
PythonNet Preview 2
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Added a Mono makefile. Thanks to Camilo Uribe for help in testing and
|
||||
working out problems on Mono. Note that it not currently possible to
|
||||
build PythonNet using mono, due to the use of some IL attributes that
|
||||
the mono assembler / disassembler doesn't support yet.
|
||||
|
||||
- Preliminary tests show that PythonNet *does* actually run under mono,
|
||||
though the test suite bombs out before the end with an "out of memory"
|
||||
error from the mono runtime. It's just a guess at this point, but I
|
||||
suspect there may be a limited pool for allocating certain reflection
|
||||
structures, and Python uses the reflection infrastructure quite heavily.
|
||||
|
||||
- Removed decoys like the non-working embedding APIs; lots of internal
|
||||
refactoring.
|
||||
|
||||
- Implemented indexer support. Managed instances that implement indexers
|
||||
can now be used naturally from Python ( e.g. someobject[0] ).
|
||||
|
||||
- Implemented sequence protocol support for managed arrays.
|
||||
|
||||
- Implemented basic thread state management; calls to managed methods
|
||||
no longer block Python. I won't go so far as to say the thread
|
||||
choreography is "finished", as I don't have a comprehensive set of
|
||||
tests to back that up yet (and it will take some work to write a
|
||||
sufficiently large and evil set of tests).
|
||||
|
||||
- Fixed a bug that caused conversions of managed strings to PyUnicode to
|
||||
produce mangled values in certain situations.
|
||||
|
||||
- Fixed a number of problems related to subclassing a managed class,
|
||||
including the fact that it didn't work :)
|
||||
|
||||
- Fixed all of the bugs that were causing tests to fail. This release
|
||||
contains all new bugs and new failing tests. Progress! :)
|
||||
|
||||
|
||||
PythonNet Preview 1
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
- Initial (mostly) working experimental release.
|
|
@ -0,0 +1,210 @@
|
|||
<html>
|
||||
<head>
|
||||
|
||||
<title>Python for .NET</title>
|
||||
|
||||
<style type="text/css"><!--
|
||||
|
||||
body {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
background: #ffffff;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
p {
|
||||
font: 8pt/16pt georgia;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font: bold 14pt;
|
||||
color: #000044;
|
||||
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: bold 14pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: bold 12pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
a:link {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
text-decoration: underline;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace;
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
}
|
||||
|
||||
li {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
font: bold 14pt;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
.menu ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
//--></style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table width="98%" border="0" cellspacing="4">
|
||||
|
||||
<tr>
|
||||
<!--
|
||||
<td align="left" valign="top" width="20%" class="menu">
|
||||
|
||||
<h1>Python for .NET</h1>
|
||||
|
||||
|
||||
</td>
|
||||
-->
|
||||
|
||||
<td align="left" valign="top">
|
||||
|
||||
<h1>Python for .NET</h1>
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that this package does <em>not</em> 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
|
||||
<a href="http://www.ironpython.com">IronPython</a> project, which is in
|
||||
active development.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Python for .NET is currently compatible with Python releases 2.3 and greater.
|
||||
To subscribe to the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
Python for .NET mailing list
|
||||
</a> or read the
|
||||
<a href="http://mail.python.org/pipermail/pythondotnet/">
|
||||
online archives
|
||||
</a> of the list, see the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
mailing list information
|
||||
</a> page. You can also send questions or comments to me at
|
||||
<a href="mailto:brian.lloyd@revolution.com">brian.lloyd@revolution.com</a>
|
||||
or use the
|
||||
<a href="http://sourceforge.net/tracker/?group_id=162464">
|
||||
Python for .NET issue tracker</a> to report issues.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
My <a href="http://brianlloyd.blogspot.com">blog site</a> is also
|
||||
(sometimes) a good source for more information on Python for .NET ;)
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>The <a href="./readme.html">README</a>
|
||||
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.
|
||||
</li>
|
||||
|
||||
<li>Checkout the
|
||||
<a href="http://cvs.sourceforge.net/viewcvs.py/pythonnet">PythonNet</a>
|
||||
code
|
||||
from CVS. See the <a href="http://sourceforge.net/cvs/?group_id=162464">
|
||||
instructions on Source Forge</a> for details.
|
||||
</li>
|
||||
|
||||
<li><strong>Python 2.4 Releases</strong>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.4-clr1.1.exe">
|
||||
pythonnet-1.0-rc2-py2.4-clr1.1.exe
|
||||
</a>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.4-clr1.1-src.tgz">
|
||||
pythonnet-1.0-rc2-py2.4-clr1.1-src.tgz
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li><strong>Python 2.3 Releases</strong>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.3-clr1.1.exe">
|
||||
pythonnet-1.0-rc2-py2.3-clr1.1.exe
|
||||
</a>
|
||||
<br />
|
||||
<a href="./Releases/pythonnet-1.0-rc2-py2.3-clr1.1-src.tgz">
|
||||
pythonnet-1.0-rc2-py2.3-clr1.1-src.tgz
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,61 @@
|
|||
Zope Public License (ZPL) Version 2.0
|
||||
-----------------------------------------------
|
||||
|
||||
This software is Copyright (c) Zope Corporation (tm) and
|
||||
Contributors. All rights reserved.
|
||||
|
||||
This license has been certified as open source. It has also
|
||||
been designated as GPL compatible by the Free Software
|
||||
Foundation (FSF).
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions in source code must retain the above
|
||||
copyright notice, this list of conditions, and the following
|
||||
disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions, and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
3. The name Zope Corporation (tm) must not be used to
|
||||
endorse or promote products derived from this software
|
||||
without prior written permission from Zope Corporation.
|
||||
|
||||
4. The right to distribute this software or to use it for
|
||||
any purpose does not give you the right to use Servicemarks
|
||||
(sm) or Trademarks (tm) of Zope Corporation. Use of them is
|
||||
covered in a separate agreement (see
|
||||
http://www.zope.com/Marks).
|
||||
|
||||
5. If any files are modified, you must cause the modified
|
||||
files to carry prominent notices stating that you changed
|
||||
the files and the date of any change.
|
||||
|
||||
Disclaimer
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
|
||||
AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
|
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -0,0 +1,870 @@
|
|||
<html>
|
||||
<head>
|
||||
|
||||
<title>Python for .NET</title>
|
||||
|
||||
<style type="text/css"><!--
|
||||
|
||||
body {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
background: #ffffff;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
p {
|
||||
font: 8pt/16pt georgia;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font: bold 14pt;
|
||||
color: #000044;
|
||||
/*
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
*/
|
||||
}
|
||||
|
||||
h2 {
|
||||
font: bold 14pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font: bold 12pt;
|
||||
margin-bottom: 0px;
|
||||
color: #000044;
|
||||
}
|
||||
|
||||
a:link {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
a:hover, a:active {
|
||||
text-decoration: underline;
|
||||
color: #000066;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: monospace;
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
}
|
||||
|
||||
li {
|
||||
font: 8pt/16pt georgia,verdana;
|
||||
text-decoration: none;
|
||||
color: #555753;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
font: bold 14pt;
|
||||
}
|
||||
|
||||
.menu {
|
||||
background-color: #EFEFFF;
|
||||
color: #000044;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #555753;
|
||||
padding: 6px, 2px, 6px, 2px;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
.menu ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
//--></style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table width="98%" border="0" cellspacing="4">
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top" width="20%" class="menu">
|
||||
|
||||
<h1>Python for .NET</h1>
|
||||
|
||||
<ul>
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#getting_started">Getting Started</a></li>
|
||||
<li><a href="#importing">Importing Modules</a></li>
|
||||
<li><a href="#classes">Using Classes</a></li>
|
||||
<li><a href="#fields">Fields and Properties</a></li>
|
||||
<li><a href="#indexers">Using Indexers</a></li>
|
||||
<li><a href="#methods">Using Methods</a></li>
|
||||
<li><a href="#delegates">Delegates and Events</a></li>
|
||||
<li><a href="#exceptions">Exception Handling</a></li>
|
||||
<li><a href="#arrays">Using Arrays</a></li>
|
||||
<li><a href="#collections">Using Collections</a></li>
|
||||
<li><a href="#com">COM Components</a></li>
|
||||
<li><a href="#types">Type Conversion</a></li>
|
||||
<li><a href="#assemblies">Using Assemblies</a></li>
|
||||
<li><a href="#embedding">Embedding Python</a></li>
|
||||
<li><a href="#license">License</a></li>
|
||||
</ul>
|
||||
|
||||
</td>
|
||||
|
||||
<td align="left" valign="top">
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that this package does <em>not</em> 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
|
||||
<a href="http://www.ironpython.com">IronPython</a> project, which is in
|
||||
active development.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Python for .NET is currently compatible with Python releases 2.3 and greater.
|
||||
Current releases are available at the
|
||||
<a href="http://pythonnet.sourceforge.net/">
|
||||
Python for .NET website
|
||||
</a>. To subscribe to the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
Python for .NET mailing list
|
||||
</a> or read the
|
||||
<a href="http://mail.python.org/pipermail/pythondotnet/">
|
||||
online archives
|
||||
</a> of the list, see the
|
||||
<a href="http://mail.python.org/mailman/listinfo/pythondotnet">
|
||||
mailing list information
|
||||
</a> page.
|
||||
</p>
|
||||
|
||||
<a name="#installation"></a>
|
||||
|
||||
<h2>Installation</h2>
|
||||
|
||||
<p>
|
||||
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
|
||||
<a href="http://pythonnet.sourceforge.net/">
|
||||
Python for .NET website
|
||||
</a>. 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Running on Linux/Mono:</strong> preliminary testing shows that
|
||||
PythonNet will run under <a href="http://www.go-mono.com">Mono</a>, 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
ln -s /usr/lib/libpython2.4.so ./python24.so
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="getting_started"></a>
|
||||
|
||||
<h2>Getting Started</h2>
|
||||
|
||||
<p>
|
||||
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#").
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A good way to start is to run <strong>python.exe</strong> 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.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="importing"></a>
|
||||
|
||||
<h2>Importing Modules</h2>
|
||||
|
||||
<p>
|
||||
Python for .NET allows CLR namespaces to be treated essentially as
|
||||
Python packages. The top-level package is named <code>CLR</code>, and
|
||||
acts as the root for accessing all CLR namespaces:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import String
|
||||
import CLR.System as System
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
# This will implicitly load the System.Windows.Forms assembly
|
||||
|
||||
from CLR.System.Windows.Forms import Form
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <code>sys.path</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To load assemblies with names that do not correspond with a namespace,
|
||||
you can use the standard mechanisms provided by the CLR:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Reflection import Assembly
|
||||
|
||||
a = Assembly.LoadWithPartialName("SomeAssembly")
|
||||
|
||||
# now we can import namespaces defined in that assembly
|
||||
|
||||
from CLR.SomeNamespace import Something
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <code>dir()</code> 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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It also means that <code>from somemodule import *</code> 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 ;)
|
||||
</p>
|
||||
|
||||
|
||||
<a name="classes"></a>
|
||||
|
||||
<h2>Using Classes</h2>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Drawing import Point
|
||||
|
||||
p = Point(5, 5)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
You can also subclass managed classes in Python. See the
|
||||
<code>helloform.py</code> file in the <code>/demo</code> directory of the
|
||||
distribution for a simple Windows Forms example that demonstrates
|
||||
subclassing a managed class.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="fields"></a>
|
||||
|
||||
<h2>Fields And Properties</h2>
|
||||
|
||||
<p>
|
||||
You can get and set fields and properties of CLR objects just as if
|
||||
they were regular attributes:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import Environment
|
||||
|
||||
name = Environment.MachineName
|
||||
Environment.ExitCode = 1
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="indexers"></a>
|
||||
|
||||
<h2>Using Indexers</h2>
|
||||
|
||||
<p>
|
||||
If a managed object implements one or more indexers, you can call
|
||||
the indexer using standard Python indexing syntax:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Collections import Hashtable
|
||||
|
||||
table = Hashtable()
|
||||
table["key 1"] = "value 1"
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Overloaded indexers are supported, using the same notation one
|
||||
would use in C#:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
items[0, 2]
|
||||
|
||||
items[0, 2, 3]
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="methods"></a>
|
||||
|
||||
<h2>Using Methods</h2>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import Environment
|
||||
|
||||
drives = Environment.GetLogicalDrives()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
It is also possible to call managed methods <code>unbound</code> (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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>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.</em>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 <code>help</code> method to inspect
|
||||
a managed class:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System import Environment
|
||||
|
||||
print Environment.GetFolderPath.__doc__
|
||||
|
||||
help(Environment)
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="delegates"></a>
|
||||
|
||||
<h2>Delegates And Events</h2>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
|
||||
<p>
|
||||
Multicast delegates can be implemented by adding more callable objects
|
||||
to a delegate instance:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
d += self.method1
|
||||
d += self.method2
|
||||
d()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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
|
||||
<code>+=</code> and <code>-=</code> operators in a way very similar to
|
||||
the C# idiom:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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(...)
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="exceptions"></a>
|
||||
|
||||
<h2>Exception Handling</h2>
|
||||
|
||||
<p>
|
||||
You can raise and catch managed exceptions just the same as you would
|
||||
pure-Python exceptions:
|
||||
<pre>
|
||||
from CLR.System import NullReferenceException
|
||||
|
||||
try:
|
||||
raise NullReferenceException("aiieee!")
|
||||
except NullReferenceException, e:
|
||||
print e.Message
|
||||
print e.Source
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
|
||||
<a name="arrays"></a>
|
||||
|
||||
<h2>Using Arrays</h2>
|
||||
|
||||
<p>
|
||||
Managed arrays support the standard Python sequence protocols:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Multidimensional arrays support indexing using the same notation one
|
||||
would use in C#:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
items[0, 2]
|
||||
|
||||
items[0, 2, 3]
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="collections"></a>
|
||||
|
||||
<h2>Using Collections</h2>
|
||||
|
||||
<p>
|
||||
Managed arrays and managed objects that implement the IEnumerable
|
||||
interface can be iterated over using the standard iteration Python
|
||||
idioms:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
domain = System.AppDomain.CurrentDomain
|
||||
|
||||
for item in domain.GetAssemblies():
|
||||
name = item.GetName()
|
||||
</pre>
|
||||
|
||||
|
||||
<a name="com"></a>
|
||||
|
||||
<h2>Using COM Components</h2>
|
||||
|
||||
<p>
|
||||
Using Microsoft-provided tools such as <strong>aximp.exe</strong> and
|
||||
<strong>tlbimp.exe</strong>, 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.
|
||||
</p>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<a name="types"></a>
|
||||
|
||||
<h2>Type Conversion</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Types that do not have a logical equivalent in Python are exposed as
|
||||
instances of managed classes or structs (System.Decimal is an example).
|
||||
</p>
|
||||
<p>
|
||||
The .NET architecture makes a distinction between <code>value types</code>
|
||||
and <code>reference types</code>. Reference types are allocated on the heap,
|
||||
and value types are allocated either on the stack or in-line within an
|
||||
object.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A process called <code>boxing</code> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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".
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here is a simple example that demonstrates an issue. If you are an
|
||||
experienced C# programmer, you might write the following code:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
items = CLR.System.Array.CreateInstance(Point, 3)
|
||||
for i in range(3):
|
||||
items[i] = Point(0, 0)
|
||||
|
||||
items[0].X = 1 # won't work!!
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
While the spelling of <code>items[0].X = 1</code> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 <code>items[0]</code> itself doesn't change is that
|
||||
when you say <code>items[0]</code>, that getitem operation creates a Python
|
||||
object that holds a reference to the object at <code>items[0]</code> via a
|
||||
GCHandle. That causes a ValueType (like Point) to be boxed, so the following
|
||||
setattr (<code>.X = 1</code>) <em>changes the state of the boxed value, not
|
||||
the original unboxed value</em>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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 <code>lost
|
||||
update</code> problems (generally because an implicit boxing happened that
|
||||
was not taken into account in the code).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="assemblies"></a>
|
||||
|
||||
<h2>Using Assemblies</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
It <em>is</em> possible to load a specific version of an assembly if you
|
||||
need to using code similar to the following:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
from CLR.System.Reflection import Assembly, AssemblyName
|
||||
|
||||
name = AssemblyName(...) # set required version, etc.
|
||||
assembly = Assembly.Load(name)
|
||||
|
||||
# now import namespaces from the loaded assembly
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You <em>can</em> still use particular versions of objects in this case - you
|
||||
just have to do more work to get the right versions of objects:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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)
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
|
||||
<a name="embedding"></a>
|
||||
|
||||
<h2>Embedding Python</h2>
|
||||
|
||||
<p>
|
||||
<strong>Note:</strong> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Python runtime assembly defines a number of public classes that
|
||||
provide a subset of the functionality provided by the Python C API.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At a very high level, to embed Python in your application you
|
||||
will need to:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>Reference Python.Runtime.dll in your build environment</li>
|
||||
<li>Call PythonEngine.Intialize() to initialize Python</li>
|
||||
<li>Call PythonEngine.ImportModule(name) to import a module</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Important Note for embedders:</strong> 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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 <code>PythonEngine.AcquireLock</code>
|
||||
method. The only exception to this rule is the
|
||||
<code>PythonEngine.Initialize</code> method, which may be called at startup
|
||||
without having acquired the GIL.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When finished using Python APIs, managed code must call a corresponding
|
||||
<code>PythonEngine.ReleaseLock</code> to release the GIL and allow other
|
||||
threads to use Python.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The AcquireLock and ReleaseLock methods are thin wrappers over the
|
||||
unmanaged <code>PyGILState_Ensure</code> and <code>PyGILState_Release</code>
|
||||
functions from the Python API, and the documentation for those APIs applies
|
||||
to the managed versions.
|
||||
</p>
|
||||
|
||||
|
||||
<a name="license" />
|
||||
|
||||
<h2>License</h2>
|
||||
|
||||
<p>
|
||||
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
|
||||
<a href="http://pythonnet.sourceforge.net/license.txt">
|
||||
ZPL online
|
||||
</a>. Some distributions of this package include a copy of the C Python
|
||||
dlls and standard library, which are covered by the
|
||||
<a href="http://www.python.org/license.html">
|
||||
Python license
|
||||
</a>.
|
||||
</p>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,73 @@
|
|||
; --------------------------------------------------------------------------------
|
||||
; Setup script for Python for .NET (based on InnoSetup 5.0.8)
|
||||
; --------------------------------------------------------------------------------
|
||||
|
||||
[Setup]
|
||||
|
||||
SourceDir=..
|
||||
OutputDir=release
|
||||
|
||||
AppName=Python for .NET
|
||||
AppVerName=Python for .NET 1.0 RC2
|
||||
AppPublisher=Brian Lloyd
|
||||
AppCopyright=Copyright © 2005 Zope Corporation
|
||||
DefaultDirName={pf}\PythonNet
|
||||
DefaultGroupName=Python for .NET
|
||||
LicenseFile=installer\license.txt
|
||||
DisableProgramGroupPage=yes
|
||||
WizardImageFile=installer\left.bmp
|
||||
WizardSmallImageFile=installer\top.bmp
|
||||
WizardImageStretch=no
|
||||
|
||||
|
||||
[Tasks]
|
||||
|
||||
Name: "existing"; Description: "Install .NET support in &existing python installation"; Flags: unchecked
|
||||
Name: "icon"; Description: "Create a &desktop icon"; Flags: unchecked
|
||||
|
||||
|
||||
|
||||
[Files]
|
||||
|
||||
Source: "makefile"; DestDir: "{app}"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion
|
||||
Source: "python.exe"; DestDir: "{app}"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion
|
||||
|
||||
Source: "*.dll"; DestDir: "{app}"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion
|
||||
Source: "demo\*.*"; DestDir: "{app}\demo"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion recursesubdirs
|
||||
Source: "doc\*.*"; DestDir: "{app}\doc"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion recursesubdirs
|
||||
Source: "src\*.*"; DestDir: "{app}\src"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion recursesubdirs
|
||||
Source: "redist\2.3\*.*"; DestDir: "{app}"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion recursesubdirs
|
||||
Source: "doc/readme.html"; DestDir: "{app}/doc"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion isreadme
|
||||
|
||||
Source: "*Python.Runtime.dll"; DestDir: "{code:GetPythonDir}"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion recursesubdirs; Check: UpdateExisting
|
||||
Source: "CLR.dll"; DestDir: "{code:GetPythonDir}"; Excludes: ".svn*,~*,CVS*"; Flags: ignoreversion recursesubdirs; Check: UpdateExisting
|
||||
|
||||
[Icons]
|
||||
|
||||
Name: "{group}\Python for .NET"; Filename: "{app}\python.exe"
|
||||
Name: "{userdesktop}\Python for .NET"; Filename: "{app}\python.exe"; Tasks: icon
|
||||
|
||||
|
||||
[Code]
|
||||
|
||||
function GetPythonDir(Default: String): string;
|
||||
var
|
||||
path : string;
|
||||
begin
|
||||
path := '';
|
||||
RegQueryStringValue(HKLM, 'Software\Python\PythonCore\2.3\InstallPath', '', path);
|
||||
Result := path;
|
||||
end;
|
||||
|
||||
function UpdateExisting(): boolean;
|
||||
var
|
||||
temp: string;
|
||||
res: boolean;
|
||||
begin
|
||||
temp := WizardSelectedTasks(False);
|
||||
res := (Pos('existing', temp) <> 0);
|
||||
temp := GetPythonDir('');
|
||||
Result := res and (Pos('Python', temp) <> 0);
|
||||
end;
|
||||
|
||||
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 28 KiB |
|
@ -0,0 +1,59 @@
|
|||
Zope Public License (ZPL) Version 2.0
|
||||
-----------------------------------------------
|
||||
|
||||
This software is Copyright (c) Zope Corporation (tm) and
|
||||
Contributors. All rights reserved.
|
||||
|
||||
This license has been certified as open source. It has also
|
||||
been designated as GPL compatible by the Free Software
|
||||
Foundation (FSF).
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions in source code must retain the above
|
||||
copyright notice, this list of conditions, and the following
|
||||
disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions, and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
3. The name Zope Corporation (tm) must not be used to
|
||||
endorse or promote products derived from this software
|
||||
without prior written permission from Zope Corporation.
|
||||
|
||||
4. The right to distribute this software or to use it for
|
||||
any purpose does not give you the right to use Servicemarks
|
||||
(sm) or Trademarks (tm) of Zope Corporation. Use of them is
|
||||
covered in a separate agreement (see
|
||||
http://www.zope.com/Marks).
|
||||
|
||||
5. If any files are modified, you must cause the modified
|
||||
files to carry prominent notices stating that you changed
|
||||
the files and the date of any change.
|
||||
|
||||
Disclaimer
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS''
|
||||
AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
|
||||
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
|
||||
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.
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 4.1 KiB |
|
@ -0,0 +1,99 @@
|
|||
# Makefile for the PythonRuntime .NET assembly and tests. Thanks to
|
||||
# Camilo Uribe <kmilo@softhome.net> 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
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
# Makefile for the PythonRuntime .NET assembly and tests. Thanks to
|
||||
# Camilo Uribe <kmilo@softhome.net> 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
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// 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;
|
||||
|
||||
[assembly: System.Reflection.AssemblyProduct("Python for .NET")]
|
||||
[assembly: System.Reflection.AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyTitleAttribute("Python Console")]
|
||||
[assembly: AssemblyDefaultAliasAttribute("python.exe")]
|
||||
[assembly: CLSCompliant(true)]
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
|
||||
[assembly:PermissionSetAttribute(SecurityAction.RequestMinimum,
|
||||
Name = "FullTrust")]
|
|
@ -0,0 +1,34 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Implements a Python type for managed arrays. This type is essentially
|
||||
/// the same as a ClassObject, except that it provides sequence semantics
|
||||
/// to support natural array usage (indexing) from Python.
|
||||
/// </summary>
|
||||
|
||||
internal class ArrayObject : ClassBase {
|
||||
|
||||
internal ArrayObject(Type tp) : base(tp) {}
|
||||
|
||||
internal override bool CanSubclass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// 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")]
|
|
@ -0,0 +1,300 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Base class for Python types that reflect managed types / classes.
|
||||
/// Concrete subclasses include ClassObject and DelegateObject. This
|
||||
/// class provides common attributes and common machinery for doing
|
||||
/// class initialization (initialization of the class __dict__). The
|
||||
/// concrete subclasses provide slot implementations appropriate for
|
||||
/// each variety of reflected type.
|
||||
/// </summary>
|
||||
|
||||
internal class ClassBase : ManagedType {
|
||||
|
||||
internal 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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,331 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// The ClassManager is responsible for creating and managing instances
|
||||
/// that implement the Python type objects that reflect managed classes.
|
||||
///
|
||||
/// Each managed type reflected to Python is represented by an instance
|
||||
/// of a concrete subclass of ClassBase. Each instance is associated with
|
||||
/// a generated Python type object, whose slots point to static methods
|
||||
/// of the managed instance's class.
|
||||
/// </summary>
|
||||
|
||||
internal class ClassManager {
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Managed class that provides the implementation for reflected types.
|
||||
/// Managed classes and value types are represented in Python by actual
|
||||
/// Python type objects. Each of those type objects is associated with
|
||||
/// an instance of ClassObject, which provides its implementation.
|
||||
/// </summary>
|
||||
|
||||
internal class ClassObject : ClassBase {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// 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
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Several places in the runtime generate code on the fly to support
|
||||
/// dynamic functionality. The CodeGenerator class manages the dynamic
|
||||
/// assembly used for code generation and provides utility methods for
|
||||
/// certain repetitive tasks.
|
||||
/// </summary>
|
||||
|
||||
internal class CodeGenerator {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,668 @@
|
|||
// 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Debugging helper utilities.
|
||||
/// </summary>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// The DelegateManager class manages the creation of true managed
|
||||
/// delegate instances that dispatch calls to Python methods.
|
||||
/// </summary>
|
||||
|
||||
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) {}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Managed class that provides the implementation for reflected delegate
|
||||
/// types. Delegates are represented in Python by generated type objects.
|
||||
/// Each of those type objects is associated an instance of this class,
|
||||
/// which provides its implementation.
|
||||
/// </summary>
|
||||
|
||||
internal class DelegateObject : ClassBase {
|
||||
|
||||
MethodBinder binder;
|
||||
|
||||
internal DelegateObject(Type tp) : base(tp) {
|
||||
binder = new MethodBinder(tp.GetMethod("Invoke"));
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Given a PyObject pointer to an instance of a delegate type, return
|
||||
// the true managed delegate the Python object represents (or null).
|
||||
//====================================================================
|
||||
|
||||
private static Delegate GetTrueDelegate(IntPtr op) {
|
||||
CLRObject o = GetManagedObject(op) as CLRObject;
|
||||
if (o != null) {
|
||||
Delegate d = o.inst as Delegate;
|
||||
return d;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
internal override bool CanSubclass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// DelegateObject __new__ implementation. The result of this is a new
|
||||
// PyObject whose type is DelegateObject and whose ob_data is a handle
|
||||
// to an actual delegate instance. The method wrapped by the actual
|
||||
// delegate instance belongs to an object generated to relay the call
|
||||
// to the Python callable passed in.
|
||||
//====================================================================
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
// 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("<event '{0}'>", 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,381 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates the Python exception APIs.
|
||||
/// </summary>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetException Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Retrieve Python exception information as a PythonException
|
||||
/// instance. The properties of the PythonException may be used
|
||||
/// to access the exception type, value and traceback info.
|
||||
/// </remarks>
|
||||
|
||||
public static PythonException GetException() {
|
||||
// TODO: implement this.
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExceptionMatches Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the current Python exception matches the given
|
||||
/// Python object. This is a wrapper for PyErr_ExceptionMatches.
|
||||
/// </remarks>
|
||||
|
||||
public static bool ExceptionMatches(IntPtr ob) {
|
||||
return Runtime.PyErr_ExceptionMatches(ob) != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ExceptionMatches Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given Python exception matches the given
|
||||
/// Python object. This is a wrapper for PyErr_GivenExceptionMatches.
|
||||
/// </remarks>
|
||||
|
||||
public static bool ExceptionMatches(IntPtr exc, IntPtr ob) {
|
||||
int i = Runtime.PyErr_GivenExceptionMatches(exc, ob);
|
||||
return (i != 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetError Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the current Python exception given a native string.
|
||||
/// This is a wrapper for the Python PyErr_SetString call.
|
||||
/// </remarks>
|
||||
|
||||
public static void SetError(IntPtr ob, string value) {
|
||||
Runtime.PyErr_SetString(ob, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetError Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the current Python exception given a Python object.
|
||||
/// This is a wrapper for the Python PyErr_SetObject call.
|
||||
/// </remarks>
|
||||
|
||||
public static void SetError(IntPtr ob, IntPtr value) {
|
||||
Runtime.PyErr_SetObject(ob, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// SetError Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the current Python exception given a CLR exception
|
||||
/// object. The CLR exception instance is wrapped as a Python
|
||||
/// object, allowing it to be handled naturally from Python.
|
||||
/// </remarks>
|
||||
|
||||
public static void SetError(Exception e) {
|
||||
|
||||
// Because delegates allow arbitrary nestings of Python calling
|
||||
// managed calling Python calling... etc. it is possible that we
|
||||
// might get a managed exception raised that is a wrapper for a
|
||||
// Python exception. In that case we'd rather have the real thing.
|
||||
|
||||
PythonException pe = e as PythonException;
|
||||
if (pe != null) {
|
||||
Runtime.PyErr_SetObject(pe.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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ErrorOccurred Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if an exception occurred in the Python runtime.
|
||||
/// This is a wrapper for the Python PyErr_Occurred call.
|
||||
/// </remarks>
|
||||
|
||||
public static bool ErrorOccurred() {
|
||||
return Runtime.PyErr_Occurred() != 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Clear any exception that has been set in the Python runtime.
|
||||
/// </remarks>
|
||||
|
||||
public static void Clear() {
|
||||
Runtime.PyErr_Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================================================================
|
||||
// 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Base class for extensions whose instances *share* a single Python
|
||||
/// type object, such as the types that represent CLR methods, fields,
|
||||
/// etc. Instances implemented by this class do not support subtyping.
|
||||
/// </summary>
|
||||
|
||||
internal abstract class ExtensionType : ManagedType {
|
||||
|
||||
public ExtensionType() : base() {
|
||||
|
||||
// Create a new PyObject whose type is a generated type that is
|
||||
// implemented by the particuar concrete ExtensionType subclass.
|
||||
// The Python instance object is related to an instance of a
|
||||
// particular concrete subclass with a hidden CLR gchandle.
|
||||
|
||||
IntPtr tp = TypeManager.GetTypeHandle(this.GetType());
|
||||
|
||||
// int rc = (int)Marshal.ReadIntPtr(tp, TypeOffset.ob_refcnt);
|
||||
// if (rc > 1050) {
|
||||
// DebugUtil.Print("tp is: ", tp);
|
||||
// DebugUtil.DumpType(tp);
|
||||
// }
|
||||
|
||||
IntPtr py = Runtime.PyType_GenericAlloc(tp, 0);
|
||||
|
||||
GCHandle gc = GCHandle.Alloc(this);
|
||||
Marshal.WriteIntPtr(py, ObjectOffset.magic(), (IntPtr)gc);
|
||||
|
||||
// We have to support gc because the type machinery makes it very
|
||||
// hard not to - but we really don't have a need for it in most
|
||||
// concrete extension types, so untrack the object to save calls
|
||||
// from Python into the managed runtime that are pure overhead.
|
||||
|
||||
Runtime.PyObject_GC_UnTrack(py);
|
||||
|
||||
this.tpHandle = tp;
|
||||
this.pyHandle = py;
|
||||
this.gcHandle = gc;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Common finalization code to support custom tp_deallocs.
|
||||
//====================================================================
|
||||
|
||||
public static void FinalizeObject(ManagedType self) {
|
||||
Runtime.PyObject_GC_Del(self.pyHandle);
|
||||
Runtime.Decref(self.tpHandle);
|
||||
self.gcHandle.Free();
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// Type __setattr__ implementation.
|
||||
//====================================================================
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
// 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("<field '{0}'>", self.info.Name);
|
||||
return Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Provides the implementation for reflected interface types. Managed
|
||||
/// interfaces are represented in Python by actual Python type objects.
|
||||
/// Each of those type objects is associated with an instance of this
|
||||
/// class, which provides the implementation for the Python type.
|
||||
/// </summary>
|
||||
|
||||
internal class InterfaceObject : ClassBase {
|
||||
|
||||
internal ConstructorInfo ctor;
|
||||
|
||||
internal InterfaceObject(Type tp) : base(tp) {
|
||||
CoClassAttribute coclass = (CoClassAttribute)
|
||||
Attribute.GetCustomAttribute(tp, cc_attr);
|
||||
if (coclass != null) {
|
||||
ctor = coclass.CoClass.GetConstructor(Type.EmptyTypes);
|
||||
}
|
||||
}
|
||||
|
||||
static Type cc_attr;
|
||||
|
||||
static InterfaceObject() {
|
||||
cc_attr = typeof(CoClassAttribute);
|
||||
}
|
||||
|
||||
//====================================================================
|
||||
// Implements __new__ for reflected interface types.
|
||||
//====================================================================
|
||||
|
||||
[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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,408 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// ===========================================================================
|
||||
//
|
||||
// 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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
// 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("<method '{0}'>", 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// A MethodWrapper wraps a static method of a managed type,
|
||||
/// making it callable by Python as a PyCFunction object. This is
|
||||
/// currently used mainly to implement special cases like the CLR
|
||||
/// import hook.
|
||||
/// </summary>
|
||||
|
||||
internal class MethodWrapper {
|
||||
|
||||
public IntPtr mdef;
|
||||
public IntPtr ptr;
|
||||
|
||||
public MethodWrapper(Type type, string name) {
|
||||
|
||||
// Turn the managed method into a function pointer
|
||||
|
||||
IntPtr fp = Interop.GetThunk(type.GetMethod(name));
|
||||
|
||||
// XXX - here we create a Python string object, then take the
|
||||
// char * of the internal string to pass to our methoddef
|
||||
// structure. Its a hack, and the name is leaked!
|
||||
|
||||
IntPtr ps = Runtime.PyString_FromString(name);
|
||||
IntPtr sp = Runtime.PyString_AS_STRING(ps);
|
||||
|
||||
// Allocate and initialize a PyMethodDef structure to represent
|
||||
// the managed method, then create a PyCFunction.
|
||||
|
||||
mdef = Runtime.PyMem_Malloc(4 * IntPtr.Size);
|
||||
Marshal.WriteIntPtr(mdef, sp);
|
||||
Marshal.WriteIntPtr(mdef, (1 * IntPtr.Size), fp);
|
||||
Marshal.WriteIntPtr(mdef, (2 * IntPtr.Size), (IntPtr)0x0002);
|
||||
Marshal.WriteIntPtr(mdef, (3 * IntPtr.Size), IntPtr.Zero);
|
||||
ptr = Runtime.PyCFunction_New(mdef, IntPtr.Zero);
|
||||
}
|
||||
|
||||
public IntPtr Call(IntPtr args, IntPtr kw) {
|
||||
return Runtime.PyCFunction_Call(ptr, args, kw);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
// 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("<module '{0}'>", self.moduleName);
|
||||
return Runtime.PyString_FromString(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Provides support for calling native code indirectly through
|
||||
/// function pointers. Most of the important parts of the Python
|
||||
/// C API can just be wrapped with p/invoke, but there are some
|
||||
/// situations (specifically, calling functions through Python
|
||||
/// type structures) where we need to call functions indirectly.
|
||||
///
|
||||
/// This class uses Reflection.Emit to generate IJW thunks that
|
||||
/// support indirect calls to native code using various common
|
||||
/// call signatures. This is mainly a workaround for the fact
|
||||
/// that you can't spell an indirect call in C# (but can in IL).
|
||||
///
|
||||
/// Another approach that would work is for this to be turned
|
||||
/// into a separate utility program that could be run during the
|
||||
/// build process to generate the thunks as a separate assembly
|
||||
/// that could then be referenced by the main Python runtime.
|
||||
/// </summary>
|
||||
|
||||
internal class NativeCall {
|
||||
|
||||
static AssemblyBuilder aBuilder;
|
||||
static ModuleBuilder mBuilder;
|
||||
|
||||
public static INativeCall Impl;
|
||||
|
||||
static NativeCall() {
|
||||
|
||||
// The static constructor is responsible for generating the
|
||||
// assembly and the methods that implement the IJW thunks.
|
||||
//
|
||||
// To do this, we actually use reflection on the INativeCall
|
||||
// interface (defined below) and generate the required thunk
|
||||
// code based on the method signatures.
|
||||
|
||||
AssemblyName aname = new AssemblyName();
|
||||
aname.Name = "e__NativeCall_Assembly";
|
||||
AssemblyBuilderAccess aa = AssemblyBuilderAccess.Run;
|
||||
|
||||
aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa);
|
||||
mBuilder = aBuilder.DefineDynamicModule("e__NativeCall_Module");
|
||||
|
||||
TypeAttributes ta = TypeAttributes.Public;
|
||||
TypeBuilder tBuilder = mBuilder.DefineType("e__NativeCall", ta);
|
||||
|
||||
Type iType = typeof(INativeCall);
|
||||
tBuilder.AddInterfaceImplementation(iType);
|
||||
|
||||
// Use reflection to loop over the INativeCall interface methods,
|
||||
// calling GenerateThunk to create a managed thunk for each one.
|
||||
|
||||
foreach (MethodInfo method in iType.GetMethods()) {
|
||||
GenerateThunk(tBuilder, method);
|
||||
}
|
||||
|
||||
Type theType = tBuilder.CreateType();
|
||||
|
||||
Impl = (INativeCall)Activator.CreateInstance(theType);
|
||||
|
||||
}
|
||||
|
||||
private static void GenerateThunk(TypeBuilder tb, MethodInfo method) {
|
||||
|
||||
ParameterInfo[] pi = method.GetParameters();
|
||||
int count = pi.Length;
|
||||
int argc = count - 1;
|
||||
|
||||
Type[] args = new Type[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
args[i] = pi[i].ParameterType;
|
||||
}
|
||||
|
||||
MethodBuilder mb = tb.DefineMethod(
|
||||
method.Name,
|
||||
MethodAttributes.Public |
|
||||
MethodAttributes.Virtual,
|
||||
method.ReturnType,
|
||||
args
|
||||
);
|
||||
|
||||
// Build the method signature for the actual native function.
|
||||
// This is essentially the signature of the wrapper method
|
||||
// minus the first argument (the passed in function pointer).
|
||||
|
||||
Type[] nargs = new Type[argc];
|
||||
for (int i = 1; i < count; i++) {
|
||||
nargs[(i - 1)] = args[i];
|
||||
}
|
||||
|
||||
// IL generation: the (implicit) first argument of the method
|
||||
// is the 'this' pointer and the second is the function pointer.
|
||||
// This code pushes the real args onto the stack, followed by
|
||||
// the function pointer, then the calli opcode to make the call.
|
||||
|
||||
ILGenerator il = mb.GetILGenerator();
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
il.Emit(OpCodes.Ldarg_S, (i + 2));
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
il.EmitCalli(OpCodes.Calli,
|
||||
CallingConvention.Cdecl,
|
||||
method.ReturnType,
|
||||
nargs
|
||||
);
|
||||
|
||||
il.Emit(OpCodes.Ret);
|
||||
|
||||
tb.DefineMethodOverride(mb, method);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
public static void Void_Call_1(IntPtr fp, IntPtr a1) {
|
||||
Impl.Void_Call_1(fp, a1);
|
||||
}
|
||||
|
||||
public static IntPtr Call_3(IntPtr fp, IntPtr a1, IntPtr a2,
|
||||
IntPtr a3) {
|
||||
return Impl.Call_3(fp, a1, a2, a3);
|
||||
}
|
||||
|
||||
public static int Int_Call_3(IntPtr fp, IntPtr a1, IntPtr a2,
|
||||
IntPtr a3) {
|
||||
return Impl.Int_Call_3(fp, a1, a2, a3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Defines native call signatures to be generated by NativeCall.
|
||||
/// </summary>
|
||||
|
||||
public interface INativeCall {
|
||||
|
||||
void Void_Call_0(IntPtr funcPtr);
|
||||
|
||||
void Void_Call_1(IntPtr funcPtr, IntPtr arg1);
|
||||
|
||||
int Int_Call_3(IntPtr funcPtr, IntPtr t, IntPtr n, IntPtr v);
|
||||
|
||||
IntPtr Call_3(IntPtr funcPtr, IntPtr a1, IntPtr a2, IntPtr a3);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
// 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("<property '{0}'>", self.info.Name);
|
||||
return Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python dictionary object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/dictObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyDict : PyObject {
|
||||
|
||||
/// <summary>
|
||||
/// PyDict Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyDict from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyDict Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python dictionary object.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict() : base() {
|
||||
obj = Runtime.PyDict_New();
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyDict Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyDict from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python dictionary object.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict(PyObject o) : base() {
|
||||
if (!IsDictType(o)) {
|
||||
throw new ArgumentException("object is not a dict");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsDictType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsDictType(PyObject value) {
|
||||
return Runtime.PyDict_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasKey Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object key appears in the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasKey(PyObject key) {
|
||||
return (Runtime.PyMapping_HasKey(obj, key.obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasKey Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the string key appears in the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasKey(string key) {
|
||||
return HasKey(new PyString(key));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Keys Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a sequence containing the keys of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Keys() {
|
||||
IntPtr items = Runtime.PyDict_Keys(obj);
|
||||
if (items == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(items);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Values Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a sequence containing the values of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Values() {
|
||||
IntPtr items = Runtime.PyDict_Values(obj);
|
||||
if (items == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(items);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Items Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a sequence containing the items of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Items() {
|
||||
IntPtr items = Runtime.PyDict_Items(obj);
|
||||
if (items == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(items);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Copy Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns a copy of the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public PyDict Copy() {
|
||||
IntPtr op = Runtime.PyDict_Copy(obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyDict(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Update the dictionary from another dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public void Update(PyObject other) {
|
||||
int result = Runtime.PyDict_Update(obj, other.obj);
|
||||
if (result < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clear Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Clears the dictionary.
|
||||
/// </remarks>
|
||||
|
||||
public void Clear() {
|
||||
Runtime.PyDict_Clear(obj);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python float object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/floatObjects.html
|
||||
/// </summary>
|
||||
|
||||
public class PyFloat : PyNumber {
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyFloat from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyFloat from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python float object.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(PyObject o) : base() {
|
||||
if (!IsFloatType(o)) {
|
||||
throw new ArgumentException("object is not a float");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python float from a double value.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(double value) : base() {
|
||||
obj = Runtime.PyFloat_FromDouble(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyFloat Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python float from a string value.
|
||||
/// </remarks>
|
||||
|
||||
public PyFloat(string value) : base() {
|
||||
PyString s = new PyString(value);
|
||||
obj = Runtime.PyFloat_FromString(s.obj, IntPtr.Zero);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsFloatType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python float.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsFloatType(PyObject value) {
|
||||
return Runtime.PyFloat_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsFloat Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python float if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "float(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyFloat AsFloat(PyObject value) {
|
||||
IntPtr op = Runtime.PyNumber_Float(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyFloat(op);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python integer object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/intObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyInt : PyNumber {
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyInt from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyInt from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python int object.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(PyObject o) : base() {
|
||||
if (!IsIntType(o)) {
|
||||
throw new ArgumentException("object is not an int");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an int32 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(int value) : base() {
|
||||
obj = Runtime.PyInt_FromInt32(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a uint32 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(uint value) : base(IntPtr.Zero) {
|
||||
obj = Runtime.PyInt_FromInt64((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an int64 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(long value) : base(IntPtr.Zero) {
|
||||
obj = Runtime.PyInt_FromInt64(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a uint64 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(ulong value) : base(IntPtr.Zero) {
|
||||
obj = Runtime.PyInt_FromInt64((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an int16 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(short value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a uint16 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(ushort value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a byte value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(byte value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from an sbyte value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyInt(sbyte value) : this((int)value) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyInt Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python int from a string value.
|
||||
/// </remarks>
|
||||
|
||||
public PyInt(string value) : base() {
|
||||
obj = Runtime.PyInt_FromString(value, IntPtr.Zero, 0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsIntType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python int.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsIntType(PyObject value) {
|
||||
return Runtime.PyInt_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsInt Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python int if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "int(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyInt AsInt(PyObject value) {
|
||||
IntPtr op = Runtime.PyNumber_Int(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyInt(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt16 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python int object as an int16.
|
||||
/// </remarks>
|
||||
|
||||
public short ToInt16() {
|
||||
return System.Convert.ToInt16(this.ToInt32());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt32 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python int object as an int32.
|
||||
/// </remarks>
|
||||
|
||||
public int ToInt32() {
|
||||
return Runtime.PyInt_AsLong(obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToInt64 Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the value of the Python int object as an int64.
|
||||
/// </remarks>
|
||||
|
||||
public long ToInt64() {
|
||||
return System.Convert.ToInt64(this.ToInt32());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a standard Python list object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/listObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyList : PySequence {
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyList from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyList(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyList from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python list object.
|
||||
/// </remarks>
|
||||
|
||||
public PyList(PyObject o) : base() {
|
||||
if (!IsListType(o)) {
|
||||
throw new ArgumentException("object is not a list");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new empty Python list object.
|
||||
/// </remarks>
|
||||
|
||||
public PyList() : base() {
|
||||
obj = Runtime.PyList_New(0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyList Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new Python list object from an array of PyObjects.
|
||||
/// </remarks>
|
||||
|
||||
public PyList(PyObject[] items) : base() {
|
||||
int count = items.Length;
|
||||
obj = Runtime.PyList_New(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntPtr ptr = items[i].obj;
|
||||
Runtime.Incref(ptr);
|
||||
int r = Runtime.PyList_SetItem(obj, i, ptr);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsListType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python list.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsListType(PyObject value) {
|
||||
return Runtime.PyList_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsList Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Converts a Python object to a Python list if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "list(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyList AsList(PyObject value) {
|
||||
IntPtr op = Runtime.PySequence_List(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyList(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Append Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Append an item to the list object.
|
||||
/// </remarks>
|
||||
|
||||
public void Append(PyObject item) {
|
||||
int r = Runtime.PyList_Append(obj, item.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Insert an item in the list object at the given index.
|
||||
/// </remarks>
|
||||
|
||||
public void Insert(int index, PyObject item) {
|
||||
int r = Runtime.PyList_Insert(obj, index, item.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reverse Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Reverse the order of the list object in place.
|
||||
/// </remarks>
|
||||
|
||||
public void Reverse() {
|
||||
int r = Runtime.PyList_Reverse(obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sort Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sort the list in place.
|
||||
/// </remarks>
|
||||
|
||||
public void Sort() {
|
||||
int r = Runtime.PyList_Sort(obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python long int object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/longObjects.html
|
||||
/// </summary>
|
||||
|
||||
public class PyLong : PyNumber {
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyLong from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python long object.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(PyObject o) : base() {
|
||||
if (!IsLongType(o)) {
|
||||
throw new ArgumentException("object is not a long");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an int32 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(int value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a uint32 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(uint value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an int64 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(long value) : base() {
|
||||
obj = Runtime.PyLong_FromLong(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a uint64 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(ulong value) : base() {
|
||||
obj = Runtime.PyLong_FromUnsignedLongLong(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an int16 value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(short value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an uint16 value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(ushort value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a byte value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(byte value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an sbyte value.
|
||||
/// </remarks>
|
||||
|
||||
[CLSCompliant(false)]
|
||||
public PyLong(sbyte value) : base() {
|
||||
obj = Runtime.PyLong_FromLong((long)value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from an double value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(double value) : base() {
|
||||
obj = Runtime.PyLong_FromDouble(value);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyLong Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyLong from a string value.
|
||||
/// </remarks>
|
||||
|
||||
public PyLong(string value) : base() {
|
||||
obj = Runtime.PyLong_FromString(value, IntPtr.Zero, 0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsLongType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python long.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsLongType(PyObject value) {
|
||||
return Runtime.PyLong_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsLong Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python long if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "long(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyLong AsLong(PyObject value) {
|
||||
IntPtr op = Runtime.PyNumber_Long(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyLong(op);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generic Python number. The methods of this class are
|
||||
/// equivalent to the Python "abstract number API". See
|
||||
/// http://www.python.org/doc/current/api/number.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyNumber : PyObject {
|
||||
|
||||
protected PyNumber(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
protected PyNumber() : base() {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsNumberType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python numeric type.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsNumberType(PyObject value) {
|
||||
return Runtime.PyNumber_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
// TODO: add all of the PyNumber_XXX methods.
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,873 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generic Python object. The methods of this class are
|
||||
/// generally equivalent to the Python "abstract object API". See
|
||||
/// http://www.python.org/doc/current/api/object.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyObject : IDisposable {
|
||||
|
||||
protected internal IntPtr obj = IntPtr.Zero;
|
||||
private bool disposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// PyObject Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyObject from an IntPtr object reference. Note that
|
||||
/// the PyObject instance assumes ownership of the object reference
|
||||
/// and the reference will be DECREFed when the PyObject is garbage
|
||||
/// collected or explicitly disposed.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject(IntPtr ptr) {
|
||||
obj = ptr;
|
||||
}
|
||||
|
||||
// Protected default constructor to allow subclasses to manage
|
||||
// initialization in different ways as appropriate.
|
||||
|
||||
protected PyObject() {}
|
||||
|
||||
// Ensure that encapsulated Python object is decref'ed appropriately
|
||||
// when the managed wrapper is garbage-collected.
|
||||
|
||||
~PyObject() {
|
||||
Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handle Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Gets the native handle of the underlying Python object. This
|
||||
/// value is generally for internal use by the PythonNet runtime.
|
||||
/// </remarks>
|
||||
|
||||
public IntPtr Handle {
|
||||
get { return obj; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// FromManagedObject Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given an arbitrary managed object, return a Python instance that
|
||||
/// reflects the managed object.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject FromManagedObject(object ob) {
|
||||
// Special case: if ob is null, we return None.
|
||||
if (ob == null) {
|
||||
Runtime.Incref(Runtime.PyNone);
|
||||
return new PyObject(Runtime.PyNone);
|
||||
}
|
||||
IntPtr op = CLRObject.GetInstHandle(ob);
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsManagedObject Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a managed object of the given type, based on the
|
||||
/// value of the Python object.
|
||||
/// </remarks>
|
||||
|
||||
public object AsManagedObject(Type t) {
|
||||
Object result;
|
||||
if (!Converter.ToManaged(this.Handle, t, out result, false)) {
|
||||
throw new InvalidCastException(
|
||||
"cannot convert object to target type"
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// The Dispose method provides a way to explicitly release the
|
||||
/// Python object represented by a PyObject instance. It is a good
|
||||
/// idea to call Dispose on PyObjects that wrap resources that are
|
||||
/// limited or need strict lifetime control. Otherwise, references
|
||||
/// to Python objects will not be released until a managed garbage
|
||||
/// collection occurs.
|
||||
/// </remarks>
|
||||
|
||||
public void Dispose() {
|
||||
if (!disposed) {
|
||||
if (Runtime.Py_IsInitialized() > 0) {
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
Runtime.Decref(obj);
|
||||
obj = IntPtr.Zero;
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetPythonType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the Python type of the object. This method is equivalent
|
||||
/// to the Python expression: type(object).
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetPythonType() {
|
||||
IntPtr tp = Runtime.PyObject_Type(obj);
|
||||
return new PyObject(tp);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// TypeCheck Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object o is of type typeOrClass or a subtype
|
||||
/// of typeOrClass.
|
||||
/// </remarks>
|
||||
|
||||
public bool TypeCheck(PyObject typeOrClass) {
|
||||
return Runtime.PyObject_TypeCheck(obj, typeOrClass.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object has an attribute with the given name.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasAttr(string name) {
|
||||
return (Runtime.PyObject_HasAttrString(obj, name) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// HasAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object has an attribute with the given name,
|
||||
/// where name is a PyObject wrapping a string or unicode object.
|
||||
/// </remarks>
|
||||
|
||||
public bool HasAttr(PyObject name) {
|
||||
return (Runtime.PyObject_HasAttr(obj, name.obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object, or raises a
|
||||
/// PythonException if the attribute access fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(string name) {
|
||||
IntPtr op = Runtime.PyObject_GetAttrString(obj, name);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object, or the given
|
||||
/// default object if the attribute access fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(string name, PyObject _default) {
|
||||
IntPtr op = Runtime.PyObject_GetAttrString(obj, name);
|
||||
if (op == IntPtr.Zero) {
|
||||
Runtime.PyErr_Clear();
|
||||
return _default;
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object or raises a
|
||||
/// PythonException if the attribute access fails. The name argument
|
||||
/// is a PyObject wrapping a Python string or unicode object.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(PyObject name) {
|
||||
IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the named attribute of the Python object, or the given
|
||||
/// default object if the attribute access fails. The name argument
|
||||
/// is a PyObject wrapping a Python string or unicode object.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetAttr(PyObject name, PyObject _default) {
|
||||
IntPtr op = Runtime.PyObject_GetAttr(obj, name.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
Runtime.PyErr_Clear();
|
||||
return _default;
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Set an attribute of the object with the given name and value. This
|
||||
/// method throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void SetAttr(string name, PyObject value) {
|
||||
int r = Runtime.PyObject_SetAttrString(obj, name, value.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Set an attribute of the object with the given name and value,
|
||||
/// where the name is a Python string or unicode object. This method
|
||||
/// throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void SetAttr(PyObject name, PyObject value) {
|
||||
int r = Runtime.PyObject_SetAttr(obj, name.obj, value.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Delete the named attribute of the Python object. This method
|
||||
/// throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void DelAttr(string name) {
|
||||
int r = Runtime.PyObject_SetAttrString(obj, name, IntPtr.Zero);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelAttr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Delete the named attribute of the Python object, where name is a
|
||||
/// PyObject wrapping a Python string or unicode object. This method
|
||||
/// throws a PythonException if the attribute set fails.
|
||||
/// </remarks>
|
||||
|
||||
public void DelAttr(PyObject name) {
|
||||
int r = Runtime.PyObject_SetAttr(obj, name.obj, IntPtr.Zero);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// return the item at the given object index. This method raises a
|
||||
/// PythonException if the indexing operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject GetItem(PyObject key) {
|
||||
IntPtr op = Runtime.PyObject_GetItem(obj, key.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// return the item at the given string index. This method raises a
|
||||
/// PythonException if the indexing operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject GetItem(string key) {
|
||||
return GetItem(new PyString(key));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// return the item at the given numeric index. This method raises a
|
||||
/// PythonException if the indexing operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject GetItem(int index) {
|
||||
PyInt key = new PyInt(index);
|
||||
return GetItem((PyObject)key);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// set the item at the given object index to the given value. This
|
||||
/// method raises a PythonException if the set operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void SetItem(PyObject key, PyObject value) {
|
||||
int r = Runtime.PyObject_SetItem(obj, key.obj, value.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// set the item at the given string index to the given value. This
|
||||
/// method raises a PythonException if the set operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void SetItem(string key, PyObject value) {
|
||||
SetItem(new PyString(key), value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// set the item at the given numeric index to the given value. This
|
||||
/// method raises a PythonException if the set operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void SetItem(int index, PyObject value) {
|
||||
SetItem(new PyInt(index), value);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// delete the item at the given object index. This method raises a
|
||||
/// PythonException if the delete operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void DelItem(PyObject key) {
|
||||
int r = Runtime.PyObject_DelItem(obj, key.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// delete the item at the given string index. This method raises a
|
||||
/// PythonException if the delete operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void DelItem(string key) {
|
||||
DelItem(new PyString(key));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelItem Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For objects that support the Python sequence or mapping protocols,
|
||||
/// delete the item at the given numeric index. This method raises a
|
||||
/// PythonException if the delete operation fails.
|
||||
/// </remarks>
|
||||
|
||||
public virtual void DelItem(int index) {
|
||||
DelItem(new PyInt(index));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Length Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the length for objects that support the Python sequence
|
||||
/// protocol, or 0 if the object does not support the protocol.
|
||||
/// </remarks>
|
||||
|
||||
public virtual int Length() {
|
||||
int s = Runtime.PyObject_Size(obj);
|
||||
if (s < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// String Indexer
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Provides a shorthand for the string versions of the GetItem and
|
||||
/// SetItem methods.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject this[string key] {
|
||||
get { return GetItem(key); }
|
||||
set { SetItem(key, value); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyObject Indexer
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Provides a shorthand for the object versions of the GetItem and
|
||||
/// SetItem methods.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject this[PyObject key] {
|
||||
get { return GetItem(key); }
|
||||
set { SetItem(key, value); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Numeric Indexer
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Provides a shorthand for the numeric versions of the GetItem and
|
||||
/// SetItem methods.
|
||||
/// </remarks>
|
||||
|
||||
public virtual PyObject this[int index] {
|
||||
get { return GetItem(index); }
|
||||
set { SetItem(index, value); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetIterator Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a new (Python) iterator for the object. This is equivalent
|
||||
/// to the Python expression "iter(object)". A PythonException will be
|
||||
/// raised if the object cannot be iterated.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetIterator() {
|
||||
IntPtr r = Runtime.PyObject_GetIter(obj);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given arguments, passed as a
|
||||
/// PyObject[]. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(params PyObject[] args) {
|
||||
PyTuple t = new PyTuple(args);
|
||||
IntPtr r = Runtime.PyObject_Call(obj, t.obj, IntPtr.Zero);
|
||||
t.Dispose();
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given arguments, passed as a
|
||||
/// Python tuple. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(PyTuple args) {
|
||||
IntPtr r = Runtime.PyObject_Call(obj, args.obj, IntPtr.Zero);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given positional and keyword
|
||||
/// arguments. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(PyObject[] args, PyDict kw) {
|
||||
PyTuple t = new PyTuple(args);
|
||||
IntPtr r = Runtime.PyObject_Call(obj, t.obj, kw.obj);
|
||||
t.Dispose();
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invoke Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the callable object with the given positional and keyword
|
||||
/// arguments. A PythonException is raised if the invokation fails.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Invoke(PyTuple args, PyDict kw) {
|
||||
IntPtr r = Runtime.PyObject_Call(obj, args.obj, kw.obj);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, params PyObject[] args) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, PyTuple args) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments
|
||||
/// and keyword arguments. Keyword args are passed as a PyDict object.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, PyObject[] args, PyDict kw) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args, kw);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// InvokeMethod Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Invoke the named method of the object with the given arguments
|
||||
/// and keyword arguments. Keyword args are passed as a PyDict object.
|
||||
/// A PythonException is raised if the invokation is unsuccessful.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject InvokeMethod(string name, PyTuple args, PyDict kw) {
|
||||
PyObject method = GetAttr(name);
|
||||
PyObject result = method.Invoke(args, kw);
|
||||
method.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsInstance Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the object is an instance of the given Python type
|
||||
/// or class. This method always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsInstance(PyObject typeOrClass) {
|
||||
int r = Runtime.PyObject_IsInstance(obj, typeOrClass.obj);
|
||||
if (r < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
return (r != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsSubclass Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the object is identical to or derived from the
|
||||
/// given Python type or class. This method always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsSubclass(PyObject typeOrClass) {
|
||||
int r = Runtime.PyObject_IsSubclass(obj, typeOrClass.obj);
|
||||
if (r < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
return (r != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsCallable Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the object is a callable object. This method
|
||||
/// always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsCallable() {
|
||||
return (Runtime.PyCallable_Check(obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsTrue Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the object is true according to Python semantics.
|
||||
/// This method always succeeds.
|
||||
/// </remarks>
|
||||
|
||||
public bool IsTrue() {
|
||||
return (Runtime.PyObject_IsTrue(obj) != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dir Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a list of the names of the attributes of the object. This
|
||||
/// is equivalent to the Python expression "dir(object)".
|
||||
/// </remarks>
|
||||
|
||||
public PyList Dir() {
|
||||
IntPtr r = Runtime.PyObject_Dir(obj);
|
||||
if (r == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyList(r);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Repr Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a string representation of the object. This method is
|
||||
/// the managed equivalent of the Python expression "repr(object)".
|
||||
/// </remarks>
|
||||
|
||||
public string Repr() {
|
||||
IntPtr strval = Runtime.PyObject_Repr(obj);
|
||||
string result = Runtime.GetManagedString(strval);
|
||||
Runtime.Decref(strval);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ToString Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the string representation of the object. This method is
|
||||
/// the managed equivalent of the Python expression "str(object)".
|
||||
/// </remarks>
|
||||
|
||||
public override string ToString() {
|
||||
IntPtr strval = Runtime.PyObject_Str(obj);
|
||||
string result = Runtime.GetManagedString(strval);
|
||||
Runtime.Decref(strval);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Equals Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if this object is equal to the given object. This
|
||||
/// method is based on Python equality semantics.
|
||||
/// </remarks>
|
||||
|
||||
public override bool Equals(object o) {
|
||||
if (!(o is PyObject)) {
|
||||
return false;
|
||||
}
|
||||
if (obj == ((PyObject) o).obj) {
|
||||
return true;
|
||||
}
|
||||
int r = Runtime.PyObject_Compare(obj, ((PyObject) o).obj);
|
||||
if (Exceptions.ErrorOccurred()) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return (r == 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetHashCode Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return a hashcode based on the Python object. This returns the
|
||||
/// hash as computed by Python, equivalent to the Python expression
|
||||
/// "hash(obj)".
|
||||
/// </remarks>
|
||||
|
||||
public override int GetHashCode() {
|
||||
return Runtime.PyObject_Hash(obj).ToInt32();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a generic Python sequence. The methods of this class are
|
||||
/// equivalent to the Python "abstract sequence API". See
|
||||
/// http://www.python.org/doc/current/api/sequence.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PySequence : PyObject {
|
||||
|
||||
protected PySequence(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
protected PySequence() : base() {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsSequenceType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object implements the sequence protocol.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsSequenceType(PyObject value) {
|
||||
return Runtime.PySequence_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// GetSlice Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the slice of the sequence with the given indices.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject GetSlice(int i1, int i2) {
|
||||
IntPtr op = Runtime.PySequence_GetSlice(obj, i1, i2);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// SetSlice Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Sets the slice of the sequence with the given indices.
|
||||
/// </remarks>
|
||||
|
||||
public void SetSlice(int i1, int i2, PyObject v) {
|
||||
int r = Runtime.PySequence_SetSlice(obj, i1, i2, v.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// DelSlice Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Deletes the slice of the sequence with the given indices.
|
||||
/// </remarks>
|
||||
|
||||
public void DelSlice(int i1, int i2) {
|
||||
int r = Runtime.PySequence_DelSlice(obj, i1, i2);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Index Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the index of the given item in the sequence, or -1 if
|
||||
/// the item does not appear in the sequence.
|
||||
/// </remarks>
|
||||
|
||||
public int Index(PyObject item) {
|
||||
int r = Runtime.PySequence_Index(obj, item.obj);
|
||||
if (r < 0) {
|
||||
Runtime.PyErr_Clear();
|
||||
return -1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Contains Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return true if the sequence contains the given item. This method
|
||||
/// throws a PythonException if an error occurs during the check.
|
||||
/// </remarks>
|
||||
|
||||
public bool Contains(PyObject item) {
|
||||
int r = Runtime.PySequence_Contains(obj, item.obj);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return (r != 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Concat Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the concatenation of the sequence object with the passed in
|
||||
/// sequence object.
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Concat(PyObject other) {
|
||||
IntPtr op = Runtime.PySequence_Concat(obj, other.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Repeat Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Return the sequence object repeated N times. This is equivalent
|
||||
/// to the Python expression "object * count".
|
||||
/// </remarks>
|
||||
|
||||
public PyObject Repeat(int count) {
|
||||
IntPtr op = Runtime.PySequence_Repeat(obj, count);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python (ansi) string object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/stringObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyString : PySequence {
|
||||
|
||||
/// <summary>
|
||||
/// PyString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyString from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyString(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyString from a generic PyObject.
|
||||
/// An ArgumentException will be thrown if the given object is not
|
||||
/// a Python string object.
|
||||
/// </remarks>
|
||||
|
||||
public PyString(PyObject o) : base() {
|
||||
if (!IsStringType(o)) {
|
||||
throw new ArgumentException("object is not a string");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyString Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a Python string from a managed string.
|
||||
/// </remarks>
|
||||
|
||||
public PyString(string s) : base() {
|
||||
obj = Runtime.PyString_FromStringAndSize(s, s.Length);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsStringType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python string.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsStringType(PyObject value) {
|
||||
return Runtime.PyString_Check(value.obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// This class provides the public interface of the Python runtime.
|
||||
/// </summary>
|
||||
|
||||
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
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initialize Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Initialize the Python runtime. It is safe to call this method
|
||||
/// more than once, though initialization will only happen on the
|
||||
/// first call. It is *not* necessary to hold the Python global
|
||||
/// interpreter lock (GIL) to call this method.
|
||||
/// </remarks>
|
||||
|
||||
public static void Initialize() {
|
||||
if (!initialized) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Shutdown Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Shutdown and release resources held by the Python runtime. The
|
||||
/// Python runtime can no longer be used in the current process
|
||||
/// after calling the Shutdown method.
|
||||
/// </remarks>
|
||||
|
||||
public static void Shutdown() {
|
||||
if (initialized) {
|
||||
Runtime.Shutdown();
|
||||
initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AcquireLock Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Acquire the Python global interpreter lock (GIL). Managed code
|
||||
/// *must* call this method before using any objects or calling any
|
||||
/// methods on objects in the Python.Runtime namespace. The only
|
||||
/// exception is PythonEngine.Initialize, which may be called without
|
||||
/// first calling AcquireLock.
|
||||
///
|
||||
/// Each call to AcquireLock must be matched by a corresponding call
|
||||
/// to ReleaseLock, passing the token obtained from AcquireLock.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static IntPtr AcquireLock() {
|
||||
return Runtime.PyGILState_Ensure();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ReleaseLock Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Release the Python global interpreter lock using a token obtained
|
||||
/// from a previous call to AcquireLock.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static void ReleaseLock(IntPtr gs) {
|
||||
Runtime.PyGILState_Release(gs);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// BeginAllowThreads Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Release the Python global interpreter lock to allow other threads
|
||||
/// to run. This is equivalent to the Py_BEGIN_ALLOW_THREADS macro
|
||||
/// provided by the C Python API.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static IntPtr BeginAllowThreads() {
|
||||
return Runtime.PyEval_SaveThread();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// EndAllowThreads Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Re-aquire the Python global interpreter lock for the current
|
||||
/// thread. This is equivalent to the Py_END_ALLOW_THREADS macro
|
||||
/// provided by the C Python API.
|
||||
///
|
||||
/// For more information, see the "Extending and Embedding" section
|
||||
/// of the Python documentation on www.python.org.
|
||||
/// </remarks>
|
||||
|
||||
public static void EndAllowThreads(IntPtr ts) {
|
||||
Runtime.PyEval_RestoreThread(ts);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ImportModule Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given a fully-qualified module or package name, import the
|
||||
/// module and return the resulting module object as a PyObject
|
||||
/// or null if an exception is raised.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject ImportModule(string name) {
|
||||
IntPtr op = Runtime.PyImport_ImportModule(name);
|
||||
if (op == IntPtr.Zero) {
|
||||
return null;
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ReloadModule Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given a PyObject representing a previously loaded module, reload
|
||||
/// the module.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject ReloadModule(PyObject module) {
|
||||
IntPtr op = Runtime.PyImport_ReloadModule(module.Handle);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(op);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// ModuleFromString Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Given a string module name and a string containing Python code,
|
||||
/// execute the code in and return a module of the given name.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject ModuleFromString(string name, string code) {
|
||||
IntPtr c = Runtime.Py_CompileString(code, "none", (IntPtr)257);
|
||||
if (c == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
IntPtr m = Runtime.PyImport_ExecCodeModule(name, c);
|
||||
if (m == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyObject(m);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// RunString Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Run a string containing Python code. Returns the result of
|
||||
/// executing the code string as a PyObject instance, or null if
|
||||
/// an exception was raised.
|
||||
/// </remarks>
|
||||
|
||||
public static PyObject RunString(string code) {
|
||||
IntPtr globals = Runtime.PyEval_GetGlobals();
|
||||
IntPtr locals = Runtime.PyDict_New();
|
||||
|
||||
IntPtr builtins = Runtime.PyEval_GetBuiltins();
|
||||
Runtime.PyDict_SetItemString(locals, "__builtins__", builtins);
|
||||
|
||||
IntPtr flag = (IntPtr)257; /* Py_file_input */
|
||||
IntPtr result = Runtime.PyRun_String(code, flag, globals, locals);
|
||||
Runtime.Decref(locals);
|
||||
if (result == IntPtr.Zero) {
|
||||
return null;
|
||||
}
|
||||
return new PyObject(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Provides a managed interface to exceptions thrown by the Python
|
||||
/// runtime.
|
||||
/// </summary>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Type Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the exception type as a Python object.
|
||||
/// </remarks>
|
||||
|
||||
public IntPtr Type {
|
||||
get {
|
||||
return excType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Value Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the exception value as a Python object.
|
||||
/// </remarks>
|
||||
|
||||
public IntPtr Value {
|
||||
get {
|
||||
return excValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traceback Property
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns the exception traceback as a Python object.
|
||||
/// </remarks>
|
||||
|
||||
public IntPtr Traceback {
|
||||
get {
|
||||
return excTb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Dispose Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// The Dispose method provides a way to explicitly release the
|
||||
/// Python objects represented by a PythonException.
|
||||
/// </remarks>
|
||||
|
||||
public void Dispose() {
|
||||
if (!disposed) {
|
||||
if (Runtime.Py_IsInitialized() > 0) {
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
Runtime.Decref(excType);
|
||||
Runtime.Decref(excValue);
|
||||
Runtime.Decref(excTb);
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Matches Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the Python exception type represented by the
|
||||
/// PythonException instance matches the given exception type.
|
||||
/// </remarks>
|
||||
|
||||
public static bool Matches(IntPtr ob) {
|
||||
return Runtime.PyErr_ExceptionMatches(ob) != 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
// 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 {
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Python tuple object. See the documentation at
|
||||
/// http://www.python.org/doc/current/api/tupleObjects.html for details.
|
||||
/// </summary>
|
||||
|
||||
public class PyTuple : PySequence {
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyTuple from an existing object reference. Note
|
||||
/// that the instance assumes ownership of the object reference.
|
||||
/// The object reference is not checked for type-correctness.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple(IntPtr ptr) : base(ptr) {}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Copy constructor - obtain a PyTuple from a generic PyObject. An
|
||||
/// ArgumentException will be thrown if the given object is not a
|
||||
/// Python tuple object.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple(PyObject o) : base() {
|
||||
if (!IsTupleType(o)) {
|
||||
throw new ArgumentException("object is not a tuple");
|
||||
}
|
||||
Runtime.Incref(o.obj);
|
||||
obj = o.obj;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new empty PyTuple.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple() : base() {
|
||||
obj = Runtime.PyTuple_New(0);
|
||||
if (obj == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// PyTuple Constructor
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Creates a new PyTuple from an array of PyObject instances.
|
||||
/// </remarks>
|
||||
|
||||
public PyTuple(PyObject[] items) : base() {
|
||||
int count = items.Length;
|
||||
obj = Runtime.PyTuple_New(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
IntPtr ptr = items[i].obj;
|
||||
Runtime.Incref(ptr);
|
||||
int r = Runtime.PyTuple_SetItem(obj, i, ptr);
|
||||
if (r < 0) {
|
||||
throw new PythonException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// IsTupleType Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Returns true if the given object is a Python tuple.
|
||||
/// </remarks>
|
||||
|
||||
public static bool IsTupleType(PyObject value) {
|
||||
return Runtime.PyTuple_Check(value.obj);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AsTuple Method
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// Convert a Python object to a Python tuple if possible, raising
|
||||
/// a PythonException if the conversion is not possible. This is
|
||||
/// equivalent to the Python expression "tuple(object)".
|
||||
/// </remarks>
|
||||
|
||||
public static PyTuple AsTuple(PyObject value) {
|
||||
IntPtr op = Runtime.PySequence_Tuple(value.obj);
|
||||
if (op == IntPtr.Zero) {
|
||||
throw new PythonException();
|
||||
}
|
||||
return new PyTuple(op);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,444 @@
|
|||
// 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,333 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
// 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 {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// 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 {
|
||||
|
||||
//========================================================================
|
||||
// These classes support the CLR constructor unit tests.
|
||||
//========================================================================
|
||||
|
||||
public class EnumConstructorTest {
|
||||
|
||||
public TypeCode value;
|
||||
|
||||
public EnumConstructorTest(TypeCode v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class FlagsConstructorTest {
|
||||
|
||||
public FileAccess value;
|
||||
|
||||
public FlagsConstructorTest(FileAccess v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class StructConstructorTest {
|
||||
|
||||
public Guid value;
|
||||
|
||||
public StructConstructorTest(Guid v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class SubclassConstructorTest {
|
||||
|
||||
public Control value;
|
||||
|
||||
public SubclassConstructorTest(Control v) {
|
||||
this.value = v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
// 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;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
// 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 enum unit tests.
|
||||
//========================================================================
|
||||
|
||||
public enum ByteEnum : byte {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
public enum SByteEnum : sbyte {
|
||||
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
public enum ShortEnum : short {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
public enum UShortEnum : ushort {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
public enum IntEnum : int{
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
public enum UIntEnum : uint {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
public enum LongEnum : long {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
public enum ULongEnum : ulong {
|
||||
Zero,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
Five
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
// 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +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.
|
||||
|
||||
using System;
|
||||
|
||||
//========================================================================
|
||||
// Supports units tests for access to types without a namespace.
|
||||
//========================================================================
|
||||
|
||||
public class NoNamespaceType {}
|
||||
|
||||
|
|
@ -0,0 +1,356 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
// 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 interface IPublicInterface {}
|
||||
|
||||
internal interface IInternalInterface {}
|
||||
|
||||
|
||||
|
||||
public interface ISayHello1 {
|
||||
string SayHello();
|
||||
}
|
||||
|
||||
public interface ISayHello2 {
|
||||
string SayHello();
|
||||
}
|
||||
|
||||
public class InterfaceTest : ISayHello1, ISayHello2{
|
||||
|
||||
public InterfaceTest() {}
|
||||
|
||||
public string HelloProperty {
|
||||
get { return "hello"; }
|
||||
}
|
||||
|
||||
string ISayHello1.SayHello() {
|
||||
return "hello 1";
|
||||
}
|
||||
|
||||
string ISayHello2.SayHello() {
|
||||
return "hello 2";
|
||||
}
|
||||
|
||||
public interface IPublic {}
|
||||
|
||||
protected interface IProtected {}
|
||||
|
||||
internal interface IInternal {}
|
||||
|
||||
private interface IPrivate {}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
// 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; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,424 @@
|
|||
# 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 gc
|
||||
|
||||
class LeakTest:
|
||||
"""A leak-check test for the objects implemented in the managed
|
||||
runtime. For each kind of object tested, memory should reach
|
||||
a particular level after warming up and stay essentially the
|
||||
same, net of minor fluctuation induced by GC."""
|
||||
|
||||
def __init__(self):
|
||||
self.count = 50000
|
||||
self.quiet = 0
|
||||
self._ws = 0
|
||||
|
||||
def notify(self, msg):
|
||||
if not self.quiet:
|
||||
print msg
|
||||
|
||||
def start_test(self):
|
||||
System.GC.Collect(System.GC.MaxGeneration)
|
||||
gc.collect()
|
||||
self._ws = System.Environment.WorkingSet
|
||||
|
||||
def end_test(self):
|
||||
start = self._ws
|
||||
System.GC.Collect(System.GC.MaxGeneration)
|
||||
gc.collect()
|
||||
end = System.Environment.WorkingSet
|
||||
diff = end - start
|
||||
if diff > 0:
|
||||
diff = '+%d' % diff
|
||||
else:
|
||||
diff = '%d' % diff
|
||||
print " start: %d end: %d diff: %s" % (start, end, diff)
|
||||
print ""
|
||||
|
||||
def run(self):
|
||||
self.testModules()
|
||||
self.testClasses()
|
||||
self.testEnumerations()
|
||||
self.testEvents()
|
||||
self.testDelegates()
|
||||
|
||||
|
||||
def report(self):
|
||||
import sys, gc
|
||||
gc.collect()
|
||||
dicttype = type({})
|
||||
for item in gc.get_objects():
|
||||
if type(item) != dicttype:
|
||||
print item, sys.getrefcount(item)
|
||||
|
||||
|
||||
def testModules(self):
|
||||
self.notify("Running module leak check...")
|
||||
|
||||
for i in xrange(self.count):
|
||||
if i == 10:
|
||||
self.start_test()
|
||||
|
||||
__import__('CLR')
|
||||
__import__('CLR.System')
|
||||
__import__('CLR.System.IO')
|
||||
__import__('CLR.System.Net')
|
||||
__import__('CLR.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
|
||||
|
||||
self.notify("Running class leak check...")
|
||||
|
||||
for i in xrange(self.count):
|
||||
if i == 10:
|
||||
self.start_test()
|
||||
|
||||
# Reference type
|
||||
x = Hashtable()
|
||||
del x
|
||||
|
||||
# Value type
|
||||
x = Int32(99)
|
||||
del x
|
||||
|
||||
# Delegate type
|
||||
x = StringDelegate(hello)
|
||||
del x
|
||||
|
||||
self.end_test()
|
||||
|
||||
|
||||
def testEnumerations(self):
|
||||
from CLR.Python import Test
|
||||
|
||||
self.notify("Running enum leak check...")
|
||||
|
||||
for i in xrange(self.count):
|
||||
if i == 10:
|
||||
self.start_test()
|
||||
|
||||
x = Test.ByteEnum.Zero
|
||||
del x
|
||||
|
||||
x = Test.SByteEnum.Zero
|
||||
del x
|
||||
|
||||
x = Test.ShortEnum.Zero
|
||||
del x
|
||||
|
||||
x = Test.UShortEnum.Zero
|
||||
del x
|
||||
|
||||
x = Test.IntEnum.Zero
|
||||
del x
|
||||
|
||||
x = Test.UIntEnum.Zero
|
||||
del x
|
||||
|
||||
x = Test.LongEnum.Zero
|
||||
del x
|
||||
|
||||
x = Test.ULongEnum.Zero
|
||||
del x
|
||||
|
||||
self.end_test()
|
||||
|
||||
|
||||
def testEvents(self):
|
||||
from CLR.Python.Test import EventTest, TestEventArgs
|
||||
|
||||
self.notify("Running event leak check...")
|
||||
|
||||
for i in xrange(self.count):
|
||||
if i == 10:
|
||||
self.start_test()
|
||||
|
||||
testob = EventTest()
|
||||
|
||||
# Instance method event handler
|
||||
handler = GenericHandler()
|
||||
testob.PublicEvent += handler.handler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= handler.handler
|
||||
del handler
|
||||
|
||||
# Vararg method event handler
|
||||
handler = VariableArgsHandler()
|
||||
testob.PublicEvent += handler.handler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= handler.handler
|
||||
del handler
|
||||
|
||||
# Callable object event handler
|
||||
handler = CallableHandler()
|
||||
testob.PublicEvent += handler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= handler
|
||||
del handler
|
||||
|
||||
# Callable vararg event handler
|
||||
handler = VarCallableHandler()
|
||||
testob.PublicEvent += handler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= handler
|
||||
del handler
|
||||
|
||||
# Static method event handler
|
||||
handler = StaticMethodHandler()
|
||||
StaticMethodHandler.value = None
|
||||
testob.PublicEvent += handler.handler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= handler.handler
|
||||
del handler
|
||||
|
||||
# Class method event handler
|
||||
handler = ClassMethodHandler()
|
||||
ClassMethodHandler.value = None
|
||||
testob.PublicEvent += handler.handler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= handler.handler
|
||||
del handler
|
||||
|
||||
# Managed instance event handler
|
||||
testob.PublicEvent += testob.GenericHandler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= testob.GenericHandler
|
||||
|
||||
# Static managed event handler
|
||||
testob.PublicEvent += EventTest.StaticHandler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= EventTest.StaticHandler
|
||||
|
||||
# Function event handler
|
||||
dict = {'value':None}
|
||||
def handler(sender, args, dict=dict):
|
||||
dict['value'] = args.value
|
||||
|
||||
testob.PublicEvent += handler
|
||||
testob.PublicEvent(testob, TestEventArgs(10))
|
||||
testob.PublicEvent -= handler
|
||||
del handler
|
||||
|
||||
self.end_test()
|
||||
|
||||
|
||||
def testDelegates(self):
|
||||
from CLR.Python.Test import DelegateTest, StringDelegate
|
||||
from CLR import System
|
||||
|
||||
self.notify("Running delegate leak check...")
|
||||
|
||||
for i in xrange(self.count):
|
||||
if i == 10:
|
||||
self.start_test()
|
||||
|
||||
# Delegate from function
|
||||
testob = DelegateTest()
|
||||
d = StringDelegate(hello)
|
||||
testob.CallStringDelegate(d)
|
||||
testob.stringDelegate = d
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del d
|
||||
|
||||
# Delegate from instance method
|
||||
inst = Hello()
|
||||
testob = DelegateTest()
|
||||
d = StringDelegate(inst.hello)
|
||||
testob.CallStringDelegate(d)
|
||||
testob.stringDelegate = d
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del inst
|
||||
del d
|
||||
|
||||
# Delegate from static method
|
||||
testob = DelegateTest()
|
||||
d = StringDelegate(Hello.s_hello)
|
||||
testob.CallStringDelegate(d)
|
||||
testob.stringDelegate = d
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del d
|
||||
|
||||
# Delegate from class method
|
||||
testob = DelegateTest()
|
||||
d = StringDelegate(Hello.c_hello)
|
||||
testob.CallStringDelegate(d)
|
||||
testob.stringDelegate = d
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del d
|
||||
|
||||
# Delegate from callable object
|
||||
inst = Hello()
|
||||
testob = DelegateTest()
|
||||
d = StringDelegate(inst)
|
||||
testob.CallStringDelegate(d)
|
||||
testob.stringDelegate = d
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del inst
|
||||
del d
|
||||
|
||||
# Delegate from managed instance method
|
||||
testob = DelegateTest()
|
||||
d = StringDelegate(testob.SayHello)
|
||||
testob.CallStringDelegate(d)
|
||||
testob.stringDelegate = d
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del d
|
||||
|
||||
# Delegate from managed static method
|
||||
testob = DelegateTest()
|
||||
d = StringDelegate(DelegateTest.StaticSayHello)
|
||||
testob.CallStringDelegate(d)
|
||||
testob.stringDelegate = d
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del d
|
||||
|
||||
# Nested delegates
|
||||
testob = DelegateTest()
|
||||
d1 = StringDelegate(hello)
|
||||
d2 = StringDelegate(d1)
|
||||
testob.CallStringDelegate(d2)
|
||||
testob.stringDelegate = d2
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del d1
|
||||
del d2
|
||||
|
||||
# Multicast delegates
|
||||
testob = DelegateTest()
|
||||
d1 = StringDelegate(hello)
|
||||
d2 = StringDelegate(hello)
|
||||
md = System.Delegate.Combine(d1, d2)
|
||||
testob.CallStringDelegate(md)
|
||||
testob.stringDelegate = md
|
||||
testob.stringDelegate()
|
||||
testob.stringDelegate = None
|
||||
del testob
|
||||
del d1
|
||||
del d2
|
||||
del md
|
||||
|
||||
self.end_test()
|
||||
|
||||
|
||||
class GenericHandler:
|
||||
"""A generic handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def handler(self, sender, args):
|
||||
self.value = args.value
|
||||
|
||||
|
||||
class VariableArgsHandler:
|
||||
"""A variable args handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def handler(self, *args):
|
||||
ob, eventargs = args
|
||||
self.value = eventargs.value
|
||||
|
||||
|
||||
class CallableHandler:
|
||||
"""A callable handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def __call__(self, sender, args):
|
||||
self.value = args.value
|
||||
|
||||
|
||||
class VarCallableHandler:
|
||||
"""A variable args callable handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def __call__(self, *args):
|
||||
ob, eventargs = args
|
||||
self.value = eventargs.value
|
||||
|
||||
|
||||
class StaticMethodHandler(object):
|
||||
"""A static method handler to test event callbacks."""
|
||||
|
||||
value = None
|
||||
|
||||
def handler(sender, args):
|
||||
StaticMethodHandler.value = args.value
|
||||
|
||||
handler = staticmethod(handler)
|
||||
|
||||
|
||||
class ClassMethodHandler(object):
|
||||
"""A class method handler to test event callbacks."""
|
||||
|
||||
value = None
|
||||
|
||||
def handler(cls, sender, args):
|
||||
cls.value = args.value
|
||||
|
||||
handler = classmethod(handler)
|
||||
|
||||
|
||||
class Hello:
|
||||
def hello(self):
|
||||
return "hello"
|
||||
|
||||
def __call__(self):
|
||||
return "hello"
|
||||
|
||||
def s_hello():
|
||||
return "hello"
|
||||
|
||||
s_hello = staticmethod(s_hello)
|
||||
|
||||
def c_hello(cls):
|
||||
return "hello"
|
||||
|
||||
c_hello = classmethod(c_hello)
|
||||
|
||||
|
||||
def hello():
|
||||
return "hello"
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test = LeakTest()
|
||||
test.run()
|
||||
test.report()
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
"""Run all of the unit tests for this package over and over,
|
||||
in order to provide for better profiling."""
|
||||
|
||||
def main():
|
||||
import sys, os, gc, time
|
||||
|
||||
dirname = os.path.split(__file__)
|
||||
sys.path.append(dirname)
|
||||
import runtests
|
||||
|
||||
gc.set_debug(gc.DEBUG_LEAK)
|
||||
|
||||
start = time.clock()
|
||||
|
||||
for i in range(50):
|
||||
print 'iteration: %d' % i
|
||||
runtests.main()
|
||||
|
||||
stop = time.clock()
|
||||
took = str(stop - start)
|
||||
print 'Total Time: %s' % took
|
||||
|
||||
|
||||
for item in gc.get_objects():
|
||||
print item, sys.getrefcount(item)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
sys.exit(0)
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
"""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()
|
||||
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
# 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
|
||||
multithreaded way to stress the system. This makes it possible to look
|
||||
for memory leaks and threading issues and provides a good target for a
|
||||
profiler to accumulate better data.
|
||||
"""
|
||||
|
||||
import sys, os, gc, time, threading, thread
|
||||
|
||||
class StressTest:
|
||||
|
||||
def __init__(self):
|
||||
self.dirname = os.path.split(__file__)[0]
|
||||
sys.path.append(self.dirname)
|
||||
gc.set_debug(gc.DEBUG_LEAK)
|
||||
import runtests
|
||||
self.module = runtests
|
||||
self.done = []
|
||||
|
||||
def dprint(self, msg):
|
||||
# Debugging helper to trace thread-related tests.
|
||||
if 1: print msg
|
||||
|
||||
def markStart(self):
|
||||
self._start = time.clock()
|
||||
|
||||
def markFinish(self):
|
||||
self._finish = time.clock()
|
||||
|
||||
def elapsed(self):
|
||||
return self._finish - self._start
|
||||
|
||||
def printGCReport(self):
|
||||
for item in gc.get_objects():
|
||||
print item, sys.getrefcount(item)
|
||||
|
||||
def runThread(self, iterations):
|
||||
thread_id = thread.get_ident()
|
||||
self.dprint("thread %s starting..." % thread_id)
|
||||
time.sleep(0.1)
|
||||
for i in range(iterations):
|
||||
self.dprint("thread %s iter %d start" % (thread_id, i))
|
||||
self.module.main()
|
||||
self.dprint("thread %s iter %d end" % (thread_id, i))
|
||||
self.done.append(None)
|
||||
self.dprint("thread %s done" % thread_id)
|
||||
|
||||
def stressTest(self, iterations=1, threads=1):
|
||||
args = (iterations,)
|
||||
self.markStart()
|
||||
for i in range(threads):
|
||||
thread = threading.Thread(target=self.runThread, args=args)
|
||||
thread.start()
|
||||
while len(self.done) < (iterations * threads):
|
||||
self.dprint(len(self.done))
|
||||
time.sleep(0.1)
|
||||
self.markFinish()
|
||||
took = self.elapsed()
|
||||
self.printGCReport()
|
||||
|
||||
|
||||
def main():
|
||||
test = StressTest()
|
||||
test.stressTest(2, 10)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
sys.exit(0)
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
"""Basic stress test."""
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
import time
|
||||
start = time.clock()
|
||||
|
||||
for i in range(2000):
|
||||
print i
|
||||
for name in (
|
||||
'test_module',
|
||||
'test_conversion',
|
||||
#'test_class',
|
||||
'test_interface',
|
||||
'test_enum',
|
||||
'test_field',
|
||||
'test_property',
|
||||
'test_indexer',
|
||||
'test_event',
|
||||
'test_method',
|
||||
#'test_delegate',
|
||||
'test_array',
|
||||
):
|
||||
module = __import__(name)
|
||||
module.main()
|
||||
|
||||
#import pdb; pdb.set_trace()
|
||||
|
||||
stop = time.clock()
|
||||
took = str(stop - start)
|
||||
print 'Total Time: %s' % took
|
||||
|
||||
import gc
|
||||
for i in gc.get_objects():
|
||||
print i
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,246 @@
|
|||
# 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
|
||||
import sys, os, string, unittest, types
|
||||
import CLR.Python.Test as Test
|
||||
import CLR.System as System
|
||||
|
||||
|
||||
class ClassTests(unittest.TestCase):
|
||||
"""Test CLR class support."""
|
||||
|
||||
def testBasicReferenceType(self):
|
||||
"""Test usage of CLR defined reference types."""
|
||||
String = System.String
|
||||
self.assertEquals(String.Empty, "")
|
||||
|
||||
|
||||
def testBasicValueType(self):
|
||||
"""Test usage of CLR defined value types."""
|
||||
Int32 = System.Int32
|
||||
self.assertEquals(Int32.MaxValue, 2147483647)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def testClassDocstrings(self):
|
||||
"""Test standard class docstring generation"""
|
||||
value = 'Void .ctor()'
|
||||
self.failUnless(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")
|
||||
|
||||
|
||||
def testClassDefaultRepr(self):
|
||||
"""Test the default __repr__ implementation for managed objects."""
|
||||
s = System.String("this is a test")
|
||||
self.failUnless(repr(s).startswith("<CLR.System.String object"))
|
||||
|
||||
|
||||
def testNonPublicClass(self):
|
||||
"""Test that non-public classes are inaccessible."""
|
||||
from CLR.Python import Test
|
||||
|
||||
def test():
|
||||
from CLR.Python.Test import InternalClass
|
||||
|
||||
self.failUnlessRaises(ImportError, test)
|
||||
|
||||
def test():
|
||||
x = Test.InternalClass
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
def testBasicSubclass(self):
|
||||
"""Test basic subclass of a managed class."""
|
||||
|
||||
class MyTable(Hashtable):
|
||||
def howMany(self):
|
||||
return self.Count
|
||||
|
||||
table = MyTable()
|
||||
|
||||
self.failUnless(table.__class__.__name__.endswith('MyTable'))
|
||||
self.failUnless(type(table).__name__.endswith('MyTable'))
|
||||
self.failUnless(len(table.__class__.__bases__) == 1)
|
||||
self.failUnless(table.__class__.__bases__[0] == Hashtable)
|
||||
|
||||
self.failUnless(table.howMany() == 0)
|
||||
self.failUnless(table.Count == 0)
|
||||
|
||||
table.set_Item('one', 'one')
|
||||
|
||||
self.failUnless(table.howMany() == 1)
|
||||
self.failUnless(table.Count == 1)
|
||||
|
||||
MyTable = None
|
||||
|
||||
|
||||
def testSubclassWithNoArgConstructor(self):
|
||||
"""Test subclass of a managed class with a no-arg constructor."""
|
||||
from CLR.Python.Test import ClassCtorTest1
|
||||
|
||||
class SubClass(ClassCtorTest1):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
# This failed in earlier versions
|
||||
inst = SubClass('test')
|
||||
|
||||
def testSubclassWithVariousConstructors(self):
|
||||
"""Test subclass of a managed class with various constructors."""
|
||||
from CLR.Python.Test import ClassCtorTest2
|
||||
|
||||
class SubClass(ClassCtorTest2):
|
||||
def __init__(self, v):
|
||||
ClassCtorTest2.__init__(self)
|
||||
self.value = v
|
||||
|
||||
inst = SubClass('test')
|
||||
self.failUnless(inst.value == 'test')
|
||||
|
||||
class SubClass2(ClassCtorTest2):
|
||||
def __init__(self, v):
|
||||
ClassCtorTest2.__init__(self)
|
||||
self.value = v
|
||||
|
||||
inst = SubClass2('test')
|
||||
self.failUnless(inst.value == 'test')
|
||||
|
||||
|
||||
def testStructConstruction(self):
|
||||
"""Test construction of structs."""
|
||||
from CLR.System.Drawing import Point
|
||||
|
||||
def test():
|
||||
p = Point()
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
p = Point(0, 0)
|
||||
self.failUnless(p.X == 0)
|
||||
self.failUnless(p.Y == 0)
|
||||
|
||||
p.X = 10
|
||||
p.Y = 10
|
||||
|
||||
self.failUnless(p.X == 10)
|
||||
self.failUnless(p.Y == 10)
|
||||
|
||||
|
||||
|
||||
# test strange __new__ interactions
|
||||
|
||||
# test weird metatype
|
||||
# test recursion
|
||||
# test
|
||||
|
||||
|
||||
def testIEnumerableIteration(self):
|
||||
"""Test iteration over objects supporting IEnumerable."""
|
||||
list = Test.ClassTest.GetArrayList()
|
||||
|
||||
for item in list:
|
||||
self.failUnless((item > -1) and (item < 10))
|
||||
|
||||
dict = Test.ClassTest.GetHashtable()
|
||||
|
||||
for item in dict:
|
||||
cname = item.__class__.__name__
|
||||
self.failUnless(cname.endswith('DictionaryEntry'))
|
||||
|
||||
|
||||
def testIEnumeratorIteration(self):
|
||||
"""Test iteration over objects supporting IEnumerator."""
|
||||
chars = Test.ClassTest.GetEnumerator()
|
||||
|
||||
for item in chars:
|
||||
self.failUnless(item in 'test string')
|
||||
|
||||
|
||||
|
||||
|
||||
def testOverrideGetItem(self):
|
||||
"""Test managed subclass overriding __getitem__."""
|
||||
|
||||
class MyTable(Hashtable):
|
||||
|
||||
def __getitem__(self, key):
|
||||
value = Hashtable.__getitem__(self, key)
|
||||
return 'my ' + str(value)
|
||||
|
||||
table = MyTable()
|
||||
table['one'] = 'one'
|
||||
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.failUnless(table.Count == 3)
|
||||
|
||||
|
||||
def testOverrideSetItem(self):
|
||||
"""Test managed subclass overriding __setitem__."""
|
||||
|
||||
class MyTable(Hashtable):
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
value = 'my ' + str(value)
|
||||
Hashtable.__setitem__(self, key, value)
|
||||
|
||||
table = MyTable()
|
||||
table['one'] = 'one'
|
||||
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.failUnless(table.Count == 3)
|
||||
|
||||
|
||||
|
||||
class ClassicClass:
|
||||
def kind(self):
|
||||
return 'classic'
|
||||
|
||||
class NewStyleClass(object):
|
||||
def kind(self):
|
||||
return 'new-style'
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(ClassTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
# 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
|
||||
|
||||
|
||||
class ConstructorTests(unittest.TestCase):
|
||||
"""Test CLR class constructor support."""
|
||||
|
||||
def testEnumConstructor(self):
|
||||
"""Test enum constructor args"""
|
||||
from Test import EnumConstructorTest
|
||||
|
||||
ob = EnumConstructorTest(TypeCode.Int32)
|
||||
self.failUnless(ob.value == TypeCode.Int32)
|
||||
|
||||
|
||||
def testFlagsConstructor(self):
|
||||
"""Test flags constructor args"""
|
||||
from Test import FlagsConstructorTest
|
||||
from System.IO import FileAccess
|
||||
|
||||
flags = FileAccess.Read | FileAccess.Write
|
||||
ob = FlagsConstructorTest(flags)
|
||||
self.failUnless(ob.value == flags)
|
||||
|
||||
|
||||
def testStructConstructor(self):
|
||||
"""Test struct constructor args"""
|
||||
from Test import StructConstructorTest
|
||||
|
||||
guid = Guid.NewGuid()
|
||||
ob = StructConstructorTest(guid)
|
||||
self.failUnless(ob.value == guid)
|
||||
|
||||
|
||||
def testSubclassConstructor(self):
|
||||
"""Test subclass constructor args"""
|
||||
from Test import SubclassConstructorTest
|
||||
from System.Windows.Forms import Form, Control
|
||||
|
||||
class sub(Form):
|
||||
pass
|
||||
|
||||
form = sub()
|
||||
ob = SubclassConstructorTest(form)
|
||||
self.failUnless(isinstance(ob.value, Control))
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(ConstructorTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,876 @@
|
|||
# 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
|
||||
|
||||
|
||||
class ConversionTests(unittest.TestCase):
|
||||
"""Test CLR <-> Python type conversions."""
|
||||
|
||||
def testBoolConversion(self):
|
||||
"""Test bool conversion."""
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.BooleanField == False)
|
||||
self.failUnless(object.BooleanField is False)
|
||||
self.failUnless(object.BooleanField == 0)
|
||||
|
||||
object.BooleanField = True
|
||||
self.failUnless(object.BooleanField == True)
|
||||
self.failUnless(object.BooleanField is True)
|
||||
self.failUnless(object.BooleanField == 1)
|
||||
|
||||
object.BooleanField = False
|
||||
self.failUnless(object.BooleanField == False)
|
||||
self.failUnless(object.BooleanField is False)
|
||||
self.failUnless(object.BooleanField == 0)
|
||||
|
||||
object.BooleanField = 1
|
||||
self.failUnless(object.BooleanField == True)
|
||||
self.failUnless(object.BooleanField is True)
|
||||
self.failUnless(object.BooleanField == 1)
|
||||
|
||||
object.BooleanField = 0
|
||||
self.failUnless(object.BooleanField == False)
|
||||
self.failUnless(object.BooleanField is False)
|
||||
self.failUnless(object.BooleanField == 0)
|
||||
|
||||
object.BooleanField = System.Boolean(None)
|
||||
self.failUnless(object.BooleanField == False)
|
||||
self.failUnless(object.BooleanField is False)
|
||||
self.failUnless(object.BooleanField == 0)
|
||||
|
||||
object.BooleanField = System.Boolean('')
|
||||
self.failUnless(object.BooleanField == False)
|
||||
self.failUnless(object.BooleanField is False)
|
||||
self.failUnless(object.BooleanField == 0)
|
||||
|
||||
object.BooleanField = System.Boolean(0)
|
||||
self.failUnless(object.BooleanField == False)
|
||||
self.failUnless(object.BooleanField is False)
|
||||
self.failUnless(object.BooleanField == 0)
|
||||
|
||||
object.BooleanField = System.Boolean(1)
|
||||
self.failUnless(object.BooleanField == True)
|
||||
self.failUnless(object.BooleanField is True)
|
||||
self.failUnless(object.BooleanField == 1)
|
||||
|
||||
object.BooleanField = System.Boolean('a')
|
||||
self.failUnless(object.BooleanField == True)
|
||||
self.failUnless(object.BooleanField is True)
|
||||
self.failUnless(object.BooleanField == 1)
|
||||
|
||||
|
||||
def testSByteConversion(self):
|
||||
"""Test sbyte conversion."""
|
||||
self.failUnless(System.SByte.MaxValue == 127)
|
||||
self.failUnless(System.SByte.MinValue == -128)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.SByteField == 0)
|
||||
|
||||
object.SByteField = 127
|
||||
self.failUnless(object.SByteField == 127)
|
||||
|
||||
object.SByteField = -128
|
||||
self.failUnless(object.SByteField == -128)
|
||||
|
||||
object.SByteField = System.SByte(127)
|
||||
self.failUnless(object.SByteField == 127)
|
||||
|
||||
object.SByteField = System.SByte(-128)
|
||||
self.failUnless(object.SByteField == -128)
|
||||
|
||||
def test():
|
||||
ConversionTest().SByteField = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().SByteField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().SByteField = 128
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().SByteField = -129
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.SByte(128)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.SByte(-129)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testByteConversion(self):
|
||||
"""Test byte conversion."""
|
||||
self.failUnless(System.Byte.MaxValue == 255)
|
||||
self.failUnless(System.Byte.MinValue == 0)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.ByteField == 0)
|
||||
|
||||
object.ByteField = 255
|
||||
self.failUnless(object.ByteField == 255)
|
||||
|
||||
object.ByteField = 0
|
||||
self.failUnless(object.ByteField == 0)
|
||||
|
||||
object.ByteField = System.Byte(255)
|
||||
self.failUnless(object.ByteField == 255)
|
||||
|
||||
object.ByteField = System.Byte(0)
|
||||
self.failUnless(object.ByteField == 0)
|
||||
|
||||
def test():
|
||||
ConversionTest().ByteField = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().ByteField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().ByteField = 256
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().ByteField = -1
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Byte(256)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Byte(-1)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testCharConversion(self):
|
||||
"""Test char conversion."""
|
||||
self.failUnless(System.Char.MaxValue == unichr(65535))
|
||||
self.failUnless(System.Char.MinValue == unichr(0))
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.CharField == u'A')
|
||||
|
||||
object.CharField = 'B'
|
||||
self.failUnless(object.CharField == u'B')
|
||||
|
||||
object.CharField = u'B'
|
||||
self.failUnless(object.CharField == u'B')
|
||||
|
||||
object.CharField = 67
|
||||
self.failUnless(object.CharField == u'C')
|
||||
|
||||
def test():
|
||||
ConversionTest().CharField = 65536
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().CharField = -1
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().CharField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testInt16Conversion(self):
|
||||
"""Test int16 conversion."""
|
||||
self.failUnless(System.Int16.MaxValue == 32767)
|
||||
self.failUnless(System.Int16.MinValue == -32768)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.Int16Field == 0)
|
||||
|
||||
object.Int16Field = 32767
|
||||
self.failUnless(object.Int16Field == 32767)
|
||||
|
||||
object.Int16Field = -32768
|
||||
self.failUnless(object.Int16Field == -32768)
|
||||
|
||||
object.Int16Field = System.Int16(32767)
|
||||
self.failUnless(object.Int16Field == 32767)
|
||||
|
||||
object.Int16Field = System.Int16(-32768)
|
||||
self.failUnless(object.Int16Field == -32768)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int16Field = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int16Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int16Field = 32768
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int16Field = -32769
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Int16(32768)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Int16(-32769)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testInt32Conversion(self):
|
||||
"""Test int32 conversion."""
|
||||
self.failUnless(System.Int32.MaxValue == 2147483647)
|
||||
self.failUnless(System.Int32.MinValue == -2147483648)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.Int32Field == 0)
|
||||
|
||||
object.Int32Field = 2147483647
|
||||
self.failUnless(object.Int32Field == 2147483647)
|
||||
|
||||
object.Int32Field = -2147483648
|
||||
self.failUnless(object.Int32Field == -2147483648)
|
||||
|
||||
object.Int32Field = System.Int32(2147483647)
|
||||
self.failUnless(object.Int32Field == 2147483647)
|
||||
|
||||
object.Int32Field = System.Int32(-2147483648)
|
||||
self.failUnless(object.Int32Field == -2147483648)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int32Field = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int32Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int32Field = 2147483648
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int32Field = -2147483649
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Int32(2147483648)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Int32(-2147483649)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testInt64Conversion(self):
|
||||
"""Test int64 conversion."""
|
||||
self.failUnless(System.Int64.MaxValue == 9223372036854775807L)
|
||||
self.failUnless(System.Int64.MinValue == -9223372036854775808L)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.Int64Field == 0)
|
||||
|
||||
object.Int64Field = 9223372036854775807L
|
||||
self.failUnless(object.Int64Field == 9223372036854775807L)
|
||||
|
||||
object.Int64Field = -9223372036854775808L
|
||||
self.failUnless(object.Int64Field == -9223372036854775808L)
|
||||
|
||||
object.Int64Field = System.Int64(9223372036854775807L)
|
||||
self.failUnless(object.Int64Field == 9223372036854775807L)
|
||||
|
||||
object.Int64Field = System.Int64(-9223372036854775808L)
|
||||
self.failUnless(object.Int64Field == -9223372036854775808L)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int64Field = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int64Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int64Field = 9223372036854775808L
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().Int64Field = -9223372036854775809L
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Int64(9223372036854775808L)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Int64(-9223372036854775809L)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testUInt16Conversion(self):
|
||||
"""Test uint16 conversion."""
|
||||
self.failUnless(System.UInt16.MaxValue == 65535)
|
||||
self.failUnless(System.UInt16.MinValue == 0)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.UInt16Field == 0)
|
||||
|
||||
object.UInt16Field = 65535
|
||||
self.failUnless(object.UInt16Field == 65535)
|
||||
|
||||
object.UInt16Field = -0
|
||||
self.failUnless(object.UInt16Field == 0)
|
||||
|
||||
object.UInt16Field = System.UInt16(65535)
|
||||
self.failUnless(object.UInt16Field == 65535)
|
||||
|
||||
object.UInt16Field = System.UInt16(0)
|
||||
self.failUnless(object.UInt16Field == 0)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt16Field = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt16Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt16Field = 65536
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt16Field = -1
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.UInt16(65536)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.UInt16(-1)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testUInt32Conversion(self):
|
||||
"""Test uint32 conversion."""
|
||||
self.failUnless(System.UInt32.MaxValue == 4294967295L)
|
||||
self.failUnless(System.UInt32.MinValue == 0)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.UInt32Field == 0)
|
||||
|
||||
object.UInt32Field = 4294967295L
|
||||
self.failUnless(object.UInt32Field == 4294967295L)
|
||||
|
||||
object.UInt32Field = -0
|
||||
self.failUnless(object.UInt32Field == 0)
|
||||
|
||||
object.UInt32Field = System.UInt32(4294967295L)
|
||||
self.failUnless(object.UInt32Field == 4294967295L)
|
||||
|
||||
object.UInt32Field = System.UInt32(0)
|
||||
self.failUnless(object.UInt32Field == 0)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt32Field = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt32Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt32Field = 4294967296L
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt32Field = -1
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.UInt32(4294967296L)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.UInt32(-1)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testUInt64Conversion(self):
|
||||
"""Test uint64 conversion."""
|
||||
self.failUnless(System.UInt64.MaxValue == 18446744073709551615L)
|
||||
self.failUnless(System.UInt64.MinValue == 0)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.UInt64Field == 0)
|
||||
|
||||
object.UInt64Field = 18446744073709551615L
|
||||
self.failUnless(object.UInt64Field == 18446744073709551615L)
|
||||
|
||||
object.UInt64Field = -0
|
||||
self.failUnless(object.UInt64Field == 0)
|
||||
|
||||
object.UInt64Field = System.UInt64(18446744073709551615L)
|
||||
self.failUnless(object.UInt64Field == 18446744073709551615L)
|
||||
|
||||
object.UInt64Field = System.UInt64(0)
|
||||
self.failUnless(object.UInt64Field == 0)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt64Field = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt64Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt64Field = 18446744073709551616L
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().UInt64Field = -1
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.UInt64(18446744073709551616L)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.UInt64(-1)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testSingleConversion(self):
|
||||
"""Test single conversion."""
|
||||
self.failUnless(System.Single.MaxValue == 3.402823e38)
|
||||
self.failUnless(System.Single.MinValue == -3.402823e38)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.SingleField == 0.0)
|
||||
|
||||
object.SingleField = 3.402823e38
|
||||
self.failUnless(object.SingleField == 3.402823e38)
|
||||
|
||||
object.SingleField = -3.402823e38
|
||||
self.failUnless(object.SingleField == -3.402823e38)
|
||||
|
||||
object.SingleField = System.Single(3.402823e38)
|
||||
self.failUnless(object.SingleField == 3.402823e38)
|
||||
|
||||
object.SingleField = System.Single(-3.402823e38)
|
||||
self.failUnless(object.SingleField == -3.402823e38)
|
||||
|
||||
def test():
|
||||
ConversionTest().SingleField = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().SingleField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().SingleField = 3.402824e38
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().SingleField = -3.402824e38
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Single(3.402824e38)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Single(-3.402824e38)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testDoubleConversion(self):
|
||||
"""Test double conversion."""
|
||||
self.failUnless(System.Double.MaxValue == 1.7976931348623157e308)
|
||||
self.failUnless(System.Double.MinValue == -1.7976931348623157e308)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.DoubleField == 0.0)
|
||||
|
||||
object.DoubleField = 1.7976931348623157e308
|
||||
self.failUnless(object.DoubleField == 1.7976931348623157e308)
|
||||
|
||||
object.DoubleField = -1.7976931348623157e308
|
||||
self.failUnless(object.DoubleField == -1.7976931348623157e308)
|
||||
|
||||
object.DoubleField = System.Double(1.7976931348623157e308)
|
||||
self.failUnless(object.DoubleField == 1.7976931348623157e308)
|
||||
|
||||
object.DoubleField = System.Double(-1.7976931348623157e308)
|
||||
self.failUnless(object.DoubleField == -1.7976931348623157e308)
|
||||
|
||||
def test():
|
||||
ConversionTest().DoubleField = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().DoubleField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().DoubleField = 1.7976931348623159e308
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().DoubleField = -1.7976931348623159e308
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Double(1.7976931348623159e308)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
value = System.Double(-1.7976931348623159e308)
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
|
||||
def testDecimalConversion(self):
|
||||
"""Test decimal conversion."""
|
||||
from CLR.System import Decimal
|
||||
|
||||
max_d = Decimal.Parse("79228162514264337593543950335")
|
||||
min_d = Decimal.Parse("-79228162514264337593543950335")
|
||||
|
||||
self.failUnless(Decimal.ToInt64(Decimal(10)) == 10L)
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.DecimalField == Decimal(0))
|
||||
|
||||
object.DecimalField = Decimal(10)
|
||||
self.failUnless(object.DecimalField == Decimal(10))
|
||||
|
||||
object.DecimalField = Decimal.One
|
||||
self.failUnless(object.DecimalField == Decimal.One)
|
||||
|
||||
object.DecimalField = Decimal.Zero
|
||||
self.failUnless(object.DecimalField == Decimal.Zero)
|
||||
|
||||
object.DecimalField = max_d
|
||||
self.failUnless(object.DecimalField == max_d)
|
||||
|
||||
object.DecimalField = min_d
|
||||
self.failUnless(object.DecimalField == min_d)
|
||||
|
||||
def test():
|
||||
ConversionTest().DecimalField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().DecimalField = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().DecimalField = 1
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testStringConversion(self):
|
||||
"""Test string / unicode conversion."""
|
||||
object = ConversionTest()
|
||||
|
||||
self.failUnless(object.StringField == "spam")
|
||||
self.failUnless(object.StringField == u"spam")
|
||||
|
||||
object.StringField = "eggs"
|
||||
self.failUnless(object.StringField == "eggs")
|
||||
self.failUnless(object.StringField == u"eggs")
|
||||
|
||||
object.StringField = u"spam"
|
||||
self.failUnless(object.StringField == "spam")
|
||||
self.failUnless(object.StringField == u"spam")
|
||||
|
||||
object.StringField = u'\uffff\uffff'
|
||||
self.failUnless(object.StringField == u'\uffff\uffff')
|
||||
|
||||
object.StringField = System.String("spam")
|
||||
self.failUnless(object.StringField == "spam")
|
||||
self.failUnless(object.StringField == u"spam")
|
||||
|
||||
object.StringField = System.String(u'\uffff\uffff')
|
||||
self.failUnless(object.StringField == u'\uffff\uffff')
|
||||
|
||||
object.StringField = None
|
||||
self.failUnless(object.StringField == None)
|
||||
|
||||
def test():
|
||||
ConversionTest().StringField = 1
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testInterfaceConversion(self):
|
||||
"""Test interface conversion."""
|
||||
from CLR.Python.Test import Spam, ISpam
|
||||
|
||||
object = ConversionTest()
|
||||
|
||||
self.failUnless(ISpam(object.SpamField).GetValue() == "spam")
|
||||
self.failUnless(object.SpamField.GetValue() == "spam")
|
||||
|
||||
object.SpamField = Spam("eggs")
|
||||
self.failUnless(ISpam(object.SpamField).GetValue() == "eggs")
|
||||
self.failUnless(object.SpamField.GetValue() == "eggs")
|
||||
|
||||
# need to test spam subclass here.
|
||||
|
||||
object.SpamField = None
|
||||
self.failUnless(object.SpamField == None)
|
||||
|
||||
def test():
|
||||
object = ConversionTest()
|
||||
object.SpamField = System.String("bad")
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = ConversionTest()
|
||||
object.SpamField = System.Int32(1)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testObjectConversion(self):
|
||||
"""Test object conversion."""
|
||||
from CLR.Python.Test import Spam
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.ObjectField == None)
|
||||
|
||||
object.ObjectField = Spam("eggs")
|
||||
self.failUnless(object.ObjectField.__class__.__name__ == "Spam")
|
||||
self.failUnless(object.ObjectField.GetValue() == "eggs")
|
||||
|
||||
object.ObjectField = None
|
||||
self.failUnless(object.ObjectField == None)
|
||||
|
||||
object.ObjectField = System.String("spam")
|
||||
self.failUnless(object.ObjectField == "spam")
|
||||
|
||||
object.ObjectField = System.Int32(1)
|
||||
self.failUnless(object.ObjectField == 1)
|
||||
|
||||
# need to test subclass here
|
||||
|
||||
def test():
|
||||
object = ConversionTest()
|
||||
object.ObjectField = self
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testEnumConversion(self):
|
||||
"""Test enum conversion."""
|
||||
from CLR.Python.Test import ShortEnum
|
||||
|
||||
object = ConversionTest()
|
||||
self.failUnless(object.EnumField == ShortEnum.Zero)
|
||||
|
||||
object.EnumField = ShortEnum.One
|
||||
self.failUnless(object.EnumField == ShortEnum.One)
|
||||
|
||||
object.EnumField = 0
|
||||
self.failUnless(object.EnumField == ShortEnum.Zero)
|
||||
self.failUnless(object.EnumField == 0)
|
||||
|
||||
object.EnumField = 1
|
||||
self.failUnless(object.EnumField == ShortEnum.One)
|
||||
self.failUnless(object.EnumField == 1)
|
||||
|
||||
def test():
|
||||
object = ConversionTest()
|
||||
object.EnumField = 10
|
||||
|
||||
self.failUnlessRaises(ValueError, test)
|
||||
|
||||
def test():
|
||||
object = ConversionTest()
|
||||
object.EnumField = 255
|
||||
|
||||
self.failUnlessRaises(ValueError, test)
|
||||
|
||||
def test():
|
||||
object = ConversionTest()
|
||||
object.EnumField = 1000000
|
||||
|
||||
self.failUnlessRaises(OverflowError, test)
|
||||
|
||||
def test():
|
||||
object = ConversionTest()
|
||||
object.EnumField = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testNullConversion(self):
|
||||
"""Test null conversion."""
|
||||
object = ConversionTest()
|
||||
|
||||
object.StringField = None
|
||||
self.failUnless(object.StringField == None)
|
||||
|
||||
object.ObjectField = None
|
||||
self.failUnless(object.ObjectField == None)
|
||||
|
||||
object.SpamField = None
|
||||
self.failUnless(object.SpamField == None)
|
||||
|
||||
# Primitive types and enums should not be set to null.
|
||||
|
||||
def test():
|
||||
ConversionTest().Int32Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
ConversionTest().EnumField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testByteArrayConversion(self):
|
||||
"""Test byte array conversion."""
|
||||
object = ConversionTest()
|
||||
|
||||
self.failUnless(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)
|
||||
|
||||
value = "testing"
|
||||
object.ByteArrayField = value
|
||||
array = object.ByteArrayField
|
||||
for i in range(len(value)):
|
||||
self.failUnless(array[i] == ord(value[i]))
|
||||
|
||||
|
||||
def testSByteArrayConversion(self):
|
||||
"""Test sbyte array conversion."""
|
||||
object = ConversionTest()
|
||||
|
||||
self.failUnless(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)
|
||||
|
||||
value = "testing"
|
||||
object.SByteArrayField = value
|
||||
array = object.SByteArrayField
|
||||
for i in range(len(value)):
|
||||
self.failUnless(array[i] == ord(value[i]))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(ConversionTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,325 @@
|
|||
# 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 DelegateTest, PublicDelegate
|
||||
from CLR.Python.Test import StringDelegate, ObjectDelegate
|
||||
import sys, os, string, unittest, types
|
||||
import CLR.Python.Test as Test
|
||||
import CLR.System as System
|
||||
|
||||
|
||||
class DelegateTests(unittest.TestCase):
|
||||
"""Test CLR delegate support."""
|
||||
|
||||
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)
|
||||
|
||||
|
||||
def testGlobalDelegateVisibility(self):
|
||||
"""Test visibility of module-level delegates."""
|
||||
from CLR.Python.Test import PublicDelegate
|
||||
|
||||
self.failUnless(PublicDelegate.__name__ == 'PublicDelegate')
|
||||
self.failUnless(Test.PublicDelegate.__name__ == 'PublicDelegate')
|
||||
|
||||
def test():
|
||||
from CLR.Python.Test import InternalDelegate
|
||||
|
||||
self.failUnlessRaises(ImportError, test)
|
||||
|
||||
def test():
|
||||
i = Test.InternalDelegate
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
def testNestedDelegateVisibility(self):
|
||||
"""Test visibility of nested delegates."""
|
||||
ob = DelegateTest.PublicDelegate
|
||||
self.failUnless(ob.__name__ == 'PublicDelegate')
|
||||
|
||||
ob = DelegateTest.ProtectedDelegate
|
||||
self.failUnless(ob.__name__ == 'ProtectedDelegate')
|
||||
|
||||
def test():
|
||||
ob = DelegateTest.InternalDelegate
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
ob = DelegateTest.PrivateDelegate
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
def testDelegateFromFunction(self):
|
||||
"""Test delegate implemented with a Python function."""
|
||||
|
||||
def sayhello():
|
||||
return "hello"
|
||||
|
||||
d = StringDelegate(sayhello)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateFromMethod(self):
|
||||
"""Test delegate implemented with a Python instance method."""
|
||||
|
||||
class Hello:
|
||||
def sayhello(self):
|
||||
return "hello"
|
||||
|
||||
inst = Hello()
|
||||
d = StringDelegate(inst.sayhello)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateFromUnboundMethod(self):
|
||||
"""Test failure mode for unbound methods."""
|
||||
|
||||
class Hello:
|
||||
def sayhello(self):
|
||||
return "hello"
|
||||
|
||||
def test():
|
||||
d = StringDelegate(Hello.sayhello)
|
||||
d()
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testDelegateFromStaticMethod(self):
|
||||
"""Test delegate implemented with a Python static method."""
|
||||
|
||||
class Hello:
|
||||
def sayhello():
|
||||
return "hello"
|
||||
sayhello = staticmethod(sayhello)
|
||||
|
||||
d = StringDelegate(Hello.sayhello)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
inst = Hello()
|
||||
d = StringDelegate(inst.sayhello)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateFromClassMethod(self):
|
||||
"""Test delegate implemented with a Python class method."""
|
||||
|
||||
class Hello:
|
||||
def sayhello(self):
|
||||
return "hello"
|
||||
sayhello = classmethod(sayhello)
|
||||
|
||||
d = StringDelegate(Hello.sayhello)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
inst = Hello()
|
||||
d = StringDelegate(inst.sayhello)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateFromCallable(self):
|
||||
"""Test delegate implemented with a Python callable object."""
|
||||
|
||||
class Hello:
|
||||
def __call__(self):
|
||||
return "hello"
|
||||
|
||||
inst = Hello()
|
||||
d = StringDelegate(inst)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateFromManagedInstanceMethod(self):
|
||||
"""Test delegate implemented with a managed instance method."""
|
||||
ob = DelegateTest()
|
||||
d = StringDelegate(ob.SayHello)
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateFromManagedStaticMethod(self):
|
||||
"""Test delegate implemented with a managed static method."""
|
||||
d = StringDelegate(DelegateTest.StaticSayHello)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d) == "hello")
|
||||
self.failUnless(d() == "hello")
|
||||
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateFromDelegate(self):
|
||||
"""Test delegate implemented with another delegate."""
|
||||
|
||||
def sayhello():
|
||||
return "hello"
|
||||
|
||||
d1 = StringDelegate(sayhello)
|
||||
d2 = StringDelegate(d1)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(d2) == "hello")
|
||||
self.failUnless(d2() == "hello")
|
||||
|
||||
ob.stringDelegate = d2
|
||||
self.failUnless(ob.CallStringDelegate(ob.stringDelegate) == "hello")
|
||||
self.failUnless(ob.stringDelegate() == "hello")
|
||||
|
||||
|
||||
def testDelegateWithInvalidArgs(self):
|
||||
"""Test delegate instantiation with invalid (non-callable) args."""
|
||||
def test():
|
||||
d = StringDelegate(None)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
d = StringDelegate("spam")
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
d = StringDelegate(1)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testMulticastDelegate(self):
|
||||
"""Test multicast delegates."""
|
||||
|
||||
class Multi:
|
||||
def __init__(self):
|
||||
self.value = 0
|
||||
|
||||
def count(self):
|
||||
self.value += 1
|
||||
return 'ok'
|
||||
|
||||
inst = Multi()
|
||||
d1 = StringDelegate(inst.count)
|
||||
d2 = StringDelegate(inst.count)
|
||||
|
||||
md = System.Delegate.Combine(d1, d2)
|
||||
ob = DelegateTest()
|
||||
|
||||
self.failUnless(ob.CallStringDelegate(md) == "ok")
|
||||
self.failUnless(inst.value == 2)
|
||||
|
||||
self.failUnless(md() == "ok")
|
||||
self.failUnless(inst.value == 4)
|
||||
|
||||
|
||||
def testSubclassDelegateFails(self):
|
||||
"""Test that subclassing of a delegate type fails."""
|
||||
def test():
|
||||
class Boom(PublicDelegate):
|
||||
pass
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testDelegateEquality(self):
|
||||
"""Test delegate equality."""
|
||||
|
||||
def sayhello():
|
||||
return "hello"
|
||||
|
||||
d = StringDelegate(sayhello)
|
||||
ob = DelegateTest()
|
||||
ob.stringDelegate = d
|
||||
self.failUnless(ob.stringDelegate == d)
|
||||
|
||||
|
||||
# test async delegates
|
||||
|
||||
# test multicast delegates
|
||||
|
||||
# test explicit op_
|
||||
|
||||
# test sig mismatch, both on managed and Python side
|
||||
|
||||
# test return wrong type
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(DelegateTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
# 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
|
||||
|
||||
|
||||
class EngineTests(unittest.TestCase):
|
||||
"""Test PythonEngine embedding APIs."""
|
||||
|
||||
def testMultipleCallsToInitialize(self):
|
||||
"""Test that multiple initialize calls are harmless."""
|
||||
PythonEngine.Initialize();
|
||||
PythonEngine.Initialize();
|
||||
PythonEngine.Initialize();
|
||||
|
||||
def testImportModule(self):
|
||||
"""Test module import."""
|
||||
m = PythonEngine.ImportModule("sys")
|
||||
n = m.GetAttr("__name__")
|
||||
self.failUnless(n.AsManagedObject(CLR.System.String) == "sys")
|
||||
|
||||
|
||||
def testRunString(self):
|
||||
"""Test the RunString method."""
|
||||
PythonEngine.AcquireLock()
|
||||
|
||||
code = "import sys; sys.singleline_worked = 1"
|
||||
PythonEngine.RunString(code)
|
||||
self.failUnless(sys.singleline_worked == 1)
|
||||
|
||||
code = "import sys\nsys.multiline_worked = 1"
|
||||
PythonEngine.RunString(code)
|
||||
self.failUnless(sys.multiline_worked == 1)
|
||||
|
||||
PythonEngine.ReleaseLock()
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(EngineTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
# 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()
|
||||
|
|
@ -0,0 +1,723 @@
|
|||
# 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 EventTest, TestEventHandler
|
||||
from CLR.Python.Test import TestEventArgs
|
||||
|
||||
|
||||
class EventTests(unittest.TestCase):
|
||||
"""Test CLR event support."""
|
||||
|
||||
def testPublicInstanceEvent(self):
|
||||
"""Test public instance events."""
|
||||
object = EventTest()
|
||||
|
||||
handler = GenericHandler()
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.PublicEvent += handler.handler
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
|
||||
|
||||
def testPublicStaticEvent(self):
|
||||
"""Test public static events."""
|
||||
handler = GenericHandler()
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
EventTest.PublicStaticEvent += handler.handler
|
||||
|
||||
EventTest.OnPublicStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testProtectedInstanceEvent(self):
|
||||
"""Test protected instance events."""
|
||||
object = EventTest()
|
||||
|
||||
handler = GenericHandler()
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.ProtectedEvent += handler.handler
|
||||
|
||||
object.OnProtectedEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.ProtectedEvent -= handler.handler
|
||||
|
||||
|
||||
def testProtectedStaticEvent(self):
|
||||
"""Test protected static events."""
|
||||
object = EventTest
|
||||
|
||||
handler = GenericHandler()
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
EventTest.ProtectedStaticEvent += handler.handler
|
||||
|
||||
EventTest.OnProtectedStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
EventTest.ProtectedStaticEvent -= handler.handler
|
||||
|
||||
|
||||
def testInternalEvents(self):
|
||||
"""Test internal events."""
|
||||
|
||||
def test():
|
||||
f = EventTest().InternalEvent
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = EventTest().InternalStaticEvent
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = EventTest.InternalStaticEvent
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
def testPrivateEvents(self):
|
||||
"""Test private events."""
|
||||
|
||||
def test():
|
||||
f = EventTest().PrivateEvent
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = EventTest().PrivateStaticEvent
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = EventTest.PrivateStaticEvent
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
def testMulticastEvent(self):
|
||||
"""Test multicast events."""
|
||||
object = EventTest()
|
||||
|
||||
handler1 = GenericHandler()
|
||||
handler2 = GenericHandler()
|
||||
handler3 = GenericHandler()
|
||||
|
||||
object.PublicEvent += handler1.handler
|
||||
object.PublicEvent += handler2.handler
|
||||
object.PublicEvent += handler3.handler
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
|
||||
self.failUnless(handler1.value == 10)
|
||||
self.failUnless(handler2.value == 10)
|
||||
self.failUnless(handler3.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
|
||||
self.failUnless(handler1.value == 20)
|
||||
self.failUnless(handler2.value == 20)
|
||||
self.failUnless(handler3.value == 20)
|
||||
|
||||
object.PublicEvent -= handler1.handler
|
||||
object.PublicEvent -= handler2.handler
|
||||
object.PublicEvent -= handler3.handler
|
||||
|
||||
|
||||
def testInstanceMethodHandler(self):
|
||||
"""Test instance method handlers."""
|
||||
object = EventTest()
|
||||
handler = GenericHandler()
|
||||
|
||||
object.PublicEvent += handler.handler
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testVarArgsInstanceMethodHandler(self):
|
||||
"""Test vararg instance method handlers."""
|
||||
object = EventTest()
|
||||
handler = VariableArgsHandler()
|
||||
|
||||
object.PublicEvent += handler.handler
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testCallableObjectHandler(self):
|
||||
"""Test callable object handlers."""
|
||||
object = EventTest()
|
||||
handler = CallableHandler()
|
||||
|
||||
object.PublicEvent += handler
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.PublicEvent -= handler
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testVarArgsCallableHandler(self):
|
||||
"""Test varargs callable handlers."""
|
||||
object = EventTest()
|
||||
handler = VarCallableHandler()
|
||||
|
||||
object.PublicEvent += handler
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.PublicEvent -= handler
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testStaticMethodHandler(self):
|
||||
"""Test static method handlers."""
|
||||
object = EventTest()
|
||||
handler = StaticMethodHandler()
|
||||
StaticMethodHandler.value = None
|
||||
|
||||
object.PublicEvent += handler.handler
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testClassMethodHandler(self):
|
||||
"""Test class method handlers."""
|
||||
object = EventTest()
|
||||
handler = ClassMethodHandler()
|
||||
ClassMethodHandler.value = None
|
||||
|
||||
object.PublicEvent += handler.handler
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testManagedInstanceMethodHandler(self):
|
||||
"""Test managed instance method handlers."""
|
||||
object = EventTest()
|
||||
|
||||
object.PublicEvent += object.GenericHandler
|
||||
self.failUnless(object.value == 0)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(object.value == 10)
|
||||
|
||||
object.PublicEvent -= object.GenericHandler
|
||||
self.failUnless(object.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(object.value == 10)
|
||||
|
||||
|
||||
def testManagedStaticMethodHandler(self):
|
||||
"""Test managed static method handlers."""
|
||||
object = EventTest()
|
||||
EventTest.s_value = 0
|
||||
|
||||
object.PublicEvent += object.StaticHandler
|
||||
self.failUnless(EventTest.s_value == 0)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(EventTest.s_value == 10)
|
||||
|
||||
object.PublicEvent -= object.StaticHandler
|
||||
self.failUnless(EventTest.s_value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(EventTest.s_value == 10)
|
||||
|
||||
|
||||
def testUnboundMethodHandler(self):
|
||||
"""Test failure mode for unbound method handlers."""
|
||||
object = EventTest()
|
||||
object.PublicEvent += GenericHandler.handler
|
||||
try:
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
except TypeError:
|
||||
object.PublicEvent -= GenericHandler.handler
|
||||
return
|
||||
|
||||
raise TypeError("should have raised a TypeError")
|
||||
|
||||
|
||||
def testFunctionHandler(self):
|
||||
"""Test function handlers."""
|
||||
object = EventTest()
|
||||
dict = {'value':None}
|
||||
|
||||
def handler(sender, args, dict=dict):
|
||||
dict['value'] = args.value
|
||||
|
||||
object.PublicEvent += handler
|
||||
self.failUnless(dict['value'] == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(dict['value'] == 10)
|
||||
|
||||
object.PublicEvent -= handler
|
||||
self.failUnless(dict['value'] == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(dict['value'] == 10)
|
||||
|
||||
|
||||
def testAddNonCallableHandler(self):
|
||||
"""Test handling of attempts to add non-callable handlers."""
|
||||
|
||||
def test():
|
||||
object = EventTest()
|
||||
object.PublicEvent += 10
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = EventTest()
|
||||
object.PublicEvent += "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
|
||||
class spam:
|
||||
pass
|
||||
|
||||
object = EventTest()
|
||||
object.PublicEvent += spam()
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testRemoveMultipleHandlers(self):
|
||||
"""Test removing multiple instances of the same handler."""
|
||||
object = EventTest()
|
||||
handler = MultipleHandler()
|
||||
|
||||
h1 = handler.handler
|
||||
object.PublicEvent += h1
|
||||
|
||||
h2 = handler.handler
|
||||
object.PublicEvent += h2
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 20)
|
||||
|
||||
object.PublicEvent -= h1
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
object.PublicEvent -= h2
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
# try again, removing in a different order.
|
||||
|
||||
object = EventTest()
|
||||
handler = MultipleHandler()
|
||||
|
||||
h1 = handler.handler
|
||||
object.PublicEvent += h1
|
||||
|
||||
h2 = handler.handler
|
||||
object.PublicEvent += h2
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 20)
|
||||
|
||||
object.PublicEvent -= h2
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
object.PublicEvent -= h1
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
|
||||
def testRemoveMultipleStaticHandlers(self):
|
||||
"""Test removing multiple instances of a static handler."""
|
||||
object = EventTest()
|
||||
handler = MultipleHandler()
|
||||
|
||||
h1 = handler.handler
|
||||
object.PublicStaticEvent += h1
|
||||
|
||||
h2 = handler.handler
|
||||
object.PublicStaticEvent += h2
|
||||
|
||||
object.OnPublicStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 20)
|
||||
|
||||
object.PublicStaticEvent -= h1
|
||||
|
||||
object.OnPublicStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
object.PublicStaticEvent -= h2
|
||||
|
||||
object.OnPublicStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
# try again, removing in a different order.
|
||||
|
||||
object = EventTest()
|
||||
handler = MultipleHandler()
|
||||
|
||||
h1 = handler.handler
|
||||
object.PublicStaticEvent += h1
|
||||
|
||||
h2 = handler.handler
|
||||
object.PublicStaticEvent += h2
|
||||
|
||||
object.OnPublicStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 20)
|
||||
|
||||
object.PublicStaticEvent -= h2
|
||||
|
||||
object.OnPublicStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
object.PublicStaticEvent -= h1
|
||||
|
||||
object.OnPublicStaticEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 30)
|
||||
|
||||
|
||||
def testRandomMultipleHandlers(self):
|
||||
"""Test random subscribe / unsubscribe of the same handlers."""
|
||||
import random
|
||||
object = EventTest()
|
||||
handler = MultipleHandler()
|
||||
handler2 = MultipleHandler()
|
||||
|
||||
object.PublicEvent += handler2.handler
|
||||
object.PublicEvent += handler2.handler
|
||||
|
||||
handlers = []
|
||||
for i in range(30):
|
||||
method = handler.handler
|
||||
object.PublicEvent += method
|
||||
handlers.append(method)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 300)
|
||||
self.failUnless(handler2.value == 20)
|
||||
handler.value = 0
|
||||
handler2.value = 0
|
||||
|
||||
for i in range(30):
|
||||
item = random.choice(handlers)
|
||||
handlers.remove(item)
|
||||
object.PublicEvent -= item
|
||||
handler.value = 0
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == (len(handlers) * 10))
|
||||
self.failUnless(handler2.value == ((i + 1) * 20))
|
||||
|
||||
handler2.value = 0
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler2.value == 20)
|
||||
|
||||
object.PublicEvent -= handler2.handler
|
||||
|
||||
handler2.value = 0
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler2.value == 10)
|
||||
|
||||
object.PublicEvent -= handler2.handler
|
||||
|
||||
handler2.value = 0
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler2.value == 0)
|
||||
|
||||
|
||||
def testRemoveInternalCallHandler(self):
|
||||
"""Test remove on an event sink implemented w/internalcall."""
|
||||
object = EventTest()
|
||||
|
||||
def h(sender, args):
|
||||
pass
|
||||
|
||||
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."""
|
||||
def test():
|
||||
object = EventTest()
|
||||
handler = GenericHandler()
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
|
||||
self.failUnlessRaises(ValueError, test)
|
||||
|
||||
|
||||
def testHandlerCallbackFailure(self):
|
||||
"""Test failure mode for inappropriate handlers."""
|
||||
|
||||
class BadHandler:
|
||||
def handler(self, one):
|
||||
return 'too many'
|
||||
|
||||
object = EventTest()
|
||||
handler = BadHandler()
|
||||
|
||||
def test():
|
||||
object.PublicEvent += handler.handler
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
|
||||
class BadHandler:
|
||||
def handler(self, one, two, three, four, five):
|
||||
return 'not enough'
|
||||
|
||||
object = EventTest()
|
||||
handler = BadHandler()
|
||||
|
||||
def test():
|
||||
object.PublicEvent += handler.handler
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
|
||||
|
||||
def testIncorrectInvokation(self):
|
||||
"""Test incorrect invokation of events."""
|
||||
object = EventTest()
|
||||
|
||||
handler = GenericHandler()
|
||||
object.PublicEvent += handler.handler
|
||||
|
||||
def test():
|
||||
object.OnPublicEvent()
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object.OnPublicEvent(32)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
object.PublicEvent -= handler.handler
|
||||
|
||||
|
||||
def testExplicitCLSEventRegistration(self):
|
||||
"""Test explicit CLS event registration."""
|
||||
object = EventTest()
|
||||
handler = GenericHandler()
|
||||
|
||||
delegate = TestEventHandler(handler.handler)
|
||||
object.add_PublicEvent(delegate)
|
||||
self.failUnless(handler.value == None)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(10))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.remove_PublicEvent(delegate)
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
object.OnPublicEvent(TestEventArgs(20))
|
||||
self.failUnless(handler.value == 10)
|
||||
|
||||
|
||||
def testImplicitCLSEventRegistration(self):
|
||||
"""Test implicit CLS event registration."""
|
||||
|
||||
def test():
|
||||
object = EventTest()
|
||||
handler = GenericHandler()
|
||||
object.add_PublicEvent(handler.handler)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testEventDescriptorAbuse(self):
|
||||
"""Test event descriptor abuse."""
|
||||
|
||||
def test():
|
||||
del EventTest.PublicEvent
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del EventTest.__dict__['PublicEvent']
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
desc = EventTest.__dict__['PublicEvent']
|
||||
|
||||
def test():
|
||||
desc.__get__(0, 0)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
desc.__set__(0, 0)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = EventTest()
|
||||
object.PublicEvent = 0
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
EventTest.PublicStaticEvent = 0
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
|
||||
class GenericHandler:
|
||||
"""A generic handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def handler(self, sender, args):
|
||||
self.value = args.value
|
||||
|
||||
|
||||
class VariableArgsHandler:
|
||||
"""A variable args handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def handler(self, *args):
|
||||
ob, eventargs = args
|
||||
self.value = eventargs.value
|
||||
|
||||
|
||||
class CallableHandler:
|
||||
"""A callable handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def __call__(self, sender, args):
|
||||
self.value = args.value
|
||||
|
||||
|
||||
class VarCallableHandler:
|
||||
"""A variable args callable handler to test event callbacks."""
|
||||
def __init__(self):
|
||||
self.value = None
|
||||
|
||||
def __call__(self, *args):
|
||||
ob, eventargs = args
|
||||
self.value = eventargs.value
|
||||
|
||||
|
||||
class StaticMethodHandler(object):
|
||||
"""A static method handler to test event callbacks."""
|
||||
|
||||
value = None
|
||||
|
||||
def handler(sender, args):
|
||||
StaticMethodHandler.value = args.value
|
||||
|
||||
handler = staticmethod(handler)
|
||||
|
||||
|
||||
class ClassMethodHandler(object):
|
||||
"""A class method handler to test event callbacks."""
|
||||
|
||||
value = None
|
||||
|
||||
def handler(cls, sender, args):
|
||||
cls.value = args.value
|
||||
|
||||
handler = classmethod(handler)
|
||||
|
||||
|
||||
class MultipleHandler:
|
||||
"""A generic handler to test multiple callbacks."""
|
||||
def __init__(self):
|
||||
self.value = 0
|
||||
|
||||
def handler(self, sender, args):
|
||||
self.value += args.value
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(EventTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
# 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
|
||||
|
||||
# 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
|
||||
# the tests in place in to document 'how it ought to work' in the hopes
|
||||
# that they'll all pass one day...
|
||||
|
||||
class ExceptionTests(unittest.TestCase):
|
||||
"""Test exception support."""
|
||||
|
||||
def testUnifiedExceptionSemantics(self):
|
||||
"""Test unified exception semantics."""
|
||||
from CLR.System import Exception, Object
|
||||
import exceptions
|
||||
|
||||
e = Exception('Something bad happened')
|
||||
self.failUnless(isinstance(e, exceptions.Exception))
|
||||
self.failUnless(isinstance(e, Exception))
|
||||
|
||||
|
||||
def testStandardExceptionAttributes(self):
|
||||
"""Test accessing standard exception attributes."""
|
||||
from CLR.System import OverflowException
|
||||
from CLR.Python.Test import ExceptionTest
|
||||
|
||||
e = ExceptionTest.GetExplicitException()
|
||||
self.failUnless(isinstance(e, OverflowException))
|
||||
|
||||
self.failUnless(e.Message == 'error')
|
||||
|
||||
e.Source = 'Test Suite'
|
||||
self.failUnless(e.Source == 'Test Suite')
|
||||
|
||||
v = e.ToString()
|
||||
self.failUnless(len(v) > 0)
|
||||
|
||||
|
||||
def testExtendedExceptionAttributes(self):
|
||||
"""Test accessing extended exception attributes."""
|
||||
from CLR.Python.Test import ExceptionTest, ExtendedException
|
||||
from CLR.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.failUnless(e.Message == 'error')
|
||||
|
||||
e.Source = 'Test Suite'
|
||||
self.failUnless(e.Source == 'Test Suite')
|
||||
|
||||
v = e.ToString()
|
||||
self.failUnless(len(v) > 0)
|
||||
|
||||
self.failUnless(e.ExtraProperty == 'extra')
|
||||
e.ExtraProperty = 'changed'
|
||||
self.failUnless(e.ExtraProperty == 'changed')
|
||||
|
||||
self.failUnless(e.GetExtraInfo() == 'changed')
|
||||
|
||||
|
||||
def testRaiseClassException(self):
|
||||
"""Test class exception propagation."""
|
||||
from CLR.System import NullReferenceException
|
||||
|
||||
def test():
|
||||
raise NullReferenceException
|
||||
|
||||
self.failUnlessRaises(NullReferenceException, test)
|
||||
|
||||
try:
|
||||
raise NullReferenceException
|
||||
except:
|
||||
type, value, tb = sys.exc_info()
|
||||
self.failUnless(type is NullReferenceException)
|
||||
self.failUnless(isinstance(value, NullReferenceException))
|
||||
|
||||
|
||||
def testRaiseClassExceptionWithValue(self):
|
||||
"""Test class exception propagation with associated value."""
|
||||
from CLR.System import NullReferenceException
|
||||
|
||||
def test():
|
||||
raise NullReferenceException, 'Aiiieee!'
|
||||
|
||||
self.failUnlessRaises(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!')
|
||||
|
||||
|
||||
def testRaiseInstanceException(self):
|
||||
"""Test instance exception propagation."""
|
||||
from CLR.System import NullReferenceException
|
||||
|
||||
def test():
|
||||
raise NullReferenceException()
|
||||
|
||||
self.failUnlessRaises(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)
|
||||
|
||||
|
||||
def testRaiseInstanceExceptionWithArgs(self):
|
||||
"""Test instance exception propagation with args."""
|
||||
from CLR.System import NullReferenceException
|
||||
|
||||
def test():
|
||||
raise NullReferenceException("Aiieeee!")
|
||||
|
||||
self.failUnlessRaises(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!')
|
||||
|
||||
|
||||
def testManagedExceptionPropagation(self):
|
||||
"""Test propagation of exceptions raised in managed code."""
|
||||
from CLR.System import Decimal, OverflowException
|
||||
|
||||
def test():
|
||||
l = Decimal.ToInt64(Decimal.MaxValue)
|
||||
|
||||
self.failUnlessRaises(OverflowException, test)
|
||||
|
||||
|
||||
def testManagedExceptionConversion(self):
|
||||
"""Test conversion of managed exceptions."""
|
||||
from CLR.System import Exception, OverflowException
|
||||
from CLR.Python.Test import ExceptionTest
|
||||
|
||||
e = ExceptionTest.GetBaseException()
|
||||
self.failUnless(isinstance(e, Exception))
|
||||
|
||||
e = ExceptionTest.GetExplicitException()
|
||||
self.failUnless(isinstance(e, OverflowException))
|
||||
self.failUnless(isinstance(e, Exception))
|
||||
|
||||
e = ExceptionTest.GetWidenedException()
|
||||
self.failUnless(isinstance(e, OverflowException))
|
||||
self.failUnless(isinstance(e, Exception))
|
||||
|
||||
v = ExceptionTest.SetBaseException(Exception('error'))
|
||||
self.failUnless(v)
|
||||
|
||||
v = ExceptionTest.SetExplicitException(OverflowException('error'))
|
||||
self.failUnless(v)
|
||||
|
||||
v = ExceptionTest.SetWidenedException(OverflowException('error'))
|
||||
self.failUnless(v)
|
||||
|
||||
|
||||
def testCatchExceptionFromManagedMethod(self):
|
||||
"""Test catching an exception from a managed method."""
|
||||
from CLR.Python.Test import ExceptionTest
|
||||
from CLR.System import OverflowException
|
||||
|
||||
try:
|
||||
ExceptionTest().ThrowException()
|
||||
except OverflowException, e:
|
||||
self.failUnless(isinstance(e, OverflowException))
|
||||
return
|
||||
|
||||
raise SystemError('failed to catch exception from managed method')
|
||||
|
||||
|
||||
def testCatchExceptionFromManagedProperty(self):
|
||||
"""Test catching an exception from a managed property."""
|
||||
from CLR.Python.Test import ExceptionTest
|
||||
from CLR.System import OverflowException
|
||||
|
||||
try:
|
||||
v = ExceptionTest().ThrowProperty
|
||||
except OverflowException, e:
|
||||
self.failUnless(isinstance(e, OverflowException))
|
||||
return
|
||||
|
||||
try:
|
||||
ExceptionTest().ThrowProperty = 1
|
||||
except OverflowException, e:
|
||||
self.failUnless(isinstance(e, OverflowException))
|
||||
return
|
||||
|
||||
raise SystemError('failed to catch exception from managed property')
|
||||
|
||||
|
||||
def testCatchExceptionManagedClass(self):
|
||||
"""Test catching the managed class of an exception."""
|
||||
from CLR.System import OverflowException
|
||||
|
||||
try:
|
||||
raise OverflowException('overflow')
|
||||
except OverflowException:
|
||||
return
|
||||
|
||||
raise SystemError('failed to catch managed class exception')
|
||||
|
||||
|
||||
def testCatchExceptionPythonClass(self):
|
||||
"""Test catching the python class of an exception."""
|
||||
from CLR.System import OverflowException
|
||||
from exceptions import Exception
|
||||
|
||||
try:
|
||||
raise OverflowException('overflow')
|
||||
except Exception:
|
||||
return
|
||||
|
||||
raise SystemError('failed to catch python class exception')
|
||||
|
||||
|
||||
def testCatchExceptionBaseClass(self):
|
||||
"""Test catching the base of an exception."""
|
||||
from CLR.System import OverflowException, ArithmeticException
|
||||
|
||||
try:
|
||||
raise OverflowException('overflow')
|
||||
except ArithmeticException:
|
||||
return
|
||||
|
||||
raise SystemError('failed to catch base exception')
|
||||
|
||||
|
||||
def testCatchExceptionNestedBaseClass(self):
|
||||
"""Test catching the nested base of an exception."""
|
||||
from CLR.System import OverflowException, SystemException
|
||||
|
||||
try:
|
||||
raise OverflowException('overflow')
|
||||
except SystemException:
|
||||
return
|
||||
|
||||
raise SystemError('failed to catch nested base exception')
|
||||
|
||||
|
||||
def testCatchExceptionWithAssignment(self):
|
||||
"""Test catching an exception with assignment."""
|
||||
from CLR.System import OverflowException
|
||||
|
||||
try:
|
||||
raise OverflowException('overflow')
|
||||
except OverflowException, e:
|
||||
self.failUnless(isinstance(e, OverflowException))
|
||||
|
||||
|
||||
def testCatchExceptionUnqualified(self):
|
||||
"""Test catching an unqualified exception."""
|
||||
from CLR.System import OverflowException
|
||||
|
||||
try:
|
||||
raise OverflowException('overflow')
|
||||
except:
|
||||
return
|
||||
|
||||
raise SystemError('failed to catch unqualified exception')
|
||||
|
||||
|
||||
def testApparentModuleOfException(self):
|
||||
"""Test the apparent module of an exception."""
|
||||
from CLR.System import Exception, OverflowException
|
||||
|
||||
self.failUnless(Exception.__module__ == 'CLR.System')
|
||||
self.failUnless(OverflowException.__module__ == 'CLR.System')
|
||||
|
||||
|
||||
def testStrOfException(self):
|
||||
"""Test the str() representation of an exception."""
|
||||
from CLR.System import NullReferenceException
|
||||
from CLR.System import Convert, FormatException
|
||||
|
||||
e = NullReferenceException('')
|
||||
self.failUnless(str(e) == '')
|
||||
|
||||
e = NullReferenceException('Something bad happened')
|
||||
self.failUnless(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)
|
||||
|
||||
|
||||
def testExceptionIsInstanceOfSystemObject(self):
|
||||
"""Test behavior of isinstance(<managed exception>, System.Object)."""
|
||||
# This is an anti-test, in that this is a caveat of the current
|
||||
# implementation. Because exceptions are not allowed to be new-style
|
||||
# classes, we wrap managed exceptions in a general-purpose old-style
|
||||
# class that delegates to the wrapped object. This makes _almost_
|
||||
# everything work as expected, except that an isinstance check against
|
||||
# CLR.System.Object will fail for a managed exception (because a new
|
||||
# style class cannot appear in the __bases__ of an old-style class
|
||||
# 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
|
||||
|
||||
o = OverflowException('error')
|
||||
self.failIf(isinstance(o, Object))
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(ExceptionTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
|
@ -0,0 +1,467 @@
|
|||
# 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
|
||||
|
||||
|
||||
class FieldTests(unittest.TestCase):
|
||||
"""Test CLR field support."""
|
||||
|
||||
def testPublicInstanceField(self):
|
||||
"""Test public instance fields."""
|
||||
object = FieldTest();
|
||||
self.failUnless(object.PublicField == 0)
|
||||
|
||||
object.PublicField = 1
|
||||
self.failUnless(object.PublicField == 1)
|
||||
|
||||
def test():
|
||||
del FieldTest().PublicField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testPublicStaticField(self):
|
||||
"""Test public static fields."""
|
||||
object = FieldTest();
|
||||
self.failUnless(FieldTest.PublicStaticField == 0)
|
||||
|
||||
FieldTest.PublicStaticField = 1
|
||||
self.failUnless(FieldTest.PublicStaticField == 1)
|
||||
|
||||
self.failUnless(object.PublicStaticField == 1)
|
||||
object.PublicStaticField = 0
|
||||
self.failUnless(object.PublicStaticField == 0)
|
||||
|
||||
def test():
|
||||
del FieldTest.PublicStaticField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del FieldTest().PublicStaticField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testProtectedInstanceField(self):
|
||||
"""Test protected instance fields."""
|
||||
object = FieldTest();
|
||||
self.failUnless(object.ProtectedField == 0)
|
||||
|
||||
object.ProtectedField = 1
|
||||
self.failUnless(object.ProtectedField == 1)
|
||||
|
||||
def test():
|
||||
del FieldTest().ProtectedField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testProtectedStaticField(self):
|
||||
"""Test protected static fields."""
|
||||
object = FieldTest();
|
||||
self.failUnless(FieldTest.ProtectedStaticField == 0)
|
||||
|
||||
FieldTest.ProtectedStaticField = 1
|
||||
self.failUnless(FieldTest.ProtectedStaticField == 1)
|
||||
|
||||
self.failUnless(object.ProtectedStaticField == 1)
|
||||
object.ProtectedStaticField = 0
|
||||
self.failUnless(object.ProtectedStaticField == 0)
|
||||
|
||||
def test():
|
||||
del FieldTest.ProtectedStaticField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del FieldTest().ProtectedStaticField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testReadOnlyInstanceField(self):
|
||||
"""Test readonly instance fields."""
|
||||
self.failUnless(FieldTest().ReadOnlyField == 0)
|
||||
|
||||
def test():
|
||||
FieldTest().ReadOnlyField = 1
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del FieldTest().ReadOnlyField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testReadOnlyStaticField(self):
|
||||
"""Test readonly static fields."""
|
||||
object = FieldTest();
|
||||
|
||||
self.failUnless(FieldTest.ReadOnlyStaticField == 0)
|
||||
self.failUnless(object.ReadOnlyStaticField == 0)
|
||||
|
||||
def test():
|
||||
FieldTest.ReadOnlyStaticField = 1
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
FieldTest().ReadOnlyStaticField = 1
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del FieldTest.ReadOnlyStaticField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del FieldTest().ReadOnlyStaticField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testConstantField(self):
|
||||
"""Test const fields."""
|
||||
object = FieldTest();
|
||||
|
||||
self.failUnless(FieldTest.ConstField == 0)
|
||||
self.failUnless(object.ConstField == 0)
|
||||
|
||||
def test():
|
||||
FieldTest().ConstField = 1
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
FieldTest.ConstField = 1
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del FieldTest().ConstField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
del FieldTest.ConstField
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testInternalField(self):
|
||||
"""Test internal fields."""
|
||||
|
||||
def test():
|
||||
f = FieldTest().InternalField
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = FieldTest().InternalStaticField
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = FieldTest.InternalStaticField
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
def testPrivateField(self):
|
||||
"""Test private fields."""
|
||||
|
||||
def test():
|
||||
f = FieldTest().PrivateField
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = FieldTest().PrivateStaticField
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
f = FieldTest.PrivateStaticField
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
def testFieldDescriptorGetSet(self):
|
||||
"""Test field descriptor get / set."""
|
||||
|
||||
# This test ensures that setting an attribute implemented with
|
||||
# a descriptor actually goes through the descriptor (rather than
|
||||
# silently replacing the descriptor in the instance or type dict.
|
||||
|
||||
object = FieldTest()
|
||||
|
||||
self.failUnless(FieldTest.PublicStaticField == 0)
|
||||
self.failUnless(object.PublicStaticField == 0)
|
||||
|
||||
descriptor = FieldTest.__dict__['PublicStaticField']
|
||||
self.failUnless(type(descriptor) != types.IntType)
|
||||
|
||||
object.PublicStaticField = 0
|
||||
descriptor = FieldTest.__dict__['PublicStaticField']
|
||||
self.failUnless(type(descriptor) != types.IntType)
|
||||
|
||||
FieldTest.PublicStaticField = 0
|
||||
descriptor = FieldTest.__dict__['PublicStaticField']
|
||||
self.failUnless(type(descriptor) != types.IntType)
|
||||
|
||||
|
||||
def testFieldDescriptorWrongType(self):
|
||||
"""Test setting a field using a value of the wrong type."""
|
||||
def test():
|
||||
FieldTest().PublicField = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testFieldDescriptorAbuse(self):
|
||||
"""Test field descriptor abuse."""
|
||||
desc = FieldTest.__dict__['PublicField']
|
||||
|
||||
def test():
|
||||
desc.__get__(0, 0)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
desc.__set__(0, 0)
|
||||
|
||||
self.failUnlessRaises(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)
|
||||
|
||||
object.BooleanField = True
|
||||
self.failUnless(object.BooleanField == True)
|
||||
|
||||
object.BooleanField = False
|
||||
self.failUnless(object.BooleanField == False)
|
||||
|
||||
object.BooleanField = 1
|
||||
self.failUnless(object.BooleanField == True)
|
||||
|
||||
object.BooleanField = 0
|
||||
self.failUnless(object.BooleanField == False)
|
||||
|
||||
|
||||
def testSByteField(self):
|
||||
"""Test sbyte fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.SByteField == 0)
|
||||
|
||||
object.SByteField = 1
|
||||
self.failUnless(object.SByteField == 1)
|
||||
|
||||
|
||||
def testByteField(self):
|
||||
"""Test byte fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.ByteField == 0)
|
||||
|
||||
object.ByteField = 1
|
||||
self.failUnless(object.ByteField == 1)
|
||||
|
||||
|
||||
def testCharField(self):
|
||||
"""Test char fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.CharField == u'A')
|
||||
self.failUnless(object.CharField == 'A')
|
||||
|
||||
object.CharField = 'B'
|
||||
self.failUnless(object.CharField == u'B')
|
||||
self.failUnless(object.CharField == 'B')
|
||||
|
||||
object.CharField = u'C'
|
||||
self.failUnless(object.CharField == u'C')
|
||||
self.failUnless(object.CharField == 'C')
|
||||
|
||||
|
||||
def testInt16Field(self):
|
||||
"""Test int16 fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.Int16Field == 0)
|
||||
|
||||
object.Int16Field = 1
|
||||
self.failUnless(object.Int16Field == 1)
|
||||
|
||||
|
||||
def testInt32Field(self):
|
||||
"""Test int32 fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.Int32Field == 0)
|
||||
|
||||
object.Int32Field = 1
|
||||
self.failUnless(object.Int32Field == 1)
|
||||
|
||||
|
||||
def testInt64Field(self):
|
||||
"""Test int64 fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.Int64Field == 0)
|
||||
|
||||
object.Int64Field = 1
|
||||
self.failUnless(object.Int64Field == 1)
|
||||
|
||||
|
||||
def testUInt16Field(self):
|
||||
"""Test uint16 fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.UInt16Field == 0)
|
||||
|
||||
object.UInt16Field = 1
|
||||
self.failUnless(object.UInt16Field == 1)
|
||||
|
||||
|
||||
def testUInt32Field(self):
|
||||
"""Test uint32 fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.UInt32Field == 0)
|
||||
|
||||
object.UInt32Field = 1
|
||||
self.failUnless(object.UInt32Field == 1)
|
||||
|
||||
|
||||
def testUInt64Field(self):
|
||||
"""Test uint64 fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.UInt64Field == 0)
|
||||
|
||||
object.UInt64Field = 1
|
||||
self.failUnless(object.UInt64Field == 1)
|
||||
|
||||
|
||||
def testSingleField(self):
|
||||
"""Test single fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.SingleField == 0.0)
|
||||
|
||||
object.SingleField = 1.1
|
||||
self.failUnless(object.SingleField == 1.1)
|
||||
|
||||
|
||||
def testDoubleField(self):
|
||||
"""Test double fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.DoubleField == 0.0)
|
||||
|
||||
object.DoubleField = 1.1
|
||||
self.failUnless(object.DoubleField == 1.1)
|
||||
|
||||
|
||||
def testDecimalField(self):
|
||||
"""Test decimal fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.DecimalField == System.Decimal(0))
|
||||
|
||||
object.DecimalField = System.Decimal(1)
|
||||
self.failUnless(object.DecimalField == System.Decimal(1))
|
||||
|
||||
|
||||
def testStringField(self):
|
||||
"""Test string fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.StringField == "spam")
|
||||
|
||||
object.StringField = "eggs"
|
||||
self.failUnless(object.StringField == "eggs")
|
||||
|
||||
|
||||
def testInterfaceField(self):
|
||||
"""Test interface fields."""
|
||||
from CLR.Python.Test import Spam, ISpam
|
||||
|
||||
object = FieldTest()
|
||||
|
||||
self.failUnless(ISpam(object.SpamField).GetValue() == "spam")
|
||||
self.failUnless(object.SpamField.GetValue() == "spam")
|
||||
|
||||
object.SpamField = Spam("eggs")
|
||||
self.failUnless(ISpam(object.SpamField).GetValue() == "eggs")
|
||||
self.failUnless(object.SpamField.GetValue() == "eggs")
|
||||
|
||||
|
||||
def testObjectField(self):
|
||||
"""Test object fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.ObjectField == None)
|
||||
|
||||
object.ObjectField = System.String("spam")
|
||||
self.failUnless(object.ObjectField == "spam")
|
||||
|
||||
object.ObjectField = System.Int32(1)
|
||||
self.failUnless(object.ObjectField == 1)
|
||||
|
||||
object.ObjectField = None
|
||||
self.failUnless(object.ObjectField == None)
|
||||
|
||||
|
||||
def testEnumField(self):
|
||||
"""Test enum fields."""
|
||||
object = FieldTest()
|
||||
self.failUnless(object.EnumField == ShortEnum.Zero)
|
||||
|
||||
object.EnumField = ShortEnum.One
|
||||
self.failUnless(object.EnumField == ShortEnum.One)
|
||||
|
||||
|
||||
def testNullableField(self):
|
||||
"""Test nullable fields."""
|
||||
object = FieldTest()
|
||||
|
||||
object.StringField = None
|
||||
self.failUnless(object.StringField == None)
|
||||
|
||||
object.ObjectField = None
|
||||
self.failUnless(object.ObjectField == None)
|
||||
|
||||
object.SpamField = None
|
||||
self.failUnless(object.SpamField == None)
|
||||
|
||||
# Primitive types and enums should not be set to null.
|
||||
|
||||
def test():
|
||||
FieldTest().Int32Field = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
FieldTest().EnumField = None
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(FieldTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,707 @@
|
|||
# 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
|
||||
|
||||
|
||||
class IndexerTests(unittest.TestCase):
|
||||
"""Test support for indexer properties."""
|
||||
|
||||
def testPublicIndexer(self):
|
||||
"""Test public indexers."""
|
||||
object = Test.PublicIndexerTest()
|
||||
|
||||
object[0] = "zero"
|
||||
self.failUnless(object[0] == "zero")
|
||||
|
||||
object[1] = "one"
|
||||
self.failUnless(object[1] == "one")
|
||||
|
||||
self.failUnless(object[10] == None)
|
||||
|
||||
|
||||
def testProtectedIndexer(self):
|
||||
"""Test protected indexers."""
|
||||
object = Test.ProtectedIndexerTest()
|
||||
|
||||
object[0] = "zero"
|
||||
self.failUnless(object[0] == "zero")
|
||||
|
||||
object[1] = "one"
|
||||
self.failUnless(object[1] == "one")
|
||||
|
||||
self.failUnless(object[10] == None)
|
||||
|
||||
|
||||
def testInternalIndexer(self):
|
||||
"""Test internal indexers."""
|
||||
object = Test.InternalIndexerTest()
|
||||
|
||||
def test():
|
||||
object[0] = "zero"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
Test.InternalIndexerTest.__getitem__(object, 0)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object.__getitem__(0)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testPrivateIndexer(self):
|
||||
"""Test private indexers."""
|
||||
object = Test.PrivateIndexerTest()
|
||||
|
||||
def test():
|
||||
object[0] = "zero"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
Test.PrivateIndexerTest.__getitem__(object, 0)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object.__getitem__(0)
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testBooleanIndexer(self):
|
||||
"""Test boolean indexers."""
|
||||
object = Test.BooleanIndexerTest()
|
||||
|
||||
self.failUnless(object[True] == None)
|
||||
self.failUnless(object[1] == None)
|
||||
|
||||
object[0] = "false"
|
||||
self.failUnless(object[0] == "false")
|
||||
|
||||
object[1] = "true"
|
||||
self.failUnless(object[1] == "true")
|
||||
|
||||
object[False] = "false"
|
||||
self.failUnless(object[False] == "false")
|
||||
|
||||
object[True] = "true"
|
||||
self.failUnless(object[True] == "true")
|
||||
|
||||
|
||||
def testByteIndexer(self):
|
||||
"""Test byte indexers."""
|
||||
object = Test.ByteIndexerTest()
|
||||
max = 255
|
||||
min = 0
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.ByteIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.ByteIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testSByteIndexer(self):
|
||||
"""Test sbyte indexers."""
|
||||
object = Test.SByteIndexerTest()
|
||||
max = 127
|
||||
min = -128
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.SByteIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.SByteIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testCharIndexer(self):
|
||||
"""Test char indexers."""
|
||||
object = Test.CharIndexerTest()
|
||||
max = unichr(65535)
|
||||
min = unichr(0)
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = "max"
|
||||
self.failUnless(object[max] == "max")
|
||||
|
||||
object[min] = "min"
|
||||
self.failUnless(object[min] == "min")
|
||||
|
||||
def test():
|
||||
object = Test.CharIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.CharIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testInt16Indexer(self):
|
||||
"""Test Int16 indexers."""
|
||||
object = Test.Int16IndexerTest()
|
||||
max = 32767
|
||||
min = -32768
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.Int16IndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.Int16IndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testInt32Indexer(self):
|
||||
"""Test Int32 indexers."""
|
||||
object = Test.Int32IndexerTest()
|
||||
max = 2147483647
|
||||
min = -2147483648
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.Int32IndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.Int32IndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testInt64Indexer(self):
|
||||
"""Test Int64 indexers."""
|
||||
object = Test.Int64IndexerTest()
|
||||
max = 9223372036854775807L
|
||||
min = -9223372036854775808L
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.Int64IndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.Int64IndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testUInt16Indexer(self):
|
||||
"""Test UInt16 indexers."""
|
||||
object = Test.UInt16IndexerTest()
|
||||
max = 65535
|
||||
min = 0
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.UInt16IndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.UInt16IndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testUInt32Indexer(self):
|
||||
"""Test UInt32 indexers."""
|
||||
object = Test.UInt32IndexerTest()
|
||||
max = 4294967295L
|
||||
min = 0
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.UInt32IndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.UInt32IndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testUInt64Indexer(self):
|
||||
"""Test UInt64 indexers."""
|
||||
object = Test.UInt64IndexerTest()
|
||||
max = 18446744073709551615L
|
||||
min = 0
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = str(max)
|
||||
self.failUnless(object[max] == str(max))
|
||||
|
||||
object[min] = str(min)
|
||||
self.failUnless(object[min] == str(min))
|
||||
|
||||
def test():
|
||||
object = Test.UInt64IndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.UInt64IndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testSingleIndexer(self):
|
||||
"""Test Single indexers."""
|
||||
object = Test.SingleIndexerTest()
|
||||
max = 3.402823e38
|
||||
min = -3.402823e38
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = "max"
|
||||
self.failUnless(object[max] == "max")
|
||||
|
||||
object[min] = "min"
|
||||
self.failUnless(object[min] == "min")
|
||||
|
||||
def test():
|
||||
object = Test.SingleIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.SingleIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testDoubleIndexer(self):
|
||||
"""Test Double indexers."""
|
||||
object = Test.DoubleIndexerTest()
|
||||
max = 1.7976931348623157e308
|
||||
min = -1.7976931348623157e308
|
||||
|
||||
self.failUnless(object[max] == None)
|
||||
|
||||
object[max] = "max"
|
||||
self.failUnless(object[max] == "max")
|
||||
|
||||
object[min] = "min"
|
||||
self.failUnless(object[min] == "min")
|
||||
|
||||
def test():
|
||||
object = Test.DoubleIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.DoubleIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testDecimalIndexer(self):
|
||||
"""Test Decimal indexers."""
|
||||
object = Test.DecimalIndexerTest()
|
||||
|
||||
from CLR.System import Decimal
|
||||
max_d = Decimal.Parse("79228162514264337593543950335")
|
||||
min_d = Decimal.Parse("-79228162514264337593543950335")
|
||||
|
||||
self.failUnless(object[max_d] == None)
|
||||
|
||||
object[max_d] = "max"
|
||||
self.failUnless(object[max_d] == "max")
|
||||
|
||||
object[min_d] = "min"
|
||||
self.failUnless(object[min_d] == "min")
|
||||
|
||||
def test():
|
||||
object = Test.DecimalIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.DecimalIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testStringIndexer(self):
|
||||
"""Test String indexers."""
|
||||
object = Test.StringIndexerTest()
|
||||
|
||||
self.failUnless(object["spam"] == None)
|
||||
self.failUnless(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")
|
||||
|
||||
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")
|
||||
|
||||
def test():
|
||||
object = Test.StringIndexerTest()
|
||||
object[1]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.StringIndexerTest()
|
||||
object[1] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testEnumIndexer(self):
|
||||
"""Test enum indexers."""
|
||||
object = Test.EnumIndexerTest()
|
||||
|
||||
key = Test.ShortEnum.One
|
||||
|
||||
self.failUnless(object[key] == None)
|
||||
|
||||
object[key] = "spam"
|
||||
self.failUnless(object[key] == "spam")
|
||||
|
||||
object[key] = "eggs"
|
||||
self.failUnless(object[key] == "eggs")
|
||||
|
||||
object[1] = "spam"
|
||||
self.failUnless(object[1] == "spam")
|
||||
|
||||
def test():
|
||||
object = Test.EnumIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.EnumIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testObjectIndexer(self):
|
||||
"""Test object indexers."""
|
||||
object = Test.ObjectIndexerTest()
|
||||
|
||||
from CLR.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)
|
||||
|
||||
object[spam] = "spam"
|
||||
self.failUnless(object[spam] == "spam")
|
||||
|
||||
object["spam"] = "eggs"
|
||||
self.failUnless(object["spam"] == "eggs")
|
||||
|
||||
object[1] = "one"
|
||||
self.failUnless(object[1] == "one")
|
||||
|
||||
object[1L] = "long"
|
||||
self.failUnless(object[1L] == "long")
|
||||
|
||||
def test():
|
||||
class eggs:
|
||||
pass
|
||||
key = eggs()
|
||||
object = Test.ObjectIndexerTest()
|
||||
object[key] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testInterfaceIndexer(self):
|
||||
"""Test interface indexers."""
|
||||
object = Test.InterfaceIndexerTest()
|
||||
|
||||
from CLR.Python.Test import Spam
|
||||
spam = Spam("spam")
|
||||
|
||||
self.failUnless(object[spam] == None)
|
||||
|
||||
object[spam] = "spam"
|
||||
self.failUnless(object[spam] == "spam")
|
||||
|
||||
object[spam] = "eggs"
|
||||
self.failUnless(object[spam] == "eggs")
|
||||
|
||||
def test():
|
||||
object = Test.InterfaceIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.InterfaceIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testTypedIndexer(self):
|
||||
"""Test typed indexers."""
|
||||
object = Test.TypedIndexerTest()
|
||||
|
||||
from CLR.Python.Test import Spam
|
||||
spam = Spam("spam")
|
||||
|
||||
self.failUnless(object[spam] == None)
|
||||
|
||||
object[spam] = "spam"
|
||||
self.failUnless(object[spam] == "spam")
|
||||
|
||||
object[spam] = "eggs"
|
||||
self.failUnless(object[spam] == "eggs")
|
||||
|
||||
def test():
|
||||
object = Test.TypedIndexerTest()
|
||||
object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.TypedIndexerTest()
|
||||
object["wrong"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testMultiArgIndexer(self):
|
||||
"""Test indexers that take multiple index arguments."""
|
||||
object = Test.MultiArgIndexerTest()
|
||||
|
||||
object[0, 1] = "zero one"
|
||||
self.failUnless(object[0, 1] == "zero one")
|
||||
|
||||
object[1, 9] = "one nine"
|
||||
self.failUnless(object[1, 9] == "one nine")
|
||||
|
||||
self.failUnless(object[10, 50] == None)
|
||||
|
||||
def test():
|
||||
object = Test.MultiArgIndexerTest()
|
||||
v = object[0, "one"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.MultiArgIndexerTest()
|
||||
object[0, "one"] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testMultiTypeIndexer(self):
|
||||
"""Test indexers that take multiple indices of different types."""
|
||||
object = Test.MultiTypeIndexerTest()
|
||||
spam = Test.Spam("spam")
|
||||
|
||||
object[0, "one", spam] = "zero one spam"
|
||||
self.failUnless(object[0, "one", spam] == "zero one spam")
|
||||
|
||||
object[1, "nine", spam] = "one nine spam"
|
||||
self.failUnless(object[1, "nine", spam] == "one nine spam")
|
||||
|
||||
def test():
|
||||
object = Test.MultiTypeIndexerTest()
|
||||
v = object[0, 1, spam]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.MultiTypeIndexerTest()
|
||||
object[0, 1, spam] = "wrong"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testIndexerWrongKeyType(self):
|
||||
"""Test calling an indexer using a key of the wrong type."""
|
||||
|
||||
def test():
|
||||
object = Test.PublicIndexerTest()
|
||||
v = object["wrong"]
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
def test():
|
||||
object = Test.PublicIndexerTest()
|
||||
object["wrong"] = "spam"
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testIndexerWrongValueType(self):
|
||||
"""Test calling an indexer using a value of the wrong type."""
|
||||
|
||||
def test():
|
||||
object = Test.PublicIndexerTest()
|
||||
object[1] = 9993.9
|
||||
|
||||
self.failUnlessRaises(TypeError, test)
|
||||
|
||||
|
||||
def testUnboundIndexer(self):
|
||||
"""Test calling an unbound indexer."""
|
||||
object = Test.PublicIndexerTest()
|
||||
|
||||
Test.PublicIndexerTest.__setitem__(object, 0, "zero")
|
||||
self.failUnless(object[0] == "zero")
|
||||
|
||||
Test.PublicIndexerTest.__setitem__(object, 1, "one")
|
||||
self.failUnless(object[1] == "one")
|
||||
|
||||
self.failUnless(object[10] == None)
|
||||
|
||||
|
||||
def testIndexerAbuse(self):
|
||||
"""Test indexer abuse."""
|
||||
_class = Test.PublicIndexerTest
|
||||
object = Test.PublicIndexerTest()
|
||||
|
||||
def test():
|
||||
del _class.__getitem__
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
del object.__getitem__
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
del _class.__setitem__
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
def test():
|
||||
del object.__setitem__
|
||||
|
||||
self.failUnlessRaises(AttributeError, test)
|
||||
|
||||
|
||||
|
||||
def test_suite():
|
||||
return unittest.makeSuite(IndexerTests)
|
||||
|
||||
def main():
|
||||
unittest.TextTestRunner().run(test_suite())
|
||||
|
||||
if __name__ == '__main__':
|
||||
testcase.setup()
|
||||
main()
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
# 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()
|
||||
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче