A RenameMethodsBase metaclass is defined in the django.utils.deprecation module. It seems that Django uses it to deal with methods renaming. Below is a simplified explanation of how it works.
First we subclass the RenameMethodsBase to specify the old and new method names, as well as the type of warning. Then we use it as a metaclass on two classes Field1 and Field2.
import warnings warnings.simplefilter("always") from django.utils.deprecation import * class RenameFieldMethods(RenameMethodsBase): renamed_methods = ( ('_has_changed', 'has_changed', DeprecationWarning), ) class Field1(metaclass=RenameFieldMethods): def _has_changed(self): print('_has_changed') class Field2(metaclass=RenameFieldMethods): def has_changed(self): print('has_changed')
If we instantiate Field1 and call both old and new methods, the following results:
>>> f1 = Field1() >>> f1.has_changed() _has_changed >>> f1._has_changed() __main__:1: DeprecationWarning: `Field1._has_changed` is deprecated, use `has_changed` instead. _has_changed
On the other hand if we instantiate Field2 and call both old and new methods, the following results:
>>> f2 = t2.Field2() >>> f2.has_changed() has_changed >>> f2._has_changed() __main__:1: DeprecationWarning: `Field2._has_changed` is deprecated, use `has_changed` instead. has_changed
In short, both methods will succeed, but if called by the name of the old method, a warning is issued.