using System;
using System.Linq;
using System.IO;
using System.Reflection;
namespace Python.Runtime
{
///
/// The CLR module is the root handler used by the magic import hook
/// to import assemblies. It has a fixed module name "clr" and doesn't
/// provide a namespace.
///
[Serializable]
internal class CLRModule : ModuleObject
{
protected static bool interactive_preload = true;
internal static bool preload;
// XXX Test performance of new features //
internal static bool _SuppressDocs = false;
internal static bool _SuppressOverloads = false;
static CLRModule()
{
Reset();
}
private CLRModule() : base("clr")
{
_namespace = string.Empty;
}
internal static NewReference Create(out CLRModule module)
{
module = new CLRModule();
return module.Alloc();
}
public static void Reset()
{
interactive_preload = true;
preload = false;
// XXX Test performance of new features //
_SuppressDocs = false;
_SuppressOverloads = false;
}
///
/// The initializing of the preload hook has to happen as late as
/// possible since sys.ps1 is created after the CLR module is
/// created.
///
internal void InitializePreload()
{
if (interactive_preload)
{
interactive_preload = false;
if (!Runtime.PySys_GetObject("ps1").IsNull)
{
preload = true;
}
else
{
Exceptions.Clear();
preload = false;
}
}
}
[ModuleFunction]
public static bool getPreload()
{
return preload;
}
[ModuleFunction]
public static void setPreload(bool preloadFlag)
{
preload = preloadFlag;
}
//[ModuleProperty]
public static bool SuppressDocs
{
get { return _SuppressDocs; }
set { _SuppressDocs = value; }
}
//[ModuleProperty]
public static bool SuppressOverloads
{
get { return _SuppressOverloads; }
set { _SuppressOverloads = value; }
}
[ModuleFunction]
[ForbidPythonThreads]
public static Assembly AddReference(string name)
{
AssemblyManager.UpdatePath();
var origNs = AssemblyManager.GetNamespaces();
Assembly? 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;
}
///
/// Get a Type instance for a class object.
/// clr.GetClrType(IComparable) gives you the Type for IComparable,
/// that you can e.g. perform reflection on. Similar to typeof(IComparable) in C#
/// or clr.GetClrType(IComparable) in IronPython.
///
///
///
/// The Type object
[ModuleFunction]
public static Type GetClrType(Type type)
{
return type;
}
[ModuleFunction]
[ForbidPythonThreads]
public static string FindAssembly(string name)
{
AssemblyManager.UpdatePath();
return AssemblyManager.FindAssembly(name);
}
[ModuleFunction]
public static string[] ListAssemblies(bool verbose)
{
AssemblyName[] assnames = AssemblyManager.ListAssemblies();
var names = new string[assnames.Length];
for (var i = 0; i < assnames.Length; i++)
{
if (verbose)
{
names[i] = assnames[i].FullName;
}
else
{
names[i] = assnames[i].Name;
}
}
return names;
}
///
/// Note: This should *not* be called directly.
/// The function that get/import a CLR assembly as a python module.
/// This function should only be called by the import machinery as seen
/// in importhook.cs
///
/// A ModuleSpec Python object
/// A new reference to the imported module, as a PyObject.
[ModuleFunction]
[ForbidPythonThreads]
public static PyObject _load_clr_module(PyObject spec)
{
using var modname = spec.GetAttr("name");
string name = modname.As() ?? throw new ArgumentException("name must not be None");
var mod = ImportHook.Import(name);
return mod;
}
[ModuleFunction]
[ForbidPythonThreads]
public static int _add_pending_namespaces() => ImportHook.AddPendingNamespaces();
}
}