6
6
using System . Runtime . InteropServices ;
7
7
using System . Diagnostics ;
8
8
using Python . Runtime . Slots ;
9
+ using static Python . Runtime . PythonException ;
9
10
10
11
namespace Python . Runtime
11
12
{
@@ -142,7 +143,7 @@ internal static IntPtr GetTypeHandle(ManagedType obj, Type type)
142
143
/// </summary>
143
144
internal static IntPtr CreateType ( Type impl )
144
145
{
145
- IntPtr type = AllocateTypeObject ( impl . Name ) ;
146
+ IntPtr type = AllocateTypeObject ( impl . Name , metatype : Runtime . PyTypeType ) ;
146
147
int ob_size = ObjectOffset . Size ( type ) ;
147
148
148
149
// Set tp_basicsize to the size of our managed instance objects.
@@ -211,7 +212,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
211
212
base_ = bc . pyHandle ;
212
213
}
213
214
214
- IntPtr type = AllocateTypeObject ( name ) ;
215
+ IntPtr type = AllocateTypeObject ( name , Runtime . PyCLRMetaType ) ;
215
216
216
217
Marshal . WriteIntPtr ( type , TypeOffset . ob_type , Runtime . PyCLRMetaType ) ;
217
218
Runtime . XIncref ( Runtime . PyCLRMetaType ) ;
@@ -302,6 +303,7 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType)
302
303
303
304
internal static IntPtr CreateSubType ( IntPtr py_name , IntPtr py_base_type , IntPtr py_dict )
304
305
{
306
+ var dictRef = new BorrowedReference ( py_dict ) ;
305
307
// Utility to create a subtype of a managed type with the ability for the
306
308
// a python subtype able to override the managed implementation
307
309
string name = Runtime . GetManagedString ( py_name ) ;
@@ -311,40 +313,29 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr
311
313
object assembly = null ;
312
314
object namespaceStr = null ;
313
315
314
- var disposeList = new List < PyObject > ( ) ;
315
- try
316
+ using ( var assemblyKey = new PyString ( "__assembly__" ) )
316
317
{
317
- var assemblyKey = new PyObject ( Converter . ToPython ( "__assembly__" , typeof ( string ) ) ) ;
318
- disposeList . Add ( assemblyKey ) ;
319
- if ( 0 != Runtime . PyMapping_HasKey ( py_dict , assemblyKey . Handle ) )
318
+ var assemblyPtr = Runtime . PyDict_GetItemWithError ( dictRef , assemblyKey . Reference ) ;
319
+ if ( assemblyPtr . IsNull )
320
320
{
321
- var pyAssembly = new PyObject ( Runtime . PyDict_GetItem ( py_dict , assemblyKey . Handle ) ) ;
322
- Runtime . XIncref ( pyAssembly . Handle ) ;
323
- disposeList . Add ( pyAssembly ) ;
324
- if ( ! Converter . ToManagedValue ( pyAssembly . Handle , typeof ( string ) , out assembly , false ) )
325
- {
326
- throw new InvalidCastException ( "Couldn't convert __assembly__ value to string" ) ;
327
- }
321
+ if ( Exceptions . ErrorOccurred ( ) ) return IntPtr . Zero ;
322
+ }
323
+ else if ( ! Converter . ToManagedValue ( assemblyPtr , typeof ( string ) , out assembly , false ) )
324
+ {
325
+ return Exceptions . RaiseTypeError ( "Couldn't convert __assembly__ value to string" ) ;
328
326
}
329
327
330
- var namespaceKey = new PyObject ( Converter . ToPythonImplicit ( "__namespace__" ) ) ;
331
- disposeList . Add ( namespaceKey ) ;
332
- if ( 0 != Runtime . PyMapping_HasKey ( py_dict , namespaceKey . Handle ) )
328
+ using ( var namespaceKey = new PyString ( "__namespace__" ) )
333
329
{
334
- var pyNamespace = new PyObject ( Runtime . PyDict_GetItem ( py_dict , namespaceKey . Handle ) ) ;
335
- Runtime . XIncref ( pyNamespace . Handle ) ;
336
- disposeList . Add ( pyNamespace ) ;
337
- if ( ! Converter . ToManagedValue ( pyNamespace . Handle , typeof ( string ) , out namespaceStr , false ) )
330
+ var pyNamespace = Runtime . PyDict_GetItemWithError ( dictRef , namespaceKey . Reference ) ;
331
+ if ( pyNamespace . IsNull )
338
332
{
339
- throw new InvalidCastException ( "Couldn't convert __namespace__ value to string" ) ;
333
+ if ( Exceptions . ErrorOccurred ( ) ) return IntPtr . Zero ;
334
+ }
335
+ else if ( ! Converter . ToManagedValue ( pyNamespace , typeof ( string ) , out namespaceStr , false ) )
336
+ {
337
+ return Exceptions . RaiseTypeError ( "Couldn't convert __namespace__ value to string" ) ;
340
338
}
341
- }
342
- }
343
- finally
344
- {
345
- foreach ( PyObject o in disposeList )
346
- {
347
- o . Dispose ( ) ;
348
339
}
349
340
}
350
341
@@ -370,14 +361,14 @@ internal static IntPtr CreateSubType(IntPtr py_name, IntPtr py_base_type, IntPtr
370
361
// by default the class dict will have all the C# methods in it, but as this is a
371
362
// derived class we want the python overrides in there instead if they exist.
372
363
IntPtr cls_dict = Marshal . ReadIntPtr ( py_type , TypeOffset . tp_dict ) ;
373
- Runtime . PyDict_Update ( cls_dict , py_dict ) ;
364
+ ThrowIfIsNotZero ( Runtime . PyDict_Update ( cls_dict , py_dict ) ) ;
374
365
Runtime . XIncref ( py_type ) ;
375
366
// Update the __classcell__ if it exists
376
367
var cell = new BorrowedReference ( Runtime . PyDict_GetItemString ( cls_dict , "__classcell__" ) ) ;
377
368
if ( ! cell . IsNull )
378
369
{
379
- Runtime . PyCell_Set ( cell , py_type ) ;
380
- Runtime . PyDict_DelItemString ( cls_dict , "__classcell__" ) ;
370
+ ThrowIfIsNotZero ( Runtime . PyCell_Set ( cell , py_type ) ) ;
371
+ ThrowIfIsNotZero ( Runtime . PyDict_DelItemString ( cls_dict , "__classcell__" ) ) ;
381
372
}
382
373
383
374
return py_type ;
@@ -436,12 +427,15 @@ internal static IntPtr CreateMetaType(Type impl, out SlotsHolder slotsHolder)
436
427
// the standard type slots, and has to subclass PyType_Type for
437
428
// certain functions in the C runtime to work correctly with it.
438
429
439
- IntPtr type = AllocateTypeObject ( "CLR Metatype" ) ;
440
- IntPtr py_type = Runtime . PyTypeType ;
430
+ IntPtr type = AllocateTypeObject ( "CLR Metatype" , metatype : Runtime . PyTypeType ) ;
441
431
432
+ IntPtr py_type = Runtime . PyTypeType ;
442
433
Marshal . WriteIntPtr ( type , TypeOffset . tp_base , py_type ) ;
443
434
Runtime . XIncref ( py_type ) ;
444
435
436
+ int size = TypeOffset . magic ( ) + IntPtr . Size ;
437
+ Marshal . WriteIntPtr ( type , TypeOffset . tp_basicsize , new IntPtr ( size ) ) ;
438
+
445
439
const int flags = TypeFlags . Default
446
440
| TypeFlags . Managed
447
441
| TypeFlags . HeapType
@@ -531,7 +525,7 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
531
525
// Utility to create a subtype of a std Python type, but with
532
526
// a managed type able to override implementation
533
527
534
- IntPtr type = AllocateTypeObject ( name ) ;
528
+ IntPtr type = AllocateTypeObject ( name , metatype : Runtime . PyTypeType ) ;
535
529
//Marshal.WriteIntPtr(type, TypeOffset.tp_basicsize, (IntPtr)obSize);
536
530
//Marshal.WriteIntPtr(type, TypeOffset.tp_itemsize, IntPtr.Zero);
537
531
@@ -573,9 +567,9 @@ internal static IntPtr BasicSubType(string name, IntPtr base_, Type impl)
573
567
/// <summary>
574
568
/// Utility method to allocate a type object & do basic initialization.
575
569
/// </summary>
576
- internal static IntPtr AllocateTypeObject ( string name )
570
+ internal static IntPtr AllocateTypeObject ( string name , IntPtr metatype )
577
571
{
578
- IntPtr type = Runtime . PyType_GenericAlloc ( Runtime . PyTypeType , 0 ) ;
572
+ IntPtr type = Runtime . PyType_GenericAlloc ( metatype , 0 ) ;
579
573
// Clr type would not use __slots__,
580
574
// and the PyMemberDef after PyHeapTypeObject will have other uses(e.g. type handle),
581
575
// thus set the ob_size to 0 for avoiding slots iterations.
0 commit comments