Monkey patching in Python
A monkey patch, as defined in wikipedia, is a way for a program to extend or modify supporting system software locally (affecting only the running instance of the program).
Why is monkey patching important? Because it allows us to adjust interfaces and modify behaviors for our classes and objects at runtime, making it easier to support (and patch) issues that arise with API changes between libraries.
To explain it clearer, we will use a concrete example. Using pyppeteer in python 3.5.2 is not supported, because the typings module does not contain the Coroutine class. It was later added, so python 3.5.6 supports it. However, ubuntu 16 is only shipped with python 3.5.2 by default.
In our case, we need to run the application in several servers, so we can either configure python to a different version than the default, or patch the application to support the version we have.
The error is simple and is present in pypeteer’s github. Python is unable to import the Coroutine class from the typings module.
In pypi, however, we can find a module that provides the definitions for the missing classes: typing extensions.
The idea behind monkey patching is to modify your modules at runtime, so the underlying logic does not notice that there were missing things. You patch everything as you go, to make sure that everything is in the state it needs to be when it is required. In this specific case, we inject the Coroutine class as follows:
try: from pyppeteer import launch except ImportError: from typing_extensions import Coroutine typing.Coroutine = Coroutine from pyppeteer import launch
The code is pretty straightforward. We try to import the module that does not support python 3.5.2. This will fail. In this case we catch the error, import the class that we need, and put it inside the typings module. Once we do that, we will be able to import the module we originally wanted to, because now the module has its component defined.
This can be seen as something “hacky”, and indeed it is. We are attaching foreign elements to the module just to be able to run under some circumstances. This should be avoided whenever possible. Explicitly coding your classes and modules to behave as they should is the best way to go.
However, there are valid cases where a simple monkey patch can save you a lot of effort to support edge cases. This is yet another useful tool to have in your belt when you have to attack a problem… use it wisely.