diff --git a/.travis.yml b/.travis.yml
index 2062a35da..ab76d3b27 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,6 +2,7 @@ dist: xenial
sudo: false
language: python
python:
+ - 3.9
- 3.8
- 3.7
- 3.6
diff --git a/AUTHORS.md b/AUTHORS.md
index 5dbf1e1ce..85812a47d 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -73,4 +73,5 @@
- ([@rmadsen-ks](https://github.com/rmadsen-ks))
- ([@stonebig](https://github.com/stonebig))
- ([@testrunner123](https://github.com/testrunner123))
+- ([@DanBarzilian](https://github.com/DanBarzilian))
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ad4016450..e884341bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,15 +5,25 @@ project adheres to [Semantic Versioning][].
This document follows the conventions laid out in [Keep a CHANGELOG][].
-## [Unreleased][]
-### Added
+## [2.5.2](https://github.com/pythonnet/pythonnet/releases/tag/v2.5.2) - 2021-02-05
-### Changed
+Bugfix release.
### Fixed
+- Fix `object[]` parameters taking precedence when should not in overload resolution
+- Empty parameter names (as can be generated from F#) do not cause crashes
+
+## [2.5.1](https://github.com/pythonnet/pythonnet/releases/tag/v2.5.1) - 2020-06-18
+
+Bugfix release.
+
+### Fixed
+
+- Fix incorrect dereference of wrapper object in `tp_repr`, which may result in a program crash
+- Fix incorrect dereference in params array handling
-## [2.5.0][] - 2020-06-14
+## [2.5.0](https://github.com/pythonnet/pythonnet/releases/tag/v2.5.0) - 2020-06-14
This version improves performance on benchmarks significantly compared to 2.3.
@@ -65,7 +75,7 @@ This version improves performance on benchmarks significantly compared to 2.3.
- Fixed issue with params methods that are not passed an array.
- Use UTF8 to encode strings passed to `PyRun_String` on Python 3
-## [2.4.0][] - 2019-05-15
+## [2.4.0](https://github.com/pythonnet/pythonnet/releases/tag/v2.4.0) - 2019-05-15
### Added
diff --git a/appveyor.yml b/appveyor.yml
index b58b72372..6268798af 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,8 +2,8 @@ version: '{branch}-{build}'
build: off
image:
- - Visual Studio 2017
-
+ - Visual Studio 2019
+
platform:
- x86
- x64
@@ -15,6 +15,8 @@ environment:
CODECOV_ENV: PYTHON_VERSION, PLATFORM
matrix:
+ - PYTHON_VERSION: 3.9
+ BUILD_OPTS: --xplat
- PYTHON_VERSION: 3.8
BUILD_OPTS: --xplat
- PYTHON_VERSION: 3.7
@@ -23,14 +25,14 @@ environment:
BUILD_OPTS: --xplat
- PYTHON_VERSION: 3.5
BUILD_OPTS: --xplat
- - PYTHON_VERSION: 2.7
+ - PYTHON_VERSION: 2.7
BUILD_OPTS: --xplat
+ - PYTHON_VERSION: 3.9
- PYTHON_VERSION: 3.8
- PYTHON_VERSION: 3.7
- PYTHON_VERSION: 3.6
- PYTHON_VERSION: 3.5
- PYTHON_VERSION: 2.7
-
init:
# Update Environment Variables based on matrix/platform
- set PY_VER=%PYTHON_VERSION:.=%
diff --git a/requirements.txt b/requirements.txt
index 29c2e4566..78570cb95 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
# Requirements for both Travis and AppVeyor
-pytest==3.2.5
+pytest
coverage
psutil
@@ -7,6 +7,5 @@ psutil
codecov
# Platform specific requirements
-# pip; sys_platform == 'win32'
-wheel; sys_platform == 'win32'
-pycparser; sys_platform != 'win32'
+wheel
+pycparser
diff --git a/setup.py b/setup.py
index 216620211..9dd4ec990 100644
--- a/setup.py
+++ b/setup.py
@@ -13,10 +13,10 @@
import subprocess
import sys
import sysconfig
-from distutils import spawn
-from distutils.command import install, build, build_ext, install_data, install_lib
from setuptools import Extension, setup
+from distutils import spawn
+from distutils.command import install, build, build_ext, install_data, install_lib
try:
from wheel import bdist_wheel
@@ -629,7 +629,7 @@ def run(self):
setup(
name="pythonnet",
- version="2.5.0",
+ version="2.5.2",
description=".Net and Mono integration for Python",
url="https://pythonnet.github.io/",
license="MIT",
@@ -652,6 +652,7 @@ def run(self):
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Operating System :: MacOS :: MacOS X",
diff --git a/src/SharedAssemblyInfo.cs b/src/SharedAssemblyInfo.cs
index dd057b144..2b96e0daf 100644
--- a/src/SharedAssemblyInfo.cs
+++ b/src/SharedAssemblyInfo.cs
@@ -25,4 +25,4 @@
// Version Information. Keeping it simple. May need to revisit for Nuget
// See: https://codingforsmarties.wordpress.com/2016/01/21/how-to-version-assemblies-destined-for-nuget/
// AssemblyVersion can only be numeric
-[assembly: AssemblyVersion("2.5.0")]
+[assembly: AssemblyVersion("2.5.2")]
diff --git a/src/clrmodule/ClrModule.cs b/src/clrmodule/ClrModule.cs
index 377be66d1..e8ef1ae77 100644
--- a/src/clrmodule/ClrModule.cs
+++ b/src/clrmodule/ClrModule.cs
@@ -53,7 +53,7 @@ public static void initclr()
{
#if USE_PYTHON_RUNTIME_VERSION
// Has no effect until SNK works. Keep updated anyways.
- Version = new Version("2.5.0"),
+ Version = new Version("2.5.2"),
#endif
CultureInfo = CultureInfo.InvariantCulture
};
diff --git a/src/clrmodule/clrmodule.15.csproj b/src/clrmodule/clrmodule.15.csproj
index 7fc9c2dda..eba365b76 100644
--- a/src/clrmodule/clrmodule.15.csproj
+++ b/src/clrmodule/clrmodule.15.csproj
@@ -9,7 +9,7 @@
clrmodule
clrmodule
clrmodule
- 2.5.0
+ 2.5.2
false
false
false
diff --git a/src/console/Console.15.csproj b/src/console/Console.15.csproj
index 3c51caa31..4397feb7b 100644
--- a/src/console/Console.15.csproj
+++ b/src/console/Console.15.csproj
@@ -8,7 +8,7 @@
nPython
Python.Runtime
nPython
- 2.5.0
+ 2.5.2
false
false
false
diff --git a/src/embed_tests/Python.EmbeddingTest.15.csproj b/src/embed_tests/Python.EmbeddingTest.15.csproj
index eb6957656..8fed4dc99 100644
--- a/src/embed_tests/Python.EmbeddingTest.15.csproj
+++ b/src/embed_tests/Python.EmbeddingTest.15.csproj
@@ -10,7 +10,7 @@
Python.EmbeddingTest
Python.EmbeddingTest
Python.EmbeddingTest
- 2.5.0
+ 2.5.2
false
false
false
diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj
index d753a5dff..a9a86536f 100644
--- a/src/runtime/Python.Runtime.15.csproj
+++ b/src/runtime/Python.Runtime.15.csproj
@@ -8,7 +8,7 @@
Python.Runtime
Python.Runtime
pythonnet
- 2.5.0
+ 2.5.2
true
false
Python.NET
diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj
index 75f5e2fab..9f8acff92 100644
--- a/src/runtime/Python.Runtime.csproj
+++ b/src/runtime/Python.Runtime.csproj
@@ -1,4 +1,4 @@
-
+
Debug
@@ -165,6 +165,7 @@
+
diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs
index 144bac9d3..43ec6ea72 100644
--- a/src/runtime/classbase.cs
+++ b/src/runtime/classbase.cs
@@ -266,6 +266,7 @@ public static IntPtr tp_repr(IntPtr ob)
//otherwise use the standard object.__repr__(inst)
IntPtr args = Runtime.PyTuple_New(1);
+ Runtime.XIncref(ob);
Runtime.PyTuple_SetItem(args, 0, ob);
IntPtr reprFunc = Runtime.PyObject_GetAttrString(Runtime.PyBaseObjectType, "__repr__");
var output = Runtime.PyObject_Call(reprFunc, args, IntPtr.Zero);
diff --git a/src/runtime/interop39.cs b/src/runtime/interop39.cs
new file mode 100644
index 000000000..e042cb57d
--- /dev/null
+++ b/src/runtime/interop39.cs
@@ -0,0 +1,244 @@
+
+// Auto-generated by geninterop.py.
+// DO NOT MODIFY BY HAND.
+
+
+#if PYTHON39
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Text;
+
+namespace Python.Runtime
+{
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal static class TypeOffset
+ {
+ static TypeOffset()
+ {
+ Type type = typeof(TypeOffset);
+ FieldInfo[] fi = type.GetFields();
+ int size = IntPtr.Size;
+ for (int i = 0; i < fi.Length; i++)
+ {
+ fi[i].SetValue(null, i * size);
+ }
+ }
+
+ public static int magic()
+ {
+ return ob_size;
+ }
+
+ // Auto-generated from PyHeapTypeObject in Python.h
+ public static int ob_refcnt = 0;
+ public static int ob_type = 0;
+ public static int ob_size = 0;
+ public static int tp_name = 0;
+ public static int tp_basicsize = 0;
+ public static int tp_itemsize = 0;
+ public static int tp_dealloc = 0;
+ public static int tp_vectorcall_offset = 0;
+ public static int tp_getattr = 0;
+ public static int tp_setattr = 0;
+ public static int tp_as_async = 0;
+ public static int tp_repr = 0;
+ public static int tp_as_number = 0;
+ public static int tp_as_sequence = 0;
+ public static int tp_as_mapping = 0;
+ public static int tp_hash = 0;
+ public static int tp_call = 0;
+ public static int tp_str = 0;
+ public static int tp_getattro = 0;
+ public static int tp_setattro = 0;
+ public static int tp_as_buffer = 0;
+ public static int tp_flags = 0;
+ public static int tp_doc = 0;
+ public static int tp_traverse = 0;
+ public static int tp_clear = 0;
+ public static int tp_richcompare = 0;
+ public static int tp_weaklistoffset = 0;
+ public static int tp_iter = 0;
+ public static int tp_iternext = 0;
+ public static int tp_methods = 0;
+ public static int tp_members = 0;
+ public static int tp_getset = 0;
+ public static int tp_base = 0;
+ public static int tp_dict = 0;
+ public static int tp_descr_get = 0;
+ public static int tp_descr_set = 0;
+ public static int tp_dictoffset = 0;
+ public static int tp_init = 0;
+ public static int tp_alloc = 0;
+ public static int tp_new = 0;
+ public static int tp_free = 0;
+ public static int tp_is_gc = 0;
+ public static int tp_bases = 0;
+ public static int tp_mro = 0;
+ public static int tp_cache = 0;
+ public static int tp_subclasses = 0;
+ public static int tp_weaklist = 0;
+ public static int tp_del = 0;
+ public static int tp_version_tag = 0;
+ public static int tp_finalize = 0;
+ public static int tp_vectorcall = 0;
+ public static int am_await = 0;
+ public static int am_aiter = 0;
+ public static int am_anext = 0;
+ public static int nb_add = 0;
+ public static int nb_subtract = 0;
+ public static int nb_multiply = 0;
+ public static int nb_remainder = 0;
+ public static int nb_divmod = 0;
+ public static int nb_power = 0;
+ public static int nb_negative = 0;
+ public static int nb_positive = 0;
+ public static int nb_absolute = 0;
+ public static int nb_bool = 0;
+ public static int nb_invert = 0;
+ public static int nb_lshift = 0;
+ public static int nb_rshift = 0;
+ public static int nb_and = 0;
+ public static int nb_xor = 0;
+ public static int nb_or = 0;
+ public static int nb_int = 0;
+ public static int nb_reserved = 0;
+ public static int nb_float = 0;
+ public static int nb_inplace_add = 0;
+ public static int nb_inplace_subtract = 0;
+ public static int nb_inplace_multiply = 0;
+ public static int nb_inplace_remainder = 0;
+ public static int nb_inplace_power = 0;
+ public static int nb_inplace_lshift = 0;
+ public static int nb_inplace_rshift = 0;
+ public static int nb_inplace_and = 0;
+ public static int nb_inplace_xor = 0;
+ public static int nb_inplace_or = 0;
+ public static int nb_floor_divide = 0;
+ public static int nb_true_divide = 0;
+ public static int nb_inplace_floor_divide = 0;
+ public static int nb_inplace_true_divide = 0;
+ public static int nb_index = 0;
+ public static int nb_matrix_multiply = 0;
+ public static int nb_inplace_matrix_multiply = 0;
+ public static int mp_length = 0;
+ public static int mp_subscript = 0;
+ public static int mp_ass_subscript = 0;
+ public static int sq_length = 0;
+ public static int sq_concat = 0;
+ public static int sq_repeat = 0;
+ public static int sq_item = 0;
+ public static int was_sq_slice = 0;
+ public static int sq_ass_item = 0;
+ public static int was_sq_ass_slice = 0;
+ public static int sq_contains = 0;
+ public static int sq_inplace_concat = 0;
+ public static int sq_inplace_repeat = 0;
+ public static int bf_getbuffer = 0;
+ public static int bf_releasebuffer = 0;
+ public static int name = 0;
+ public static int ht_slots = 0;
+ public static int qualname = 0;
+ public static int ht_cached_keys = 0;
+ public static int ht_module = 0;
+
+ /* here are optional user slots, followed by the members. */
+ public static int members = 0;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PyNumberMethods
+ {
+ public IntPtr nb_add;
+ public IntPtr nb_subtract;
+ public IntPtr nb_multiply;
+ public IntPtr nb_remainder;
+ public IntPtr nb_divmod;
+ public IntPtr nb_power;
+ public IntPtr nb_negative;
+ public IntPtr nb_positive;
+ public IntPtr nb_absolute;
+ public IntPtr nb_bool;
+ public IntPtr nb_invert;
+ public IntPtr nb_lshift;
+ public IntPtr nb_rshift;
+ public IntPtr nb_and;
+ public IntPtr nb_xor;
+ public IntPtr nb_or;
+ public IntPtr nb_int;
+ public IntPtr nb_reserved;
+ public IntPtr nb_float;
+ public IntPtr nb_inplace_add;
+ public IntPtr nb_inplace_subtract;
+ public IntPtr nb_inplace_multiply;
+ public IntPtr nb_inplace_remainder;
+ public IntPtr nb_inplace_power;
+ public IntPtr nb_inplace_lshift;
+ public IntPtr nb_inplace_rshift;
+ public IntPtr nb_inplace_and;
+ public IntPtr nb_inplace_xor;
+ public IntPtr nb_inplace_or;
+ public IntPtr nb_floor_divide;
+ public IntPtr nb_true_divide;
+ public IntPtr nb_inplace_floor_divide;
+ public IntPtr nb_inplace_true_divide;
+ public IntPtr nb_index;
+ public IntPtr nb_matrix_multiply;
+ public IntPtr nb_inplace_matrix_multiply;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PySequenceMethods
+ {
+ public IntPtr sq_length;
+ public IntPtr sq_concat;
+ public IntPtr sq_repeat;
+ public IntPtr sq_item;
+ public IntPtr was_sq_slice;
+ public IntPtr sq_ass_item;
+ public IntPtr was_sq_ass_slice;
+ public IntPtr sq_contains;
+ public IntPtr sq_inplace_concat;
+ public IntPtr sq_inplace_repeat;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PyMappingMethods
+ {
+ public IntPtr mp_length;
+ public IntPtr mp_subscript;
+ public IntPtr mp_ass_subscript;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PyAsyncMethods
+ {
+ public IntPtr am_await;
+ public IntPtr am_aiter;
+ public IntPtr am_anext;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PyBufferProcs
+ {
+ public IntPtr bf_getbuffer;
+ public IntPtr bf_releasebuffer;
+ }
+
+ internal static partial class SlotTypes
+ {
+ public static readonly Type[] Types = {
+ typeof(PyNumberMethods),
+ typeof(PySequenceMethods),
+ typeof(PyMappingMethods),
+ typeof(PyAsyncMethods),
+ typeof(PyBufferProcs),
+ };
+ }
+
+}
+#endif
+
diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs
index b74f21754..077297a90 100644
--- a/src/runtime/methodbinder.cs
+++ b/src/runtime/methodbinder.cs
@@ -203,6 +203,16 @@ internal static int ArgPrecedence(Type t)
return 3000;
}
+ if (t.IsArray)
+ {
+ Type e = t.GetElementType();
+ if (e == objectType)
+ {
+ return 2500;
+ }
+ return 100 + ArgPrecedence(e);
+ }
+
TypeCode tc = Type.GetTypeCode(t);
// TODO: Clean up
switch (tc)
@@ -250,16 +260,6 @@ internal static int ArgPrecedence(Type t)
return 40;
}
- if (t.IsArray)
- {
- Type e = t.GetElementType();
- if (e == objectType)
- {
- return 2500;
- }
- return 100 + ArgPrecedence(e);
- }
-
return 2000;
}
@@ -372,7 +372,7 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out bool isNewReference)
{
isNewReference = false;
- IntPtr op;
+ IntPtr op;
// for a params method, we may have a sequence or single/multiple items
// here we look to see if the item at the paramIndex is there or not
// and then if it is a sequence itself.
@@ -390,10 +390,6 @@ static IntPtr HandleParamsArray(IntPtr args, int arrayStart, int pyArgCount, out
{
isNewReference = true;
op = Runtime.PyTuple_GetSlice(args, arrayStart, pyArgCount);
- if (item != IntPtr.Zero)
- {
- Runtime.XDecref(item);
- }
}
}
else
@@ -431,7 +427,7 @@ static object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
for (int paramIndex = 0; paramIndex < pi.Length; paramIndex++)
{
var parameter = pi[paramIndex];
- bool hasNamedParam = kwargDict.ContainsKey(parameter.Name);
+ bool hasNamedParam = parameter.Name != null ? kwargDict.ContainsKey(parameter.Name) : false;
bool isNewReference = false;
if (paramIndex >= pyArgCount && !(hasNamedParam || (paramsArray && paramIndex == arrayStart)))
diff --git a/src/runtime/resources/clr.py b/src/runtime/resources/clr.py
index 78fae0d3a..18b4ba93f 100644
--- a/src/runtime/resources/clr.py
+++ b/src/runtime/resources/clr.py
@@ -2,7 +2,7 @@
Code in this module gets loaded into the main clr module.
"""
-__version__ = "2.5.0"
+__version__ = "2.5.1"
class clrproperty(object):
diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs
index 8cf24ba70..8db9c3d13 100644
--- a/src/runtime/runtime.cs
+++ b/src/runtime/runtime.cs
@@ -68,8 +68,11 @@ public class Runtime
#elif PYTHON38
internal const string _pyversion = "3.8";
internal const string _pyver = "38";
+#elif PYTHON39
+ internal const string _pyversion = "3.9";
+ internal const string _pyver = "39";
#else
-#error You must define one of PYTHON34 to PYTHON38 or PYTHON27
+#error You must define one of PYTHON34 to PYTHON39 or PYTHON27
#endif
#if MONO_LINUX || MONO_OSX // Linux/macOS use dotted version string
diff --git a/src/testing/Python.Test.15.csproj b/src/testing/Python.Test.15.csproj
index 0e19adf91..75a26bd1c 100644
--- a/src/testing/Python.Test.15.csproj
+++ b/src/testing/Python.Test.15.csproj
@@ -7,7 +7,7 @@
Python.Test
Python.Test
Python.Test
- 2.5.0
+ 2.5.2
bin\
false
$(OutputPath)\$(AssemblyName).xml
diff --git a/src/testing/methodtest.cs b/src/testing/methodtest.cs
index 91836b727..9a4c408d6 100644
--- a/src/testing/methodtest.cs
+++ b/src/testing/methodtest.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Linq;
using System.Runtime.InteropServices;
namespace Python.Test
@@ -84,7 +85,7 @@ public Type[] TestNullArrayConversion(Type[] v)
public static string[] TestStringParamsArg(params string[] args)
{
- return args;
+ return args.Concat(new []{"tail"}).ToArray();
}
public static object[] TestObjectParamsArg(params object[] args)
diff --git a/src/tests/test_method.py b/src/tests/test_method.py
index 69f1b5e72..8456ddc9f 100644
--- a/src/tests/test_method.py
+++ b/src/tests/test_method.py
@@ -208,17 +208,20 @@ def test_null_array_conversion():
def test_string_params_args():
"""Test use of string params."""
result = MethodTest.TestStringParamsArg('one', 'two', 'three')
- assert result.Length == 3
- assert len(result) == 3, result
+ assert result.Length == 4
+ assert len(result) == 4, result
assert result[0] == 'one'
assert result[1] == 'two'
assert result[2] == 'three'
+ # ensures params string[] overload takes precedence over params object[]
+ assert result[3] == 'tail'
result = MethodTest.TestStringParamsArg(['one', 'two', 'three'])
- assert len(result) == 3
+ assert len(result) == 4
assert result[0] == 'one'
assert result[1] == 'two'
assert result[2] == 'three'
+ assert result[3] == 'tail'
def test_object_params_args():
diff --git a/tools/geninterop/geninterop.py b/tools/geninterop/geninterop.py
index 902296229..aed646dd4 100644
--- a/tools/geninterop/geninterop.py
+++ b/tools/geninterop/geninterop.py
@@ -21,6 +21,11 @@
import sysconfig
import subprocess
+if sys.version_info.major > 2:
+ from io import StringIO
+else:
+ from StringIO import StringIO
+
from pycparser import c_ast, c_parser
_log = logging.getLogger()
@@ -48,22 +53,25 @@ class AstParser(object):
"""Walk an AST and determine the members of all structs"""
def __init__(self):
- self.__typedefs = {}
- self.__typedecls = {}
- self.__structs = {}
- self.__struct_stack = []
- self.__struct_members_stack = []
- self.__ptr_decl_depth = 0
- self.__struct_members = {}
+ self._typedefs = {}
+ self._typedecls = {}
+ self._structs = {}
+ self._struct_stack = []
+ self._struct_members_stack = []
+ self._ptr_decl_depth = 0
+ self._struct_members = {}
+ self._decl_names = {}
def get_struct_members(self, name):
"""return a list of (name, type) of struct members"""
- if name in self.__typedefs:
- node = self.__get_leaf_node(self.__typedefs[name])
- name = node.name
- if name not in self.__struct_members:
- raise Exception("Unknown struct '%s'" % name)
- return self.__struct_members[name]
+ defs = self._typedefs.get(name)
+ if defs is None:
+ return None
+ node = self._get_leaf_node(defs)
+ name = node.name
+ if name is None:
+ name = defs.declname
+ return self._struct_members.get(name)
def visit(self, node):
if isinstance(node, c_ast.FileAST):
@@ -88,26 +96,27 @@ def visit_ast(self, ast):
self.visit(node)
def visit_typedef(self, typedef):
- self.__typedefs[typedef.name] = typedef.type
+ self._typedefs[typedef.name] = typedef.type
self.visit(typedef.type)
def visit_typedecl(self, typedecl):
+ self._decl_names[typedecl.type] = typedecl.declname
self.visit(typedecl.type)
def visit_struct(self, struct):
- self.__structs[self.__get_struct_name(struct)] = struct
if struct.decls:
+ self._structs[self._get_struct_name(struct)] = struct
# recurse into the struct
- self.__struct_stack.insert(0, struct)
+ self._struct_stack.insert(0, struct)
for decl in struct.decls:
- self.__struct_members_stack.insert(0, decl.name)
+ self._struct_members_stack.insert(0, decl.name)
self.visit(decl)
- self.__struct_members_stack.pop(0)
- self.__struct_stack.pop(0)
- elif self.__ptr_decl_depth:
+ self._struct_members_stack.pop(0)
+ self._struct_stack.pop(0)
+ elif self._ptr_decl_depth:
# the struct is empty, but add it as a member to the current
# struct as the current member maybe a pointer to it.
- self.__add_struct_member(struct.name)
+ self._add_struct_member(struct.name)
def visit_decl(self, decl):
self.visit(decl.type)
@@ -116,51 +125,72 @@ def visit_funcdecl(self, funcdecl):
self.visit(funcdecl.type)
def visit_ptrdecl(self, ptrdecl):
- self.__ptr_decl_depth += 1
+ self._ptr_decl_depth += 1
self.visit(ptrdecl.type)
- self.__ptr_decl_depth -= 1
+ self._ptr_decl_depth -= 1
def visit_identifier(self, identifier):
type_name = " ".join(identifier.names)
- self.__add_struct_member(type_name)
+ self._add_struct_member(type_name)
- def __add_struct_member(self, type_name):
- if not (self.__struct_stack and self.__struct_members_stack):
+ def _add_struct_member(self, type_name):
+ if not (self._struct_stack and self._struct_members_stack):
return
# add member to current struct
- current_struct = self.__struct_stack[0]
- member_name = self.__struct_members_stack[0]
- struct_members = self.__struct_members.setdefault(
- self.__get_struct_name(current_struct), [])
+ current_struct = self._struct_stack[0]
+ member_name = self._struct_members_stack[0]
+ struct_members = self._struct_members.setdefault(
+ self._get_struct_name(current_struct), [])
# get the node associated with this type
node = None
- if type_name in self.__typedefs:
- node = self.__get_leaf_node(self.__typedefs[type_name])
- elif type_name in self.__structs:
- node = self.__structs[type_name]
+ if type_name in self._typedefs:
+ node = self._get_leaf_node(self._typedefs[type_name])
+ # If the struct was only declared when the typedef was created, its member
+ # information will not have been recorded and we have to look it up in the
+ # structs
+ if isinstance(node, c_ast.Struct) and node.decls is None:
+ if node.name in self._structs:
+ node = self._structs[node.name]
+ elif type_name in self._structs:
+ node = self._structs[type_name]
# If it's a struct (and not a pointer to a struct) expand
# it into the current struct definition
- if not self.__ptr_decl_depth and isinstance(node, c_ast.Struct):
+ if not self._ptr_decl_depth and isinstance(node, c_ast.Struct):
for decl in node.decls or []:
- self.__struct_members_stack.insert(0, decl.name)
+ self._struct_members_stack.insert(0, decl.name)
self.visit(decl)
- self.__struct_members_stack.pop(0)
+ self._struct_members_stack.pop(0)
else:
# otherwise add it as a single member
struct_members.append((member_name, type_name))
- def __get_leaf_node(self, node):
+ def _get_leaf_node(self, node):
if isinstance(node, c_ast.Typedef):
- return self.__get_leaf_node(node.type)
+ return self._get_leaf_node(node.type)
if isinstance(node, c_ast.TypeDecl):
- return self.__get_leaf_node(node.type)
+ return self._get_leaf_node(node.type)
return node
- def __get_struct_name(self, node):
- return node.name or "_struct_%d" % id(node)
+ def _get_struct_name(self, node):
+ return node.name or self._decl_names.get(node) or "_struct_%d" % id(node)
+
+
+class Writer(object):
+
+ def __init__(self):
+ self._stream = StringIO()
+
+ def append(self, indent=0, code=""):
+ self._stream.write("%s%s\n" % (indent * " ", code))
+
+ def extend(self, s):
+ self._stream.write(s)
+
+ def to_string(self):
+ return self._stream.getvalue()
def preprocess_python_headers():
@@ -188,6 +218,7 @@ def preprocess_python_headers():
defines.extend([
"-D", "__inline=inline",
"-D", "__ptr32=",
+ "-D", "__ptr64=",
"-D", "__declspec(x)=",
])
@@ -211,9 +242,8 @@ def preprocess_python_headers():
return "\n".join(lines)
-def gen_interop_code(members):
- """Generate the TypeOffset C# class"""
+def gen_interop_head(writer):
defines = [
"PYTHON{0}{1}".format(PY_MAJOR, PY_MINOR)
]
@@ -243,8 +273,23 @@ def gen_interop_code(members):
namespace Python.Runtime
{
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
- internal class TypeOffset
+""" % (filename, defines_str)
+ writer.extend(class_definition)
+
+
+def gen_interop_tail(writer):
+ tail = """}
+#endif
+"""
+ writer.extend(tail)
+
+
+def gen_heap_type_members(parser, writer):
+ """Generate the TypeOffset C# class"""
+ members = parser.get_struct_members("PyHeapTypeObject")
+ class_definition = """
+ [StructLayout(LayoutKind.Sequential)]
+ internal static class TypeOffset
{
static TypeOffset()
{
@@ -263,7 +308,7 @@ def gen_interop_code(members):
}
// Auto-generated from PyHeapTypeObject in Python.h
-""" % (filename, defines_str)
+"""
# All the members are sizeof(void*) so we don't need to do any
# extra work to determine the size based on the type.
@@ -275,11 +320,36 @@ def gen_interop_code(members):
/* here are optional user slots, followed by the members. */
public static int members = 0;
}
-}
-#endif
"""
- return class_definition
+ writer.extend(class_definition)
+
+
+def gen_structure_code(parser, writer, type_name, indent):
+ members = parser.get_struct_members(type_name)
+ if members is None:
+ return False
+ out = writer.append
+ out(indent, "[StructLayout(LayoutKind.Sequential)]")
+ out(indent, "internal struct %s" % type_name)
+ out(indent, "{")
+ for name, tpy in members:
+ out(indent + 1, "public IntPtr %s;" % name)
+ out(indent, "}")
+ out()
+ return True
+
+
+def gen_supported_slot_record(writer, types, indent):
+ out = writer.append
+ out(indent, "internal static partial class SlotTypes")
+ out(indent, "{")
+ out(indent + 1, "public static readonly Type[] Types = {")
+ for name in types:
+ out(indent + 2, "typeof(%s)," % name)
+ out(indent + 1, "};")
+ out(indent, "}")
+ out()
def main():
@@ -292,10 +362,29 @@ def main():
ast_parser = AstParser()
ast_parser.visit(ast)
+ writer = Writer()
# generate the C# code
- members = ast_parser.get_struct_members("PyHeapTypeObject")
- interop_cs = gen_interop_code(members)
+ gen_interop_head(writer)
+
+ gen_heap_type_members(ast_parser, writer)
+ slots_types = [
+ "PyNumberMethods",
+ "PySequenceMethods",
+ "PyMappingMethods",
+ "PyAsyncMethods",
+ "PyBufferProcs",
+ ]
+ supported_types = []
+ indent = 1
+ for type_name in slots_types:
+ if not gen_structure_code(ast_parser, writer, type_name, indent):
+ continue
+ supported_types.append(type_name)
+ gen_supported_slot_record(writer, supported_types, indent)
+
+ gen_interop_tail(writer)
+ interop_cs = writer.to_string()
if len(sys.argv) > 1:
with open(sys.argv[1], "w") as fh:
fh.write(interop_cs)
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy