Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.

Extend patch decorator to add methods to class types#11932

Merged
giograno merged 6 commits intomasterfrom
extend-patch
Nov 27, 2024
Merged

Extend patch decorator to add methods to class types#11932
giograno merged 6 commits intomasterfrom
extend-patch

Conversation

@giograno
Copy link
Copy Markdown
Member

@giograno giograno commented Nov 26, 2024

Motivation

Our patch decorator easily allows us to patch a class method and extend its behavior.
However, it does not support the case where a given type does not implement a function and we want to add it.
Patch now would support the following use case:

@patch(MyClass)
def new_method(self, *args):
    # some implementation
    ...

c = MyClass()
c.new_method()

If the class already implements a method with the given name, the patch won't have any effect.
Like our current implementation, a patch can be easily undone:

new_method.patch.undo()
c.new_method() # raises AttributeError

Changes

  • Extending patch to support the use case of adding a new function to a class type;
  • Unit tests to verify the behavior of the new use case.

@giograno giograno added the semver: patch Non-breaking changes which can be included in patch releases label Nov 26, 2024
@giograno giograno marked this pull request as ready for review November 26, 2024 15:43
@github-actions
Copy link
Copy Markdown

github-actions bot commented Nov 26, 2024

LocalStack Community integration with Pro

    2 files  ±0      2 suites  ±0   1h 49m 17s ⏱️ +18s
3 733 tests ±0  3 387 ✅ ±0  346 💤 ±0  0 ❌ ±0 
3 735 runs  ±0  3 387 ✅ ±0  348 💤 ±0  0 ❌ ±0 

Results for commit 014281a. ± Comparison against base commit 0d02e67.

♻️ This comment has been updated with latest results.

Copy link
Copy Markdown
Member

@thrau thrau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice new feature! just a couple of comments regarding code organization and implementation details

Comment on lines +136 to +138
if inspect.isclass(target):
# Special case: when a class type is passed, we bound the function to the class type patching __getattr__
return Patch._extend_class(target, fn)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think having this check here doesn't make a ton of sense, since this is explicitly to patch functions. i think this check should be in patch

return self

@staticmethod
def _extend_class(target: Callable, fn: Callable):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would put this on the same footing as function

Suggested change
def _extend_class(target: Callable, fn: Callable):
def extend_class(target: Callable, fn: Callable):

Comment on lines +92 to +101
try:
self.old = getattr(self.obj, name)
if self.old and name == "__getattr__":
raise Exception("You can't patch class types implementing __getattr__")
except AttributeError as e:
# When we want to add a function to a class type, we want to intercept this exception and check if the
# name is `__getattr__`.
if name != "__getattr__":
raise e
self.old = None
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this check should be in apply so we don't cause exceptions while instantiating the object

@giograno giograno requested a review from thrau November 26, 2024 20:34
Copy link
Copy Markdown
Member

@thrau thrau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is much cleaner, thanks! just one minor nit that i missed, please just amend and merge :-)

return self

@staticmethod
def extend_class(target: Callable, fn: Callable):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: sorry i missed this, but the type hint should by Type, right?

@giograno giograno merged commit 1ff7a48 into master Nov 27, 2024
@giograno giograno deleted the extend-patch branch November 27, 2024 15:58
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

semver: patch Non-breaking changes which can be included in patch releases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants