• R/O
  • SSH

Joypy: Commit

This repo is not current. Development has moved from Hg to Git. For the latest code use the "Source Code" tab above to go to the "Thun" git repo or navigate to:
https://osdn.net/projects/joypy/scm/git/Thun


Commit MetaInfo

Révision541f3eb4e9816dac6adb2c5c48af4f7aa0acab63 (tree)
l'heure2018-04-22 07:37:19
AuteurSimon Forman <sforman@hush...>
CommiterSimon Forman

Message de Log

Let the name of wrapped functions appear in tracebacks.

Change Summary

Modification

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
Afficher sur ancien navigateur de dépôt.