Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to get class name from an annotation for static method?

Here is my code:

import os
import pickle
import hashlib

def read_file(path):
    # Implement your read_file logic here
    pass

def write_file(path, content):
    # Implement your write_file logic here
    pass

class CachedStaticMethod:
    path = "cache"
    
    def __init__(self, func):
        self.func = func

    def __get__(self, instance, owner):
        if instance is None:
            return self  # Return the decorator instance for staticmethod to use
        return self.func.__get__(instance, owner)  # For regular methods

    def __call__(self, *args, **kwargs):
        cache_path = self.__get_path(*args, **kwargs)

        try:
            content = read_file(cache_path)
            result = pickle.loads(content)
        except Exception as e:
            result = self.func(*args, **kwargs)
            content = pickle.dumps(result)
            write_file(cache_path, content)
        return result    

    def __get_path(self, *args, **kwargs):
        class_name = self.func.__qualname__.split('.<locals>', 1)[0]
        function_name = self.func.__name__
        
        hash_input = f"{class_name}.{function_name}({args}, {kwargs})".encode("utf-8")
        hash_value = hashlib.md5(hash_input).hexdigest()
        filename = f"{hash_value}.cache"
        return os.path.join(self.path, filename)

class MyClass:
    @CachedStaticMethod
    @staticmethod
    def my_static_method(param1: int, param2: str) -> float:
        """
        This is a cached static method of MyClass.
        """
        result = 3.14 * param1 + len(param2)
        return result

# Usage
result1 = MyClass.my_static_method(5, "hello")
result2 = MyClass.my_static_method(5, "hello")  # Should use cached result

print(result1)
print(result2)

This is the Error it’s throwing:

AttributeError Traceback (most recent call
last) in
54
55 # Usage
—> 56 result1 = MyClass.my_static_method(5, "hello")
57 result2 = MyClass.my_static_method(5, "hello") # Should use cached result
58

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

in call(self, *args, **kwargs)
23
24 def call(self, *args, **kwargs):
—> 25 cache_path = self.__get_path(*args, **kwargs)
26
27 try:

in __get_path(self, *args, **kwargs)
35
36 def __get_path(self, *args, **kwargs):
—> 37 class_name = self.func.qualname.split(‘.’, 1)[0]
38 function_name = self.func.name
39

AttributeError: ‘staticmethod’ object has no attribute ‘qualname

>Solution :

This is a Python version issue. staticmethods don’t have a __qualname__ until Python 3.10.

You could access the underlying function with __func__, but you’re already implementing the descriptor protocol yourself, so it’d be easier to just not use staticmethod at all. Handling staticmethod‘s functionality is straightforward and makes using your decorator simpler:

class CachedStaticMethod:
    def __init__(self, func):
        self.func = func
    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return self.func
    ...

class MyClass:
    # No @staticmethod
    @CachedStaticMethod
    def my_static_method(...):
        ...

Also, the way you’ve designed your __get__, you’re only caching calls like MyClass.my_static_method(...). Calls on an instance, MyClass().my_static_method(...), bypass the cache, even though they still don’t receive self. You might want to just remove your __get__ entirely, so all calls use the cache.

If you really want to keep self.func as a staticmethod, then you could do self.func.__func__.__qualname__ to get the qualname.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading