PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython/Modules/imp.cs

http://github.com/IronLanguages/main
C# | 342 lines | 257 code | 64 blank | 21 comment | 55 complexity | 978bc8cef978429949a944c5e9fba5e3 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Diagnostics;
  17. using System.IO;
  18. using System.Reflection;
  19. using System.Runtime.CompilerServices;
  20. using Microsoft.Scripting;
  21. using Microsoft.Scripting.Runtime;
  22. using Microsoft.Scripting.Utils;
  23. using IronPython.Runtime;
  24. using IronPython.Runtime.Operations;
  25. using IronPython.Runtime.Types;
  26. [assembly: PythonModule("imp", typeof(IronPython.Modules.PythonImport))]
  27. namespace IronPython.Modules {
  28. public static class PythonImport {
  29. public const string __doc__ = "Provides functions for programmatically creating and importing modules and packages.";
  30. internal const int PythonSource = 1;
  31. internal const int PythonCompiled = 2;
  32. internal const int CExtension = 3;
  33. internal const int PythonResource = 4;
  34. internal const int PackageDirectory = 5;
  35. internal const int CBuiltin = 6;
  36. internal const int PythonFrozen = 7;
  37. internal const int PythonCodeResource = 8;
  38. internal const int SearchError = 0;
  39. internal const int ImporterHook = 9;
  40. private static readonly object _lockCountKey = new object();
  41. [SpecialName]
  42. public static void PerformModuleReload(PythonContext/*!*/ context, PythonDictionary/*!*/ dict) {
  43. // set the lock count to zero on the 1st load, don't reset the lock count on reloads
  44. if (!context.HasModuleState(_lockCountKey)) {
  45. context.SetModuleState(_lockCountKey, 0L);
  46. }
  47. }
  48. public static string get_magic() {
  49. return "";
  50. }
  51. public static List get_suffixes() {
  52. return List.FromArrayNoCopy(PythonOps.MakeTuple(".py", "U", PythonSource));
  53. }
  54. public static PythonTuple find_module(CodeContext/*!*/ context, string/*!*/ name) {
  55. if (name == null) throw PythonOps.TypeError("find_module() argument 1 must be string, not None");
  56. return FindBuiltinOrSysPath(context, name);
  57. }
  58. public static PythonTuple find_module(CodeContext/*!*/ context, string/*!*/ name, List path) {
  59. if (name == null) throw PythonOps.TypeError("find_module() argument 1 must be string, not None");
  60. if (path == null) {
  61. return FindBuiltinOrSysPath(context, name);
  62. } else {
  63. return FindModulePath(context, name, path);
  64. }
  65. }
  66. public static object load_module(CodeContext/*!*/ context, string name, PythonFile file, string filename, PythonTuple/*!*/ description) {
  67. if (description == null) {
  68. throw PythonOps.TypeError("load_module() argument 4 must be 3-item sequence, not None");
  69. } else if (description.__len__() != 3) {
  70. throw PythonOps.TypeError("load_module() argument 4 must be sequence of length 3, not {0}", description.__len__());
  71. }
  72. PythonContext pythonContext = PythonContext.GetContext(context);
  73. // already loaded? do reload()
  74. PythonModule module = pythonContext.GetModuleByName(name);
  75. if (module != null) {
  76. Importer.ReloadModule(context, module, file);
  77. return module;
  78. }
  79. int type = PythonContext.GetContext(context).ConvertToInt32(description[2]);
  80. switch (type) {
  81. case PythonSource:
  82. return LoadPythonSource(pythonContext, name, file, filename);
  83. case CBuiltin:
  84. return LoadBuiltinModule(context, name);
  85. case PackageDirectory:
  86. return LoadPackageDirectory(pythonContext, name, filename);
  87. default:
  88. throw PythonOps.TypeError("don't know how to import {0}, (type code {1}", name, type);
  89. }
  90. }
  91. [Documentation("new_module(name) -> module\nCreates a new module without adding it to sys.modules.")]
  92. public static PythonModule/*!*/ new_module(CodeContext/*!*/ context, string/*!*/ name) {
  93. if (name == null) throw PythonOps.TypeError("new_module() argument 1 must be string, not None");
  94. PythonModule res = new PythonModule();
  95. res.__dict__["__name__"] = name;
  96. res.__dict__["__doc__"] = null;
  97. res.__dict__["__package__"] = null;
  98. return res;
  99. }
  100. public static bool lock_held(CodeContext/*!*/ context) {
  101. return GetLockCount(context) != 0;
  102. }
  103. public static void acquire_lock(CodeContext/*!*/ context) {
  104. lock (_lockCountKey) {
  105. SetLockCount(context, GetLockCount(context) + 1);
  106. }
  107. }
  108. public static void release_lock(CodeContext/*!*/ context) {
  109. lock (_lockCountKey) {
  110. long lockCount = GetLockCount(context);
  111. if (lockCount == 0) {
  112. throw PythonOps.RuntimeError("not holding the import lock");
  113. }
  114. SetLockCount(context, lockCount - 1);
  115. }
  116. }
  117. public const int PY_SOURCE = PythonSource;
  118. public const int PY_COMPILED = PythonCompiled;
  119. public const int C_EXTENSION = CExtension;
  120. public const int PY_RESOURCE = PythonResource;
  121. public const int PKG_DIRECTORY = PackageDirectory;
  122. public const int C_BUILTIN = CBuiltin;
  123. public const int PY_FROZEN = PythonFrozen;
  124. public const int PY_CODERESOURCE = PythonCodeResource;
  125. public const int SEARCH_ERROR = SearchError;
  126. public const int IMP_HOOK = ImporterHook;
  127. public static object init_builtin(CodeContext/*!*/ context, string/*!*/ name) {
  128. if (name == null) throw PythonOps.TypeError("init_builtin() argument 1 must be string, not None");
  129. return LoadBuiltinModule(context, name);
  130. }
  131. public static object init_frozen(string name) {
  132. return null;
  133. }
  134. public static object get_frozen_object(string name) {
  135. throw PythonOps.ImportError("No such frozen object named {0}", name);
  136. }
  137. public static int is_builtin(CodeContext/*!*/ context, string/*!*/ name) {
  138. if (name == null) throw PythonOps.TypeError("is_builtin() argument 1 must be string, not None");
  139. Type ty;
  140. if (PythonContext.GetContext(context).BuiltinModules.TryGetValue(name, out ty)) {
  141. if (ty.GetTypeInfo().Assembly == typeof(PythonContext).GetTypeInfo().Assembly) {
  142. // supposedly these can't be re-initialized and return -1 to
  143. // indicate that here, but CPython does allow passing them
  144. // to init_builtin.
  145. return -1;
  146. }
  147. return 1;
  148. }
  149. return 0;
  150. }
  151. public static bool is_frozen(string name) {
  152. return false;
  153. }
  154. public static object load_compiled(string name, string pathname) {
  155. return null;
  156. }
  157. public static object load_compiled(string name, string pathname, PythonFile file) {
  158. return null;
  159. }
  160. public static object load_dynamic(string name, string pathname) {
  161. return null;
  162. }
  163. public static object load_dynamic(string name, string pathname, PythonFile file) {
  164. return null;
  165. }
  166. public static object load_package(CodeContext/*!*/ context, string/*!*/ name, string/*!*/ pathname) {
  167. if (name == null) throw PythonOps.TypeError("load_package() argument 1 must be string, not None");
  168. if (pathname == null) throw PythonOps.TypeError("load_package() argument 2 must be string, not None");
  169. return (Importer.LoadPackageFromSource(context, name, pathname) ??
  170. CreateEmptyPackage(context, name, pathname));
  171. }
  172. private static PythonModule/*!*/ CreateEmptyPackage(CodeContext/*!*/ context, string/*!*/ name, string/*!*/ pathname) {
  173. PythonContext pc = PythonContext.GetContext(context);
  174. PythonModule mod = new PythonModule();
  175. mod.__dict__["__name__"] = name;
  176. mod.__dict__["__path__"] = pathname;
  177. pc.SystemStateModules[name] = mod;
  178. return mod;
  179. }
  180. public static object load_source(CodeContext/*!*/ context, string/*!*/ name, string/*!*/ pathname) {
  181. if (name == null) throw PythonOps.TypeError("load_source() argument 1 must be string, not None");
  182. if (pathname == null) throw PythonOps.TypeError("load_source() argument 2 must be string, not None");
  183. // TODO: is this supposed to open PythonFile with Python-specific behavior?
  184. // we may need to insert additional layer to SourceUnit content provider if so
  185. PythonContext pc = PythonContext.GetContext(context);
  186. if (!pc.DomainManager.Platform.FileExists(pathname)) {
  187. throw PythonOps.IOError("Couldn't find file: {0}", pathname);
  188. }
  189. SourceUnit sourceUnit = pc.CreateFileUnit(pathname, pc.DefaultEncoding, SourceCodeKind.File);
  190. return pc.CompileModule(pathname, name, sourceUnit, ModuleOptions.Initialize);
  191. }
  192. public static object load_source(CodeContext/*!*/ context, string/*!*/ name, string/*!*/ pathname, PythonFile/*!*/ file) {
  193. if (name == null) throw PythonOps.TypeError("load_source() argument 1 must be string, not None");
  194. if (pathname == null) throw PythonOps.TypeError("load_source() argument 2 must be string, not None");
  195. if (file == null) throw PythonOps.TypeError("load_source() argument 3 must be file, not None");
  196. return LoadPythonSource(PythonContext.GetContext(context), name, file, pathname);
  197. }
  198. public static object reload(CodeContext/*!*/ context, PythonModule scope) {
  199. return Builtin.reload(context, scope);
  200. }
  201. #region Implementation
  202. private static PythonTuple FindBuiltinOrSysPath(CodeContext/*!*/ context, string/*!*/ name) {
  203. List sysPath;
  204. if (!PythonContext.GetContext(context).TryGetSystemPath(out sysPath)) {
  205. throw PythonOps.ImportError("sys.path must be a list of directory names");
  206. }
  207. return FindModuleBuiltinOrPath(context, name, sysPath);
  208. }
  209. private static PythonTuple FindModulePath(CodeContext/*!*/ context, string name, List path) {
  210. Debug.Assert(path != null);
  211. if (name == null) {
  212. throw PythonOps.TypeError("find_module() argument 1 must be string, not None");
  213. }
  214. PlatformAdaptationLayer pal = context.LanguageContext.DomainManager.Platform;
  215. foreach (object d in path) {
  216. string dir = d as string;
  217. if (dir == null) continue; // skip invalid entries
  218. string pathName = Path.Combine(dir, name);
  219. if (pal.DirectoryExists(pathName)) {
  220. if (pal.FileExists(Path.Combine(pathName, "__init__.py"))) {
  221. return PythonTuple.MakeTuple(null, pathName, PythonTuple.MakeTuple("", "", PackageDirectory));
  222. }
  223. }
  224. string fileName = pathName + ".py";
  225. if (pal.FileExists(fileName)) {
  226. Stream fs = pal.OpenInputFileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  227. PythonFile pf = PythonFile.Create(context, fs, fileName, "U");
  228. return PythonTuple.MakeTuple(pf, fileName, PythonTuple.MakeTuple(".py", "U", PythonSource));
  229. }
  230. }
  231. throw PythonOps.ImportError("No module named {0}", name);
  232. }
  233. private static PythonTuple FindModuleBuiltinOrPath(CodeContext/*!*/ context, string name, List path) {
  234. if (name.Equals("sys")) return BuiltinModuleTuple(name);
  235. if (name.Equals("clr")) {
  236. context.ShowCls = true;
  237. return BuiltinModuleTuple(name);
  238. }
  239. Type ty;
  240. if (PythonContext.GetContext(context).BuiltinModules.TryGetValue(name, out ty)) {
  241. return BuiltinModuleTuple(name);
  242. }
  243. return FindModulePath(context, name, path);
  244. }
  245. private static PythonTuple BuiltinModuleTuple(string name) {
  246. return PythonTuple.MakeTuple(null, name, PythonTuple.MakeTuple("", "", CBuiltin));
  247. }
  248. private static PythonModule/*!*/ LoadPythonSource(PythonContext/*!*/ context, string/*!*/ name, PythonFile/*!*/ file, string/*!*/ fileName) {
  249. SourceUnit sourceUnit = context.CreateSnippet(file.read(), String.IsNullOrEmpty(fileName) ? null : fileName, SourceCodeKind.File);
  250. return context.CompileModule(fileName, name, sourceUnit, ModuleOptions.Initialize);
  251. }
  252. private static PythonModule/*!*/ LoadPackageDirectory(PythonContext/*!*/ context, string moduleName, string path) {
  253. string initPath = Path.Combine(path, "__init__.py");
  254. SourceUnit sourceUnit = context.CreateFileUnit(initPath, context.DefaultEncoding);
  255. return context.CompileModule(initPath, moduleName, sourceUnit, ModuleOptions.Initialize);
  256. }
  257. private static object LoadBuiltinModule(CodeContext/*!*/ context, string/*!*/ name) {
  258. Assert.NotNull(context, name);
  259. return Importer.ImportBuiltin(context, name);
  260. }
  261. #endregion
  262. private static long GetLockCount(CodeContext/*!*/ context) {
  263. return (long)PythonContext.GetContext(context).GetModuleState(_lockCountKey);
  264. }
  265. private static void SetLockCount(CodeContext/*!*/ context, long lockCount) {
  266. PythonContext.GetContext(context).SetModuleState(_lockCountKey, lockCount);
  267. }
  268. [PythonType]
  269. public sealed class NullImporter {
  270. public NullImporter(string path_string) {
  271. }
  272. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  273. public object find_module(params object[] args) {
  274. return null;
  275. }
  276. }
  277. }
  278. }