Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move patched methods to parent class #612

Merged

Conversation

comhar
Copy link
Contributor

@comhar comhar commented Aug 19, 2024

#609

This PR updates py2pyi so that patched methods are moved to their parent class. See #609 for more info.

TODO

  • verify that the general approach is reasonable
  • add unit tests
  • add multi-parent support

Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@comhar comhar marked this pull request as draft August 19, 2024 16:06
@comhar
Copy link
Contributor Author

comhar commented Aug 19, 2024

@jph00 I've taken a quick stab at #609.

If you think the general approach is ok, I'll go ahead and add:

  • support for nested classes (assuming we need to support this case)
  • unit tests.

I've been live testing using the example below.

Example
from fastcore.utils import patch


class A:
    def a(self, b, c):
        pass


class B:
    def b(self):
        pass


class C:
    def c(self):
        pass

    def c2(self):
        pass


@patch
def patch_a(self: A):
    pass


@patch
def a(self: A, x, y, z):
    pass


def unpatched_method():
    pass


@patch
def patch_a2(self: A):
    pass


@patch
def patch_c(self: C):
    pass


def unpatched_method2():
    pass

Here's the result.

Result
from fastcore.utils import patch

class A:

    def a(self, x, y, z):
        ...

    def patch_a(self):
        ...

    def patch_a2(self):
        ...

class B:

    def b(self):
        ...

class C:

    def c(self):
        ...

    def patch_c(self):
        ...

def some_f():
    ...

def some_f2():
    ...

@jph00
Copy link
Member

jph00 commented Aug 20, 2024

Well done -- very impressive! :D On nested classes -- I think it's fine to skip that, personally, unless it's easy to add with minimal complexity.

@comhar comhar force-pushed the feature/609-move-patched-methods-to-parent branch 4 times, most recently from aed83cf to e0c9bed Compare August 20, 2024 17:13
@comhar comhar force-pushed the feature/609-move-patched-methods-to-parent branch from e0c9bed to 4cc01bc Compare August 20, 2024 17:16
@comhar comhar marked this pull request as ready for review August 20, 2024 17:17
@comhar
Copy link
Contributor Author

comhar commented Aug 20, 2024

Well done -- very impressive! :D On nested classes -- I think it's fine to skip that, personally, unless it's easy to add with minimal complexity.

Thanks 😊. I've added unit tests and multi-parent support. I haven't explored nested classes. Might be better to handle that scenario in a separate issue (if at all) and keep this PR as concise as possible.

Note: I only added a single unit test for _proc_patches as the underlying methods in _proc_patches have good coverage and we should be able to catch future regressions by inspecting any changes to test_py2pyi.pyi.

Copy link
Contributor Author

@comhar comhar Aug 20, 2024

Choose a reason for hiding this comment

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

Both imports are now unused. Thoughts on creating a separate issue to remove them?

Copy link
Member

Choose a reason for hiding this comment

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

Sure feel free.

Copy link
Contributor Author

@comhar comhar Aug 20, 2024

Choose a reason for hiding this comment

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

As fastcore doesn't have any dependencies that automatically remove unused imports (correct me if I'm wrong) I took a quick look at rolling our own unused import remover (just for delegates and patches). While the code snippet below works, it is ~30 lines long and doesn't cover all import situations. No doubt there are cleaner solutions out there but given the small benefit of removing the imports, I guess it is probably better to leave things as is and not implement the import remover?

Unused Import Remover
def _remove_unused_imports(tree):
    "Remove patch/delegates imports if unused."
    should_remove_delegates_import = True
    should_remove_patch_import = True

    # let's check if the delegates and patch decorators are used
    for node in ast.walk(tree):
        if not hasattr(node, "decorator_list"):
            continue
        for deco in node.decorator_list:
            deco_id = _deco_id(deco)
            if deco_id == "delegates": should_remove_delegates_import = False
            elif deco_id == "patch": should_remove_patch_import = False
            # if both decorators are being used we can exit early
            if should_remove_delegates_import is False and should_remove_patch_import is False:
                return

    # let's remove the delegates and patch imports if they exist and are unused
    i = 0
    while i < len(tree.body):
        node = tree.body[i]
        # TODO: Are there other ways to import delegates and patch?
        if isinstance(node, ast.ImportFrom):
            for imp in node.names:
                if imp.name == "delegates" and should_remove_delegates_import:
                    tree.body.pop(i)
                    i -= 1
                    break
                elif imp.name == "patch" and should_remove_patch_import:
                    tree.body.pop(i)
                    i -= 1
                    break
        i += 1

@jph00 jph00 added the enhancement New feature or request label Aug 20, 2024
@jph00 jph00 merged commit 5a2498b into fastai:master Aug 20, 2024
12 checks passed
@jph00
Copy link
Member

jph00 commented Aug 20, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants