12

I'm importing a library someone else made and I'm wanting to change the way a particular class method works from that library so I've copied the class method to my own file and wanting to replace it at runtime. This seems to work just fine for functions but seems to fall apart for class methods.

a.library.package.library_file.py

class LibraryClass(ParentClass):
 @classmethod
 def get_cost(cls, time):
 return int(time * cls.hourly)

I'm wanting to replace it with this

class LibraryClass(ParentClass):
 @classmethod
 def get_cost(cls, time):
 return 1234

I've tried to just do a normal replace which works just fine for regular functions

import a.library.package.library_file
...
a.library.package.library_file.LibraryClass.get_cost = get_cost

But it doesn't seem to work right at all, the method is called with the wrong arguments at the wrong time and results in a crash. After some research on Google, StackOverflow, and Python I began trying to use the mock classes.

from unittest.mock import patch
@patch.object('a.library.package.library_file.LibraryClass', 'get_cost')
def get_cost(cls, time):
 return 1234

The good news is it doesn't crash, bad news is it doesn't do anything, the old code is still there and it's like my code doesn't exist.

I've tried all kinds of other ways to do this such as

import a.library.package.library_file
@patch.object(a.library.package.library_file.LibraryClass, 'get_cost')
...

or

from a.library.package.library_file import LibraryClass
@patch.object(LibraryClass, 'get_cost')
...

but every time the method is never touched. It's like my code doesn't exist and the old code is used.

halfer
20.2k19 gold badges110 silver badges207 bronze badges
asked Sep 25, 2020 at 18:14

2 Answers 2

22

It turns out the solution was simple as I thought it might be. It took more than a day of digging and there's just no help anywhere online but I found an obscure random post from china on page 2 of Google which finally answered my question. Link Here

This is the resulting code that works

from types import MethodType
from a.library.package.library_file.py import LibraryClass
def get_cost(cls, time):
 return 1234
LibraryClass.get_cost = MethodType(get_cost, LibraryClass)

It's the same as replacing a function only you need to wrap it in "MethodType" because the code your swapping out has "classmethod" ties to the class and so the new code needs to be tied the same in order to work.

Dharman
33.9k27 gold badges103 silver badges154 bronze badges
answered Sep 25, 2020 at 22:22
Sign up to request clarification or add additional context in comments.

2 Comments

I think it's even a little simpler, just LibraryClass.get_cost = classmethod(get_cost).
The suggestion from @rascalking is not just simpler - it works in situations where the MethodType approach does not - e.g. for subclasses, the cls argument is correctly set to the subclass when using classmethod but is always set to the base class if you use MethodType.
2

Can you just import the original class and create your own class that inherits from the original class ? Then you redefine the method that you want to override and just use your custom class instead of the original class:

from a_library import LibraryClass
class YourClass(LibraryClass):
 @classmethod
 def get_cost(cls, time):
 # redefine the method here
 return 1234
cost = YourClass.get_cost(time)

Then just use YourClass instead of the library class. It will behave exactly like the library class, but with your method instead of the original method.

answered Sep 25, 2020 at 18:40

4 Comments

No because many other code uses the class from the library. I'm trying to change some code for an existing system so I need all instances of that class and other code that uses it to begin using my code instead. This is the reason why I'm replacing the code and not just overriding it.
Ok, did you install the library you're modifying with pip ?
I didn't, I'm making a python plugin for an existing system.
To make the approach in this answer work, you could have followed up by monkey-patching the original LibraryClass with YourClass.get_cost.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.