The AssemblyManager maintains information about loaded assemblies namespaces and provides an interface for name-based type lookup.
Example #1
0
        /// <summary>
        /// Implementation of [] semantics for reflected types. This exists
        /// both to implement the Array[int] syntax for creating arrays and
        /// to support generic name overload resolution using [].
        /// </summary>
        public override IntPtr type_subscript(IntPtr idx)
        {
            if (!type.Valid)
            {
                return(Exceptions.RaiseTypeError(type.DeletedMessage));
            }

            // If this type is the Array type, the [<type>] means we need to
            // construct and return an array type of the given element type.
            if (type.Value == typeof(Array))
            {
                if (Runtime.PyTuple_Check(idx))
                {
                    return(Exceptions.RaiseTypeError("type expected"));
                }
                var  c = GetManagedObject(idx) as ClassBase;
                Type t = c != null ? c.type.Value : Converter.GetTypeByAlias(idx);
                if (t == null)
                {
                    return(Exceptions.RaiseTypeError("type expected"));
                }
                Type      a = t.MakeArrayType();
                ClassBase o = ClassManager.GetClass(a);
                Runtime.XIncref(o.pyHandle);
                return(o.pyHandle);
            }

            // If there are generics in our namespace with the same base name
            // as the current type, then [<type>] means the caller wants to
            // bind the generic type matching the given type parameters.
            Type[] types = Runtime.PythonArgsToTypeArray(idx);
            if (types == null)
            {
                return(Exceptions.RaiseTypeError("type(s) expected"));
            }

            Type gtype = AssemblyManager.LookupTypes($"{type.Value.FullName}`{types.Length}").FirstOrDefault();

            if (gtype != null)
            {
                var g = ClassManager.GetClass(gtype) as GenericType;
                return(g.type_subscript(idx));
                //Runtime.XIncref(g.pyHandle);
                //return g.pyHandle;
            }
            return(Exceptions.RaiseTypeError("unsubscriptable object"));
        }
Example #2
0
        //====================================================================
        // Implementation of [] semantics for reflected types. This exists
        // both to implement the Array[int] syntax for creating arrays and
        // to support generic name overload resolution using [].
        //====================================================================

        public override IntPtr type_subscript(IntPtr idx)
        {
            // If this type is the Array type, the [<type>] means we need to
            // construct and return an array type of the given element type.

            if ((this.type) == typeof(Array))
            {
                if (Runtime.PyTuple_Check(idx))
                {
                    return(Exceptions.RaiseTypeError("type expected"));
                }
                ClassBase c = GetManagedObject(idx) as ClassBase;
                Type      t = (c != null) ? c.type : Converter.GetTypeByAlias(idx);
                if (t == null)
                {
                    return(Exceptions.RaiseTypeError("type expected"));
                }
                Type      a = t.MakeArrayType();
                ClassBase o = ClassManager.GetClass(a);
                Runtime.Incref(o.pyHandle);
                return(o.pyHandle);
            }

            // If there are generics in our namespace with the same base name
            // as the current type, then [<type>] means the caller wants to
            // bind the generic type matching the given type parameters.

            Type[] types = Runtime.PythonArgsToTypeArray(idx);
            if (types == null)
            {
                return(Exceptions.RaiseTypeError("type(s) expected"));
            }

            string gname = this.type.FullName + "`" + types.Length.ToString();
            Type   gtype = AssemblyManager.LookupType(gname);

            if (gtype != null)
            {
                GenericType g = ClassManager.GetClass(gtype) as GenericType;
                return(g.type_subscript(idx));

                /*Runtime.Incref(g.pyHandle);
                 * return g.pyHandle;*/
            }
            return(Exceptions.RaiseTypeError("unsubscriptable object"));
        }
Example #3
0
        public static Assembly AddReference(string name)
        {
            AssemblyManager.UpdatePath();
            Assembly assembly = null;

            assembly = AssemblyManager.LoadAssemblyPath(name);
            if (assembly == null)
            {
                assembly = AssemblyManager.LoadAssembly(name);
            }
            if (assembly == null)
            {
                string msg = String.Format("Unable to find assembly '{0}'.", name);
                throw new System.IO.FileNotFoundException(msg);
            }
            return(assembly);
        }
Example #4
0
 public static String[] ListAssemblies(bool verbose)
 {
     AssemblyName[] assnames = AssemblyManager.ListAssemblies();
     String[]       names    = new String[assnames.Length];
     for (int i = 0; i < assnames.Length; i++)
     {
         if (verbose)
         {
             names[i] = assnames[i].FullName;
         }
         else
         {
             names[i] = assnames[i].Name;
         }
     }
     return(names);
 }
Example #5
0
        public ModuleObject(string name)
        {
            if (name == string.Empty)
            {
                throw new ArgumentException("Name must not be empty!");
            }
            moduleName = name;
            cache      = new Dictionary <string, ManagedType>();
            _namespace = name;

            // Use the filename from any of the assemblies just so there's something for
            // anything that expects __file__ to be set.
            var filename  = "unknown";
            var docstring = "Namespace containing types from the following assemblies:\n\n";

            foreach (Assembly a in AssemblyManager.GetAssemblies(name))
            {
                if (!a.IsDynamic && a.Location != null)
                {
                    filename = a.Location;
                }
                docstring += "- " + a.FullName + "\n";
            }

            dict = Runtime.PyDict_New();
            IntPtr pyname      = Runtime.PyString_FromString(moduleName);
            IntPtr pyfilename  = Runtime.PyString_FromString(filename);
            IntPtr pydocstring = Runtime.PyString_FromString(docstring);
            IntPtr pycls       = TypeManager.GetTypeHandle(GetType());

            Runtime.PyDict_SetItem(dict, PyIdentifier.__name__, pyname);
            Runtime.PyDict_SetItem(dict, PyIdentifier.__file__, pyfilename);
            Runtime.PyDict_SetItem(dict, PyIdentifier.__doc__, pydocstring);
            Runtime.PyDict_SetItem(dict, PyIdentifier.__class__, pycls);
            Runtime.XDecref(pyname);
            Runtime.XDecref(pyfilename);
            Runtime.XDecref(pydocstring);

            Runtime.XIncref(dict);
            SetObjectDict(pyHandle, dict);

            InitializeModuleMembers();
        }
Example #6
0
        /// <summary>
        /// Preloads all currently-known names for the module namespace. This
        /// can be called multiple times, to add names from assemblies that
        /// may have been loaded since the last call to the method.
        /// </summary>
        public void LoadNames()
        {
            ManagedType m = null;

            foreach (string name in AssemblyManager.GetNames(_namespace))
            {
                cache.TryGetValue(name, out m);
                if (m != null)
                {
                    continue;
                }
                BorrowedReference attr = Runtime.PyDict_GetItemString(DictRef, name);
                // If __dict__ has already set a custom property, skip it.
                if (!attr.IsNull)
                {
                    continue;
                }
                GetAttribute(name, true);
            }
        }
Example #7
0
        /// <summary>
        /// Preloads all currently-known names for the module namespace. This
        /// can be called multiple times, to add names from assemblies that
        /// may have been loaded since the last call to the method.
        /// </summary>
        public void LoadNames()
        {
            ManagedType m = null;

            foreach (string name in AssemblyManager.GetNames(_namespace))
            {
                cache.TryGetValue(name, out m);
                if (m != null)
                {
                    continue;
                }
                IntPtr attr = Runtime.PyDict_GetItemString(dict, name);
                // If __dict__ has already set a custom property, skip it.
                if (attr != IntPtr.Zero)
                {
                    continue;
                }
                GetAttribute(name, true);
            }
        }
Example #8
0
        public ModuleObject(string name)
        {
            if (name == string.Empty)
            {
                throw new ArgumentException("Name must not be empty!");
            }
            moduleName = name;
            cache      = new Dictionary <string, ManagedType>();
            _namespace = name;

            // Use the filename from any of the assemblies just so there's something for
            // anything that expects __file__ to be set.
            var filename  = "unknown";
            var docstring = "Namespace containing types from the following assemblies:\n\n";

            foreach (Assembly a in AssemblyManager.GetAssemblies(name))
            {
                if (!a.IsDynamic && a.Location != null)
                {
                    filename = a.Location;
                }
                docstring += "- " + a.FullName + "\n";
            }

            var dictRef = Runtime.PyObject_GenericGetDict(ObjectReference);

            PythonException.ThrowIfIsNull(dictRef);
            dict = dictRef.DangerousMoveToPointer();

            using var pyname      = NewReference.DangerousFromPointer(Runtime.PyString_FromString(moduleName));
            using var pyfilename  = NewReference.DangerousFromPointer(Runtime.PyString_FromString(filename));
            using var pydocstring = NewReference.DangerousFromPointer(Runtime.PyString_FromString(docstring));
            BorrowedReference pycls = TypeManager.GetTypeReference(GetType());

            Runtime.PyDict_SetItem(DictRef, PyIdentifier.__name__, pyname);
            Runtime.PyDict_SetItem(DictRef, PyIdentifier.__file__, pyfilename);
            Runtime.PyDict_SetItem(DictRef, PyIdentifier.__doc__, pydocstring);
            Runtime.PyDict_SetItem(DictRef, PyIdentifier.__class__, pycls);

            InitializeModuleMembers();
        }
Example #9
0
        //====================================================================
        // xxx
        //====================================================================

        public static List <Type> GenericsForType(Type t)
        {
            Dictionary <string, List <string> > nsmap = null;

            mapping.TryGetValue(t.Namespace, out nsmap);
            if (nsmap == null)
            {
                return(null);
            }

            string basename = t.Name;
            int    tick     = basename.IndexOf("`");

            if (tick > -1)
            {
                basename = basename.Substring(0, tick);
            }

            List <string> names = null;

            nsmap.TryGetValue(basename, out names);
            if (names == null)
            {
                return(null);
            }

            List <Type> result = new List <Type>();

            foreach (string name in names)
            {
                string qname = t.Namespace + "." + name;
                Type   o     = AssemblyManager.LookupType(qname);
                if (o != null)
                {
                    result.Add(o);
                }
            }

            return(result);
        }
        public ModuleObject(string name) : base()
        {
            if (name == String.Empty)
            {
                throw new ArgumentException("Name must not be empty!");
            }
            moduleName = name;
            cache      = new Dictionary <string, ManagedType>();
            _namespace = name;

            // Use the filename from any of the assemblies just so there's something for
            // anything that expects __file__ to be set.
            string filename  = "unknown";
            string docstring = "Namespace containing types from the following assemblies:\n\n";

            foreach (Assembly a in AssemblyManager.GetAssemblies(name))
            {
                filename   = a.Location;
                docstring += "- " + a.FullName + "\n";
            }

            dict = Runtime.PyDict_New();
            IntPtr pyname      = Runtime.PyString_FromString(moduleName);
            IntPtr pyfilename  = Runtime.PyString_FromString(filename);
            IntPtr pydocstring = Runtime.PyString_FromString(docstring);
            IntPtr pycls       = TypeManager.GetTypeHandle(this.GetType());

            Runtime.PyDict_SetItemString(dict, "__name__", pyname);
            Runtime.PyDict_SetItemString(dict, "__file__", pyfilename);
            Runtime.PyDict_SetItemString(dict, "__doc__", pydocstring);
            Runtime.PyDict_SetItemString(dict, "__class__", pycls);
            Runtime.Decref(pyname);
            Runtime.Decref(pyfilename);
            Runtime.Decref(pydocstring);

            Marshal.WriteIntPtr(this.pyHandle, ObjectOffset.DictOffset(this.pyHandle), dict);

            InitializeModuleMembers();
        }
Example #11
0
        public static List <Type> GenericsByName(string ns, string basename)
        {
            Dictionary <string, List <string> > nsmap = null;

            mapping.TryGetValue(ns, out nsmap);
            if (nsmap == null)
            {
                return(null);
            }

            int tick = basename.IndexOf("`");

            if (tick > -1)
            {
                basename = basename.Substring(0, tick);
            }

            List <string> names = null;

            nsmap.TryGetValue(basename, out names);
            if (names == null)
            {
                return(null);
            }

            var result = new List <Type>();

            foreach (string name in names)
            {
                string qname = ns + "." + name;
                Type   o     = AssemblyManager.LookupTypes(qname).FirstOrDefault();
                if (o != null)
                {
                    result.Add(o);
                }
            }

            return(result);
        }
Example #12
0
        public static Assembly AddReference(string name)
        {
            AssemblyManager.UpdatePath();
            var      origNs   = AssemblyManager.GetNamespaces();
            Assembly assembly = null;

            assembly = AssemblyManager.FindLoadedAssembly(name);
            if (assembly == null)
            {
                assembly = AssemblyManager.LoadAssemblyPath(name);
            }
            if (assembly == null && AssemblyManager.TryParseAssemblyName(name) is { } parsedName)
            {
                assembly = AssemblyManager.LoadAssembly(parsedName);
            }
            if (assembly == null)
            {
                assembly = AssemblyManager.LoadAssemblyFullPath(name);
            }
            if (assembly == null)
            {
                throw new FileNotFoundException($"Unable to find assembly '{name}'.");
            }
            // Classes that are not in a namespace needs an extra nudge to be found.
            ImportHook.UpdateCLRModuleDict();

            // A bit heavyhanded, but we can't use the AssemblyManager's AssemblyLoadHandler
            // method because it may be called from other threads, leading to deadlocks
            // if it is called while Python code is executing.
            var currNs = AssemblyManager.GetNamespaces().Except(origNs);

            foreach (var ns in currNs)
            {
                ImportHook.AddNamespaceWithGIL(ns);
            }
            return(assembly);
        }
Example #13
0
        //===================================================================
        // Preloads all currently-known names for the module namespace. This
        // can be called multiple times, to add names from assemblies that
        // may have been loaded since the last call to the method.
        //===================================================================

        public void LoadNames()
        {
            foreach (string name in AssemblyManager.GetNames(_namespace))
            {
                if (!this.cache.ContainsKey(name))
                {
                    ManagedType attr = this.GetAttribute(name);
                    if (Runtime.wrap_exceptions)
                    {
                        if (attr is ClassBase)
                        {
                            ClassBase c = attr as ClassBase;
                            if (c.is_exception)
                            {
                                IntPtr p = attr.pyHandle;
                                IntPtr r = Exceptions.GetExceptionClassWrapper(p);
                                Runtime.PyDict_SetItemString(dict, name, r);
                                Runtime.Incref(r);
                            }
                        }
                    }
                }
            }
        }
Example #14
0
        /// <summary>
        /// Preloads all currently-known names for the module namespace. This
        /// can be called multiple times, to add names from assemblies that
        /// may have been loaded since the last call to the method.
        /// </summary>
        public void LoadNames()
        {
            ManagedType m = null;

            foreach (string name in AssemblyManager.GetNames(_namespace))
            {
                cache.TryGetValue(name, out m);
                if (m != null)
                {
                    continue;
                }
                BorrowedReference attr = Runtime.PyDict_GetItemString(DictRef, name);
                // If __dict__ has already set a custom property, skip it.
                if (!attr.IsNull)
                {
                    continue;
                }

                if (GetAttribute(name, true) != null)
                {
                    // if it's a valid attribute, add it to __all__
                    var pyname = Runtime.PyString_FromString(name);
                    try
                    {
                        if (Runtime.PyList_Append(new BorrowedReference(__all__), new BorrowedReference(pyname)) != 0)
                        {
                            throw PythonException.ThrowLastAsClrException();
                        }
                    }
                    finally
                    {
                        Runtime.XDecref(pyname);
                    }
                }
            }
        }
Example #15
0
        //===================================================================
        // The actual import hook that ties Python to the managed world.
        //===================================================================

        public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
        {
            // Replacement for the builtin __import__. The original import
            // hook is saved as this.py_import. This version handles CLR
            // import and defers to the normal builtin for everything else.

            int num_args = Runtime.PyTuple_Size(args);

            if (num_args < 1)
            {
                return(Exceptions.RaiseTypeError(
                           "__import__() takes at least 1 argument (0 given)"
                           ));
            }

            // borrowed reference
            IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0);

            if ((py_mod_name == IntPtr.Zero) ||
                (!Runtime.IsStringType(py_mod_name)))
            {
                return(Exceptions.RaiseTypeError("string expected"));
            }

            // Check whether the import is of the form 'from x import y'.
            // This determines whether we return the head or tail module.

            IntPtr fromList = IntPtr.Zero;
            bool   fromlist = false;

            if (num_args >= 4)
            {
                fromList = Runtime.PyTuple_GetItem(args, 3);
                if ((fromList != IntPtr.Zero) &&
                    (Runtime.PyObject_IsTrue(fromList) == 1))
                {
                    fromlist = true;
                }
            }

            string mod_name = Runtime.GetManagedString(py_mod_name);

            // Check these BEFORE the built-in import runs; may as well
            // do the Incref()ed return here, since we've already found
            // the module.
            if (mod_name == "clr")
            {
                root.InitializePreload();
                Runtime.Incref(root.pyHandle);
                return(root.pyHandle);
            }
            if (mod_name == "CLR")
            {
                Exceptions.deprecation("The CLR module is deprecated. " +
                                       "Please use 'clr'.");
                root.InitializePreload();
                Runtime.Incref(root.pyHandle);
                return(root.pyHandle);
            }
            string realname = mod_name;

            if (mod_name.StartsWith("CLR."))
            {
                realname = mod_name.Substring(4);
                string msg = String.Format("Importing from the CLR.* namespace " +
                                           "is deprecated. Please import '{0}' directly.", realname);
                Exceptions.deprecation(msg);
            }
            else
            {
                // 2010-08-15: Always seemed smart to let python try first...
                // This shaves off a few tenths of a second on test_module.py
                // and works around a quirk where 'sys' is found by the
                // LoadImplicit() deprecation logic.
                // Turns out that the AssemblyManager.ResolveHandler() checks to see if any
                // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
                // little sense to me.
                IntPtr res = Runtime.PyObject_Call(py_import, args, kw);
                if (res != IntPtr.Zero)
                {
                    // There was no error.
                    return(res);
                }
                // There was an error
                if (!Exceptions.ExceptionMatches(Exceptions.ImportError))
                {
                    // and it was NOT an ImportError; bail out here.
                    return(IntPtr.Zero);
                }
                // Otherwise,  just clear the it.
                Exceptions.Clear();
            }

            string[] names = realname.Split('.');

            // Now we need to decide if the name refers to a CLR module,
            // and may have to do an implicit load (for b/w compatibility)
            // using the AssemblyManager. The assembly manager tries
            // really hard not to use Python objects or APIs, because
            // parts of it can run recursively and on strange threads.
            //
            // It does need an opportunity from time to time to check to
            // see if sys.path has changed, in a context that is safe. Here
            // we know we have the GIL, so we'll let it update if needed.

            AssemblyManager.UpdatePath();
            if (!AssemblyManager.IsValidNamespace(realname))
            {
                bool fromFile = false;
                if (AssemblyManager.LoadImplicit(realname, out fromFile))
                {
                    if (true == fromFile)
                    {
                        string deprWarning = String.Format("\nThe module was found, but not in a referenced namespace.\n" +
                                                           "Implicit loading is deprecated. Please use clr.AddReference(\"{0}\").", realname);
                        Exceptions.deprecation(deprWarning);
                    }
                }
                else
                {
                    // May be called when a module being imported imports a module.
                    // In particular, I've seen decimal import copy import org.python.core
                    return(Runtime.PyObject_Call(py_import, args, kw));
                }
            }

            // See if sys.modules for this interpreter already has the
            // requested module. If so, just return the exising module.

            IntPtr modules = Runtime.PyImport_GetModuleDict();
            IntPtr module  = Runtime.PyDict_GetItem(modules, py_mod_name);

            if (module != IntPtr.Zero)
            {
                if (fromlist)
                {
                    Runtime.Incref(module);
                    return(module);
                }
                module = Runtime.PyDict_GetItemString(modules, names[0]);
                Runtime.Incref(module);
                return(module);
            }
            Exceptions.Clear();

            // Traverse the qualified module name to get the named module
            // and place references in sys.modules as we go. Note that if
            // we are running in interactive mode we pre-load the names in
            // each module, which is often useful for introspection. If we
            // are not interactive, we stick to just-in-time creation of
            // objects at lookup time, which is much more efficient.
            // NEW: The clr got a new module variable preload. You can
            // enable preloading in a non-interactive python processing by
            // setting clr.preload = True

            ModuleObject head = (mod_name == realname) ? null : root;
            ModuleObject tail = root;

            root.InitializePreload();

            for (int i = 0; i < names.Length; i++)
            {
                string      name = names[i];
                ManagedType mt   = tail.GetAttribute(name, true);
                if (!(mt is ModuleObject))
                {
                    string error = String.Format("No module named {0}", name);
                    Exceptions.SetError(Exceptions.ImportError, error);
                    return(IntPtr.Zero);
                }
                if (head == null)
                {
                    head = (ModuleObject)mt;
                }
                tail = (ModuleObject)mt;
                if (CLRModule.preload)
                {
                    tail.LoadNames();
                }
                Runtime.PyDict_SetItemString(modules, tail.moduleName,
                                             tail.pyHandle
                                             );
            }

            ModuleObject mod = fromlist ? tail : head;

            if (fromlist && Runtime.PySequence_Size(fromList) == 1)
            {
                IntPtr fp = Runtime.PySequence_GetItem(fromList, 0);
                if ((!CLRModule.preload) && Runtime.GetManagedString(fp) == "*")
                {
                    mod.LoadNames();
                }
                Runtime.Decref(fp);
            }

            Runtime.Incref(mod.pyHandle);
            return(mod.pyHandle);
        }
Example #16
0
 public static string FindAssembly(string name)
 {
     AssemblyManager.UpdatePath();
     return(AssemblyManager.FindAssembly(name));
 }
Example #17
0
        /// <summary>
        /// Returns a ClassBase object representing a type that appears in
        /// this module's namespace or a ModuleObject representing a child
        /// namespace (or null if the name is not found). This method does
        /// not increment the Python refcount of the returned object.
        /// </summary>
        public ManagedType GetAttribute(string name, bool guess)
        {
            ManagedType cached = null;

            cache.TryGetValue(name, out cached);
            if (cached != null)
            {
                return(cached);
            }

            ModuleObject m;
            ClassBase    c;
            Type         type;

            //if (AssemblyManager.IsValidNamespace(name))
            //{
            //    IntPtr py_mod_name = Runtime.PyString_FromString(name);
            //    IntPtr modules = Runtime.PyImport_GetModuleDict();
            //    IntPtr module = Runtime.PyDict_GetItem(modules, py_mod_name);
            //    if (module != IntPtr.Zero)
            //        return (ManagedType)this;
            //    return null;
            //}

            string qname = _namespace == string.Empty
                ? name
                : _namespace + "." + name;

            // If the fully-qualified name of the requested attribute is
            // a namespace exported by a currently loaded assembly, return
            // a new ModuleObject representing that namespace.
            if (AssemblyManager.IsValidNamespace(qname))
            {
                m = new ModuleObject(qname);
                StoreAttribute(name, m);
                return(m);
            }

            // Look for a type in the current namespace. Note that this
            // includes types, delegates, enums, interfaces and structs.
            // Only public namespace members are exposed to Python.
            type = AssemblyManager.LookupType(qname);
            if (type != null)
            {
                if (!type.IsPublic)
                {
                    return(null);
                }
                c = ClassManager.GetClass(type);
                StoreAttribute(name, c);
                return(c);
            }

            // This is a little repetitive, but it ensures that the right
            // thing happens with implicit assembly loading at a reasonable
            // cost. Ask the AssemblyManager to do implicit loading for each
            // of the steps in the qualified name, then try it again.
            bool ignore = name.StartsWith("__");

            if (AssemblyManager.LoadImplicit(qname, !ignore))
            {
                if (AssemblyManager.IsValidNamespace(qname))
                {
                    m = new ModuleObject(qname);
                    StoreAttribute(name, m);
                    return(m);
                }

                type = AssemblyManager.LookupType(qname);
                if (type != null)
                {
                    if (!type.IsPublic)
                    {
                        return(null);
                    }
                    c = ClassManager.GetClass(type);
                    StoreAttribute(name, c);
                    return(c);
                }
            }

            // We didn't find the name, so we may need to see if there is a
            // generic type with this base name. If so, we'll go ahead and
            // return it. Note that we store the mapping of the unmangled
            // name to generic type -  it is technically possible that some
            // future assembly load could contribute a non-generic type to
            // the current namespace with the given basename, but unlikely
            // enough to complicate the implementation for now.
            if (guess)
            {
                string gname = GenericUtil.GenericNameForBaseName(_namespace, name);
                if (gname != null)
                {
                    ManagedType o = GetAttribute(gname, false);
                    if (o != null)
                    {
                        StoreAttribute(name, o);
                        return(o);
                    }
                }
            }

            return(null);
        }
Example #18
0
        //===================================================================
        // Returns a ClassBase object representing a type that appears in
        // this module's namespace or a ModuleObject representing a child
        // namespace (or null if the name is not found). This method does
        // not increment the Python refcount of the returned object.
        //===================================================================

        public ManagedType GetAttribute(string name)
        {
            Object ob = this.cache[name];

            if (ob != null)
            {
                return((ManagedType)ob);
            }

            string qname = (_namespace == String.Empty) ? name :
                           _namespace + "." + name;

            ModuleObject m;
            ClassBase    c;

            // If the fully-qualified name of the requested attribute is
            // a namespace exported by a currently loaded assembly, return
            // a new ModuleObject representing that namespace.

            if (AssemblyManager.IsValidNamespace(qname))
            {
                m = new ModuleObject(qname);
                StoreAttribute(name, m);
                return((ManagedType)m);
            }

            // Look for a type in the current namespace. Note that this
            // includes types, delegates, enums, interfaces and structs.
            // Only public namespace members are exposed to Python.

            Type type = AssemblyManager.LookupType(qname);

            if (type != null)
            {
                if (!type.IsPublic)
                {
                    return(null);
                }
                c = ClassManager.GetClass(type);
                StoreAttribute(name, c);
                return((ManagedType)c);
            }

            // This is a little repetitive, but it ensures that the right
            // thing happens with implicit assembly loading at a reasonable
            // cost. Ask the AssemblyManager to do implicit loading for each
            // of the steps in the qualified name, then try it again.

            if (AssemblyManager.LoadImplicit(qname))
            {
                if (AssemblyManager.IsValidNamespace(qname))
                {
                    m = new ModuleObject(qname);
                    StoreAttribute(name, m);
                    return((ManagedType)m);
                }

                type = AssemblyManager.LookupType(qname);
                if (type != null)
                {
                    if (!type.IsPublic)
                    {
                        return(null);
                    }
                    c = ClassManager.GetClass(type);
                    StoreAttribute(name, c);
                    return((ManagedType)c);
                }
            }

            return(null);
        }
Example #19
0
        /// <summary>
        /// Creates a new managed type derived from a base type with any virtual
        /// methods overridden to call out to python if the associated python
        /// object has overridden the method.
        /// </summary>
        internal static Type CreateDerivedType(string name,
                                               Type baseType,
                                               BorrowedReference dictRef,
                                               string namespaceStr,
                                               string assemblyName,
                                               string moduleName = "Python.Runtime.Dynamic.dll")
        {
            // TODO: clean up
            IntPtr py_dict = dictRef.DangerousGetAddress();

            if (null != namespaceStr)
            {
                name = namespaceStr + "." + name;
            }

            if (null == assemblyName)
            {
                assemblyName = "Python.Runtime.Dynamic";
            }

            ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName);

            Type baseClass  = baseType;
            var  interfaces = new List <Type> {
                typeof(IPythonDerivedType)
            };

            // if the base type is an interface then use System.Object as the base class
            // and add the base type to the list of interfaces this new class will implement.
            if (baseType.IsInterface)
            {
                interfaces.Add(baseType);
                baseClass = typeof(object);
            }

            TypeBuilder typeBuilder = moduleBuilder.DefineType(name,
                                                               TypeAttributes.Public | TypeAttributes.Class,
                                                               baseClass,
                                                               interfaces.ToArray());

            // add a field for storing the python object pointer
            // FIXME: fb not used
            FieldBuilder fb = typeBuilder.DefineField("__pyobj__", typeof(CLRObject), FieldAttributes.Public);

            // override any constructors
            ConstructorInfo[] constructors = baseClass.GetConstructors();
            foreach (ConstructorInfo ctor in constructors)
            {
                AddConstructor(ctor, baseType, typeBuilder);
            }

            // Override any properties explicitly overridden in python
            var pyProperties = new HashSet <string>();

            if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict))
            {
                Runtime.XIncref(py_dict);
                using (var dict = new PyDict(py_dict))
                    using (PyObject keys = dict.Keys())
                    {
                        foreach (PyObject pyKey in keys)
                        {
                            using (PyObject value = dict[pyKey])
                            {
                                if (value.HasAttr("_clr_property_type_"))
                                {
                                    string propertyName = pyKey.ToString();
                                    pyProperties.Add(propertyName);

                                    // Add the property to the type
                                    AddPythonProperty(propertyName, value, typeBuilder);
                                }
                            }
                        }
                    }
            }

            // override any virtual methods not already overridden by the properties above
            MethodInfo[] methods        = baseType.GetMethods();
            var          virtualMethods = new HashSet <string>();

            foreach (MethodInfo method in methods)
            {
                if (!method.Attributes.HasFlag(MethodAttributes.Virtual) |
                    method.Attributes.HasFlag(MethodAttributes.Final))
                {
                    continue;
                }

                // skip if this property has already been overridden
                if ((method.Name.StartsWith("get_") || method.Name.StartsWith("set_")) &&
                    pyProperties.Contains(method.Name.Substring(4)))
                {
                    continue;
                }

                // keep track of the virtual methods redirected to the python instance
                virtualMethods.Add(method.Name);

                // override the virtual method to call out to the python method, if there is one.
                AddVirtualMethod(method, baseType, typeBuilder);
            }

            // Add any additional methods and properties explicitly exposed from Python.
            if (py_dict != IntPtr.Zero && Runtime.PyDict_Check(py_dict))
            {
                Runtime.XIncref(py_dict);
                using (var dict = new PyDict(py_dict))
                    using (PyObject keys = dict.Keys())
                    {
                        foreach (PyObject pyKey in keys)
                        {
                            using (PyObject value = dict[pyKey])
                            {
                                if (value.HasAttr("_clr_return_type_") && value.HasAttr("_clr_arg_types_"))
                                {
                                    string methodName = pyKey.ToString();

                                    // if this method has already been redirected to the python method skip it
                                    if (virtualMethods.Contains(methodName))
                                    {
                                        continue;
                                    }

                                    // Add the method to the type
                                    AddPythonMethod(methodName, value, typeBuilder);
                                }
                            }
                        }
                    }
            }

            // add the destructor so the python object created in the constructor gets destroyed
            MethodBuilder methodBuilder = typeBuilder.DefineMethod("Finalize",
                                                                   MethodAttributes.Family |
                                                                   MethodAttributes.Virtual |
                                                                   MethodAttributes.HideBySig,
                                                                   CallingConventions.Standard,
                                                                   typeof(void),
                                                                   Type.EmptyTypes);
            ILGenerator il = methodBuilder.GetILGenerator();

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("Finalize"));
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, baseClass.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance));
            il.Emit(OpCodes.Ret);

            Type type = typeBuilder.CreateType();

            // scan the assembly so the newly added class can be imported
            Assembly assembly = Assembly.GetAssembly(type);

            AssemblyManager.ScanAssembly(assembly);

            // FIXME: assemblyBuilder not used
            AssemblyBuilder assemblyBuilder = assemblyBuilders[assemblyName];

            return(type);
        }
Example #20
0
        /// <summary>
        /// The actual import hook that ties Python to the managed world.
        /// </summary>
        public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
        {
            // Replacement for the builtin __import__. The original import
            // hook is saved as this.py_import. This version handles CLR
            // import and defers to the normal builtin for everything else.

            var num_args = Runtime.PyTuple_Size(args);

            if (num_args < 1)
            {
                return(Exceptions.RaiseTypeError("__import__() takes at least 1 argument (0 given)"));
            }

            // borrowed reference
            IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0);

            if (py_mod_name == IntPtr.Zero ||
                !Runtime.IsStringType(py_mod_name))
            {
                return(Exceptions.RaiseTypeError("string expected"));
            }

            // Check whether the import is of the form 'from x import y'.
            // This determines whether we return the head or tail module.

            IntPtr fromList = IntPtr.Zero;
            var    fromlist = false;

            if (num_args >= 4)
            {
                fromList = Runtime.PyTuple_GetItem(args, 3);
                if (fromList != IntPtr.Zero &&
                    Runtime.PyObject_IsTrue(fromList) == 1)
                {
                    fromlist = true;
                }
            }

            string mod_name = Runtime.GetManagedString(py_mod_name);

            // Check these BEFORE the built-in import runs; may as well
            // do the Incref()ed return here, since we've already found
            // the module.
            if (mod_name == "clr" || mod_name == "CLR")
            {
                if (mod_name == "CLR")
                {
                    Exceptions.deprecation("The CLR module is deprecated. Please use 'clr'.");
                }
                IntPtr clr_module = GetCLRModule(fromList);
                if (clr_module != IntPtr.Zero)
                {
                    IntPtr sys_modules = Runtime.PyImport_GetModuleDict();
                    if (sys_modules != IntPtr.Zero)
                    {
                        Runtime.PyDict_SetItemString(sys_modules, "clr", clr_module);
                    }
                }
                return(clr_module);
            }

            string realname   = mod_name;
            string clr_prefix = null;

            if (mod_name.StartsWith("CLR."))
            {
                clr_prefix = "CLR."; // prepend when adding the module to sys.modules
                realname   = mod_name.Substring(4);
                string msg = $"Importing from the CLR.* namespace is deprecated. Please import '{realname}' directly.";
                Exceptions.deprecation(msg);
            }
            else
            {
                // 2010-08-15: Always seemed smart to let python try first...
                // This shaves off a few tenths of a second on test_module.py
                // and works around a quirk where 'sys' is found by the
                // LoadImplicit() deprecation logic.
                // Turns out that the AssemblyManager.ResolveHandler() checks to see if any
                // Assembly's FullName.ToLower().StartsWith(name.ToLower()), which makes very
                // little sense to me.
                IntPtr res = Runtime.PyObject_Call(py_import, args, kw);
                if (res != IntPtr.Zero)
                {
                    // There was no error.
                    if (fromlist && IsLoadAll(fromList))
                    {
                        var mod = ManagedType.GetManagedObject(res) as ModuleObject;
                        mod?.LoadNames();
                    }
                    return(res);
                }
                // There was an error
                if (!Exceptions.ExceptionMatches(Exceptions.ImportError))
                {
                    // and it was NOT an ImportError; bail out here.
                    return(IntPtr.Zero);
                }

                if (mod_name == string.Empty)
                {
                    // Most likely a missing relative import.
                    // For example site-packages\bs4\builder\__init__.py uses it to check if a package exists:
                    //     from . import _html5lib
                    // We don't support them anyway
                    return(IntPtr.Zero);
                }
                // Otherwise,  just clear the it.
                Exceptions.Clear();
            }

            string[] names = realname.Split('.');

            // Now we need to decide if the name refers to a CLR module,
            // and may have to do an implicit load (for b/w compatibility)
            // using the AssemblyManager. The assembly manager tries
            // really hard not to use Python objects or APIs, because
            // parts of it can run recursively and on strange threads.
            //
            // It does need an opportunity from time to time to check to
            // see if sys.path has changed, in a context that is safe. Here
            // we know we have the GIL, so we'll let it update if needed.

            AssemblyManager.UpdatePath();
            if (!AssemblyManager.IsValidNamespace(realname))
            {
                var loadExceptions = new List <Exception>();
                if (!AssemblyManager.LoadImplicit(realname, assemblyLoadErrorHandler: loadExceptions.Add))
                {
                    // May be called when a module being imported imports a module.
                    // In particular, I've seen decimal import copy import org.python.core
                    IntPtr importResult = Runtime.PyObject_Call(py_import, args, kw);
                    // TODO: use ModuleNotFoundError in Python 3.6+
                    if (importResult == IntPtr.Zero && loadExceptions.Count > 0 &&
                        Exceptions.ExceptionMatches(Exceptions.ImportError))
                    {
                        loadExceptions.Add(new PythonException());
                        var importError = new PyObject(new BorrowedReference(Exceptions.ImportError));
                        importError.SetAttr("__cause__", new AggregateException(loadExceptions).ToPython());
                        Runtime.PyErr_SetObject(new BorrowedReference(Exceptions.ImportError), importError.Reference);
                    }
                    return(importResult);
                }
            }

            // See if sys.modules for this interpreter already has the
            // requested module. If so, just return the existing module.
            IntPtr modules = Runtime.PyImport_GetModuleDict();
            IntPtr module  = Runtime.PyDict_GetItem(modules, py_mod_name);

            if (module != IntPtr.Zero)
            {
                if (fromlist)
                {
                    if (IsLoadAll(fromList))
                    {
                        var mod = ManagedType.GetManagedObject(module) as ModuleObject;
                        mod?.LoadNames();
                    }
                    Runtime.XIncref(module);
                    return(module);
                }
                if (clr_prefix != null)
                {
                    return(GetCLRModule(fromList));
                }
                module = Runtime.PyDict_GetItemString(modules, names[0]);
                Runtime.XIncref(module);
                return(module);
            }
            Exceptions.Clear();

            // Traverse the qualified module name to get the named module
            // and place references in sys.modules as we go. Note that if
            // we are running in interactive mode we pre-load the names in
            // each module, which is often useful for introspection. If we
            // are not interactive, we stick to just-in-time creation of
            // objects at lookup time, which is much more efficient.
            // NEW: The clr got a new module variable preload. You can
            // enable preloading in a non-interactive python processing by
            // setting clr.preload = True

            ModuleObject head = mod_name == realname ? null : root;
            ModuleObject tail = root;

            root.InitializePreload();

            foreach (string name in names)
            {
                ManagedType mt = tail.GetAttribute(name, true);
                if (!(mt is ModuleObject))
                {
                    Exceptions.SetError(Exceptions.ImportError, $"No module named {name}");
                    return(IntPtr.Zero);
                }
                if (head == null)
                {
                    head = (ModuleObject)mt;
                }
                tail = (ModuleObject)mt;
                if (CLRModule.preload)
                {
                    tail.LoadNames();
                }

                // Add the module to sys.modules
                Runtime.PyDict_SetItemString(modules, tail.moduleName, tail.pyHandle);

                // If imported from CLR add CLR.<modulename> to sys.modules as well
                if (clr_prefix != null)
                {
                    Runtime.PyDict_SetItemString(modules, clr_prefix + tail.moduleName, tail.pyHandle);
                }
            }

            {
                var mod = fromlist ? tail : head;

                if (fromlist && IsLoadAll(fromList))
                {
                    mod.LoadNames();
                }

                Runtime.XIncref(mod.pyHandle);
                return(mod.pyHandle);
            }
        }
Example #21
0
        public static Type GetCOMObjectType(ITypeInfo info)
        {
            Guid guid   = GetTypeInfoGuid(info);
            Type result = null;

            //If we've found it previously, no need to look again
            #region Check Type Cache

            s_Cache.TryGetValue(guid, out result);
            if (result != null)
            {
                return(result);
            }

            #endregion

            //Works for most of the cases
            #region Check AssemblyManager Assemblies

            AssemblyName[] names = AssemblyManager.ListAssemblies();
            foreach (AssemblyName an in names)
            {
                try
                {
                    Assembly a      = Assembly.Load(an);
                    Type[]   aTypes = a.GetTypes();
                    foreach (Type t in aTypes)
                    {
                        if (t.IsInterface && t.IsImport && t.GUID == guid && !t.Name.StartsWith("_"))
                        {
                            result = t;

                            List <Type> possible = aTypes.Where(x => x.Name.Equals(t.Name + "Class", StringComparison.Ordinal)).ToList <Type>();
                            if (possible.Count > 0)
                            {
                                s_Cache.Add(guid, result);
                                return(result);
                            }
                        }
                    }
                }
                catch (Exception ex) { }
            }

            if (result != null)
            {
                s_Cache.Add(guid, result);
                return(result);
            }

            #endregion

            //Extended check of assemblies
            #region Check CurrentDomain Assemblies

            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly a in assemblies)
            {
                Type[] aTypes = a.GetTypes();
                foreach (Type t in aTypes)
                {
                    if (t.IsInterface && t.IsImport && t.GUID == guid && !t.Name.StartsWith("_"))
                    {
                        result = t;

                        List <Type> possible = aTypes.Where(x => x.Name.Equals(t.Name + "Class", StringComparison.Ordinal)).ToList <Type>();
                        if (possible.Count > 0)
                        {
                            s_Cache.Add(guid, result);
                            return(result);
                        }
                    }
                }
            }

            if (result != null)
            {
                s_Cache.Add(guid, result);
                return(result);
            }

            #endregion

            //Almost never works for my cases but worth a shot i guess
            #region Check Type CLSID

            result = Type.GetTypeFromCLSID(guid);

            if (result != null)
            {
                s_Cache.Add(guid, result);
                return(result);
            }

            #endregion

            //Reliable but incredibly slow, like really really really slow
            #region Get Type for ITypeInfo

            IntPtr pInfo = Marshal.GetIUnknownForObject(info);
            result = Marshal.GetTypeForITypeInfo(pInfo);

            s_Cache.Add(guid, result);
            return(result);

            #endregion
        }
Example #22
0
        //===================================================================
        // The actual import hook that ties Python to the managed world.
        //===================================================================

        public static IntPtr __import__(IntPtr self, IntPtr args, IntPtr kw)
        {
            // Replacement for the builtin __import__. The original import
            // hook is saved as this.py_import. This version handles CLR
            // import and defers to the normal builtin for everything else.

            int num_args = Runtime.PyTuple_Size(args);

            if (num_args < 1)
            {
                return(Exceptions.RaiseTypeError(
                           "__import__() takes at least 1 argument (0 given)"
                           ));
            }

            // borrowed reference
            IntPtr py_mod_name = Runtime.PyTuple_GetItem(args, 0);

            if ((py_mod_name == IntPtr.Zero) ||
                (!Runtime.IsStringType(py_mod_name)))
            {
                return(Exceptions.RaiseTypeError("string expected"));
            }

            // Check whether the import is of the form 'from x import y'.
            // This determines whether we return the head or tail module.

            IntPtr fromList = IntPtr.Zero;
            bool   fromlist = false;

            if (num_args >= 4)
            {
                fromList = Runtime.PyTuple_GetItem(args, 3);
                if ((fromList != IntPtr.Zero) &&
                    (Runtime.PyObject_IsTrue(fromList) == 1))
                {
                    fromlist = true;
                }
            }

            string mod_name = Runtime.GetManagedString(py_mod_name);

            if (mod_name == "CLR")
            {
                Exceptions.deprecation("The CLR module is deprecated. " +
                                       "Please use 'clr'.");
                root.InitializePreload();
                Runtime.Incref(root.pyHandle);
                return(root.pyHandle);
            }

            if (mod_name == "clr")
            {
                root.InitializePreload();
                Runtime.Incref(root.pyHandle);
                return(root.pyHandle);
            }

            string realname = mod_name;

            if (mod_name.StartsWith("CLR."))
            {
                realname = mod_name.Substring(4);
                string msg = String.Format("Importing from the CLR.* namespace " +
                                           "is deprecated. Please import '{0}' directly.", realname);
                Exceptions.deprecation(msg);
            }

            string[] names = realname.Split('.');

            // Now we need to decide if the name refers to a CLR module,
            // and may have to do an implicit load (for b/w compatibility)
            // using the AssemblyManager. The assembly manager tries
            // really hard not to use Python objects or APIs, because
            // parts of it can run recursively and on strange threads.
            //
            // It does need an opportunity from time to time to check to
            // see if sys.path has changed, in a context that is safe. Here
            // we know we have the GIL, so we'll let it update if needed.

            AssemblyManager.UpdatePath();
            AssemblyManager.LoadImplicit(realname);
            if (!AssemblyManager.IsValidNamespace(realname))
            {
                return(Runtime.PyObject_Call(py_import, args, kw));
            }

            // See if sys.modules for this interpreter already has the
            // requested module. If so, just return the exising module.

            IntPtr modules = Runtime.PyImport_GetModuleDict();
            IntPtr module  = Runtime.PyDict_GetItem(modules, py_mod_name);

            if (module != IntPtr.Zero)
            {
                if (fromlist)
                {
                    Runtime.Incref(module);
                    return(module);
                }
                module = Runtime.PyDict_GetItemString(modules, names[0]);
                Runtime.Incref(module);
                return(module);
            }
            Exceptions.Clear();

            // Traverse the qualified module name to get the named module
            // and place references in sys.modules as we go. Note that if
            // we are running in interactive mode we pre-load the names in
            // each module, which is often useful for introspection. If we
            // are not interactive, we stick to just-in-time creation of
            // objects at lookup time, which is much more efficient.
            // NEW: The clr got a new module variable preload. You can
            // enable preloading in a non-interactive python processing by
            // setting clr.preload = True

            ModuleObject head = (mod_name == realname) ? null : root;
            ModuleObject tail = root;

            root.InitializePreload();

            for (int i = 0; i < names.Length; i++)
            {
                string      name = names[i];
                ManagedType mt   = tail.GetAttribute(name, true);
                if (!(mt is ModuleObject))
                {
                    string error = String.Format("No module named {0}", name);
                    Exceptions.SetError(Exceptions.ImportError, error);
                    return(IntPtr.Zero);
                }
                if (head == null)
                {
                    head = (ModuleObject)mt;
                }
                tail = (ModuleObject)mt;
                if (CLRModule.preload)
                {
                    tail.LoadNames();
                }
                Runtime.PyDict_SetItemString(modules, tail.moduleName,
                                             tail.pyHandle
                                             );
            }

            ModuleObject mod = fromlist ? tail : head;

            if (fromlist && Runtime.PySequence_Size(fromList) == 1)
            {
                IntPtr fp = Runtime.PySequence_GetItem(fromList, 0);
                if ((!CLRModule.preload) && Runtime.GetManagedString(fp) == "*")
                {
                    mod.LoadNames();
                }
                Runtime.Decref(fp);
            }

            Runtime.Incref(mod.pyHandle);
            return(mod.pyHandle);
        }
Example #23
0
        //====================================================================
        // Creates a new managed type derived from a base type with any virtual
        // methods overriden to call out to python if the associated python
        // object has overriden the method.
        //====================================================================
        internal static Type CreateDerivedType(string name,
                                               Type baseType,
                                               string namespaceStr,
                                               string assemblyName,
                                               string moduleName = "Python.Runtime.Dynamic.dll")
        {
            if (null != namespaceStr)
            {
                name = namespaceStr + "." + name;
            }

            if (null == assemblyName)
            {
                assemblyName = Assembly.GetExecutingAssembly().FullName;
            }

            ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName);
            TypeBuilder   typeBuilder;

            Type        baseClass  = baseType;
            List <Type> interfaces = new List <Type> {
                typeof(IPythonDerivedType)
            };

            // if the base type is an interface then use System.Object as the base class
            // and add the base type to the list of interfaces this new class will implement.
            if (baseType.IsInterface)
            {
                interfaces.Add(baseType);
                baseClass = typeof(System.Object);
            }

            typeBuilder = moduleBuilder.DefineType(name,
                                                   TypeAttributes.Public | TypeAttributes.Class,
                                                   baseClass,
                                                   interfaces.ToArray());

            ILGenerator   il;
            MethodBuilder mb;

            // add a field for storing the python object pointer
            FieldBuilder fb = typeBuilder.DefineField("__pyobj__", typeof(CLRObject), FieldAttributes.Public);

            // override any constructors
            ConstructorInfo[] constructors = baseClass.GetConstructors();
            foreach (ConstructorInfo ctor in constructors)
            {
                ParameterInfo[] parameters     = ctor.GetParameters();
                Type[]          parameterTypes = (from param in parameters select param.ParameterType).ToArray();

                // create a method for calling the original constructor
                string baseCtorName = "_" + baseType.Name + "__cinit__";
                mb = typeBuilder.DefineMethod(baseCtorName,
                                              MethodAttributes.Public |
                                              MethodAttributes.Final |
                                              MethodAttributes.HideBySig,
                                              typeof(void),
                                              parameterTypes);

                // emit the assembly for calling the original method using call instead of callvirt
                il = mb.GetILGenerator();
                il.Emit(OpCodes.Ldarg_0);
                for (int i = 0; i < parameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldarg, i + 1);
                }
                il.Emit(OpCodes.Call, ctor);
                il.Emit(OpCodes.Ret);

                // override the original method with a new one that dispatches to python
                ConstructorBuilder cb = typeBuilder.DefineConstructor(MethodAttributes.Public |
                                                                      MethodAttributes.ReuseSlot |
                                                                      MethodAttributes.HideBySig,
                                                                      ctor.CallingConvention,
                                                                      parameterTypes);
                il = cb.GetILGenerator();
                il.DeclareLocal(typeof(Object[]));
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldstr, baseCtorName);
                il.Emit(OpCodes.Ldc_I4, parameters.Length);
                il.Emit(OpCodes.Newarr, typeof(System.Object));
                il.Emit(OpCodes.Stloc_0);
                for (int i = 0; i < parameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldloc_0);
                    il.Emit(OpCodes.Ldc_I4, i);
                    il.Emit(OpCodes.Ldarg, i + 1);
                    if (parameterTypes[i].IsValueType)
                    {
                        il.Emit(OpCodes.Box, parameterTypes[i]);
                    }
                    il.Emit(OpCodes.Stelem, typeof(Object));
                }
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeCtor"));
                il.Emit(OpCodes.Ret);
            }

            // override any virtual methods
            MethodInfo[] methods = baseType.GetMethods();
            foreach (MethodInfo method in methods)
            {
                if (!method.Attributes.HasFlag(MethodAttributes.Virtual) | method.Attributes.HasFlag(MethodAttributes.Final))
                {
                    continue;
                }

                ParameterInfo[] parameters     = method.GetParameters();
                Type[]          parameterTypes = (from param in parameters select param.ParameterType).ToArray();

                // create a method for calling the original method
                string baseMethodName = "_" + baseType.Name + "__" + method.Name;
                mb = typeBuilder.DefineMethod(baseMethodName,
                                              MethodAttributes.Public |
                                              MethodAttributes.Final |
                                              MethodAttributes.HideBySig,
                                              method.ReturnType,
                                              parameterTypes);

                // emit the assembly for calling the original method using call instead of callvirt
                il = mb.GetILGenerator();
                il.Emit(OpCodes.Ldarg_0);
                for (int i = 0; i < parameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldarg, i + 1);
                }
                il.Emit(OpCodes.Call, method);
                il.Emit(OpCodes.Ret);

                // override the original method with a new one that dispatches to python
                mb = typeBuilder.DefineMethod(method.Name,
                                              MethodAttributes.Public |
                                              MethodAttributes.ReuseSlot |
                                              MethodAttributes.Virtual |
                                              MethodAttributes.HideBySig,
                                              method.CallingConvention,
                                              method.ReturnType,
                                              parameterTypes);
                il = mb.GetILGenerator();
                il.DeclareLocal(typeof(Object[]));
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldstr, method.Name);
                il.Emit(OpCodes.Ldstr, baseMethodName);
                il.Emit(OpCodes.Ldc_I4, parameters.Length);
                il.Emit(OpCodes.Newarr, typeof(System.Object));
                il.Emit(OpCodes.Stloc_0);
                for (int i = 0; i < parameters.Length; ++i)
                {
                    il.Emit(OpCodes.Ldloc_0);
                    il.Emit(OpCodes.Ldc_I4, i);
                    il.Emit(OpCodes.Ldarg, i + 1);
                    if (parameterTypes[i].IsValueType)
                    {
                        il.Emit(OpCodes.Box, parameterTypes[i]);
                    }
                    il.Emit(OpCodes.Stelem, typeof(Object));
                }
                il.Emit(OpCodes.Ldloc_0);
                if (method.ReturnType == typeof(void))
                {
                    il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethodVoid"));
                }
                else
                {
                    il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("InvokeMethod").MakeGenericMethod(method.ReturnType));
                }
                il.Emit(OpCodes.Ret);
            }

            // add the destructor so the python object created in the constructor gets destroyed
            mb = typeBuilder.DefineMethod("Finalize",
                                          MethodAttributes.Family |
                                          MethodAttributes.Virtual |
                                          MethodAttributes.HideBySig,
                                          CallingConventions.Standard,
                                          typeof(void),
                                          Type.EmptyTypes);
            il = mb.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, typeof(PythonDerivedType).GetMethod("Finalize"));
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, baseClass.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance));
            il.Emit(OpCodes.Ret);

            Type type = typeBuilder.CreateType();

            // scan the assembly so the newly added class can be imported
            Assembly assembly = Assembly.GetAssembly(type);

            AssemblyManager.ScanAssembly(assembly);

            return(type);
        }
Example #24
0
        /// <summary>
        /// Initialize the runtime...
        /// </summary>
        internal static void Initialize()
        {
            if (Interop.Py_IsInitialized() == 0)
            {
                Interop.Py_Initialize();
            }

            if (Interop.PyEval_ThreadsInitialized() == 0)
            {
                Interop.PyEval_InitThreads();
            }

            IntPtr op;
            IntPtr dict;

            if (IsPython3)
            {
                op   = Interop.PyImport_ImportModule("builtins");
                dict = Interop.PyObject_GetAttrString(op, "__dict__");
            }
            else // Python2
            {
                dict = Interop.PyImport_GetModuleDict();
                op   = Interop.PyDict_GetItemString(dict, "__builtin__");
            }
            PyNotImplemented = Interop.PyObject_GetAttrString(op, "NotImplemented");
            PyBaseObjectType = Interop.PyObject_GetAttrString(op, "object");

            PyModuleType = PyObject_Type(op);
            PyNone       = Interop.PyObject_GetAttrString(op, "None");
            PyTrue       = Interop.PyObject_GetAttrString(op, "True");
            PyFalse      = Interop.PyObject_GetAttrString(op, "False");

            PyBoolType = PyObject_Type(PyTrue);
            PyNoneType = PyObject_Type(PyNone);
            PyTypeType = PyObject_Type(PyNoneType);

            op           = Interop.PyObject_GetAttrString(dict, "keys");
            PyMethodType = PyObject_Type(op);
            XDecref(op);

            // For some arcane reason, builtins.__dict__.__setitem__ is *not*
            // a wrapper_descriptor, even though dict.__setitem__ is.
            //
            // object.__init__ seems safe, though.
            op = Interop.PyObject_GetAttrString(PyBaseObjectType, "__init__");
            PyWrapperDescriptorType = PyObject_Type(op);
            XDecref(op);

#if PYTHON3
            XDecref(dict);
#endif

            op           = PyString_FromString("string");
            PyStringType = PyObject_Type(op);
            XDecref(op);

            op            = PyUnicode_FromString("unicode");
            PyUnicodeType = PyObject_Type(op);
            XDecref(op);

#if PYTHON3
            op          = Interop.PyBytes_FromString("bytes");
            PyBytesType = PyObject_Type(op);
            XDecref(op);
#endif

            op          = Interop.PyTuple_New(0);
            PyTupleType = PyObject_Type(op);
            XDecref(op);

            op         = Interop.PyList_New(0);
            PyListType = PyObject_Type(op);
            XDecref(op);

            op         = Interop.PyDict_New();
            PyDictType = PyObject_Type(op);
            XDecref(op);

            op        = PyInt_FromInt32(0);
            PyIntType = PyObject_Type(op);
            XDecref(op);

            op         = Interop.PyLong_FromLong(0);
            PyLongType = PyObject_Type(op);
            XDecref(op);

            op          = Interop.PyFloat_FromDouble(0);
            PyFloatType = PyObject_Type(op);
            XDecref(op);

#if PYTHON3
            PyClassType    = IntPtr.Zero;
            PyInstanceType = IntPtr.Zero;
#elif PYTHON2
            IntPtr s = Interop.PyString_FromString("_temp");
            IntPtr d = Interop.PyDict_New();

            IntPtr c = Interop.PyClass_New(IntPtr.Zero, d, s);
            PyClassType = Interop.PyObject_Type(c);

            IntPtr i = Interop.PyInstance_New(c, IntPtr.Zero, IntPtr.Zero);
            PyInstanceType = Interop.PyObject_Type(i);

            XDecref(s);
            XDecref(i);
            XDecref(c);
            XDecref(d);
#endif

            Error = new IntPtr(-1);

            IntPtr dllLocal = IntPtr.Zero;

            if (Interop.GetDllName() != "__Internal")
            {
                if (OS.IsLinux)
                {
                    dllLocal = NativeMethods_Linux.LoadLibrary(Interop.GetDllName());
                }
                else if (OS.IsOSX)
                {
                    dllLocal = NativeMethods_OSX.LoadLibrary(Interop.GetDllName());
                }
                else if (OS.IsWindows)
                {
                    dllLocal = NativeMethods_Windows.LoadLibrary(Interop.GetDllName());
                }
            }

            if (OS.IsLinux)
            {
                _PyObject_NextNotImplemented = NativeMethods_Linux.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented");
            }
            else if (OS.IsOSX)
            {
                _PyObject_NextNotImplemented = NativeMethods_OSX.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented");
            }
            else if (OS.IsWindows)
            {
                _PyObject_NextNotImplemented = NativeMethods_Windows.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented");
            }



            if (OS.IsWindows && dllLocal != IntPtr.Zero)
            {
                NativeMethods_Windows.FreeLibrary(dllLocal);
            }

            // Initialize modules that depend on the runtime class.
            AssemblyManager.Initialize();
            PyCLRMetaType = MetaType.Initialize();
            Exceptions.Initialize();
            ImportHook.Initialize();

            // Need to add the runtime directory to sys.path so that we
            // can find built-in assemblies like System.Data, et. al.
            string rtdir = RuntimeEnvironment.GetRuntimeDirectory();
            IntPtr path  = Interop.PySys_GetObject("path");
            IntPtr item  = PyString_FromString(rtdir);
            Interop.PyList_Append(path, item);
            XDecref(item);
            AssemblyManager.UpdatePath();
        }