What Is Monkey Patching

What is monkey patching?

No, it's not like any of those things. It's simply the dynamic replacement of attributes at runtime.

For instance, consider a class that has a method get_data. This method does an external lookup (on a database or web API, for example), and various other methods in the class call it. However, in a unit test, you don't want to depend on the external data source - so you dynamically replace the get_data method with a stub that returns some fixed data.

Because Python classes are mutable, and methods are just attributes of the class, you can do this as much as you like - and, in fact, you can even replace classes and functions in a module in exactly the same way.

But, as a commenter pointed out, use caution when monkeypatching:

  1. If anything else besides your test logic calls get_data as well, it will also call your monkey-patched replacement rather than the original -- which can be good or bad. Just beware.

  2. If some variable or attribute exists that also points to the get_data function by the time you replace it, this alias will not change its meaning and will continue to point to the original get_data. (Why? Python just rebinds the name get_data in your class to some other function object; other name bindings are not impacted at all.)

What is the difference between mocking and monkey patching?

Monkey patching is replacing a function/method/class by another at runtime, for testing purpses, fixing a bug or otherwise changing behaviour.

The unittest.mock library makes use of monkey patching to replace part of your software under test by mock objects. It provides functionality for writing clever unittests, such as:

  • It keeps record of how mock objects are being called, so you can test
    the calling behaviour of your code with asserts.
  • A handy decorator patch() for the actual monkey patching.
  • You can make mock objects to return specific values (return_value), raise specific exceptions (side_effect).
  • Mocking of 'magic methds' (e.g. __str__).

You can use mocking, for example, to replace network I/O (urllib, requests) in a client, so unittests work without depending on an external server.

Monkey Patching in python: When we need it?

Monkey-patching is a way to make some global under-the-hood change in a way that existing code will continue to run, but with modified behavior.

A really really trivial example of changing the behavior of the builtin str command:

b.py

def foo(msg):
s = str(msg)
print s, type(s)

a.py

import b

b.foo('foo')

# monkey-patch
import __builtin__
__builtin__.str = unicode

b.foo('foo')

# Results:
#foo <type 'str'>
#foo <type 'unicode'>

The a module has modified the behavior of other code using the str command, by patching it to use unicode instead. This would be necessary since we pretend that we have no access to b.py's code. It could have been a huge package that we simply use and can't change. But we can slip in new code to be called that changes the behavior.

A real world example from gevent

>>> import gevent
>>> from gevent import socket
>>> urls = ['www.google.com', 'www.example.com', 'www.python.org']
>>> jobs = [gevent.spawn(socket.gethostbyname, url) for url in urls]
>>> gevent.joinall(jobs, timeout=2)
>>> [job.value for job in jobs]
['74.125.79.106', '208.77.188.166', '82.94.164.162']

The example above used gevent.socket for socket operations. If the
standard socket module was used it would took it 3 times longer to
complete because the DNS requests would be sequential. Using the
standard socket module inside greenlets makes gevent rather pointless,
so what about module and packages that are built on top of socket?

That’s what monkey patching for. The functions in gevent.monkey
carefully replace functions and classes in the standard socket module
with their cooperative counterparts. That way even the modules that
are unaware of gevent can benefit from running in multi-greenlet
environment.

>>> from gevent import monkey; monkey.patch_socket()
>>> import urllib2 # it's usable from multiple greenlets now

What does 'Monkey Patching' exactly Mean in Ruby?

The short answer is that there is no "exact" meaning, because it's a novel term, and different folks use it differently. That much at least can be discerned from the Wikipedia article. There are some who insist that it only applies to "runtime" code (built-in classes, I suppose) while some would use it to refer to the run-time modification of any class.

Personally, I prefer the more inclusive definition. After all, if we were to use the term for modification of built-in classes only, how would we refer to the run-time modification of all the other classes? The important thing to me is that there's a difference between the source code and the actual running class.

In Ruby, the term monkey patch was
misunderstood to mean any dynamic
modification to a class and is often
used as a synonym for dynamically
modifying any class at runtime.

The above statement asserts that the Ruby usage is incorrect - but terms evolve, and that's not always a bad thing.

What is monkey patching regarding TypeScript ?

Because JavaScript is highly dynamic you can replace a member function (and related functionality) on any object with a new one. It allows you to modify the behaviour of a piece of code without altering the original code.

Here is a simple example in TypeScript:

// original code, assume its in some library
interface Foo {
a:number,
b():number
}
var foo:Foo = {a:123,b:function(){return this.a}}

// Monkey patch the function b with a new one
// Allows you to change the behaviour of foo without changing the original code
foo.b = function(){return 456}

More : Monkey patching is not just interception

When you replace the function but retain the original behaviour, it is function interception. Yes you use monkey patching for function interception (replace the function) but calling the original function is not a requirement for monkey patching.

  • The python answer What is monkey patching? (replacement / overriding only)

Also from Wikipedia : https://en.wikipedia.org/wiki/Monkey_patch an application that clearly replaces original behaviour:

Replace methods / classes / attributes / functions at runtime, e.g. to stub out a function during testing;

Finally, just because you can call the original doesn't mean you have to call the original when monkey patching.

What is monkeypatching with the python gevent library?

Gevent is a cooperative multitasking library. The way it works is you, the programmer, organise your code into units of work called greenlets. While a given greenlet is running, it runs alone. When it reaches a point where it would block, that is, it would have to wait for some external signal like a file, a timeout, our network data, the greenlet should cooperate by signaling gevent, who arranges for some other greenlet to run. The former greenish will be resumed once the data it waited for is ready. (This is the crayon-coloured gist of it, there may be some complexity that would be useful for you to know that is beyond the shore of this answer.)

Now, Python's standard library is (was?) not cooperative. Rather than signaling gevent that a certain greenlet can be paused, the standard behaviour is to block selfishly. This causes a problem, since only the first greenlet is running: the others never get a chance to be scheduled.

Enter money patching. The point of monkey.patch is to replace the blocking calls in the stdlib with cooperative alternatives, so that existing code can take advantage of the concurrency of greenlets without needing to be being rewritten.

Monkey Patching in Python using super.__init__

You have to monkey patch the original Message object that pyrogram uses.

from pyrogram.types import Message 

@property
def test(self):
return "test"

Message.test = test

If you really wanna update the Message class when changing the subclass (NOT RECOMMENDED!) you can do this:

from pyrogram.types import Message 

Message.__init_subclass__ = classmethod(lambda sub: [setattr(Message, k, v) for (k,v) in sub.__dict__.items() if k[:2] != '__'])

class MyMessage(Message):
def __init__(self, **kwargs):
super().__init__(**kwargs)

@property
def test(self):
return "test"

Is it possible to do monkey patching in Java, if not is there an alternative?

There are a number of techniques that might be applicable here, but your question is too vague to narrow them down to a single answer.

"Monkey patching" in the literal sense that it is used in Ruby (i.e. "replace methods of a class at runtime", see e.g. [1]) is possible with "Java Agents" and the "retransform" API, but it's much harder than it is in Ruby.

Source code patching

I need it for a java application that I applied my own patch to

If there is an app for which you have the source code, say in git, then you could fork their project, apply your own patch and build a modified version.

I want to be able to keep apply any patch I make, to the patches they make.

If you create your patch on a branch then it will be easy with git to pull in any future changes from the "upstream" project into your branch, and build a new modified version.

Replacing classes at class-load time via classpath precedence

An easy technique that more closely approximates Monkey Patching is to compile a single class from the target app, with modifications, and put it earlier on your classpath than the original JAR. (This is covered in the old Monkey Patching q at this answer: https://stackoverflow.com/a/381240/8261 )

The JVM loads all classes by name, and will use the first classfile it finds on the classpath for any class, so you can replace the classes one-by-one from the project you wish to modify. If you have the source for the target project, then copy that into your app file-by-file and then apply your patches to the java source.

(You will need to manually apply any future upstream changes with this approach.)

Transforming classes at class-load time or "retransforming" method bodies at any time via JVM Agents

The JVM has an API called "Java Agents" which lets you register code to modify classes at the time they are loaded.

There is also a "retransform" API that lets you change the definition of already loaded classes. This is used by JRebel to update code in running applications. It's much more limited that Ruby's monkey patching in that you can't add or remove methods (you can change method bodies).

This mechanism is used by https://github.com/fommil/class-monkey to "monkey patch" a JVM bug, for example.



Related Topics



Leave a reply



Submit