Пример #1
0
    def test_render_entities_data(self):
        blocks = [{
            "key": "5s7g9",
            "text": "test",
            "type": "unstyled",
            "depth": 0,
            "inlineStyleRanges": [],
            "entityRanges": [],
        }]

        def component(props):
            self.assertEqual(props["entity"]["blocks"], blocks)
            self.assertEqual(props["entity"]["block"], blocks[0])
            self.assertEqual(props["entity"]["type"], "LINK")
            self.assertEqual(props["entity"]["mutability"], "MUTABLE")
            self.assertEqual(props["entity"]["entity_range"]["key"], "0")
            return None

        entity_state = EntityState(Options.map_entities({"LINK": component}),
                                   entity_map)

        entity_state.apply(Command("start_entity", 0, "0"))
        entity_state.render_entities("Test text", blocks[0], blocks)
        entity_state.apply(Command("stop_entity", 9, "0"))
        entity_state.render_entities("Test text", blocks[0], blocks)
Пример #2
0
    def test_render_entities_data(self):
        blocks = [
            {
                'key': '5s7g9',
                'text': 'test',
                'type': 'unstyled',
                'depth': 0,
                'inlineStyleRanges': [],
                'entityRanges': [],
            },
        ]

        def component(props):
            self.assertEqual(props['entity']['blocks'], blocks)
            self.assertEqual(props['entity']['block'], blocks[0])
            self.assertEqual(props['entity']['type'], 'LINK')
            self.assertEqual(props['entity']['mutability'], 'MUTABLE')
            self.assertEqual(props['entity']['entity_range']['key'], '0')
            return None

        entity_state = EntityState(Options.map_entities({
            'LINK': component,
        }), entity_map)

        entity_state.apply(Command('start_entity', 0, '0'))
        entity_state.render_entities('Test text', blocks[0], blocks)
        entity_state.apply(Command('stop_entity', 9, '0'))
        entity_state.render_entities('Test text', blocks[0], blocks)
Пример #3
0
    def render_block(self, block, entity_map):
        element = self.wrapper_state.element_for(block)
        entity_state = EntityState(element, self.entity_decorators, entity_map)

        for (text, commands) in self.build_command_groups(block):
            for command in commands:
                entity_state.apply(command)
                self.style_state.apply(command)

            self.style_state.add_node(entity_state.current_parent(), text)
Пример #4
0
    def test_render_entities_data_no_mutability(self):
        def component(props):
            self.assertEqual(props["entity"]["mutability"], None)
            return None

        entity_state = EntityState(Options.map_entities({"LINK": component}),
                                   entity_map)

        entity_state.apply(Command("start_entity", 0, "2"))
        entity_state.render_entities("Test text", {}, [])
        entity_state.apply(Command("stop_entity", 9, "2"))
        entity_state.render_entities("Test text", {}, [])
Пример #5
0
    def test_render_entities_data_no_mutability(self):
        def component(props):
            self.assertEqual(props['entity']['mutability'], None)
            return None

        entity_state = EntityState(Options.map_entities({
            'LINK': component,
        }), entity_map)

        entity_state.apply(Command('start_entity', 0, '2'))
        entity_state.render_entities('Test text', {}, [])
        entity_state.apply(Command('stop_entity', 9, '2'))
        entity_state.render_entities('Test text', {}, [])
Пример #6
0
    def render_block(self, block: Block, entity_map: EntityMap,
                     wrapper_state: WrapperState) -> Element:
        has_styles = "inlineStyleRanges" in block and block["inlineStyleRanges"]
        has_entities = "entityRanges" in block and block["entityRanges"]
        has_decorators = should_render_decorators(self.composite_decorators,
                                                  block["text"])

        if has_styles or has_entities:
            content = DOM.create_element()
            entity_state = EntityState(self.entity_options, entity_map)
            style_state = StyleState(
                self.style_options) if has_styles else None

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    if style_state:
                        style_state.apply(command)

                # Decorators are not rendered inside entities.
                if has_decorators and entity_state.has_no_entity():
                    decorated_node = render_decorators(
                        self.composite_decorators,
                        text,
                        block,
                        wrapper_state.blocks,
                    )
                else:
                    decorated_node = text

                if style_state:
                    styled_node = style_state.render_styles(
                        decorated_node, block, wrapper_state.blocks)
                else:
                    styled_node = decorated_node
                entity_node = entity_state.render_entities(
                    styled_node, block, wrapper_state.blocks)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)

                    # Check whether there actually are two different nodes, confirming we are not inserting an upcoming entity.
                    if (styled_node != entity_node
                            and entity_state.has_no_entity()):
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        elif has_decorators:
            content = render_decorators(
                self.composite_decorators,
                block["text"],
                block,
                wrapper_state.blocks,
            )
        else:
            content = block["text"]

        return wrapper_state.element_for(block, content)
Пример #7
0
    def render_block(self, block, entity_map, wrapper_state):
        if block['inlineStyleRanges'] or block['entityRanges']:
            content = DOM.create_element()
            entity_state = EntityState(self.entity_decorators, entity_map)
            style_state = StyleState(self.style_map)

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    style_state.apply(command)

                # Decorators are not rendered inside entities.
                if entity_state.has_no_entity() and self.has_decorators:
                    decorated_node = render_decorators(self.composite_decorators, text, block, wrapper_state.blocks)
                else:
                    decorated_node = text

                styled_node = style_state.render_styles(decorated_node, block, wrapper_state.blocks)
                entity_node = entity_state.render_entities(styled_node)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)

                    # Check whether there actually are two different nodes, confirming we are not inserting an upcoming entity.
                    if styled_node != entity_node and entity_state.has_no_entity():
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        elif self.has_decorators:
            content = render_decorators(self.composite_decorators, block['text'], block, wrapper_state.blocks)
        else:
            content = block['text']

        return wrapper_state.element_for(block, content)
Пример #8
0
    def render_block(self, block, entity_map, wrapper_state):
        content = DOM.create_element()
        entity_state = EntityState(self.entity_decorators, entity_map)
        style_state = StyleState(self.style_map)

        for (text, commands) in self.build_command_groups(block):
            for command in commands:
                entity_state.apply(command)
                style_state.apply(command)

            # Decorators are not rendered inside entities.
            if text and entity_state.has_no_entity() and len(
                    self.composite_decorators) > 0:
                decorated_node = render_decorators(self.composite_decorators,
                                                   text, block)
            else:
                decorated_node = text

            styled_node = style_state.render_styles(decorated_node)
            entity_node = entity_state.render_entities(styled_node)

            if entity_node is not None:
                DOM.append_child(content, entity_node)
                if styled_node != entity_node:
                    DOM.append_child(content, styled_node)

        return wrapper_state.element_for(block, content)
Пример #9
0
    def render_block(self, block, entity_map):
        element = self.wrapper_state.element_for(block)
        entity_state = EntityState(self.entity_decorators, entity_map)

        for (text, commands) in self.build_command_groups(block):
            for command in commands:
                entity_state.apply(command)
                self.style_state.apply(command)

            style_node = self.style_state.create_node(text)
            entity_state.render_entitities(element, style_node)
Пример #10
0
class TestEntityState(unittest.TestCase):
    def setUp(self):
        self.entity_state = EntityState(etree.Element('div'), entity_decorators, entity_map)

    def test_init(self):
        self.assertIsInstance(self.entity_state, EntityState)

    @unittest.skip('TODO')
    def test_apply_start_entity(self):
        self.assertEqual(self.entity_state.entity_stack[-1][0].tag, 'div')
        self.assertEqual(self.entity_state.entity_stack[-1][1], {})
        self.entity_state.apply(Command('start_entity', 0, 0))
        self.assertEqual(self.entity_state.entity_stack[-1], {
            'data': {
                'url': 'http://example.com'
            },
            'type': 'LINK',
            'mutability': 'MUTABLE',
        })

    @unittest.skip('TODO')
    def test_apply_stop_entity(self):
        self.assertEqual(self.entity_state.entity_stack[-1][0].tag, 'div')
        self.assertEqual(self.entity_state.entity_stack[-1][1], {})
        self.entity_state.apply(Command('stop_entity', 5, 0))
        self.assertEqual(self.entity_state.entity_stack[-1][1], {
            'data': {
                'url': 'http://example.com'
            },
            'type': 'LINK',
            'mutability': 'MUTABLE',
        })

    def test_start_command_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.start_command(Command('start_entity', 0, 1))

    def test_stop_command_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.start_command(Command('stop_entity', 0, 1))
Пример #11
0
    def render_block(self, block, entity_map, wrapper_state):
        if 'inlineStyleRanges' in block and block[
                'inlineStyleRanges'] or 'entityRanges' in block and block[
                    'entityRanges']:
            content = DOM.create_element()
            entity_state = EntityState(self.entity_options, entity_map)
            style_state = StyleState(self.style_options)

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    style_state.apply(command)

                # Decorators are not rendered inside entities.
                if entity_state.has_no_entity() and self.has_decorators:
                    decorated_node = render_decorators(
                        self.composite_decorators, text, block,
                        wrapper_state.blocks)
                else:
                    decorated_node = text

                styled_node = style_state.render_styles(
                    decorated_node, block, wrapper_state.blocks)
                entity_node = entity_state.render_entities(styled_node)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)

                    # Check whether there actually are two different nodes, confirming we are not inserting an upcoming entity.
                    if styled_node != entity_node and entity_state.has_no_entity(
                    ):
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        elif self.has_decorators:
            content = render_decorators(self.composite_decorators,
                                        block['text'], block,
                                        wrapper_state.blocks)
        else:
            content = block['text']

        return wrapper_state.element_for(block, content)
Пример #12
0
    def render_block(self, block, entity_map, wrapper_state):
        content = DOM.create_element()

        if block['inlineStyleRanges'] or block['entityRanges']:
            entity_state = EntityState(self.entity_decorators, entity_map)
            style_state = StyleState(self.style_map)

            for (text, commands) in self.build_command_groups(block):
                for command in commands:
                    entity_state.apply(command)
                    style_state.apply(command)

                # Decorators are not rendered inside entities.
                if text and entity_state.has_no_entity() and len(
                        self.composite_decorators) > 0:
                    decorated_node = render_decorators(
                        self.composite_decorators, text, block,
                        wrapper_state.blocks)
                else:
                    decorated_node = text

                styled_node = style_state.render_styles(
                    decorated_node, block, wrapper_state.blocks)
                entity_node = entity_state.render_entities(styled_node)

                if entity_node is not None:
                    DOM.append_child(content, entity_node)
                    if styled_node != entity_node:
                        DOM.append_child(content, styled_node)
        # Fast track for blocks which do not contain styles nor entities, which is very common.
        else:
            if len(self.composite_decorators) > 0:
                decorated_node = render_decorators(self.composite_decorators,
                                                   block['text'], block,
                                                   wrapper_state.blocks)
            else:
                decorated_node = block['text']

            DOM.append_child(content, decorated_node)

        return wrapper_state.element_for(block, content)
Пример #13
0
 def setUp(self):
     self.entity_state = EntityState(etree.Element('div'), entity_decorators, entity_map)
class TestEntityState(unittest.TestCase):
    def setUp(self):
        self.entity_state = EntityState(entity_decorators, entity_map)

    def test_init(self):
        self.assertIsInstance(self.entity_state, EntityState)

    def test_apply_start_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command('start_entity', 0, 0))
        self.assertEqual(self.entity_state.entity_stack[-1], 0)

    def test_apply_stop_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command('start_entity', 0, 0))
        self.entity_state.apply(Command('stop_entity', 5, 0))
        self.assertEqual(len(self.entity_state.entity_stack), 0)

    def test_apply_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.apply(Command('start_entity', 0, 0))
            self.entity_state.apply(Command('stop_entity', 0, 1))

    def test_has_no_entity_default(self):
        self.assertEqual(self.entity_state.has_no_entity(), True)

    def test_has_no_entity_styled(self):
        self.entity_state.apply(Command('start_entity', 0, 0))
        self.assertEqual(self.entity_state.has_no_entity(), False)

    def test_get_entity_details(self):
        self.assertEqual(self.entity_state.get_entity_details(0), {
            'data': {
                'url': 'http://example.com'
            },
            'type': 'LINK',
            'mutability': 'MUTABLE',
        })

    def test_get_entity_details_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.get_entity_details(1)
Пример #15
0
class TestEntityState(unittest.TestCase):
    def setUp(self):
        self.entity_state = EntityState(
            Options.map_entities(entity_decorators), entity_map)

    def test_init(self):
        self.assertIsInstance(self.entity_state, EntityState)

    def test_apply_start_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command("start_entity", 0, "0"))
        self.assertEqual(self.entity_state.entity_stack[-1], "0")

    def test_apply_stop_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command("start_entity", 0, "0"))
        self.entity_state.apply(Command("stop_entity", 5, "0"))
        self.assertEqual(len(self.entity_state.entity_stack), 0)

    def test_apply_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.apply(Command("start_entity", 0, "0"))
            self.entity_state.apply(Command("stop_entity", 0, "1"))

    def test_has_no_entity_default(self):
        self.assertEqual(self.entity_state.has_no_entity(), True)

    def test_has_no_entity_styled(self):
        self.entity_state.apply(Command("start_entity", 0, "0"))
        self.assertEqual(self.entity_state.has_no_entity(), False)

    def test_get_entity_details(self):
        self.assertEqual(
            self.entity_state.get_entity_details("0"),
            {
                "data": {
                    "url": "http://example.com"
                },
                "type": "LINK",
                "mutability": "MUTABLE",
            },
        )

    def test_get_entity_details_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.get_entity_details("1")

    def test_render_entities_unstyled(self):
        self.assertEqual(
            self.entity_state.render_entities("Test text", {}, []),
            "Test text")

    def test_render_entities_unicode(self):
        self.assertEqual(self.entity_state.render_entities("🍺", {}, []), "🍺")

    def test_render_entities_inline(self):
        self.entity_state.apply(Command("start_entity", 0, "0"))
        self.entity_state.render_entities("Test text", {}, [])
        self.entity_state.apply(Command("stop_entity", 9, "0"))
        self.assertEqual(
            DOM.render_debug(
                self.entity_state.render_entities("Test text", {}, [])),
            '<a href="http://example.com">Test text</a>',
        )

    def test_render_entities_inline_multiple(self):
        self.entity_state.apply(Command("start_entity", 0, "0"))
        self.entity_state.render_entities("Test 1", {}, [])
        self.entity_state.apply(Command("stop_entity", 5, "0"))
        self.entity_state.apply(Command("start_entity", 5, "2"))
        self.assertEqual(
            DOM.render_debug(
                self.entity_state.render_entities("Test text", {}, [])),
            '<a href="http://example.com">Test 1</a>',
        )
        self.entity_state.render_entities("Test 2", {}, [])
        self.entity_state.apply(Command("stop_entity", 10, "2"))
        self.assertEqual(
            DOM.render_debug(
                self.entity_state.render_entities("Test text", {}, [])),
            '<a href="http://test.com"><fragment>Test textTest 2</fragment></a>',
        )

    def test_render_entities_data(self):
        blocks = [{
            "key": "5s7g9",
            "text": "test",
            "type": "unstyled",
            "depth": 0,
            "inlineStyleRanges": [],
            "entityRanges": [],
        }]

        def component(props):
            self.assertEqual(props["entity"]["blocks"], blocks)
            self.assertEqual(props["entity"]["block"], blocks[0])
            self.assertEqual(props["entity"]["type"], "LINK")
            self.assertEqual(props["entity"]["mutability"], "MUTABLE")
            self.assertEqual(props["entity"]["entity_range"]["key"], "0")
            return None

        entity_state = EntityState(Options.map_entities({"LINK": component}),
                                   entity_map)

        entity_state.apply(Command("start_entity", 0, "0"))
        entity_state.render_entities("Test text", blocks[0], blocks)
        entity_state.apply(Command("stop_entity", 9, "0"))
        entity_state.render_entities("Test text", blocks[0], blocks)

    def test_render_entities_data_no_mutability(self):
        def component(props):
            self.assertEqual(props["entity"]["mutability"], None)
            return None

        entity_state = EntityState(Options.map_entities({"LINK": component}),
                                   entity_map)

        entity_state.apply(Command("start_entity", 0, "2"))
        entity_state.render_entities("Test text", {}, [])
        entity_state.apply(Command("stop_entity", 9, "2"))
        entity_state.render_entities("Test text", {}, [])
Пример #16
0
 def setUp(self):
     self.entity_state = EntityState(entity_decorators, entity_map)
Пример #17
0
class TestEntityState(unittest.TestCase):
    def setUp(self):
        self.entity_state = EntityState(entity_decorators, entity_map)

    def test_init(self):
        self.assertIsInstance(self.entity_state, EntityState)

    def test_apply_start_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command('start_entity', 0, 0))
        self.assertEqual(
            self.entity_state.entity_stack[-1], {
                'data': {
                    'url': 'http://example.com'
                },
                'type': 'LINK',
                'mutability': 'MUTABLE',
            })

    def test_apply_stop_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command('start_entity', 0, 0))
        self.entity_state.apply(Command('stop_entity', 5, 0))
        self.assertEqual(len(self.entity_state.entity_stack), 0)

    def test_get_entity_details(self):
        self.assertEqual(
            self.entity_state.get_entity_details(Command('start_entity', 0,
                                                         0)),
            {
                'data': {
                    'url': 'http://example.com'
                },
                'type': 'LINK',
                'mutability': 'MUTABLE',
            })

    def test_get_entity_details_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.get_entity_details(Command('start_entity', 0, 1))

    def test_get_entity_decorator(self):
        self.assertIsInstance(
            self.entity_state.get_entity_decorator({
                'data': {
                    'url': 'http://example.com'
                },
                'type': 'LINK',
                'mutability': 'MUTABLE',
            }), Link)

    def test_get_entity_decorator_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.get_entity_decorator({
                'data': {
                    'url': 'http://example.com'
                },
                'type': 'VIDEO',
                'mutability': 'MUTABLE',
            })

    def test_start_command_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.start_command(Command('start_entity', 0, 1))

    def test_stop_command_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.start_command(Command('stop_entity', 0, 1))
Пример #18
0
 def setUp(self):
     self.entity_state = EntityState(
         Options.map_entities(entity_decorators), entity_map)
Пример #19
0
class TestEntityState(unittest.TestCase):
    def setUp(self):
        self.entity_state = EntityState(Options.map_entities(entity_decorators), entity_map)

    def test_init(self):
        self.assertIsInstance(self.entity_state, EntityState)

    def test_apply_start_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command('start_entity', 0, '0'))
        self.assertEqual(self.entity_state.entity_stack[-1], '0')

    def test_apply_stop_entity(self):
        self.assertEqual(len(self.entity_state.entity_stack), 0)
        self.entity_state.apply(Command('start_entity', 0, '0'))
        self.entity_state.apply(Command('stop_entity', 5, '0'))
        self.assertEqual(len(self.entity_state.entity_stack), 0)

    def test_apply_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.apply(Command('start_entity', 0, '0'))
            self.entity_state.apply(Command('stop_entity', 0, '1'))

    def test_has_no_entity_default(self):
        self.assertEqual(self.entity_state.has_no_entity(), True)

    def test_has_no_entity_styled(self):
        self.entity_state.apply(Command('start_entity', 0, '0'))
        self.assertEqual(self.entity_state.has_no_entity(), False)

    def test_get_entity_details(self):
        self.assertEqual(self.entity_state.get_entity_details('0'), {
            'data': {
                'url': 'http://example.com'
            },
            'type': 'LINK',
            'mutability': 'MUTABLE',
        })

    def test_get_entity_details_raises(self):
        with self.assertRaises(EntityException):
            self.entity_state.get_entity_details('1')

    def test_render_entities_unstyled(self):
        self.assertEqual(self.entity_state.render_entities('Test text', {}, []), 'Test text')

    def test_render_entities_unicode(self):
        self.assertEqual(self.entity_state.render_entities('🍺', {}, []), '🍺')

    def test_render_entities_inline(self):
        self.entity_state.apply(Command('start_entity', 0, '0'))
        self.entity_state.render_entities('Test text', {}, [])
        self.entity_state.apply(Command('stop_entity', 9, '0'))
        self.assertEqual(DOM.render_debug(self.entity_state.render_entities('Test text', {}, [])), '<a href="http://example.com">Test text</a>')

    def test_render_entities_inline_multiple(self):
        self.entity_state.apply(Command('start_entity', 0, '0'))
        self.entity_state.render_entities('Test 1', {}, [])
        self.entity_state.apply(Command('stop_entity', 5, '0'))
        self.entity_state.apply(Command('start_entity', 5, '2'))
        self.assertEqual(DOM.render_debug(self.entity_state.render_entities('Test text', {}, [])), '<a href="http://example.com">Test 1</a>')
        self.entity_state.render_entities('Test 2', {}, [])
        self.entity_state.apply(Command('stop_entity', 10, '2'))
        self.assertEqual(DOM.render_debug(self.entity_state.render_entities('Test text', {}, [])), '<a href="http://test.com"><fragment>Test textTest 2</fragment></a>')

    def test_render_entities_data(self):
        blocks = [
            {
                'key': '5s7g9',
                'text': 'test',
                'type': 'unstyled',
                'depth': 0,
                'inlineStyleRanges': [],
                'entityRanges': [],
            },
        ]

        def component(props):
            self.assertEqual(props['entity']['blocks'], blocks)
            self.assertEqual(props['entity']['block'], blocks[0])
            self.assertEqual(props['entity']['type'], 'LINK')
            self.assertEqual(props['entity']['mutability'], 'MUTABLE')
            self.assertEqual(props['entity']['entity_range']['key'], '0')
            return None

        entity_state = EntityState(Options.map_entities({
            'LINK': component,
        }), entity_map)

        entity_state.apply(Command('start_entity', 0, '0'))
        entity_state.render_entities('Test text', blocks[0], blocks)
        entity_state.apply(Command('stop_entity', 9, '0'))
        entity_state.render_entities('Test text', blocks[0], blocks)

    def test_render_entities_data_no_mutability(self):
        def component(props):
            self.assertEqual(props['entity']['mutability'], None)
            return None

        entity_state = EntityState(Options.map_entities({
            'LINK': component,
        }), entity_map)

        entity_state.apply(Command('start_entity', 0, '2'))
        entity_state.render_entities('Test text', {}, [])
        entity_state.apply(Command('stop_entity', 9, '2'))
        entity_state.render_entities('Test text', {}, [])
 def setUp(self):
     self.entity_state = EntityState(entity_decorators, entity_map)
Пример #21
0
 def setUp(self):
     self.entity_state = EntityState(DOM.create_element('div'), entity_decorators, entity_map)