python3 self variable from class to decorator - python

I'm trying to build my first decorator and implement it in a class.
# decorator class
class Cache(object):
def __init__(self,filename,**kwargs):
self.time_ago = datetime.now() - timedelta(**kwargs)
self.filename = filename
def __call__(self,fn):
if not os.path.isfile(self.filename):
return self.cache(fn(self))
time_ago = self.time_ago
filename = self.filename
c_age = datetime.fromtimestamp(os.path.getctime(filename))
m_age = datetime.fromtimestamp(os.path.getmtime(filename))
print (c_age)
print (m_age)
print (time_ago)
if c_age < time_ago or m_age < time_ago:
return self.cache(fn(self))
else:
return self.read()
def cache(self,data):
with open(self.filename,'r+') as ef:
ef.write(data)
return ef.read()
def read(self):
f = open(self.filename,'r')
data = f.read()
f.close()
return data
I'm trying to call the decorator in the below class:
class Zabb(object):
#Cache('nodes.json',minutes=1)
def getNodes(self):
return "Get Nodes"
I call it like this:
z = Zabb()
nodes = z.getNodes()
I get the following error:
Traceback (most recent call last):
File "./deco.py", line 52, in <module>
nodes = z.getNodes()
TypeError: 'str' object is not callable
I'm close to making this work. What am I doing wrong?

You need to return a higher-order-function (wrapped) from the __call__ method. Add an inner method and return it.
def __call__(self, fn):
def wrapper(*args, **kwargs): # <-- Add this wrapper
if not os.path.isfile(self.filename):
return self.cache(fn(*args, **kwargs))
time_ago = self.time_ago
filename = self.filename
c_age = datetime.fromtimestamp(os.path.getctime(filename))
m_age = datetime.fromtimestamp(os.path.getmtime(filename))
print (c_age)
print (m_age)
print (time_ago)
if c_age < time_ago or m_age < time_ago:
return self.cache(fn(*args, **kwargs))
else:
return self.read()
return wrapper # <-- Return the wrapper

Decorators are easier to understand if you forget the #deco syntactic sugar and reason on what it really do. In your example,
#Cache('nodes.json',minutes=1)
def getNodes(self):
return "Get Nodes"
really means :
def getNodes(self):
return "Get Nodes"
getNodes = Cache('nodes.json',minutes=1)(getNodes)
which actually rebinds Zabb.getNodes to the result of Cache('nodes.json',minutes=1).__call__(getNodes) - which is a string, not a function.
What you want is to make Cache.__call__ return a function that will wrap the call the decorated function, ie:
def __call__(self,fn):
def wrapper(*args, **kw):
if not os.path.isfile(self.filename):
return self.cache(fn(self))
time_ago = self.time_ago
filename = self.filename
c_age = datetime.fromtimestamp(os.path.getctime(filename))
m_age = datetime.fromtimestamp(os.path.getmtime(filename))
print (c_age)
print (m_age)
print (time_ago)
if c_age < time_ago or m_age < time_ago:
return self.cache(fn(self))
else:
return self.read()
return wrapper

Related

Decorating all functions in a file if variable is set to true in python

I have the code
chop_flag = True
def decorator(func):
def chop_num(num):
num = str(num)
num = num[:15]
return float(num)
return chop_num
def decorator2():
return decorator if chop_flag else break
And then before each function in my program I add #decorator2. This is producing a type error ("decorator2() takes 0 positional arguments but 1 was given") and I'm also pretty sure this is not a great way to do what I'm trying to do.
To summarize: I'm trying to take the output of each function in my program and run it through the chop_num() function if chop_flag = True; if chop_flag = False, I want it to just ignore the decorator. I thought I'd do this by applying a decorator to each function. Any help would be appreciated.
Updated code:
chop_flag = True
def decorator(func):
if chop_flag == True:
def chop_num(num, *args, **kwargs):
num = func(*args, **kwargs)
num = str(num)
num = num[:15]
return float(num)
return chop_num
else:
return
It now runs properly, but when I import my file into the interpreter (for example) and call the add function, it says "add() missing 1 required positional argument" even though I have put in two arguments.
I think your final decorator should look more like this
def chop_num(num):
num = str(num)
num = num[:15]
return float(num)
chop_flag = True
def decorator(func):
def wrapper(*args, **kwargs):
val = func(*args, **kwargs)
if chop_flag:
return chop_num(val)
else:
return val
return wrapper
#decorator
def nineteen_digits():
return 1_000_000_000_000_000_000
print(nineteen_digits())
# 100000000000000.0
chop_flag = False
print(nineteen_digits())
# 1000000000000000000

P2Pool: Twisted Abort Connection Error

I keep running into this error that I never had before every time I try running python run_p2pool.py, I even tried doing -n and typing in the argument and that doesn't fix it (as the internet suggested). I also have the configurations already there and even tried reinstalling python twisted with no avail. There is no error in the code I am trying to run and I am yet to figure out how to get this fixed.
# Twisted doesn't have abortConnection! Upgrade to a newer version of Twisted to avoid memory leaks!
> Pausing for 3 seconds...
> 2017-11-02 01:07:47.958817 > Traceback (most recent call last):
> 2017-11-02 01:07:47.958986 > File "run_p2pool.py", line 5, in <module>
> 2017-11-02 01:07:47.959116 > main.run()
> 2017-11-02 01:07:47.959191 > File "/var/www/html/DashPool/DPI-MASTER/Dash-Pool-Integration/p2pool/main.py", line 687, in run
> 2017-11-02 01:07:47.959422 > deferral.RobustLoopingCall(logfile.reopen).start(5)
> 2017-11-02 01:07:47.959490 > File "/var/www/html/DashPool/DPI-MASTER/Dash-Pool-Integration/p2pool/util/deferral.py", line 277, in start
> 2017-11-02 01:07:47.959605 > self._df = self._worker(period).addErrback(lambda fail: fail.trap(defer.CancelledError))
> 2017-11-02 01:07:47.959686 > File "/var/www/html/DashPool/DPI-MASTER/Dash-Pool-Integration/p2pool/util/deferral.py", line 225, in _
> 2017-11-02 01:07:47.960104 > df = defer.Deferred(cancelled)
> 2017-11-02 01:07:47.960195 > TypeError: __init__() takes exactly 1 argument (2 given)
I never had this problem before and was able to run the same program before, but just encase, here is the defferal.py file
from __future__ import division
import itertools
import random
import sys
from twisted.internet import defer, reactor
from twisted.python import failure, log
def sleep(t):
d = defer.Deferred(canceller=lambda d_: dc.cancel())
dc = reactor.callLater(t, d.callback, None)
return d
def run_repeatedly(f, *args, **kwargs):
current_dc = [None]
def step():
delay = f(*args, **kwargs)
current_dc[0] = reactor.callLater(delay, step)
step()
def stop():
current_dc[0].cancel()
return stop
class RetrySilentlyException(Exception):
pass
def retry(message='Error:', delay=3, max_retries=None, traceback=True):
'''
#retry('Error getting block:', 1)
#defer.inlineCallbacks
def get_block(hash):
...
'''
def retry2(func):
#defer.inlineCallbacks
def f(*args, **kwargs):
for i in itertools.count():
try:
result = yield func(*args, **kwargs)
except Exception as e:
if i == max_retries:
raise
if not isinstance(e, RetrySilentlyException):
if traceback:
log.err(None, message)
else:
print >>sys.stderr, message, e
yield sleep(delay)
else:
defer.returnValue(result)
return f
return retry2
class ReplyMatcher(object):
'''
Converts request/got response interface to deferred interface
'''
def __init__(self, func, timeout=5):
self.func = func
self.timeout = timeout
self.map = {}
def __call__(self, id):
if id not in self.map:
self.func(id)
df = defer.Deferred()
def timeout():
self.map[id].remove((df, timer))
if not self.map[id]:
del self.map[id]
df.errback(failure.Failure(defer.TimeoutError('in ReplyMatcher')))
timer = reactor.callLater(self.timeout, timeout)
self.map.setdefault(id, set()).add((df, timer))
return df
def got_response(self, id, resp):
if id not in self.map:
return
for df, timer in self.map.pop(id):
df.callback(resp)
timer.cancel()
class GenericDeferrer(object):
'''
Converts query with identifier/got response interface to deferred interface
'''
def __init__(self, max_id, func, timeout=5, on_timeout=lambda: None):
self.max_id = max_id
self.func = func
self.timeout = timeout
self.on_timeout = on_timeout
self.map = {}
def __call__(self, *args, **kwargs):
while True:
id = random.randrange(self.max_id)
if id not in self.map:
break
def cancel(df):
df, timer = self.map.pop(id)
timer.cancel()
try:
df = defer.Deferred(cancel)
except TypeError:
df = defer.Deferred() # handle older versions of Twisted
def timeout():
self.map.pop(id)
df.errback(failure.Failure(defer.TimeoutError('in GenericDeferrer')))
self.on_timeout()
timer = reactor.callLater(self.timeout, timeout)
self.map[id] = df, timer
self.func(id, *args, **kwargs)
return df
def got_response(self, id, resp):
if id not in self.map:
return
df, timer = self.map.pop(id)
timer.cancel()
df.callback(resp)
def respond_all(self, resp):
while self.map:
id, (df, timer) = self.map.popitem()
timer.cancel()
df.errback(resp)
class NotNowError(Exception):
pass
class DeferredCacher(object):
'''
like memoize, but for functions that return Deferreds
#DeferredCacher
def f(x):
...
return df
#DeferredCacher.with_backing(bsddb.hashopen(...))
def f(x):
...
return df
'''
#classmethod
def with_backing(cls, backing):
return lambda func: cls(func, backing)
def __init__(self, func, backing=None):
if backing is None:
backing = {}
self.func = func
self.backing = backing
self.waiting = {}
#defer.inlineCallbacks
def __call__(self, key):
if key in self.waiting:
yield self.waiting[key]
if key in self.backing:
defer.returnValue(self.backing[key])
else:
self.waiting[key] = defer.Deferred()
try:
value = yield self.func(key)
finally:
self.waiting.pop(key).callback(None)
self.backing[key] = value
defer.returnValue(value)
_nothing = object()
def call_now(self, key, default=_nothing):
if key in self.backing:
return self.backing[key]
if key not in self.waiting:
self.waiting[key] = defer.Deferred()
def cb(value):
self.backing[key] = value
self.waiting.pop(key).callback(None)
def eb(fail):
self.waiting.pop(key).callback(None)
if fail.check(RetrySilentlyException):
return
print
print 'Error when requesting noncached value:'
fail.printTraceback()
print
self.func(key).addCallback(cb).addErrback(eb)
if default is not self._nothing:
return default
raise NotNowError(key)
def deferred_has_been_called(df):
still_running = True
res2 = []
def cb(res):
if still_running:
res2[:] = [res]
else:
return res
df.addBoth(cb)
still_running = False
if res2:
return True, res2[0]
return False, None
def inlineCallbacks(f):
from functools import wraps
#wraps(f)
def _(*args, **kwargs):
gen = f(*args, **kwargs)
stop_running = [False]
def cancelled(df_):
assert df_ is df
stop_running[0] = True
if currently_waiting_on:
currently_waiting_on[0].cancel()
df = defer.Deferred(cancelled)
currently_waiting_on = []
def it(cur):
while True:
try:
if isinstance(cur, failure.Failure):
res = cur.throwExceptionIntoGenerator(gen) # external code is run here
else:
res = gen.send(cur) # external code is run here
if stop_running[0]:
return
except StopIteration:
df.callback(None)
except defer._DefGen_Return as e:
# XXX should make sure direct child threw
df.callback(e.value)
except:
df.errback()
else:
if isinstance(res, defer.Deferred):
called, res2 = deferred_has_been_called(res)
if called:
cur = res2
continue
else:
currently_waiting_on[:] = [res]
def gotResult(res2):
assert currently_waiting_on[0] is res
currently_waiting_on[:] = []
if stop_running[0]:
return
it(res2)
res.addBoth(gotResult) # external code is run between this and gotResult
else:
cur = res
continue
break
it(None)
return df
return _
class RobustLoopingCall(object):
def __init__(self, func, *args, **kwargs):
self.func, self.args, self.kwargs = func, args, kwargs
self.running = False
def start(self, period):
assert not self.running
self.running = True
self._df = self._worker(period).addErrback(lambda fail: fail.trap(defer.CancelledError))
#inlineCallbacks
def _worker(self, period):
assert self.running
while self.running:
try:
self.func(*self.args, **self.kwargs)
except:
log.err()
yield sleep(period)
def stop(self):
assert self.running
self.running = False
self._df.cancel()
return self._df

TypeError: 'NoneType' object is not callable (Python)

I have a code error that I need to debug but I'm not sure where I went wrong. When I run my code I got:
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
c3_plus_0i = create_complex(create_ordinary(3), create_ordinary(0))
File "<pyshell#30>", line 2, in create_complex
return get("make","complex")(x,y)
TypeError: 'NoneType' object is not callable
This is the code that I have:
from generic_arith_min import *
def install_complex_package():
def make_com(x,y):
return tag(repcom(x,y))
def repcom(x,y):
return (x,y)
def real(x):
return x[0]
def imag(x):
return x[1]
def tag(x):
return attach_tag("complex",x)
# add,sub,mul,div: (RepCom, RepCom) -> Generic-Com
def add_com(x,y):
return make_com( add(real(x), real(y)),
add(imag(x), imag(y)) )
def sub_com(x,y):
return make_com( sub(real(x), real(y)),
sub(imag(x), imag(y)) )
def mul_com(x,y):
return make_com(sub(mul(real(x), real(y)),
mul(imag(x), imag(y))),
add(mul(real(x), imag(y)),
mul(real(y), imag(x))))
def div_com(x,y):
com_conj = complex_conjugate(y)
x_times_com_conj = content(mul_com(x, com_conj))
y_times_com_conj = content(mul_com(y, com_conj))
return make_com(div(real(x_times_com_conj), real(y_times_com_conj)),
div(imag(x_times_com_conj), real(y_times_com_conj)));
def complex_conjugate(x):
return (real(x),negate(imag(x)))
def negate_com(x): # (RepCom) -> Generic-Com
return make_com(negate(real(x)), negate(imag(x)))
def is_zero_com(x): # (RepCom) -> Py-Bool
if is_zero(real(x)) and is_zero(imag(x)):
return True
else:
return False
def is_eq_com(x,y): # (RepCom, RepCom) -> Py-Bool
if is_equal(real(x),real(y)) and is_equal(imag(x),imag(y)):
return True
else:
return False
put("make","complex", make_com)
put("add",("complex","complex"), add_com)
put("sub",("complex","complex"), sub_com)
put("mul",("complex","complex"), mul_com)
put("div",("complex","complex"), div_com)
put("negate",("complex",), negate_com)
put("is_zero",("complex",), is_zero_com)
put("is_equal",("complex","complex"), is_eq_com)
def repord_to_repcom(x):
return repcom(create_ordinary(x),create_ordinary(0))
def CCmethod_to_OCmethod(method):
return lambda ord, com: method(repord_to_repcom(ord), com)
def CCmethod_to_COmethod(method):
return lambda com, ord: method(com, repord_to_repcom(ord))
put("add",("ordinary","complex"), CCmethod_to_OCmethod(add_com))
put("add",("complex","ordinary"), CCmethod_to_COmethod(add_com))
put("sub",("ordinary","complex"), CCmethod_to_OCmethod(sub_com))
put("sub",("complex","ordinary"), CCmethod_to_COmethod(sub_com))
put("mul",("ordinary","complex"), CCmethod_to_OCmethod(mul_com))
put("mul",("complex","ordinary"), CCmethod_to_COmethod(mul_com))
put("div",("ordinary","complex"), CCmethod_to_OCmethod(div_com))
put("div",("complex","ordinary"), CCmethod_to_COmethod(div_com))
put("is_equal",("ordinary","complex"), CCmethod_to_OCmethod(is_eq_com))
put("is_equal",("complex","ordinary"), CCmethod_to_COmethod(is_eq_com))
def create_complex(x,y):
return get("make","complex")(x,y)
#################
# Do not change #
#################
n3 = create_ordinary(3)
c3_plus_0i = create_complex(create_ordinary(3), create_ordinary(0))
c2_plus_7i = create_complex(create_ordinary(2), create_ordinary(7))
def gradeThis_complex_package():
complexA = is_equal(n3, c3_plus_0i)
complexB = is_equal(sub(add(n3, c2_plus_7i), c2_plus_7i), n3)
if complexA and complexB:
print("Well done! Your install_complex_package is complete!")
else:
print("Please check your solution for install_complex_package.")
gradeThis_complex_package()
Below is the supported file that it is imported from:
_operation_table = {} #variables with prefixed with an _ are by convention, for internal use and should not be touched.
def attach_tag(tag, content):
return (tag, content)
def type_tag(datum):
if type(datum) == tuple and len(datum) == 2:
return datum[0]
raise Exception('Bad tagged datum -- type_tag ', datum)
def content(datum):
if type(datum) == tuple and len(datum) == 2:
return datum[1]
raise Exception('Bad tagged datum -- content ', datum)
def put(op, types, value):
if op not in _operation_table:
_operation_table[op] = {}
_operation_table[op][types] = value
def get(op, types):
if op in _operation_table and types in _operation_table[op]:
return _operation_table[op][types]
else:
return None
def apply_generic(op, *args):
type_tags = tuple(map(type_tag, args))
proc = get(op, type_tags)
if proc:
return proc(*map(content, args))
raise Exception('No method for these types -- apply_generic', (op, type_tags))
##########################
# Generic Number Package #
##########################
#generic operators we want to support
def add(x,y):
return apply_generic("add", x, y)
def sub(x,y):
return apply_generic("sub", x, y)
def mul(x,y):
return apply_generic("mul", x, y)
def div(x,y):
return apply_generic("div", x, y)
def negate(x):
return apply_generic("negate", x)
def is_zero(x):
return apply_generic("is_zero", x)
def is_equal(x, y):
return apply_generic("is_equal", x, y)
#composite generic operators
def square(x):
return mul(x,x)
#Generic ordinary number package
def install_ordinary_package():
def make_ord(x):
return tag(x)
def tag(x):
return attach_tag("ordinary", x)
# add,sub,mul,div: (RepOrd, RepOrd) -> Generic-OrdNum
def add_ord(x,y):
return make_ord(x+y)
def sub_ord(x,y):
return make_ord(x-y)
def mul_ord(x,y):
return make_ord(x*y)
def div_ord(x,y):
return make_ord(x/y)
def negate_ord(x): # (RepOrd) -> Generic-Ord
return make_ord(-x)
def is_zero_ord(x): # (RepOrd) -> Py-Bool
return x == 0
def is_equal_ord(x,y): # (RepOrd, RepOrd) -> Py-Bool
return x == y
put("make","ordinary", make_ord)
put("negate",("ordinary",), negate_ord)
put("is_zero",("ordinary",), is_zero_ord)
put("add",("ordinary","ordinary"), add_ord)
put("sub",("ordinary","ordinary"), sub_ord)
put("mul",("ordinary","ordinary"), mul_ord)
put("div",("ordinary","ordinary"), div_ord)
put("is_equal",("ordinary","ordinary"), is_equal_ord)
install_ordinary_package()
def create_ordinary(x):
return get("make", "ordinary")(x)
Where exactly did the above code cause the rise to this error? If anyone could help I would really appreciate it. Thank you!
Your _operation_table dictionary does not contain an entry with make and complex therefore your get() function returns None which in fact is not callable.
print("complex" in _operation_table["make"])
False
Perhaps you've forgotten to call install_complex_package (in the same way you called install_ordinary_package) which adds the required function to _operation_table. Once called, your code works fine.

Provide a list of methods in a class for use outside of it

How can I provide a list of methods in a class for use outside of it?
What I'm looking for
When I create an object from a class extending a higher class, I want to get a list of specific methods, some "meta data" of them, and to able to call them outside the class.
Example:
def params(params):
def params_fn(f):
def params_dec(*args, **kwargs):
for i in params:
f.__setattr__(i, params[i])
return f(*args, **kwargs)
return params_dec
return params_fn
class Channel:
queue = None
# some code & docs omitted
def __init__(self, queue):
self.queue = queue
def start(self):
while True:
if not self.check():
break
class channelA(Channel):
extra_methods = ['get_users', 'get_groups']
def start(self):
# omitted
pass
def __internal_method(self, d):
# omitted
pass
#params({"name": "Get users", "desc": "Get a list of users", "icon": "user-plus"})
def get_users(self):
# omitted
return [i for i in self.queue if i.type = 1]
#params({"name": "Get groups", "desc": "Get a list of groups", "icon": "group-plus"})
def get_groups(self):
# omitted
return [i for i in self.queue if i.type = 2]
q = []
ch = channelA(q)
# some code goes here
# it may be something like
# fns = ch.get_extra_fns()
# or anything similar
for fnName in fns:
print("Callable name:", fnName)
print("Name:", fns[fnName].name)
print("Description:", fns[fnName].desc)
print("Icon ID:", fns[fnName].icon)
print("Result:")
print(ch.call(fns[fnName])())
Is it possible to achieve something like this?
You don't need a wrapper for your decorated methods, since you only set attributes of the method-object. To identify your methods, I would suggest to set a special attribute for these methods, iterate over all class methods and pick those, that have this special method set:
def special(**kw):
def mark(function):
function.is_special = True
function.keywords = kw
return function
return mark
class Channel:
def __init__(self, queue):
self.queue = queue
def start(self):
while True:
if not self.check():
break
class ChannelA(Channel):
def start(self):
# omitted
pass
#special(icon="users.png")
def get_users(self):
# omitted
return [i for i in self.queue if i.type == 1]
#special(hint="don't feed the trolls")
def get_groups(self):
# omitted
return [i for i in self.queue if i.type == 2]
ch = ChannelA(q)
for methodname in dir(type(ch)):
method = getattr(ch, methodname)
if getattr(method, 'is_special', False):
print("Callable name:", method.__name__)
print("Keywords:", method.keywords)
print("Result:", method())
def get_extra_fns(self):
fns = {}
for i in self.extra_methods:
fns['i'] = self.__getattribute__(i)
return fns
Python 3:
import types
import inspect
class A:
def a(self):
pass
class B(A):
def b(self, bool_param, int_param):
pass
b = B()
for member_name in dir(B):
member = getattr(B, member_name)
if isinstance(member, types.FunctionType):
member(b, True) # as illustrated by you... this is hardcoded
argspec = inspect.getargspec(member)
args_for_call = {}
for argname in argspec.args:
if argname == 'bool_param':
args_for_call['bool_param'] = True
if argname == 'int_param':
args_for_call['int_param'] = 3
member(b, **args_for_call) # This is less hardcoded

Call several functions and return the collective result

I want to call some functions to a single value and return the collective result.
class Foo:
def __init__(self, i):
self.i = i
def get(self):
return self.fn1(self.fn2(self.i)) #200
def fn1(self, i):
return i + i #10+10 = 20
def fn2(self, i):
return i * i #20*20 = 200
#...
foo = Foo(10)
print(foo.get())
Is there a more elegant way or pattern?
Here is my try to improve this a little bit.
def fn1(i):
return i + i #10+10 = 20
def fn2(i):
return i * i #20*20 = 200
def get(i):
funcs = [fn2, fn1]
for f in funcs:
i = f(i)
return i
print(get(10))
In general, nesting functions as you do above is the most straightforward and readable way to compose functions in Python.
If you're composing many functions, it might be worth writing a compose function.
def compose(*funcs):
if len(funcs) == 1:
return funcs[0]
else:
def composition(*args, **kwargs):
return funcs[0](compose(*funcs[1:])(*args, **kwargs))
return composition
Or, if you prefer an iterative over a recursive solution:
def compose_pair(f1, f2):
def composition(*args, **kwargs):
return f1(f2(*args, **kwargs))
return composition
def compose_iterative(*funcs):
iterfuncs = iter(funcs)
comp = next(iterfuncs)
for f in iterfuncs:
comp = compose_pair(comp, f)
return comp
Personally, two of my favorite python functions are map and reduce.
def get(i):
return reduce(lambda acc, f: f(acc), [i,fn2,fn1] )
def fn1(i):
return i + i #10+10 = 20
def fn2(i):
return i * i #20*20 = 200
print( get(10) ) # 200
You could use a decorator-style solution:
class Base()
def __init__(self, decorated):
self.decorates = decorated
def foo(self, arg):
if self.decorates:
arg = self.decorates.foo( arg )
return self._do_foo( arg )
def _do_foo(self, arg):
return arg
Your implementations will inherit from Base and implement _do_foo().
You set it up like this:
a = Subclass(None)
b = AnotherSublcass( a )
c = YetAnotherSubclass( b )
all of the Sublcasses inherit from Base. when you call c.foo( arg ), you'll get the result passed through all three _do_foo() methods.

Categories

Resources