PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/DICK.B1/IronPython/Runtime/PythonModule.cs

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