Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit46de53e

Browse files
committed
1783 Implement Interface And Inherit Class
Added support for multiple inheritance when inheriting from one base class and/or multiple interfaces.Added a unit test verifying that it works with a simple class and interface. This unit test would previously have failed since multiple types are in the class super class list.
1 parentc2fa467 commit46de53e

File tree

10 files changed

+84
-46
lines changed

10 files changed

+84
-46
lines changed

‎CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ This document follows the conventions laid out in [Keep a CHANGELOG][].
1616
- Fixed error occuring when inheriting a class containing a virtual generic method.
1717
- Make a second call to`pythonnet.load` a no-op, as it was intended.
1818

19+
- Added support for multiple inheritance when inheriting from a class and/or multiple interfaces.
20+
1921
##[3.0.1](https://github.com/pythonnet/pythonnet/releases/tag/v3.0.1) - 2022-11-03
2022

2123
###Added

‎src/python_tests_runner/PythonTestRunner.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ static IEnumerable<string[]> PythonTestCases()
3535
// Add the test that you want to debug here.
3636
yieldreturnnew[]{"test_indexer","test_boolean_indexer"};
3737
yieldreturnnew[]{"test_delegate","test_bool_delegate"};
38+
yieldreturnnew[]{"test_subclass","test_implement_interface_and_class"};
3839
}
3940

4041
/// <summary>

‎src/runtime/Runtime.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1836,6 +1836,12 @@ internal static void SetNoSiteFlag()
18361836
return*Delegates.Py_NoSiteFlag;
18371837
});
18381838
}
1839+
1840+
internalstaticuintPyTuple_GetSize(BorrowedReferencetuple)
1841+
{
1842+
IntPtrr=Delegates.PyTuple_Size(tuple);
1843+
return(uint)r.ToInt32();
1844+
}
18391845
}
18401846

18411847
internalclassBadPythonDllException: MissingMethodException

‎src/runtime/StateSerialization/MaybeType.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal struct MaybeType : ISerializable
1515
conststringSerializationName="n";
1616
readonlystringname;
1717
readonlyTypetype;
18-
18+
1919
publicstringDeletedMessage
2020
{
2121
get
@@ -61,4 +61,4 @@ public void GetObjectData(SerializationInfo serializationInfo, StreamingContext
6161
serializationInfo.AddValue(SerializationName,name);
6262
}
6363
}
64-
}
64+
}

‎src/runtime/TypeManager.cs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ static PyTuple GetBaseTypeTuple(Type clrType)
374374
returnnewPyTuple(bases);
375375
}
376376

377-
internalstaticNewReferenceCreateSubType(BorrowedReferencepy_name,BorrowedReferencepy_base_type,BorrowedReferencedictRef)
377+
internalstaticNewReferenceCreateSubType(BorrowedReferencepy_name,IList<ClassBase>py_base_type,IList<Type>interfaces,BorrowedReferencedictRef)
378378
{
379379
// Utility to create a subtype of a managed type with the ability for the
380380
// a python subtype able to override the managed implementation
@@ -415,17 +415,12 @@ internal static NewReference CreateSubType(BorrowedReference py_name, BorrowedRe
415415
}
416416

417417
// create the new managed type subclassing the base managed type
418-
if(ManagedType.GetManagedObject(py_base_type)isClassBasebaseClass)
419-
{
420-
returnReflectedClrType.CreateSubclass(baseClass,name,
421-
ns:(string?)namespaceStr,
422-
assembly:(string?)assembly,
423-
dict:dictRef);
424-
}
425-
else
426-
{
427-
returnExceptions.RaiseTypeError("invalid base class, expected CLR class type");
428-
}
418+
varbaseClass=py_base_type.FirstOrDefault();
419+
420+
returnReflectedClrType.CreateSubclass(baseClass,interfaces,name,
421+
ns:(string?)namespaceStr,
422+
assembly:(string?)assembly,
423+
dict:dictRef);
429424
}
430425

431426
internalstaticIntPtrWriteMethodDef(IntPtrmdef,IntPtrname,IntPtrfunc,PyMethodFlagsflags,IntPtrdoc)

‎src/runtime/Types/ClassDerived.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ internal static NewReference ToPython(IPythonDerivedType obj)
144144
/// </summary>
145145
internalstaticTypeCreateDerivedType(stringname,
146146
TypebaseType,
147+
IList<Type>typeInterfaces,
147148
BorrowedReferencepy_dict,
148149
string?namespaceStr,
149150
string?assemblyName,
@@ -163,7 +164,9 @@ internal static Type CreateDerivedType(string name,
163164
ModuleBuildermoduleBuilder=GetModuleBuilder(assemblyName,moduleName);
164165

165166
TypebaseClass=baseType;
166-
varinterfaces=newList<Type>{typeof(IPythonDerivedType)};
167+
varinterfaces=newHashSet<Type>{typeof(IPythonDerivedType)};
168+
foreach(varinterfaceTypeintypeInterfaces)
169+
interfaces.Add(interfaceType);
167170

168171
// if the base type is an interface then use System.Object as the base class
169172
// and add the base type to the list of interfaces this new class will implement.
@@ -214,8 +217,9 @@ internal static Type CreateDerivedType(string name,
214217
}
215218
}
216219

217-
// override any virtual methods not already overridden by the properties above
218-
MethodInfo[]methods=baseType.GetMethods();
220+
// override any virtual not already overridden by the properties above
221+
// also override any interface method.
222+
varmethods=baseType.GetMethods().Concat(interfaces.SelectMany(x=>x.GetMethods()));
219223
varvirtualMethods=newHashSet<string>();
220224
foreach(MethodInfomethodinmethods)
221225
{

‎src/runtime/Types/MetaType.cs

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
usingSystem;
2+
usingSystem.Collections.Generic;
23
usingSystem.Diagnostics;
4+
usingSystem.Linq;
5+
usingSystem.Reflection;
36
usingSystem.Runtime.InteropServices;
47
usingSystem.Runtime.Serialization;
58

@@ -79,49 +82,56 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args,
7982
BorrowedReferencebases=Runtime.PyTuple_GetItem(args,1);
8083
BorrowedReferencedict=Runtime.PyTuple_GetItem(args,2);
8184

82-
// We do not support multiple inheritance, so the bases argument
83-
// should be a 1-item tuple containing the type we are subtyping.
84-
// That type must itself have a managed implementation. We check
85-
// that by making sure its metatype is the CLR metatype.
85+
// Extract interface types and base class types.
86+
varinterfaces=newList<Type>();
87+
varbaseType=newList<ClassBase>();
8688

87-
if(Runtime.PyTuple_Size(bases)!=1)
89+
varcnt=Runtime.PyTuple_GetSize(bases);
90+
91+
for(uinti=0;i<cnt;i++)
8892
{
89-
returnExceptions.RaiseTypeError("cannot use multiple inheritance with managed classes");
93+
varbase_type2=Runtime.PyTuple_GetItem(bases,(int)i);
94+
varcb2=(ClassBase)GetManagedObject(base_type2);
95+
if(cb2!=null)
96+
{
97+
if(cb2.type.Valid&&cb2.type.Value.IsInterface)
98+
interfaces.Add(cb2.type.Value);
99+
elsebaseType.Add(cb2);
100+
}
90101
}
91-
92-
BorrowedReferencebase_type=Runtime.PyTuple_GetItem(bases,0);
93-
BorrowedReferencemt=Runtime.PyObject_TYPE(base_type);
94-
95-
if(!(mt==PyCLRMetaType||mt==Runtime.PyTypeType))
102+
// if the base type count is 0, there might still be interfaces to implement.
103+
if(baseType.Count==0)
96104
{
97-
returnExceptions.RaiseTypeError("invalid metatype");
105+
baseType.Add(newClassBase(typeof(object)));
98106
}
99107

100-
// Ensure that the reflected type is appropriate for subclassing,
101-
// disallowing subclassing of delegates, enums and array types.
108+
// Multiple inheritance is not supported, unless the other types are interfaces
109+
if(baseType.Count>1)
110+
{
111+
returnExceptions.RaiseTypeError("cannot use multiple inheritance with managed classes");
112+
}
102113

103-
if(GetManagedObject(base_type)isClassBasecb)
114+
varcb=baseType[0];
115+
try
104116
{
105-
try
106-
{
107-
if(!cb.CanSubclass())
108-
{
109-
returnExceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed");
110-
}
111-
}
112-
catch(SerializationException)
117+
if(!cb.CanSubclass())
113118
{
114-
returnExceptions.RaiseTypeError($"Underlying C# Base class{cb.type} has been deleted");
119+
returnExceptions.RaiseTypeError("delegates, enums and array types cannot be subclassed");
115120
}
116121
}
122+
catch(SerializationException)
123+
{
124+
returnExceptions.RaiseTypeError($"Underlying C# Base class{cb.type} has been deleted");
125+
}
117126

118127
BorrowedReferenceslots=Runtime.PyDict_GetItem(dict,PyIdentifier.__slots__);
119128
if(slots!=null)
120129
{
121130
returnExceptions.RaiseTypeError("subclasses of managed classes do not support __slots__");
122131
}
123132

124-
// If __assembly__ or __namespace__ are in the class dictionary then create
133+
// If the base class has a parameterless constructor, or
134+
// if __assembly__ or __namespace__ are in the class dictionary then create
125135
// a managed sub type.
126136
// This creates a new managed type that can be used from .net to call back
127137
// into python.
@@ -130,10 +140,12 @@ public static NewReference tp_new(BorrowedReference tp, BorrowedReference args,
130140
usingvarclsDict=newPyDict(dict);
131141
if(clsDict.HasKey("__assembly__")||clsDict.HasKey("__namespace__"))
132142
{
133-
returnTypeManager.CreateSubType(name,base_type,clsDict);
143+
returnTypeManager.CreateSubType(name,baseType,interfaces,clsDict);
134144
}
135145
}
136146

147+
varbase_type=Runtime.PyTuple_GetItem(bases,0);
148+
137149
// otherwise just create a basic type without reflecting back into the managed side.
138150
IntPtrfunc=Util.ReadIntPtr(Runtime.PyTypeType,TypeOffset.tp_new);
139151
NewReferencetype=NativeCall.Call_3(func,tp,args,kw);

‎src/runtime/Types/ReflectedClrType.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,15 @@ internal void Restore(ClassBase cb)
6868
TypeManager.InitializeClass(this,cb,cb.type.Value);
6969
}
7070

71-
internalstaticNewReferenceCreateSubclass(ClassBasebaseClass,
71+
internalstaticNewReferenceCreateSubclass(ClassBasebaseClass,IList<Type>interfaces,
7272
stringname,string?assembly,string?ns,
7373
BorrowedReferencedict)
7474
{
7575
try
7676
{
7777
TypesubType=ClassDerivedObject.CreateDerivedType(name,
7878
baseClass.type.Value,
79+
interfaces,
7980
dict,
8081
ns,
8182
assembly);

‎src/testing/classtest.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
usingSystem;
12
usingSystem.Collections;
23

34
namespacePython.Test
@@ -59,4 +60,15 @@ public ClassCtorTest2(string v)
5960
internalclassInternalClass
6061
{
6162
}
63+
64+
publicclassSimpleClass
65+
{
66+
publicstaticvoidTestObject(objectobj)
67+
{
68+
if((!(objisISayHello1&&objisSimpleClass)))
69+
{
70+
thrownewException("Expected ISayHello and SimpleClass instance");
71+
}
72+
}
73+
}
6274
}

‎tests/test_subclass.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
importSystem
1010
importpytest
1111
fromPython.Testimport (IInterfaceTest,SubClassTest,EventArgsTest,
12-
FunctionsTest,IGenericInterface,GenericVirtualMethodTest)
12+
FunctionsTest,IGenericInterface,GenericVirtualMethodTest,SimpleClass,ISayHello1)
1313
fromSystem.Collections.GenericimportList
1414

1515

@@ -338,4 +338,9 @@ class OverloadingSubclass2(OverloadingSubclass):
338338
obj=OverloadingSubclass2()
339339
assertobj.VirtMethod[int](5)==5
340340

341-
341+
deftest_implement_interface_and_class():
342+
classDualSubClass0(ISayHello1,SimpleClass):
343+
__namespace__="Test"
344+
defSayHello(self):
345+
return"hello"
346+
obj=DualSubClass0()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp