question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Passing a bound function fails with 0.7.0+

See original GitHub issue

We have started having a problem with 0.7.0+ due to changes in [1] where the input function is no longer wrapped.

The shortest replication of what’s going on I can make is the following

from dogpile.cache import make_region

region = make_region().configure('dogpile.cache.memory', expiration_time = 3600)

def _cache_on_arguments(*cache_on_args, **cache_on_kwargs):
    def _inner_cache_on_arguments(func):
        def _cache_decorator(obj, *args, **kwargs):
            dogpile_decorator = region.cache_on_arguments(
                *cache_on_args, **cache_on_kwargs)
            self_method = func.__get__(obj, type(obj))
            wrapped_func = dogpile_decorator(self_method)
            return wrapped_func(*args, **kwargs)
        return _cache_decorator
    return _inner_cache_on_arguments

class MainClass(object):
    @_cache_on_arguments()
    def function(self):
        print("A function")

cls = MainClass()
cls.function()

When you run this under 0.7.0 onwards you get

$ ./env/bin/python3 ./test-dp.py 
Traceback (most recent call last):
  File "./test-dp.py", line 30, in <module>
    cls.function()
  File "./test-dp.py", line 15, in _cache_decorator
    wrapped_func = dogpile_decorator(self_method)
  File "/home/iwienand/tmp/dogpile/env/lib64/python3.7/site-packages/dogpile/cache/region.py", line 1304, in cache_decorator
    user_func.set = set_
AttributeError: 'method' object has no attribute 'set'

When you run it on 0.6.8 you see “A function” printed.

The old cache_on_arguments would take the input callable, and then wrap it in it’s decorate function which then actually called out to get_or_create(key, creator, ...). It would then set the various helpers set, invalidate, refresh, get, original on the internal decorate function.

This changed with [1] where set,invalidate,get,refresh etc are being directly set on user_func. This is a problem when user_func is actually a bound method (what we found from func.__get__(obj, type(obj))) and not a function … we can’t set arbitrary things on it.

I’m a bit stumped on all this at the moment. Our use is certainly “interesting” (and yes, I’m reminded of [2] 😃. We are tracking this in [3]. The point of [1] appears to be to get rid of the wrapping to avoid signature changes, so I’m not sure about adding it back in, but I’m also not sure how to fix what we have 😕

Thoughts on this are very welcome

[1] https://gerrit.sqlalchemy.org/#/c/sqlalchemy/dogpile.cache/+/996/4/dogpile/cache/region.py [2] https://xkcd.com/1172/ [3] https://storyboard.openstack.org/#!/story/2004605

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
ankitpatel96commented, Dec 15, 2018

I kind of agree with @morganfainberg here - openstack’s use case is pretty strange and the workaround linked doesn’t look too arduous.
On top of that, decorator, doesn’t support bound methods even if I reorder the set/refresh/etc.

1reaction
morganfainbergcommented, Dec 14, 2018

I think dogpile is 100% sane here. Realistically dogpile shouldn’t need to assume that the passed in object isn’t a bound instanct. What OpenStackSDK is doing is very strange. You can see a quick fix within SDK here: https://review.openstack.org/#/c/625370/

I don’t feel strongly one way or another on revert/use decorate/etc. We could also conditionally add a subsequent simple wrap if needed if the object is a bound method.

While this is a change in behavior, I don’t think it’s an unreasonable change in behavior from pre 0.7.0. It’s weird to pass bound methods into a decorator in most cases.

Read more comments on GitHub >

github_iconTop Results From Across the Web

functions inside functions (closures) #229 - ziglang/zig - GitHub
we've already got some implicit parameter passing for "self" parameters. if we're going to support closures (which means bound variables), then that's more ......
Read more >
Error: a pointer to a bound function may only be used to call ...
It seems to work fine if HandleCurrentScreen points to a function that is also defined in the Game class. I've been looking for...
Read more >
Function.prototype.bind() - JavaScript - MDN Web Docs - Mozilla
The bound function will store the parameters passed — which include the value of this and the first few arguments — as its...
Read more >
assertr: Assertive Programming for R Analysis Pipelines
Meant for use in a data analysis pipeline, this function will just return the data it's supplied if there are no FALSEs when...
Read more >
Solidity Documentation - Read the Docs
Solidity is an object-oriented, high-level language for implementing smart contracts. Smart contracts are programs which govern the behaviour of accounts ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found