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 can I get around files not being imported when using a listener pattern in python?

I want to create an event-based system where functions can be subscribed to handle certain events.

There are a few ways to do this, I’ve chosen decorators:

# decorators.py

EVENT_HANDLERS: dict[str, set[Callable]] = defaultdict(set)


def my_event_listener(event_type: str):
    """
    A decorator to subscribe to events with the given event_type.
    """

    def decorator(callback_fn):
        EVENT_HANDLERS[event_type].add(callback_fn)
        return callback_fn

    return decorator

# events.py

def create_event(event: dict):
    for handler_fn in EVENT_HANDLERS[event[event_type]]:
        handler_fn(event)

# handlers.py

@my_event_listener(event_type="test")
def handle_test_event(event):
    logger.info(f"Test event received with payload {event['payload']}")

This works great! However I run into problems when handlers.py is not imported elsewhere in the codebase. Python only loads files when they’re imported somewhere else, and since in this case handlers.py has no reason to be imported anywhere it is never loaded, so the decorator never runs, and the callback is never registered.

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

I don’t think this is an issue with the decorator-based approach, as if I were to use a class or whatever I’d have the same problem with imports.

Other than keeping some registry of handlers somewhere, is there a way around this?

>Solution :

is there a way around this?

No.

If you’re using code to register a thing, the code naturally needs to be run.

You could, for instance,

  • keep a list of modules to import, and then importlib.import_module() them all, or
  • walk the filesystem to find all modules with e.g. a certain name (all handlers.pys?) to import, or
  • walk the filesystem to find some sort of other metadata to figure out what to import, or
  • if you’re planning on making your program pluggable, use e.g. entrypoints mechanism plugins to register themselves with.
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