The "Quick Fix" That Works: Runtime Patching in Python

Motivation
We wanted to generate demo videos with the python library Supervision but they wouldn't play in Chrome. There was a one-line fix buried inside the library -- but the public API gave us no way to reach it.
You have probably been in the same situation: a library does 99.9% of what you want, but there is one thing you cannot work around using its public APIs. Switching to a different library and rewriting your code is too much work. What do you do?
Runtime Patching Comes to the Rescue
Since Python is a dynamically typed language, its possible change the behavior of a function/class/module at runtime.
This is known as runtime patching or monkey patching.
Supervision
Supervision by Roboflow is a helper library for computer vision tasks.
One feature I particularly like is the ability to create demo videos with just a few lines of code:
import numpy as np
import supervision as sv
from rfdetr import RFDETRNano
model = RFDETRNano()
model.optimize_for_inference()
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
detections = model.predict(frame)
return box_annotator.annotate(frame.copy(), detections=detections)
sv.process_video(
source_path="input.mp4",
target_path="result.mp4",
callback=callback
)
There is one small issue though: the generated video cannot be played in Chrome.
chrome://media-internals showed that the video used an unsupported codec.
Digging into the source code, we can see that the OpenCV video writer is created here and It uses FourCC code "mp4v" by default, but what we really want is "avc1" -- I will explain why in a bit.
Here is the problem, the output video is written by a VideoSink instance. While VideoSink accepts a codec argument, there's no way to pass it through the sv.process_video() API.
What if we patch the VideoSink class so that it defaults to "avc1" instead? Well, below is one way to do just that:
def patch_sv() -> None:
orig_init = sv.VideoSink.__init__
def patched_init(self, *args, **kwargs):
kwargs.setdefault("codec", "avc1")
return orig_init(self, *args, **kwargs)
sv.VideoSink.__init__ = patched_init # type: ignore
Note the use of setdefault -- this changes the default codec without preventing callers from choosing a different one explicitly.
As long as we call patch_sv() before sv.process_video(), the generated videos will be playable in Chrome. No more re-encoding with ffmpeg!
Why "avc1"?
You might be wondering why "avc1" specifically solves the problem.
By specifying "avc1", we are requesting OpenCV to encode using H.264 (Advanced Video Coding). Think of H.264 as the JPEG of video codecs: not the latest, but the most widely supported.
This ensures that the video can be played in web browsers like Chrome.
The previous choice, "mp4v", encodes using the older MPEG-4 Part 2 codec, which web browsers never adopted.
Putting It All Together
Here is the complete working example:
import numpy as np
import supervision as sv
from rfdetr import RFDETRNano
def patch_sv() -> None:
orig_init = sv.VideoSink.__init__
def patched_init(self, *args, **kwargs):
kwargs.setdefault("codec", "avc1")
return orig_init(self, *args, **kwargs)
sv.VideoSink.__init__ = patched_init # type: ignore
model = RFDETRNano()
model.optimize_for_inference()
box_annotator = sv.BoxAnnotator()
def callback(frame: np.ndarray, _: int) -> np.ndarray:
detections = model.predict(frame)
return box_annotator.annotate(frame.copy(), detections=detections)
patch_sv()
sv.process_video(
source_path="input.mp4",
target_path="result.mp4",
callback=callback
)
Recap
Runtime patching is a legitimate tool in the pragmatic Python developer's toolbox. It lets us reach past public APIs to fix issues quickly, without forking a library or waiting for an upstream release. The same technique is also widely used in software testing, where it underpins the mocking of library dependencies.
That said, patches are inherently fragile -- a library update can move or rename the internals you depend on. A few ways to manage that risk:
Pin the library version so that updates are intentional and you can re-test your patch.
Contribute the fix upstream. A pull request or issue is the best long-term solution -- it removes the need for the patch entirely.
Keep patches small and isolated. A single, well-documented patch function is easy to find and remove later.
My recommendation is to reserve runtime patching for prototyping, research code, or code that is not on the critical path of a production application. But when the situation calls for it, don't be afraid to use it.






