Forget

forget() is a context manager designed for more advanced use cases. It enables you to selectively forget global configs or hooks from an initiate()d coma.

Forgetting Global Hooks

coma’s behavior can be easily tweaked, replaced, or extended using hooks. These are covered in great detail in their own tutorial. Here, the emphasis is on the difference between global and local hooks. Hooks can be initiate()d globally to affect coma’s behavior towards all commands or register()ed locally to only affect coma’s behavior towards a specific command.

Warning

Local hooks are appended to the list of global hooks. Local hooks do not override global hooks. When a local hook is being register()ed, the corresponding global hook can only be replaced using forget().

For example, suppose we have a class-based command with a handle() method instead of the run() method that coma expects by default:

class HandleCommand:
    def handle(self):
        print("Hello Handle!")

In order to use this command, we need to tell coma to:

  • Stop looking for run(). We will forget() the existing global hook that does this.

  • Start looking for handle() instead. We will register() a new local hook to do this.

main.py
import coma

class HandleCommand:
    def handle(self):
        print("Hello Handle!")

class RunCommand:
    def run(self):
        print("Hello Run!")

if __name__ == "__main__":
    with coma.forget(run_hook=True):
        coma.register("handle", HandleCommand,
                      run_hook=coma.hooks.run_hook.factory("handle"))
    coma.register("run", RunCommand)
    coma.wake()

In this example, we locally register()ed a run_hook that tells coma to call handle() and we used the forget() context manager to get coma to temporarily forget its default run_hook, which attempts to call run() instead.

Note

coma provides factory functions for some of the more common hooks. In this example, we used coma.hooks.run_hook.factory(), which simply creates a function that in turn calls the provided attribute (in this case, "handle") of the command object.

Because forget() is a context manager, any commands registered outside its context are unaffected. In this example, RunCommand still functions normally.

$ python main.py handle
Hello Handle!
$ python main.py run
Hello Run!

Forgetting Global Configs

As with hooks, configs can be initiate()d globally to all commands or register()ed locally to a specific command.

Let’s revisit the second of the Multiple Configurations examples from the introductory tutorial to see how we can implement it differently with forget():

main.py
from dataclasses import dataclass

import coma

@dataclass
class Greeting:
    message: str = "Hello"

@dataclass
class Receiver:
    entity: str = "World!"

if __name__ == "__main__":
    coma.register("greet", lambda g, r: print(g.message, r.entity), Greeting, Receiver)
    coma.register("leave", lambda r: print("Goodbye", r.entity), Receiver)
    coma.wake()

Notice how, in the original example, the Receiver config is register()ed (locally) to both commands. Instead, we can initiate() a coma with both configs so that they are (globally) supplied to all commands, then forget() the Greeting config just for the leave command:

main.py
from dataclasses import dataclass

import coma

@dataclass
class Greeting:
    message: str = "Hello"

@dataclass
class Receiver:
    entity: str = "World!"

if __name__ == "__main__":
    coma.initiate(Greeting, Receiver)
    coma.register("greet", lambda g, r: print(g.message, r.entity))
    with coma.forget("greeting"):
        coma.register("leave", lambda r: print("Goodbye", r.entity))
    coma.wake()

Notice that forget() takes the config identifier (in this case, we used the default identifier, which is "greeting"), not the config itself.

Note

Configs need to be uniquely identified per-command, but not across commands.