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; // Note the given instance might be uninitialized 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(type, name, mlist); ci.members[name] = ob; } return ci; }
private static void InitClassBase(Type type, ClassBase impl) { // Ensure, that matching Python type exists first. // It is required for self-referential classes // (e.g. with members, that refer to the same class) var pyType = TypeManager.GetOrCreateClass(type); // Set the handle attributes on the implementing instance. impl.tpHandle = impl.pyHandle = pyType.Handle; // 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); impl.indexer = info.indexer; impl.richcompare = new Dictionary <int, MethodObject>(); // Now we force initialize 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. TypeManager.GetOrInitializeClass(impl, type); // Finally, initialize the class __dict__ and return the object. using var dict = Runtime.PyObject_GenericGetDict(pyType.Reference); if (impl.dotNetMembers == null) { impl.dotNetMembers = new List <string>(); } IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { var item = (ManagedType)iter.Value; var name = (string)iter.Key; impl.dotNetMembers.Add(name); Runtime.PyDict_SetItemString(dict, name, item.ObjectReference); // Decref the item now that it's been used. item.DecrRefCount(); if (ClassBase.CilToPyOpMap.TryGetValue(name, out var pyOp)) { impl.richcompare.Add(pyOp, (MethodObject)item); } } // If class has constructors, generate an __doc__ attribute. NewReference doc = default; Type marker = typeof(DocStringAttribute); var attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length != 0) { var attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = NewReference.DangerousFromPointer(Runtime.PyString_FromString(docStr)); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); } var co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.NumCtors > 0) { // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { var ctors = new ConstructorBinding(type, pyType, co.binder); // ExtensionType types are untracked, so don't Incref() them. // TODO: deprecate __overloads__ soon... Runtime.PyDict_SetItem(dict, PyIdentifier.__overloads__, ctors.ObjectReference); Runtime.PyDict_SetItem(dict, PyIdentifier.Overloads, ctors.ObjectReference); ctors.DecrRefCount(); } // don't generate the docstring if one was already set from a DocStringAttribute. if (!CLRModule._SuppressDocs && doc.IsNull()) { doc = co.GetDocString(); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); } } } doc.Dispose(); // The type has been modified after PyType_Ready has been called // Refresh the type Runtime.PyType_Modified(pyType.Reference); }
private static ClassInfo GetClassInfo(Type type) { var ci = new ClassInfo(); var methods = new Hashtable(); ArrayList list; MethodInfo meth; ManagedType ob; string name; object item; Type tp; int i, n; MemberInfo[] info = type.GetMembers(BindingFlags); var local = new Hashtable(); var 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; } } // only [Flags] enums support bitwise operations if (type.IsEnum && type.IsFlagsEnum()) { var opsImpl = typeof(EnumOps <>).MakeGenericType(type); foreach (var op in opsImpl.GetMethods(OpsHelper.BindingFlags)) { local[op.Name] = 1; } info = info.Concat(opsImpl.GetMethods(OpsHelper.BindingFlags)).ToArray(); } // 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(BindingFlags); for (n = 0; n < imembers.Length; n++) { m = imembers[n]; if (local[m.Name] == null) { items.Add(m); } } } // All interface implementations inherit from Object, // but GetMembers don't return them either. var objFlags = BindingFlags.Public | BindingFlags.Instance; foreach (var mi in typeof(object).GetMembers(objFlags)) { if (local[mi.Name] == null) { items.Add(mi); } } } for (i = 0; i < items.Count; i++) { var mi = (MemberInfo)items[i]; switch (mi.MemberType) { case MemberTypes.Method: meth = (MethodInfo)mi; if (!ShouldBindMethod(meth)) { 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: var pi = (PropertyInfo)mi; if (!ShouldBindProperty(pi)) { 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: var fi = (FieldInfo)mi; if (!ShouldBindField(fi)) { continue; } ob = new FieldObject(fi); ci.members[mi.Name] = ob; continue; case MemberTypes.Event: var ei = (EventInfo)mi; if (!ShouldBindEvent(ei)) { 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; } // Note the given instance might be uninitialized ob = GetClass(tp); // GetClass returns a Borrowed ref. ci.members owns the reference. ob.IncrRefCount(); ci.members[mi.Name] = ob; continue; } } IDictionaryEnumerator iter = methods.GetEnumerator(); while (iter.MoveNext()) { name = (string)iter.Key; list = (ArrayList)iter.Value; var mlist = (MethodInfo[])list.ToArray(typeof(MethodInfo)); ob = new MethodObject(type, name, mlist); ci.members[name] = ob; if (mlist.Any(OperatorMethod.IsOperatorMethod)) { string pyName = OperatorMethod.GetPyMethodName(name); string pyNameReverse = OperatorMethod.ReversePyMethodName(pyName); OperatorMethod.FilterMethods(mlist, out var forwardMethods, out var reverseMethods); // Only methods where the left operand is the declaring type. if (forwardMethods.Length > 0) { ci.members[pyName] = new MethodObject(type, name, forwardMethods); } // Only methods where only the right operand is the declaring type. if (reverseMethods.Length > 0) { ci.members[pyNameReverse] = new MethodObject(type, name, reverseMethods); } } } if (ci.indexer == null && type.IsClass) { // Indexer may be inherited. var parent = type.BaseType; while (parent != null && ci.indexer == null) { foreach (var prop in parent.GetProperties()) { var args = prop.GetIndexParameters(); if (args.GetLength(0) > 0) { ci.indexer = new Indexer(); ci.indexer.AddProperty(prop); break; } } parent = parent.BaseType; } } return(ci); }
private static ClassInfo GetClassInfo(Type type) { var ci = new ClassInfo(type); var 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); var local = new Hashtable(); var 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++) { var 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: var 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: var fi = (FieldInfo)mi; if (!(fi.IsPublic || fi.IsFamily || fi.IsFamilyOrAssembly)) { continue; } ob = new FieldObject(fi); ci.members[mi.Name] = ob; continue; case MemberTypes.Event: var 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; } // Note the given instance might be uninitialized ob = GetClass(tp); ci.members[mi.Name] = ob; continue; } } IDictionaryEnumerator iter = methods.GetEnumerator(); while (iter.MoveNext()) { name = (string)iter.Key; list = (ArrayList)iter.Value; var mlist = (MethodInfo[])list.ToArray(typeof(MethodInfo)); ob = new MethodObject(type, name, mlist); ci.members[name] = ob; } return(ci); }
private static void InitClassBase(Type type, ClassBase impl) { // 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); 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()) { var item = (ManagedType)iter.Value; var name = (string)iter.Key; Runtime.PyDict_SetItemString(dict, name, item.pyHandle); // info.members are already useless Runtime.Py_DecRef(item.pyHandle); } // If class has constructors, generate an __doc__ attribute. IntPtr doc = IntPtr.Zero; Type marker = typeof(DocStringAttribute); var attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length == 0) { doc = IntPtr.Zero; } else { var attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = Runtime.PyString_FromString(docStr); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.XDecref(doc); } var co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.ctors.Length > 0) { // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { var ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // TODO: deprecate __overloads__ soon... Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); Runtime.Py_DecRef(ctors.pyHandle); } // don't generate the docstring if one was already set from a DocStringAttribute. if (!CLRModule._SuppressDocs && doc == IntPtr.Zero) { doc = co.GetDocString(); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.XDecref(doc); } } } }
//==================================================================== // Create a new ClassBase-derived instance that implements a reflected // managed type. The new object will be associated with a generated // Python type object. //==================================================================== private static ClassBase CreateClass(Type type) { // First, we introspect the managed type and build some class // information, including generating the member descriptors // that we'll be putting in the Python class __dict__. ClassInfo info = GetClassInfo(type); // Next, select the appropriate managed implementation class. // Different kinds of types, such as array types or interface // types, want to vary certain implementation details to make // sure that the type semantics are consistent in Python. ClassBase impl; // Check to see if the given type extends System.Exception. This // lets us check once (vs. on every lookup) in case we need to // wrap Exception-derived types in old-style classes if (type.ContainsGenericParameters) { impl = new GenericType(type); } else if (type.IsSubclassOf(dtype)) { impl = new DelegateObject(type); } else if (type.IsArray) { impl = new ArrayObject(type); } else if (type.IsInterface) { impl = new InterfaceObject(type); } else if (type == typeof(Exception) || type.IsSubclassOf(typeof(Exception))) { impl = new ExceptionClassObject(type); } else if (null != type.GetField("__pyobj__")) { impl = new ClassDerivedObject(type); } else { impl = new ClassObject(type); } impl.indexer = info.indexer; // Now we allocate the Python type object to reflect the given // managed type, filling the Python type slots with thunks that // point to the managed methods providing the implementation. IntPtr tp = TypeManager.GetTypeHandle(impl, type); impl.tpHandle = tp; // Finally, initialize the class __dict__ and return the object. IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict); IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { ManagedType item = (ManagedType)iter.Value; string name = (string)iter.Key; Runtime.PyDict_SetItemString(dict, name, item.pyHandle); } // If class has constructors, generate an __doc__ attribute. IntPtr doc; Type marker = typeof(DocStringAttribute); Attribute[] attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length == 0) { doc = IntPtr.Zero; } else { DocStringAttribute attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = Runtime.PyString_FromString(docStr); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.Decref(doc); } ClassObject co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.ctors.Length > 0) { // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { ConstructorBinding ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // XXX deprecate __overloads__ soon... Runtime.PyDict_SetItemString(dict, "__overloads__", ctors.pyHandle); Runtime.PyDict_SetItemString(dict, "Overloads", ctors.pyHandle); } if (!CLRModule._SuppressDocs) { doc = co.GetDocString(); Runtime.PyDict_SetItemString(dict, "__doc__", doc); Runtime.Decref(doc); } } } return(impl); }
//==================================================================== // 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 void InitClassBase(Type type, ClassBase impl) { // 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); impl.indexer = info.indexer; impl.richcompare = new Dictionary <int, MethodObject>(); // 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); // Finally, initialize the class __dict__ and return the object. IntPtr dict = Marshal.ReadIntPtr(tp, TypeOffset.tp_dict); if (impl.dotNetMembers == null) { impl.dotNetMembers = new List <string>(); } IDictionaryEnumerator iter = info.members.GetEnumerator(); while (iter.MoveNext()) { var item = (ManagedType)iter.Value; var name = (string)iter.Key; impl.dotNetMembers.Add(name); Runtime.PyDict_SetItemString(dict, name, item.pyHandle); // Decref the item now that it's been used. item.DecrRefCount(); if (ClassBase.CilToPyOpMap.TryGetValue(name, out var pyOp)) { impl.richcompare.Add(pyOp, (MethodObject)item); } } // If class has constructors, generate an __doc__ attribute. IntPtr doc = IntPtr.Zero; Type marker = typeof(DocStringAttribute); var attrs = (Attribute[])type.GetCustomAttributes(marker, false); if (attrs.Length == 0) { doc = IntPtr.Zero; } else { var attr = (DocStringAttribute)attrs[0]; string docStr = attr.DocString; doc = Runtime.PyString_FromString(docStr); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); Runtime.XDecref(doc); } var co = impl as ClassObject; // If this is a ClassObject AND it has constructors, generate a __doc__ attribute. // required that the ClassObject.ctors be changed to internal if (co != null) { if (co.NumCtors > 0) { // Implement Overloads on the class object if (!CLRModule._SuppressOverloads) { var ctors = new ConstructorBinding(type, tp, co.binder); // ExtensionType types are untracked, so don't Incref() them. // TODO: deprecate __overloads__ soon... Runtime.PyDict_SetItem(dict, PyIdentifier.__overloads__, ctors.pyHandle); Runtime.PyDict_SetItem(dict, PyIdentifier.Overloads, ctors.pyHandle); ctors.DecrRefCount(); } // don't generate the docstring if one was already set from a DocStringAttribute. if (!CLRModule._SuppressDocs && doc == IntPtr.Zero) { doc = co.GetDocString(); Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, doc); Runtime.XDecref(doc); } } } // The type has been modified after PyType_Ready has been called // Refresh the type Runtime.PyType_Modified(tp); }