`dir()` doesn't show the cache object attributes in Django

I can use these cache methods set(), get(), touch(), incr(), decr(), incr_version(), decr_version(), delete(), delete_many(), clear() and close() as shown below:

from django.core.cache import cache

cache.set("first_name", "John")
cache.set("last_name", "Smith")
cache.set_many({"age": 36, "gender": "Male"})

cache.get("first_name")
cache.get_or_set("last_name", "Doesn't exist")
cache.get_many(["age", "gender"])

cache.touch("first_name", 60)

cache.incr("age")
cache.decr("age")

cache.incr_version("first_name")
cache.decr_version("last_name")

cache.delete("first_name")
cache.delete_many(["last_name", "age"])

cache.clear()

cache.close()

But, dir() doesn't show these cache methods as shown below:

from django.core.cache import cache

print(dir(cache)) # Here
[
  '__class__', '__contains__', '__delattr__', '__dict__', '__dir__',
  '__doc__', '__eq__', '__format__', '__ge__', '__getattr__',
  '__getattribute__', '__gt__', '__hash__', '__init__', 
  '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__',
  '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
  '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
  '_alias', '_connections'
]

So, how can I show these cache methods?

Upvotes: 1

Views: 65

Answers (3)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477684

This is because the cache is a proxy to the default cache, indeed [GitHub]:

class ConnectionProxy:
    # …

    def __getattr__(self, item):
        return getattr(self._connections[self._alias], item)

    # …

It thus will for a method, which is an attribute, fallback on __getattr__, which will not then forward the item.

You can patch the __dir__ method through monkey patching:

from django.utils.connection import ConnectionProxy


def some_dir(self):
    return dir(self._connections[self._alias])


ConnectionProxy.__dir__ = some_dir

for example in the ready, this will then return the corresponding methods when using dir.

Update: I made a pull request [GitHub] to patch the behavior for the ConnectionProxy, although likely the same scenario will happen with all sorts of proxies and related design patterns throughout the code base.

Upvotes: 0

shaik moeed
shaik moeed

Reputation: 5785

You can show all those methods from BaseCache and even see all other available attributes.

from django.core.cache.backends.base import BaseCache

dir(BaseCache)

['__class__', '__contains__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', 
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'__weakref__', '_missing_key', 'aadd', 'aclear', 'aclose', 'add', 'adecr', 'adecr_version', 
'adelete', 'adelete_many', 'aget', 'aget_many', 'aget_or_set', 'ahas_key', 'aincr', 
'aincr_version', 'aset', 'aset_many', 'atouch', 'clear', 'close', 'decr', 'decr_version', 
'delete', 'delete_many', 'get', 'get_backend_timeout', 'get_many', 'get_or_set', 'has_key', 
'incr', 'incr_version', 'make_and_validate_key', 'make_key', 'set', 'set_many', 'touch', 
'validate_key']

From source code doc,

Caching framework.

This package defines set of cache backends that all conform to a simple API. In a nutshell, a cache is a set of values -- which can be any object that may be pickled -- identified by string keys. For the complete API, see the abstract BaseCache class in django.core.cache.backends.base.

Upvotes: 1

Anentropic
Anentropic

Reputation: 33923

You can always have a look at the source code...

In this case it's because the cache value that you import from here is actually a ConnectionProxy object.

cache = ConnectionProxy(caches, DEFAULT_CACHE_ALIAS)

https://github.com/django/django/blob/main/django/utils/connection.py#L7

...and that object does not have any of those methods, instead it uses __getattr__ to 'proxy' uses of those attributes through to some other object instance.

    def __getattr__(self, item):
        return getattr(self._connections[self._alias], item)

Unless you set up some more complicated cache config, you can probably inspect those methods by doing:

dir(cache._connections["default"])

Upvotes: 1

Related Questions