• R/O
  • SSH

Joypy: コミット

Main interpreter and library.


コミットメタ情報

リビジョン541f3eb4e9816dac6adb2c5c48af4f7aa0acab63 (tree)
日時2018-04-22 07:37:19
作者Simon Forman <sforman@hush...>
コミッターSimon Forman

ログメッセージ

Let the name of wrapped functions appear in tracebacks.

変更サマリ

差分

diff -r 922110dfdf13 -r 541f3eb4e981 joy/library.py
--- a/joy/library.py Sat Apr 21 15:20:46 2018 -0700
+++ b/joy/library.py Sat Apr 21 15:37:19 2018 -0700
@@ -29,6 +29,7 @@
2929
3030 from .parser import text_to_expression, Symbol
3131 from .utils.stack import list_to_stack, iter_stack, pick, pushback
32+from .utils.brutal_hackery import rename_code_object
3233
3334
3435 _dictionary = {}
@@ -167,6 +168,7 @@
167168 '''
168169 @FunctionWrapper
169170 @wraps(f)
171+ @rename_code_object(f.__name__)
170172 def inner(stack, expression, dictionary):
171173 return f(stack), expression, dictionary
172174 return inner
@@ -178,6 +180,7 @@
178180 '''
179181 @FunctionWrapper
180182 @wraps(f)
183+ @rename_code_object(f.__name__)
181184 def inner(stack, expression, dictionary):
182185 (a, (b, stack)) = stack
183186 result = f(b, a)
@@ -191,6 +194,7 @@
191194 '''
192195 @FunctionWrapper
193196 @wraps(f)
197+ @rename_code_object(f.__name__)
194198 def inner(stack, expression, dictionary):
195199 (a, stack) = stack
196200 result = f(a)
diff -r 922110dfdf13 -r 541f3eb4e981 joy/utils/brutal_hackery.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/joy/utils/brutal_hackery.py Sat Apr 21 15:37:19 2018 -0700
@@ -0,0 +1,93 @@
1+# -*- coding: utf-8 -*-
2+#
3+# Copyright © 2018 Simon Forman
4+#
5+# This file is part of Joypy
6+#
7+# Joypy is free software: you can redistribute it and/or modify
8+# it under the terms of the GNU General Public License as published by
9+# the Free Software Foundation, either version 3 of the License, or
10+# (at your option) any later version.
11+#
12+# Joypy is distributed in the hope that it will be useful,
13+# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+# GNU General Public License for more details.
16+#
17+# You should have received a copy of the GNU General Public License
18+# along with Joypy. If not see <http://www.gnu.org/licenses/>.
19+#
20+'''
21+I really want tracebacks to show which function was being executed when
22+an error in the wrapper function happens. In order to do that, you have
23+to do this (the function in this module.)
24+
25+Here's what it looks like when you pass too few arguments to e.g. "mul".
26+
27+ >>> from joy.library import _dictionary
28+ >>> m = _dictionary['*']
29+ >>> m((), (), {})
30+
31+ Traceback (most recent call last):
32+ File "<pyshell#49>", line 1, in <module>
33+ m((), (), {})
34+ File "joy/library.py", line 185, in mul:inner
35+ (a, (b, stack)) = stack
36+ ValueError: need more than 0 values to unpack
37+ >>>
38+
39+
40+Notice that line 185 in the library.py file is (as of this writing) in
41+the BinaryBuiltinWrapper's inner() function, but this hacky code has
42+managed to insert the name of the wrapped function ("mul") along with a
43+colon into the wrapper function's reported name.
44+
45+Normally I would frown on this sort of mad hackery, but... this is in
46+the service of ease-of-debugging! Very valuable. And note that all the
47+hideous patching is finished in the module-load-stage, it shouldn't cause
48+issues of its own at runtime.
49+
50+The main problem I see with this is that people coming to this code later
51+might be mystified if they just see a traceback with a ':' in the
52+function name! Hopefully they will discover this documentation.
53+'''
54+
55+
56+def rename_code_object(new_name):
57+ '''
58+ If you want to wrap a function in another function and have the wrapped
59+ function's name show up in the traceback, you must do this brutal
60+ hackery to change the func.__code__.co_name attribute. See:
61+
62+ https://stackoverflow.com/questions/29919804/function-decorated-using-functools-wraps-raises-typeerror-with-the-name-of-the-w
63+
64+ https://stackoverflow.com/questions/29488327/changing-the-name-of-a-generator/29488561#29488561
65+
66+ I'm just glad it's possible.
67+ '''
68+ def inner(func):
69+ name = new_name + ':' + func.__name__
70+ code_object = func.__code__
71+ return type(func)(
72+ type(code_object)(
73+ code_object.co_argcount,
74+ code_object.co_nlocals,
75+ code_object.co_stacksize,
76+ code_object.co_flags,
77+ code_object.co_code,
78+ code_object.co_consts,
79+ code_object.co_names,
80+ code_object.co_varnames,
81+ code_object.co_filename,
82+ name,
83+ code_object.co_firstlineno,
84+ code_object.co_lnotab,
85+ code_object.co_freevars,
86+ code_object.co_cellvars
87+ ),
88+ func.__globals__,
89+ name,
90+ func.__defaults__,
91+ func.__closure__
92+ )
93+ return inner
旧リポジトリブラウザで表示