FrameProcessors: do not deepcopy fields when broadcasting frames
This commit is contained in:
@@ -14,7 +14,6 @@ management, and frame flow control mechanisms.
|
|||||||
import asyncio
|
import asyncio
|
||||||
import dataclasses
|
import dataclasses
|
||||||
import traceback
|
import traceback
|
||||||
from copy import deepcopy
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import (
|
from typing import (
|
||||||
@@ -775,20 +774,21 @@ class FrameProcessor(BaseObject):
|
|||||||
"""Broadcasts a frame of the specified class upstream and downstream.
|
"""Broadcasts a frame of the specified class upstream and downstream.
|
||||||
|
|
||||||
This method creates two instances of the given frame class using the
|
This method creates two instances of the given frame class using the
|
||||||
provided keyword arguments and pushes them upstream and downstream.
|
provided keyword arguments (without deep-copying them) and pushes them
|
||||||
|
upstream and downstream.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
frame_cls: The class of the frame to be broadcasted.
|
frame_cls: The class of the frame to be broadcasted.
|
||||||
**kwargs: Keyword arguments to be passed to the frame's constructor.
|
**kwargs: Keyword arguments to be passed to the frame's constructor.
|
||||||
"""
|
"""
|
||||||
await self.push_frame(frame_cls(**deepcopy(kwargs)))
|
await self.push_frame(frame_cls(**kwargs))
|
||||||
await self.push_frame(frame_cls(**deepcopy(kwargs)), FrameDirection.UPSTREAM)
|
await self.push_frame(frame_cls(**kwargs), FrameDirection.UPSTREAM)
|
||||||
|
|
||||||
async def broadcast_frame_instance(self, frame: Frame):
|
async def broadcast_frame_instance(self, frame: Frame):
|
||||||
"""Broadcasts a frame instance upstream and downstream.
|
"""Broadcasts a frame instance upstream and downstream.
|
||||||
|
|
||||||
This method creates two new frame instances copying all fields from the
|
This method creates two new frame instances shallow-copying all fields
|
||||||
original frame except `id` and `name`, which get fresh values.
|
from the original frame except `id` and `name`, which get fresh values.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
frame: The frame instance to broadcast.
|
frame: The frame instance to broadcast.
|
||||||
@@ -806,13 +806,13 @@ class FrameProcessor(BaseObject):
|
|||||||
if not f.init and f.name not in ("id", "name")
|
if not f.init and f.name not in ("id", "name")
|
||||||
}
|
}
|
||||||
|
|
||||||
new_frame = frame_cls(**deepcopy(init_fields))
|
new_frame = frame_cls(**init_fields)
|
||||||
for k, v in deepcopy(extra_fields).items():
|
for k, v in extra_fields.items():
|
||||||
setattr(new_frame, k, v)
|
setattr(new_frame, k, v)
|
||||||
await self.push_frame(new_frame)
|
await self.push_frame(new_frame)
|
||||||
|
|
||||||
new_frame = frame_cls(**deepcopy(init_fields))
|
new_frame = frame_cls(**init_fields)
|
||||||
for k, v in deepcopy(extra_fields).items():
|
for k, v in extra_fields.items():
|
||||||
setattr(new_frame, k, v)
|
setattr(new_frame, k, v)
|
||||||
await self.push_frame(new_frame, FrameDirection.UPSTREAM)
|
await self.push_frame(new_frame, FrameDirection.UPSTREAM)
|
||||||
|
|
||||||
|
|||||||
@@ -259,11 +259,11 @@ class TestFrameProcessor(unittest.IsolatedAsyncioTestCase):
|
|||||||
self.assertEqual(up_frame.value, 42)
|
self.assertEqual(up_frame.value, 42)
|
||||||
self.assertEqual(up_frame.items, ["a", "b"])
|
self.assertEqual(up_frame.items, ["a", "b"])
|
||||||
|
|
||||||
# Verify the items lists are separate instances (not shared references)
|
# Verify the items lists are shared references (no deep copy)
|
||||||
self.assertIsNot(down_frame.items, up_frame.items)
|
self.assertIs(down_frame.items, up_frame.items)
|
||||||
|
|
||||||
async def test_broadcast_frame_instance(self):
|
async def test_broadcast_frame_instance(self):
|
||||||
"""Test that broadcast_frame_instance copies all fields except id and name."""
|
"""Test that broadcast_frame_instance shallow-copies all fields except id and name."""
|
||||||
downstream_frames: List[Frame] = []
|
downstream_frames: List[Frame] = []
|
||||||
upstream_frames: List[Frame] = []
|
upstream_frames: List[Frame] = []
|
||||||
original_frame: List[Frame] = []
|
original_frame: List[Frame] = []
|
||||||
@@ -298,7 +298,7 @@ class TestFrameProcessor(unittest.IsolatedAsyncioTestCase):
|
|||||||
|
|
||||||
pipeline = Pipeline([up_capture, broadcaster, down_capture])
|
pipeline = Pipeline([up_capture, broadcaster, down_capture])
|
||||||
|
|
||||||
# Create a frame with mutable fields to test deep copying
|
# Create a frame with mutable fields to test shallow copying
|
||||||
test_frame = BroadcastTestFrame(text="test", value=99, items=["x", "y", "z"])
|
test_frame = BroadcastTestFrame(text="test", value=99, items=["x", "y", "z"])
|
||||||
|
|
||||||
frames_to_send = [test_frame]
|
frames_to_send = [test_frame]
|
||||||
@@ -342,11 +342,8 @@ class TestFrameProcessor(unittest.IsolatedAsyncioTestCase):
|
|||||||
self.assertEqual(up_frame.pts, 12345)
|
self.assertEqual(up_frame.pts, 12345)
|
||||||
self.assertEqual(up_frame.metadata, {"key": "value", "nested": {"a": 1}})
|
self.assertEqual(up_frame.metadata, {"key": "value", "nested": {"a": 1}})
|
||||||
|
|
||||||
# Verify mutable fields are deep copied (not shared references)
|
# Verify mutable fields are shallow-copied (shared references)
|
||||||
self.assertIsNot(down_frame.items, orig.items)
|
self.assertIs(down_frame.items, orig.items)
|
||||||
self.assertIsNot(up_frame.items, orig.items)
|
self.assertIs(up_frame.items, orig.items)
|
||||||
self.assertIsNot(down_frame.items, up_frame.items)
|
self.assertIs(down_frame.metadata, orig.metadata)
|
||||||
self.assertIsNot(down_frame.metadata, orig.metadata)
|
self.assertIs(up_frame.metadata, orig.metadata)
|
||||||
self.assertIsNot(up_frame.metadata, orig.metadata)
|
|
||||||
self.assertIsNot(down_frame.metadata, up_frame.metadata)
|
|
||||||
self.assertIsNot(down_frame.metadata["nested"], up_frame.metadata["nested"])
|
|
||||||
|
|||||||
Reference in New Issue
Block a user