# Path: emit/messages.py
# class Message(object):
#     'Convenient wrapper around a dictionary to provide attribute access'
#     def __init__(self, *args, **kwargs):
#         self.bundle = dict(*args, **kwargs)
# 
#     def __getattr__(self, attr):
#         try:
#             return self.bundle[attr]
#         except KeyError:
#             raise AttributeError(
#                 '"%s" is not included in this message' % attr
#             )
# 
#     def __dir__(self):
#         'get directory of attributes. include bundle.'
#         return sorted(list(['bundle'] + list(self.bundle.keys())))
# 
#     def __repr__(self):
#         'representation of this message'
#         return 'Message(%s)' % (
#             ', '.join('%s=%s' % pair for pair in self.bundle.items())
#         )
# 
#     def __eq__(self, other):
#         'test equality of two messages'
#         return self.bundle == other.bundle
# 
#     def as_dict(self):
#         '''\
#         representation of this message as a dictionary
# 
#         :returns: dict
#         '''
#         return self.bundle
# 
#     def as_json(self):
#         '''
#         representation of this message as a json object
# 
#         :returns: str
#         '''
#         return json.dumps(self.as_dict())
# 
# class NoResult(object):
#     'single value to return from a node to stop further processing'
#     pass


from functools import wraps
from types import GeneratorType
from emit.messages import Message, NoResult
import importlib
import logging
import re
        @wraps(func)
        def wrapped(*args, **kwargs):
            'wrapped version of func'
            message = self.get_message_from_call(*args, **kwargs)
            self.logger.info('calling "%s" with %r', name, message)
            result = func(message)

            # functions can return multiple values ("emit" multiple times)
            # by yielding instead of returning. Handle this case by making
            # a list of the results and processing them all after the
            # generator successfully exits. If we were to process them as
            # they came out of the generator, we might get a partially
            # processed input sent down the graph. This may be possible in
            # the future via a flag.
            if isinstance(result, GeneratorType):
                results = [
                    self.wrap_result(name, item)
                    for item in result
                    if item is not NoResult
                ]
                self.logger.debug(
                    '%s returned generator yielding %d items', func, len(results)
                )

                [self.route(name, item) for item in results]
                return tuple(results)

            # the case of a direct return is simpler. wrap, route, and
            # return the value.
            else:

# Path: emit/messages.py
# class Message(object):
#     'Convenient wrapper around a dictionary to provide attribute access'
#     def __init__(self, *args, **kwargs):
#         self.bundle = dict(*args, **kwargs)
# 
#     def __getattr__(self, attr):
#         try:
#             return self.bundle[attr]
#         except KeyError:
#             raise AttributeError(
#                 '"%s" is not included in this message' % attr
#             )
# 
#     def __dir__(self):
#         'get directory of attributes. include bundle.'
#         return sorted(list(['bundle'] + list(self.bundle.keys())))
# 
#     def __repr__(self):
#         'representation of this message'
#         return 'Message(%s)' % (
#             ', '.join('%s=%s' % pair for pair in self.bundle.items())
#         )
# 
#     def __eq__(self, other):
#         'test equality of two messages'
#         return self.bundle == other.bundle
# 
#     def as_dict(self):
#         '''\
#         representation of this message as a dictionary
# 
#         :returns: dict
#         '''
#         return self.bundle
# 
#     def as_json(self):
#         '''
#         representation of this message as a json object
# 
#         :returns: str
#         '''
#         return json.dumps(self.as_dict())
# 
# class NoResult(object):
#     'single value to return from a node to stop further processing'
#     pass


# Path: emit/router/core.py
from functools import wraps
from types import GeneratorType
from emit.messages import Message, NoResult
import importlib
import logging
import re

        @wraps(func)
        def wrapped(*args, **kwargs):
            'wrapped version of func'
            message = self.get_message_from_call(*args, **kwargs)
            self.logger.info('calling "%s" with %r', name, message)
            result = func(message)

            # functions can return multiple values ("emit" multiple times)
            # by yielding instead of returning. Handle this case by making
            # a list of the results and processing them all after the
            # generator successfully exits. If we were to process them as
            # they came out of the generator, we might get a partially
            # processed input sent down the graph. This may be possible in
            # the future via a flag.
            if isinstance(result, GeneratorType):
                results = [
                    self.wrap_result(name, item)
                    for item in result
                    if item is not NoResult
                ]
                self.logger.debug(
                    '%s returned generator yielding %d items', func, len(results)
                )

                [self.route(name, item) for item in results]
                return tuple(results)

            # the case of a direct return is simpler. wrap, route, and
            # return the value.
            else:

                if result is NoResult: