Monkey-patching in Python: a magic trick or a powerful tool?

45
monkey-patching: a magic trick or a powerful tool? Elizaveta Shashkova @lisa_shashkova [email protected]

Transcript of Monkey-patching in Python: a magic trick or a powerful tool?

Page 1: Monkey-patching in Python: a magic trick or a powerful tool?

monkey-patching: a magic trick or a powerful tool?

Elizaveta Shashkova @lisa_shashkova

[email protected]

Page 2: Monkey-patching in Python: a magic trick or a powerful tool?

bio• Software Developer of PyCharm IDE at JetBrains • Debugger used in PyDev & PyCharm

2

Page 3: Monkey-patching in Python: a magic trick or a powerful tool?

Monkey-patching is a dynamic modification of a class or a module at runtime

def safe_sqrt(num):

# doesn’t throw exception if num < 0

if num < 0:

return math.nan

return math.original(num)

>>> import math

>>> math.original = math.sqrt

>>> math.sqrt = safe_sqrt

monkey-patching

Page 4: Monkey-patching in Python: a magic trick or a powerful tool?

monkey-patching• Guerilla patch • Does something secretly and incompatibly

with others • Gorilla patch • Monkey patch

Page 5: Monkey-patching in Python: a magic trick or a powerful tool?

other languagesRuby

class String

def upcase

self.reverse

end

end

> puts "hello".upcase"olleh"

Page 6: Monkey-patching in Python: a magic trick or a powerful tool?

pythonExplicit is better than implicit

Page 7: Monkey-patching in Python: a magic trick or a powerful tool?

what can we patch?

Everything!

Page 8: Monkey-patching in Python: a magic trick or a powerful tool?

what can we patch?Almost

Everything!

We can’t patch built-ins defined in C

Page 9: Monkey-patching in Python: a magic trick or a powerful tool?

light side of monkey-patching

9

dark side of monkey-patching

Page 10: Monkey-patching in Python: a magic trick or a powerful tool?

•Workaround for bugs in third-party code

light side

Page 11: Monkey-patching in Python: a magic trick or a powerful tool?

•Workaround for bugs in third-party code • Don’t forget to fix and create a pull request!

light side

Page 12: Monkey-patching in Python: a magic trick or a powerful tool?

•Workaround for bugs in third-party code • Don’t forget to fix and create a pull request!

•Code instrumentation

light side

Page 13: Monkey-patching in Python: a magic trick or a powerful tool?

•Workaround for bugs in third-party code • Don’t forget to fix and create a pull request!

•Code instrumentation •Testing

light side

Page 14: Monkey-patching in Python: a magic trick or a powerful tool?

•Workaround for bugs in third-party code • Don’t forget to fix and create a pull request!

•Code instrumentation •Testing •Changing of standard modules

light side

Page 15: Monkey-patching in Python: a magic trick or a powerful tool?

examples

Page 16: Monkey-patching in Python: a magic trick or a powerful tool?

light side: catching new process

Page 17: Monkey-patching in Python: a magic trick or a powerful tool?

light side: new processclass ProcessManager: def __init__(self, system_fork): self.system_fork = system_fork

def do_fork(self): pid = self.system_fork() if pid == 0: # child process start_tracing() return pid

Page 18: Monkey-patching in Python: a magic trick or a powerful tool?

import os manager = ProcessManager(os.fork) os.fork = manager.do_fork

os.fork() #tracing in a new process

light side: new process

Page 19: Monkey-patching in Python: a magic trick or a powerful tool?

light side: import hook

Page 20: Monkey-patching in Python: a magic trick or a powerful tool?

• How to patch a module as soon as possible? • Patch it right after importing

light side

Page 21: Monkey-patching in Python: a magic trick or a powerful tool?

light side: import hookclass ImportHookManager: def __init__(self, system_import): self.system_import = system_import

def do_import(self, name): module = self.system_import(name) if name == "os": orig_fork = module.fork module.fork = ProcessManager(orig_fork).do_fork return module

Page 22: Monkey-patching in Python: a magic trick or a powerful tool?

light side: import hookimport builtins manager = ImportHookManager(builtins.__import__) builtins.__import__ = manager.do_import

import os# module is patched as soon as it is imported

Page 23: Monkey-patching in Python: a magic trick or a powerful tool?

light side: gevent

Page 24: Monkey-patching in Python: a magic trick or a powerful tool?

light side: gevent● gevent provides asynchronous I/O

● Blocking system calls in the standard library

import socket

● Replace with gevent modules

from gevent import socket

Page 25: Monkey-patching in Python: a magic trick or a powerful tool?

light side: gevent! The simplest way

from gevent import monkeymonkey.patch_socket()

Page 26: Monkey-patching in Python: a magic trick or a powerful tool?

•Workaround for bugs in third-party code •Code instrumentation •Testing •Changing of standard modules

light side

Page 27: Monkey-patching in Python: a magic trick or a powerful tool?

light side of monkey-patching

27

dark side of monkey-patching

Page 28: Monkey-patching in Python: a magic trick or a powerful tool?

dark side

Implicitness

Page 29: Monkey-patching in Python: a magic trick or a powerful tool?

dark side• Implicit changes

Page 30: Monkey-patching in Python: a magic trick or a powerful tool?

dark side• Implicit changes • Undocumented changes

Page 31: Monkey-patching in Python: a magic trick or a powerful tool?

dark side• Implicit changes • Undocumented changes • Unpredictable behaviour

Page 32: Monkey-patching in Python: a magic trick or a powerful tool?

dark side• Implicit changes • Undocumented changes • Unpredictable behaviour • Patching the same

Page 33: Monkey-patching in Python: a magic trick or a powerful tool?

examples

Page 34: Monkey-patching in Python: a magic trick or a powerful tool?

dark side: gevent

Page 35: Monkey-patching in Python: a magic trick or a powerful tool?

dark side: gevent• Patches standard modules

socket, thread, time and others

• Should be done as soon as possible

Page 36: Monkey-patching in Python: a magic trick or a powerful tool?

running code under debugger• Event loop in debugger

Based on threads

• Event loop in user’s code Based on gevent loop

They should be separated

Page 37: Monkey-patching in Python: a magic trick or a powerful tool?

the problemSave the original versions of modules and use them with the patched versions

Page 38: Monkey-patching in Python: a magic trick or a powerful tool?

importing in python# very simple versiondef import_module(name): if name in sys.modules: return sys.modules[name] module = internal_import(name) sys.modules[name] = module return module

Page 39: Monkey-patching in Python: a magic trick or a powerful tool?

save modulessaved_modules.py:import socket

# save the module object

save = sys.modules.pop('socket', None)

# it's not in sys.modules, reimport

import socket as socket_saved

# put the module available for patching

sys.modules['socket'] = save

Page 40: Monkey-patching in Python: a magic trick or a powerful tool?

save modulesfrom saved_modules import saved_socketimport socket# it will patch socket in sys.pathgevent.patch_socket()# the patched functionsocket.create_connection()

# the original functionsaved_socket.create_connection()

Page 41: Monkey-patching in Python: a magic trick or a powerful tool?

the problemSave the original versions of modules and use them with the patched versions

Solved!

Page 42: Monkey-patching in Python: a magic trick or a powerful tool?

● Implicit changes ● Undocumented

changes ● Broken readability ● Incompatibility with

other patches

● Workaround for bugs in third-party code

● Code instrumentation

● Testing

● Changing of standard modules

light side of monkey-patching

dark side of monkey-patching

Page 43: Monkey-patching in Python: a magic trick or a powerful tool?

when should i use it?

If and only if there are no other solutions for the problem

Page 44: Monkey-patching in Python: a magic trick or a powerful tool?

light side of monkey-patching

44

dark side of monkey-patching

Page 45: Monkey-patching in Python: a magic trick or a powerful tool?

light side of monkey-patching

45

dark side of monkey-patching

Elizaveta Shashkova @lisa_shashkova