[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/achernet/pythonnet/develop/src/runtime/methodobject.cs [Back]  [Original]

// ==========================================================================
// 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 represents a CLR method. Method objects
    // support a subscript syntax [] to allow explicit overload selection.
    //========================================================================
    // TODO: ForbidPythonThreadsAttribute per method info

    internal class MethodObject : ExtensionType {

        internal MethodInfo[] info;
        internal string name;
        internal MethodBinding unbound;
        internal MethodBinder binder;
        internal bool is_static = false;
        internal IntPtr doc;

        public MethodObject(string name, MethodInfo[] info) : base() {
            _MethodObject(name, info);
        }

        public MethodObject(string name, MethodInfo[] info, bool allow_threads) : base()
        {
            _MethodObject(name, info);
            binder.allow_threads = allow_threads;
        }

        private void _MethodObject(string name, MethodInfo[] info)
        {
            this.name = name;
            this.info = info;
            binder = new MethodBinder();
            for (int i = 0; i < info.Length; i++)
            {
                MethodInfo item = (MethodInfo)info[i];
                binder.AddMethod(item);
                if (item.IsStatic)
                {
                    this.is_static = true;
                }
            }
        }

        public virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw) {
            return this.Invoke(inst, args, kw, null);
        }
 
        public virtual IntPtr Invoke(IntPtr target, IntPtr args, IntPtr kw,
                                     MethodBase info) {
            return binder.Invoke(target, args, kw, info, this.info);
        }

        //====================================================================
        // Helper to get docstrings from reflected method / param info.
        //====================================================================

        internal IntPtr GetDocString() {
            if (doc != IntPtr.Zero) {
                return doc;
            }
            string str = "";
			Type marker = typeof(DocStringAttribute);
            MethodBase[] methods = binder.GetMethods();
            foreach (MethodBase method in methods) {
                if (str.Length > 0)
                    str += Environment.NewLine;
				Attribute[] attrs = (Attribute[]) method.GetCustomAttributes(marker, false);
	            if (attrs.Length == 0) {
		                str += method.ToString();
		            }
				else {
					DocStringAttribute attr = (DocStringAttribute)attrs[0];
					str += attr.DocString;
				}
			}
            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() {
            return this.is_static;
        }

        //====================================================================
        // Descriptor __getattribute__ implementation. 
        //====================================================================

        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. 
        //====================================================================

        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.
        //====================================================================

        public static IntPtr tp_repr(IntPtr ob) {
            MethodObject self = (MethodObject)GetManagedObject(ob);
            string s = String.Format("", self.name);
            return Runtime.PyString_FromStringAndSize(s, s.Length);
        }

        //====================================================================
        // Descriptor dealloc implementation.
        //====================================================================

        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);
        }


    }


}

Web Proxy Viewer  |  New URL  |  Original Page