forked from mitsuhiko/badideas
-
Notifications
You must be signed in to change notification settings - Fork 0
/
implicitself.py
105 lines (81 loc) · 3.01 KB
/
implicitself.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# -*- coding: utf-8 -*-
"""
implicitself
~~~~~~~~~~~~
Implements a bytecode hack and metaclass to make the self
implicit in functions.
:copyright: (c) Copyright 2011 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import opcode
from types import FunctionType, CodeType
HAVE_ARGUMENT = opcode.HAVE_ARGUMENT
LOAD_FAST = opcode.opmap['LOAD_FAST']
STORE_FAST = opcode.opmap['STORE_FAST']
LOAD_GLOBAL = opcode.opmap['LOAD_GLOBAL']
STORE_GLOBAL = opcode.opmap['STORE_GLOBAL']
LOAD_ATTR = opcode.opmap['LOAD_ATTR']
STORE_ATTR = opcode.opmap['STORE_ATTR']
LOAD_NAME = opcode.opmap['LOAD_NAME']
STORE_NAME = opcode.opmap['STORE_NAME']
def disassemble(code):
code = map(ord, code)
i = 0
n = len(code)
while i < n:
op = code[i]
i += 1
if op >= HAVE_ARGUMENT:
oparg = code[i] | code[i + 1] << 8
i += 2
else:
oparg = None
yield op, oparg
def implicit_self(function):
code = function.func_code
bytecode, varnames, names = inject_self(code)
function.func_code = CodeType(code.co_argcount + 1, code.co_nlocals + 1,
code.co_stacksize, code.co_flags, bytecode, code.co_consts, names,
varnames, code.co_filename, code.co_name, code.co_firstlineno,
code.co_lnotab, code.co_freevars, code.co_cellvars)
def inject_self(code):
varnames = ('self',) + tuple(n for i, n in enumerate(code.co_varnames))
names = tuple(n for i, n in enumerate(code.co_names))
bytecode = []
for op, arg in disassemble(code.co_code):
if op in (LOAD_FAST, STORE_FAST):
arg = varnames.index(code.co_varnames[arg])
elif op in (LOAD_GLOBAL, STORE_GLOBAL, LOAD_NAME, STORE_NAME):
if code.co_names[arg] == 'self':
op = LOAD_FAST if op in (LOAD_GLOBAL, LOAD_NAME) \
else STORE_FAST
arg = 0
else:
arg = names.index(code.co_names[arg])
elif op in (LOAD_ATTR, STORE_ATTR):
arg = names.index(code.co_names[arg])
bytecode.append(chr(op))
if op >= opcode.HAVE_ARGUMENT:
bytecode.append(chr(arg & 0xff))
bytecode.append(chr(arg >> 8))
return ''.join(bytecode), varnames, names
class ImplicitSelfType(type):
def __new__(cls, name, bases, d):
for key, value in d.iteritems():
if isinstance(value, FunctionType):
implicit_self(value)
return type.__new__(cls, name, bases, d)
class ImplicitSelf(object):
__metaclass__ = ImplicitSelfType
if __name__ == '__main__':
import hashlib
class User(ImplicitSelf):
def __init__(username, password):
self.username = username
self.set_password(password)
def set_password(password):
self.hash = hashlib.sha1(password).hexdigest()
def check_password(password):
return hashlib.sha1(password).hexdigest() == self.hash
u = User('mitsuhiko', 'default')
print u.__dict__