On Friday 15 September 2017 11:35:49 Shai Berger wrote: > On Friday 15 September 2017 11:09:58 Anssi Kääriäinen wrote: > > > > def simple_execute_hook(execute): > > # One-time configuration and initialization. > > > > def execute_hook(sql, params, many, context): > > # Code to be executed for each cursor.execute() call. > > # If many = True, the final call will be execute_many. > > # The context parameter might contain stuff like used > > # connection. > > execute(sql, params, many, context) > > # Code to be executed after the SQL has been ran. > > > > return execute_hook > > > > You would then add the hook with the connection's context manager. > > > > The reason I'm asking is that this way the coding style would be > > immediately familiar if you have used the request/response middlewares. > > That's an interesting suggestion. At first look, it seems a nicer API than > the context manager. I'm a little worried about how errors would be > handled, though.
Well, of course, error handling was a red herring. It's up to the hook author. But while looking deeper into it, I noted something else: The "One time configuration" part doesn't really make sense. I'll explain: Since the `execute` argument is really a method on a cursor object which, potentially, doesn't even exist when the hook is installed, it needs to be passed into simple_execute_hook() near invocation time, rather than at registration time; and in fact, within the scope of one hook registration, we may need to handle separate cursors. So, the external function must be called again for every execution. Thus, the difference between code in the "one time configuration" (actually, "each time configuration") part and code in the "code to execute before query" part becomes arcane and hard to explain. So, it becomes much more sensible to turn the hook into a wrapper, defined as: def execute_wrapper(execute, sql, params, many, context): # Code to be executed for each cursor.execute() call. # If many = True, the final call will be execute_many. # The context parameter might contain stuff like used # connection. result = execute(sql, params, many, context) # Code to be executed after the SQL has been ran. return result Or even: def execute_wrapper(execute, sql, params, many, context): try: # Code to be executed for each cursor.execute() call. return execute(sql, params, many, context) finally: # Code to be executed after the SQL has been ran. For this, I just need to figure out the currying of the execute parameter. Shai