# Path: sofia/error_manager.py
# ERROR_MANAGER = ErrorManager()
# 
# Path: sofia/workflow/entity_node.py
# class EntityNode(NPartiteGraph):
#     def __init__(self, entity):
#         super().__init__(entity.alias)
#         self.head = entity
#         self.add_vertex(entity, Template.ENTITY_PARTITION)
# 
#     def add_step_node(self, node):
#         self.update(node)
#         self.add_edge(node.head, self.head)
#         node.head.outs.append(self.head)
# 
# Path: sofia/entity_type.py
# class EntityType(object):
#     """
#     An "entity" represents data that is processed by steps in a workflow. They can be considered nouns and the step can
#     be considered verbs.
#     """
#     def __init__(self, name, attributes=None, alias=None, format_string=''):
#         self.name = name
#         self.attributes = {} if attributes is None else attributes
#         self.alias = name if alias is None else alias
#         self.format_string = '{' + format_string + '}'
# 
#     def __str__(self):
#         res = [self.name if self.name == self.alias else '{} ({})'.format(self.alias, self.name)]
#         res.extend('{}={}'.format(k, str(v) if isinstance(v, str) else ','.join(v)) for k, v in sorted(self.attributes.items()))
#         return '\\n'.join(res)
# 
#     def __hash__(self):
#         attributes = tuple((key, frozenset(values)) for key, values in self.attributes.items())
#         return hash(self.name) + hash(attributes)
# 
#     def __eq__(self, other):
#         return self.name == other.name and self.attributes == other.attributes
# 
#     def __lt__(self, other):
#         return str(self) < str(other)
# 
#     def format(self, entity):
#         try:
#             if isinstance(entity, (set, list)):
#                 return ','.join(self.format_string.format(e) for e in entity)
#             return '' if entity is None else self.format_string.format(entity)
#         except Exception as e:
#             import sys
#             sys.stderr.write('Error formatting entity {}.\n'.format(self.name))
#             sys.stderr.write('Format string: {}.\n'.format(self.format_string))
#             sys.stderr.write('Entity: {}.\n'.format(entity))
#             sys.stderr.write('Error: {}\n'.format(e))
#             #raise e
#         return ''


from sofia.error_manager import ERROR_MANAGER
from sofia.workflow.entity_node import EntityNode
from sofia.entity_type import EntityType
        from sofia.resolvers.step_resolver import StepResolver
        self.maps = maps if maps else {}
        self.requested_resources = requested_resources if requested_resources else set()
        self.visited = set() if visited is None else visited

    def __str__(self):
        return self.entity_type
    
    def __iter__(self):
        is_provided = False
        for provided_entity in self.template.provided_entities:
            if provided_entity.name == self.entity_type:
                is_provided = True
                yield EntityNode(provided_entity)

        step_names = self.template.get_parents(self.entity_type)
        if len(step_names) == 0 and not is_provided:
            ERROR_MANAGER.add_error('No steps produce {}'.format(self.entity_type))

        for step_name in step_names:
            if step_name in self.visited:
                continue
            step = self.template.steps[step_name]
            it = StepResolver(step,
                              self.template,
                              self.maps,
                              self.requested_resources,
                              set(self.visited))
            for step_node in it:
                entity_type = EntityType(self.entity_type)
                entity_type.attributes = step_node.out_attributes[self.entity_type]

# Path: sofia/error_manager.py
# ERROR_MANAGER = ErrorManager()
# 
# Path: sofia/workflow/entity_node.py
# class EntityNode(NPartiteGraph):
#     def __init__(self, entity):
#         super().__init__(entity.alias)
#         self.head = entity
#         self.add_vertex(entity, Template.ENTITY_PARTITION)
# 
#     def add_step_node(self, node):
#         self.update(node)
#         self.add_edge(node.head, self.head)
#         node.head.outs.append(self.head)
# 
# Path: sofia/entity_type.py
# class EntityType(object):
#     """
#     An "entity" represents data that is processed by steps in a workflow. They can be considered nouns and the step can
#     be considered verbs.
#     """
#     def __init__(self, name, attributes=None, alias=None, format_string=''):
#         self.name = name
#         self.attributes = {} if attributes is None else attributes
#         self.alias = name if alias is None else alias
#         self.format_string = '{' + format_string + '}'
# 
#     def __str__(self):
#         res = [self.name if self.name == self.alias else '{} ({})'.format(self.alias, self.name)]
#         res.extend('{}={}'.format(k, str(v) if isinstance(v, str) else ','.join(v)) for k, v in sorted(self.attributes.items()))
#         return '\\n'.join(res)
# 
#     def __hash__(self):
#         attributes = tuple((key, frozenset(values)) for key, values in self.attributes.items())
#         return hash(self.name) + hash(attributes)
# 
#     def __eq__(self, other):
#         return self.name == other.name and self.attributes == other.attributes
# 
#     def __lt__(self, other):
#         return str(self) < str(other)
# 
#     def format(self, entity):
#         try:
#             if isinstance(entity, (set, list)):
#                 return ','.join(self.format_string.format(e) for e in entity)
#             return '' if entity is None else self.format_string.format(entity)
#         except Exception as e:
#             import sys
#             sys.stderr.write('Error formatting entity {}.\n'.format(self.name))
#             sys.stderr.write('Format string: {}.\n'.format(self.format_string))
#             sys.stderr.write('Entity: {}.\n'.format(entity))
#             sys.stderr.write('Error: {}\n'.format(e))
#             #raise e
#         return ''


# Path: sofia/resolvers/entity_resolver.py
from sofia.error_manager import ERROR_MANAGER
from sofia.workflow.entity_node import EntityNode
from sofia.entity_type import EntityType
        from sofia.resolvers.step_resolver import StepResolver

        self.maps = maps if maps else {}
        self.requested_resources = requested_resources if requested_resources else set()
        self.visited = set() if visited is None else visited

    def __str__(self):
        return self.entity_type
    
    def __iter__(self):
        is_provided = False
        for provided_entity in self.template.provided_entities:
            if provided_entity.name == self.entity_type:
                is_provided = True
                yield EntityNode(provided_entity)

        step_names = self.template.get_parents(self.entity_type)
        if len(step_names) == 0 and not is_provided:
            ERROR_MANAGER.add_error('No steps produce {}'.format(self.entity_type))

        for step_name in step_names:
            if step_name in self.visited:
                continue
            step = self.template.steps[step_name]
            it = StepResolver(step,
                              self.template,
                              self.maps,
                              self.requested_resources,
                              set(self.visited))
            for step_node in it:
                entity_type = EntityType(self.entity_type)
                entity_type.attributes = step_node.out_attributes[self.entity_type]

                entity_node = EntityNode(entity_type)