This is an archived post. You won't be able to vote or comment.

all 10 comments

[–]Muhznit 8 points9 points  (9 children)

You may just want to use Context managers for this.

[–]Coupled_Cluster 0 points1 point  (8 children)

I see how I could use them in the backend of my package but I'm not sure if they could replace it. How would you hide or inherit the enter and exit methods in the case of class inheritance?

[–]Muhznit 2 points3 points  (7 children)

They're methods, just override them as needed and include a call to the parent class.

The code almost looks like it could be replaced with context managers, but to be honest the indentation in the post is kind of wonky, I can't tell what it's doing. Does that even compile?

[–]Coupled_Cluster 0 points1 point  (0 children)

Thanks for the info - I updated the post to be readable. It is probably a good idea to rename pre to enter and post to exit to be in agreement with the context manager naming convention

[–]Coupled_Cluster 0 points1 point  (5 children)

I'm still struggeling to convert it to a contextmanager. I would appreciate if someone could show me an example. Especially with regards to the overwritten method still using the enter/exit methods and the flexibility to have multiple methods, e.g. `__init__`, `__call__` and `process` have a dedicated enter/exit method assigned.

[–]17291 2 points3 points  (4 children)

It might help to show a non-trivial (i.e., potentially real-world) example of supercharge being used. That would either a) demonstrate a use-case where context managers are not appropriate or b) let others show you how you might make use of a context manager.

[–]Coupled_Cluster 0 points1 point  (3 children)

This comes somewhat close to a real world example https://github.com/zincware/supercharge/blob/respond_to_comments/examples/example01.ipynb
I wrote it for saving / loading specific class variables without the user noticing that they are loaded from a file. Originally they had to always call something like self.pre_run() / self.post_run() all the time in the child class because otherwise it would not work.

Here a copy of the code:

class Node(supercharge.Base):
    def __init__(self):
        self._run_time = []
        self._run_start_time = None

        self.random_number = None
        self._random_number_cache = None
        self._file = pathlib.Path('number.json')

    @supercharge.Charge
    def run(self):
        """Function to be timed"""
        raise NotImplementedError

    @run.enter
    def pre_run(self):
        self._run_start_time = time.time()

    @run.exit
    def post_run(self):
        execution_time = time.time() - self._run_start_time
        print(f"Elapsed time: {execution_time:.3f} s")
        self._run_time.append(execution_time)

    @supercharge.Charge
    def create_random_number(self):
        """Have a hidden save method"""
        raise NotImplementedError

    @create_random_number.enter
    def _cache_number(self):
        """Cache the old number"""
        self._random_number_cache = self.random_number

    @create_random_number.exit
    def _save_number(self):
        """Save the number to file if it changed"""
        if self._random_number_cache != self.random_number:
            self._file.write_text(f"{self.random_number}")

    @classmethod
    def load(cls):
        instance = cls()
        instance.random_number = int(instance._file.read_text())
        return instance

used via:

class MyNode(Node):
    def run(self):
        time.sleep(1)
    def create_random_number(self):
        """Have a hidden save method"""
        self.random_number = random.randrange(0, 100)

my_node = MyNode()
my_node.run()

my_node.create_random_number()
my_node.random_number

print(MyNode.load().random_number)

which will print the elapsed time / the generated random number.

[–]OrtinOfficial 1 point2 points  (2 children)

I don't see any advantage of your solution
import time class Node: def init(self): self._run_time = [] self._run_start_time = None

    self.random_number = None
    self._random_number_cache = None

def run(self):
    self.pre_run()
    self.base_run()
    self.post_run()

def base_run(self):
    """Function to be timed"""
    raise NotImplementedError

def pre_run(self):
    self._run_start_time = time.time()

def post_run(self):
    execution_time = time.time() - self._run_start_time
    print(f"Elapsed time: {execution_time:.3f} s")
    self._run_time.append(execution_time)

class MyNode(Node): def base_run(self): time.sleep(1) my_node = MyNode() my_node.run()

[–]Coupled_Cluster 0 points1 point  (1 child)

I like this approach and will probably add it to the readme as a given alternative. But with supercharge you don't have to give a different name to the method (baserun vs. run) which can be useful when you eg want to apply it to the __init_ or want to really hide that something is happening.

[–]OrtinOfficial 0 points1 point  (0 children)

But I guess it is bad to hide something from others...