What's a hook?
Hook function (hook function), can be understood as a hook, the role is to have the need to hang a thing up. Specifically explained: hook function is our own implementation of the hook function at a certain time hooked to the target mount point.
Hook application scenarios (I)
I'm sure you're no stranger to hook functions. I've seen similar designs in requests and mitmproxy.
requests Using hooks
For example, requests requires a status code to be printed:
# requests_hooks.py import requests r = ("/get") print(f"status doce: {r.status_code}")
Printing the status code is an action that we can encapsulate in a function and pass as a hook function for requests to use.
# requests_hooks.py import requests def status_code(response, *args, **kwargs): print(f"hook status doce: {response.status_code}") r = ("/get", hooks={"response": status_code})
Code Description:
Encapsulate the print status code into a status_code() function that receives the hook function status_code() in the () method via the hooks argument.
Run results:
> python requests_hooks.py
hook status doce: 200
status_code()
As a function, you can do a lot of things, for example, further determine the status code, print the response data, and even do encryption and decryption and other processing of the corresponding data.
Hooks in mitmproxy
mitmproxy is a proxy tool, which we have also introduced in this previous article. In the process of grabbing packets, you also need to use hooks to do some additional processing of request or response.
# """ Basic skeleton of a mitmproxy addon. Run as follows: mitmproxy -s """ import logging class Counter: def __init__(self): = 0 def request(self, flow): = + 1 ("We've seen %d flows" % ) addons = [Counter()]
Running mitmproxy
> mitmproxy -s
Implement the hook yourself
What is the case when you need to implement a hook is that a function (class/method) cannot satisfy all the requirements by itself, so you can provide the possibility to extend your own capabilities by using a hook.
Implementing a hook isn't difficult, see the example:
import time class Programmer(object): """Programmer.""" def __init__(self, name, hook=None): = name self.hooks_func = hook self.now_date = ("%Y-%m-%d") def get_to_eat(self): print(f"{} - {self.now_date}: eat.") def go_to_code(self): print(f"{} - {self.now_date}: code.") def go_to_sleep(self): print(f"{} - {self.now_date}: sleep.") def everyday(self): # Three things programmers do every day self.get_to_eat() self.go_to_code() self.go_to_sleep() # check the register_hook(hooked or unhooked) # hooked if self.hooks_func is not None: self.hooks_func() def play_game(name): now_date = ("%Y-%m-%d") print(f"{name} - {now_date}: play game.") def shopping(name): now_date = ("%Y-%m-%d") print(f"{name} - {now_date}: shopping.") if __name__ == "__main__": # hook passed as an argument tom = Programmer("Tom", hook=play_game) jerry = Programmer("Jerry", hook=shopping) spike = Programmer("Spike") # The thing of the day () () ()
Code Description.
In the above example the Programmer class implements three functions: eat, code, and sleep, but programmers are ordinary people and can't just eat, code, and sleep every day, so the ability to do something else is provided through register_hook().
So, let's see what the three main characters, Tom, Jerry, and Spike, have done today!
Run results:
Tom - 2022-12-01: eat.
Tom - 2022-12-01: code.
Tom - 2022-12-01: sleep.
Tom - 2022-12-01: play game.
Jerry - 2022-12-01: eat.
Jerry - 2022-12-01: code.
Jerry - 2022-12-01: sleep.
Jerry - 2022-12-01: shopping.
Spike - 2022-12-01: eat.
Spike - 2022-12-01: code.
Spike - 2022-12-01: sleep.
Hook application scenarios (II)
If you understand hook as: defining a function and stuffing it as an argument to another class/method. Obviously, this is only one usage. I've rethought it a bit. httpRunner's file; pytest's
files, which are themselves hook files with special names. During execution, the program calls the hook functions in these files to accomplish some special tasks.
Take pytest as an example
└───project ├─── └───test_sample.py
import pytest @() def baidu_url(): """Defining Hook Functions""" return ""
- test_sample.py
import webbrowser def test_open_url(baidu_url): # call baidu_url hook function # call the browser to access baidu_url webbrowser.open_new(baidu_url)
The two files do not appear to have a direct calling relationship, and when executing thetest_sample.py
file, you can indirectly call the in the file
baidu_url()
Hook function.
execute a test
> pytest -q test_sample.py
Implementing a dynamic call to hook
Next, let's try to make a similar function out of it.
└───project ├───run_conf.py ├─── └───
- run_conf.py
def baidu_url(): """Defining Hook Functions""" name = "" return name
together with file is similar, and the hook function is implemented in this file.
import os import inspect import importlib def loader(name): """ Dynamic execution of hook functions """ # Directory of the called file stack_t = () ins = (stack_t[1][0]) file_dir = (()) # The *_conf.py file in the directory of the called file. all_hook_files = list(filter(lambda x: ("_conf.py"), (file_dir))) all_hook_module = list(map(lambda x: (".py", ""), all_hook_files)) # Dynamically load *_config.py hooks = [] for module_name in all_hook_module: (importlib.import_module(module_name)) # Look up and execute the name function from the *_conf.py file based on the name function name passed to it. for per_hook in hooks: # Execute process functions dynamically func = getattr(per_hook, name) return func()
It's a little more complicated. What he does is he throws in a function name, and he can pass it through the*_conf.py
file to find the corresponding function name and return the result of the function execution.
loader()
A function is a generic thing that you can put to use anywhere.
import webbrowser from loader import loader def test_open_url(): # call baidu_url hook function # call the browser to access baidu_url url = loader("baidu_url") webbrowser.open_new(url) if __name__ == '__main__': test_open_url()
pass (a bill or inspection etc)loader()
function executionbaidu_url
hook function and get the url.
Note that we don't need the traditional way offrom run_conf import baidu_url
Import the module, as long as you know the name of the hook function.
The implementation here is not as elegant as pytest, but it's close.
to this article on the use of python powerful hook function and application scenarios are introduced to this article, more related to the use of python hook function content, please search for my previous articles or continue to browse the following related articles I hope that you will support me more in the future!