Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is merging Python system classes with custom classes less desirable than hooking the import mechanism?

I am working on a project that aims to augment the Python socket messages with partial ordering information. The library I'm building is written in Python, and needs to be interposed on an existing system's messages sent through the socket functions.

I have read some of the resources out there, namely the answer by @Omnifarious at this question python-importing-from-builtin-library-when-module-with-same-name-exist

There is an extremely ugly and horrible thing you can do that does not involve hooking the import mechanism. This is something you should probably not do, but it will likely work. It turns your calendar module into a hybrid of the system calendar module and your calendar module.

I have implemented the import mechanism solution, but we have decided this is not the direction we'd like to take, since it relies too much on the environment. The solution to merge classes into a hybrid, rather than relying on the import mechanisms, seems to be the best approach in my case.

Why has the hybrid been called an ugly and horrible solution? I'd like to start implementing it in my project but I am wary of the warnings. It does seem a bit hackish, but since it would be part of an installation script, wouldn't it be OK to run this once?

Here is a code snippet where the interposition needs to intercept the socket message before it's sent:

class vector_clock:

  def __init__(self):
   """
   Initiate the clock with the object
   """
   self.clock = [0,0]

  def sendMessage(self):
   """
   Send Message to the server
   """
   self.msg = "This is the test message to that will be interposed on"
   self.vector_clock.increment(0) # We are clock position 0

   # Some extraneous formatting details removed for brevity….
   # connectAndSend needs interpositioning to include the vector clock

   self.client.connectAndSend(totalMsg);
   self.client.s.close()
like image 978
jspacek Avatar asked May 20 '14 17:05

jspacek


1 Answers

From my understanding of your post, you wish to modify the existing socket library to inject your own functionality into it.

Yes, this is completely doable, and possibly it is even the easiest solution to your problem, but you have to consider all of the implications of what you are doing.

The most important point is that you are not just modifying socket for yourself, but for anything that is run in any part of your process which uses the socket library unless it uses it's own class loader. I understand that there is probably some existing library you are using which uses socket and you want to inject this functionality into it, but this will affect EVERYTHING.

From this you have to consider the question: is your change 100% backwards compatible. Unless you can guarantee that you know every single use case of socket by any library used by your process (hint: you can't), then you need to make sure that it completely preserves all existing functionality or else somewhere down the road stuff in some core library is going to mysteriously break and you will have no idea why and no way to debug it. An example of something 100% backwards compatible (or as close as it is possible to get) is injecting a decorator which saves timing information to one of your own modules.

If you completely understand this and still think that your solution is a good one then I say "go for it". However, have you considered any alternatives?

If you just need to inject this functionality for a specific set of libraries that you use, then I would suggest doing something like patching: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch

You could subclass whatever core library you want to modify and then patch the library to use your class instead. At it's core, what patch does is it modifies the global bindings used in the target module to use a different class/module than the one it had originally used.

PS. I don't think yours is a situation which calls for hooking the import mechanism.

like image 136
Brendan F Avatar answered Oct 16 '22 16:10

Brendan F