PageRenderTime 38ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/Languages/IronPython/IronPython/Runtime/PythonModule.cs

http://github.com/IronLanguages/main
C# | 396 lines | 297 code | 67 blank | 32 comment | 41 complexity | 58455b05b5cc545325e635ecdbed1c08 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. #if FEATURE_CORE_DLR
  16. using System.Linq.Expressions;
  17. #endif
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Diagnostics;
  21. using System.Dynamic;
  22. using System.Reflection;
  23. using System.Runtime.CompilerServices;
  24. using System.Threading;
  25. using Microsoft.Scripting;
  26. using Microsoft.Scripting.Ast;
  27. using Microsoft.Scripting.Runtime;
  28. using IronPython.Runtime.Operations;
  29. using IronPython.Runtime.Types;
  30. using IronPython.Runtime.Binding;
  31. namespace IronPython.Runtime {
  32. /// <summary>
  33. /// Python module. Stores classes, functions, and data. Usually a module
  34. /// is created by importing a file or package from disk. But a module can also
  35. /// be directly created by calling the module type and providing a name or
  36. /// optionally a documentation string.
  37. /// </summary>
  38. [PythonType("module"), DebuggerTypeProxy(typeof(PythonModule.DebugProxy)), DebuggerDisplay("module: {GetName()}")]
  39. public class PythonModule : IDynamicMetaObjectProvider, IPythonMembersList {
  40. private readonly PythonDictionary _dict;
  41. private Scope _scope;
  42. public PythonModule() {
  43. _dict = new PythonDictionary();
  44. if (GetType() != typeof(PythonModule) && this is IPythonObject) {
  45. // we should share the user dict w/ our dict.
  46. ((IPythonObject)this).ReplaceDict(_dict);
  47. }
  48. }
  49. /// <summary>
  50. /// Creates a new module backed by a Scope. Used for creating modules for foreign Scope's.
  51. /// </summary>
  52. internal PythonModule(PythonContext context, Scope scope) {
  53. _dict = new PythonDictionary(new ScopeDictionaryStorage(context, scope));
  54. _scope = scope;
  55. }
  56. /// <summary>
  57. /// Creates a new PythonModule with the specified dictionary.
  58. ///
  59. /// Used for creating modules for builtin modules which don't have any code associated with them.
  60. /// </summary>
  61. internal PythonModule(PythonDictionary dict) {
  62. _dict = dict;
  63. }
  64. public static PythonModule/*!*/ __new__(CodeContext/*!*/ context, PythonType/*!*/ cls, params object[]/*!*/ args\u00F8) {
  65. PythonModule res;
  66. if (cls == TypeCache.Module) {
  67. res = new PythonModule();
  68. } else if (cls.IsSubclassOf(TypeCache.Module)) {
  69. res = (PythonModule)cls.CreateInstance(context);
  70. } else {
  71. throw PythonOps.TypeError("{0} is not a subtype of module", cls.Name);
  72. }
  73. return res;
  74. }
  75. [StaticExtensionMethod]
  76. public static PythonModule/*!*/ __new__(CodeContext/*!*/ context, PythonType/*!*/ cls, [ParamDictionary]IDictionary<object, object> kwDict0, params object[]/*!*/ args\u00F8) {
  77. return __new__(context, cls, args\u00F8);
  78. }
  79. public void __init__(string name) {
  80. __init__(name, null);
  81. }
  82. public void __init__(string name, string doc) {
  83. _dict["__name__"] = name;
  84. _dict["__doc__"] = doc;
  85. }
  86. public object __getattribute__(CodeContext/*!*/ context, string name) {
  87. PythonTypeSlot slot;
  88. object res;
  89. if (GetType() != typeof(PythonModule) &&
  90. DynamicHelpers.GetPythonType(this).TryResolveMixedSlot(context, name, out slot) &&
  91. slot.TryGetValue(context, this, DynamicHelpers.GetPythonType(this), out res)) {
  92. return res;
  93. }
  94. switch (name) {
  95. // never look in the dict for these...
  96. case "__dict__": return __dict__;
  97. case "__class__": return DynamicHelpers.GetPythonType(this);
  98. }
  99. if (_dict.TryGetValue(name, out res)) {
  100. return res;
  101. }
  102. // fall back to object to provide all of our other attributes (e.g. __setattr__, etc...)
  103. return ObjectOps.__getattribute__(context, this, name);
  104. }
  105. internal object GetAttributeNoThrow(CodeContext/*!*/ context, string name) {
  106. PythonTypeSlot slot;
  107. object res;
  108. if (GetType() != typeof(PythonModule) &&
  109. DynamicHelpers.GetPythonType(this).TryResolveMixedSlot(context, name, out slot) &&
  110. slot.TryGetValue(context, this, DynamicHelpers.GetPythonType(this), out res)) {
  111. return res;
  112. }
  113. switch (name) {
  114. // never look in the dict for these...
  115. case "__dict__": return __dict__;
  116. case "__class__": return DynamicHelpers.GetPythonType(this);
  117. }
  118. if (_dict.TryGetValue(name, out res)) {
  119. return res;
  120. } else if (DynamicHelpers.GetPythonType(this).TryGetNonCustomMember(context, this, name, out res)) {
  121. return res;
  122. } else if (DynamicHelpers.GetPythonType(this).TryResolveMixedSlot(context, "__getattr__", out slot) &&
  123. slot.TryGetValue(context, this, DynamicHelpers.GetPythonType(this), out res)) {
  124. return PythonCalls.Call(context, res, name);
  125. }
  126. return OperationFailed.Value;
  127. }
  128. public void __setattr__(CodeContext/*!*/ context, string name, object value) {
  129. PythonTypeSlot slot;
  130. if (GetType() != typeof(PythonModule) &&
  131. DynamicHelpers.GetPythonType(this).TryResolveMixedSlot(context, name, out slot) &&
  132. slot.TrySetValue(context, this, DynamicHelpers.GetPythonType(this), value)) {
  133. return;
  134. }
  135. switch (name) {
  136. case "__dict__": throw PythonOps.TypeError("readonly attribute");
  137. case "__class__": throw PythonOps.TypeError("__class__ assignment: only for heap types");
  138. }
  139. Debug.Assert(value != Uninitialized.Instance);
  140. _dict[name] = value;
  141. }
  142. public void __delattr__(CodeContext/*!*/ context, string name) {
  143. PythonTypeSlot slot;
  144. if (GetType() != typeof(PythonModule) &&
  145. DynamicHelpers.GetPythonType(this).TryResolveMixedSlot(context, name, out slot) &&
  146. slot.TryDeleteValue(context, this, DynamicHelpers.GetPythonType(this))) {
  147. return;
  148. }
  149. switch (name) {
  150. case "__dict__": throw PythonOps.TypeError("readonly attribute");
  151. case "__class__": throw PythonOps.TypeError("can't delete __class__ attribute");
  152. }
  153. object value;
  154. if (!_dict.TryRemoveValue(name, out value)) {
  155. throw PythonOps.AttributeErrorForMissingAttribute("module", name);
  156. }
  157. }
  158. public string/*!*/ __repr__() {
  159. return __str__();
  160. }
  161. public string/*!*/ __str__() {
  162. object fileObj, nameObj;
  163. if (!_dict.TryGetValue("__file__", out fileObj)) {
  164. fileObj = null;
  165. }
  166. if (!_dict._storage.TryGetName(out nameObj)) {
  167. nameObj = null;
  168. }
  169. string file = fileObj as string;
  170. string name = nameObj as string ?? "?";
  171. if (file == null) {
  172. return String.Format("<module '{0}' (built-in)>", name);
  173. }
  174. return String.Format("<module '{0}' from '{1}'>", name, file);
  175. }
  176. internal PythonDictionary __dict__ {
  177. get {
  178. return _dict;
  179. }
  180. }
  181. [SpecialName, PropertyMethod]
  182. public PythonDictionary Get__dict__() {
  183. return _dict;
  184. }
  185. [SpecialName, PropertyMethod]
  186. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  187. public void Set__dict__(object value) {
  188. throw PythonOps.TypeError("readonly attribute");
  189. }
  190. [SpecialName, PropertyMethod]
  191. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
  192. public void Delete__dict__() {
  193. throw PythonOps.TypeError("readonly attribute");
  194. }
  195. public Scope Scope {
  196. get {
  197. if (_scope == null) {
  198. Interlocked.CompareExchange(ref _scope, new Scope(new ObjectDictionaryExpando(_dict)), null);
  199. }
  200. return _scope;
  201. }
  202. }
  203. #region IDynamicMetaObjectProvider Members
  204. [PythonHidden] // needs to be public so that we can override it.
  205. public DynamicMetaObject GetMetaObject(Expression parameter) {
  206. return new MetaModule(this, parameter);
  207. }
  208. #endregion
  209. class MetaModule : MetaPythonObject, IPythonGetable {
  210. public MetaModule(PythonModule module, Expression self)
  211. : base(self, BindingRestrictions.Empty, module) {
  212. }
  213. public override DynamicMetaObject BindGetMember(GetMemberBinder binder) {
  214. return GetMemberWorker(binder, PythonContext.GetCodeContextMO(binder));
  215. }
  216. #region IPythonGetable Members
  217. public DynamicMetaObject GetMember(PythonGetMemberBinder member, DynamicMetaObject codeContext) {
  218. return GetMemberWorker(member, codeContext);
  219. }
  220. #endregion
  221. private DynamicMetaObject GetMemberWorker(DynamicMetaObjectBinder binder, DynamicMetaObject codeContext) {
  222. string name = GetGetMemberName(binder);
  223. var tmp = Expression.Variable(typeof(object), "res");
  224. return new DynamicMetaObject(
  225. Expression.Block(
  226. new[] { tmp },
  227. Expression.Condition(
  228. Expression.Call(
  229. typeof(PythonOps).GetMethod("ModuleTryGetMember"),
  230. PythonContext.GetCodeContext(binder),
  231. Utils.Convert(Expression, typeof(PythonModule)),
  232. Expression.Constant(name),
  233. tmp
  234. ),
  235. tmp,
  236. Expression.Convert(GetMemberFallback(this, binder, codeContext).Expression, typeof(object))
  237. )
  238. ),
  239. BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())
  240. );
  241. }
  242. public override DynamicMetaObject/*!*/ BindInvokeMember(InvokeMemberBinder/*!*/ action, DynamicMetaObject/*!*/[]/*!*/ args) {
  243. return BindingHelpers.GenericInvokeMember(action, null, this, args);
  244. }
  245. public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
  246. Debug.Assert(value.Value != Uninitialized.Instance);
  247. return new DynamicMetaObject(
  248. Expression.Block(
  249. Expression.Call(
  250. Utils.Convert(Expression, typeof(PythonModule)),
  251. typeof(PythonModule).GetMethod("__setattr__"),
  252. PythonContext.GetCodeContext(binder),
  253. Expression.Constant(binder.Name),
  254. Expression.Convert(value.Expression, typeof(object))
  255. ),
  256. Expression.Convert(value.Expression, typeof(object))
  257. ),
  258. BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())
  259. );
  260. }
  261. public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
  262. return new DynamicMetaObject(
  263. Expression.Call(
  264. Utils.Convert(Expression, typeof(PythonModule)),
  265. typeof(PythonModule).GetMethod("__delattr__"),
  266. PythonContext.GetCodeContext(binder),
  267. Expression.Constant(binder.Name)
  268. ),
  269. BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())
  270. );
  271. }
  272. public override IEnumerable<string> GetDynamicMemberNames() {
  273. foreach (object o in ((PythonModule)Value).__dict__.Keys) {
  274. string str = o as string;
  275. if (str != null) {
  276. yield return str;
  277. }
  278. }
  279. }
  280. }
  281. internal string GetFile() {
  282. object res;
  283. if (_dict.TryGetValue("__file__", out res)) {
  284. return res as string;
  285. }
  286. return null;
  287. }
  288. internal string GetName() {
  289. object res;
  290. if (_dict._storage.TryGetName(out res)) {
  291. return res as string;
  292. }
  293. return null;
  294. }
  295. #region IPythonMembersList Members
  296. IList<object> IPythonMembersList.GetMemberNames(CodeContext context) {
  297. return new List<object>(__dict__.Keys);
  298. }
  299. #endregion
  300. #region IMembersList Members
  301. IList<string> IMembersList.GetMemberNames() {
  302. List<string> res = new List<string>(__dict__.Keys.Count);
  303. foreach (object o in __dict__.Keys) {
  304. string strKey = o as string;
  305. if (strKey != null) {
  306. res.Add(strKey);
  307. }
  308. }
  309. return res;
  310. }
  311. #endregion
  312. internal class DebugProxy {
  313. private readonly PythonModule _module;
  314. public DebugProxy(PythonModule module) {
  315. _module = module;
  316. }
  317. [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
  318. public List<ObjectDebugView> Members {
  319. get {
  320. var res = new List<ObjectDebugView>();
  321. foreach (var v in _module._dict) {
  322. res.Add(new ObjectDebugView(v.Key, v.Value));
  323. }
  324. return res;
  325. }
  326. }
  327. }
  328. }
  329. }