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

Support freevars and methods that call mangled methods #68

Closed
wants to merge 12 commits into from

Conversation

graingert
Copy link
Contributor

@graingert graingert commented Mar 9, 2017

Fixes #67

patchy/api.py Outdated


def _indent(new_source):
return '\n'.join([' ' + x for x in new_source.split('\n')])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is broken in so many ways. It will mess up docstrings and functions that use tabs in py3k.

Copy link
Owner

Choose a reason for hiding this comment

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

mess up docstrings only slightly?

Also yes there will be a TabError, you could add a test for that

patchy/api.py Outdated
# Fetch the actual function we are changing
class_name = _class_name(func)
if class_name:
new_source = 'class {name}(object):\n{code}'.format(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

might be better to parse the code and do a find and replace with identifiers.

Turns out mangling works everywhere:

def _Artist__foo():
    return 'yo!'

class Artist(object):
    def method(self):
        return __foo()

def test_mangle():
    assert Artist().method() == 'yo!'

Copy link
Owner

Choose a reason for hiding this comment

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

find/replace sounds even more hacky

also that test_mangle is a bit of a WAT🦆

@adamchainz adamchainz changed the title WIP: support patching methods that call mangled methods Fixes #67 WIP: support patching methods that call mangled methods Mar 9, 2017
@@ -0,0 +1,7 @@
class Artist:
Copy link
Owner

Choose a reason for hiding this comment

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

pytest tmpdir instead to keep this inside the test function? you can always write \t in the string. just wary tabs might get complained about by future lint rules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's complained about by current lint rules

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah used the pytest tmpdir.


assert Artist().method() == "Cheese on toast"

@pytest.mark.xfail
Copy link
Owner

Choose a reason for hiding this comment

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

why does this fail? because the new method is compiled without the original _Artist__mangled_name in scope?

Copy link
Contributor Author

@graingert graingert Mar 11, 2017

Choose a reason for hiding this comment

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

yup, needed to fix freevars/closures. Interestingly it doesn't need to be the original _Artist__mangled_name, just any var with the same name.

@@ -148,25 +149,57 @@ def _get_source(func):
return source


def _set_source(func, new_source):
def _class_name(func):
Copy link
Owner

Choose a reason for hiding this comment

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

there's nothing in the stnadard library for this? 😢

Copy link
Contributor Author

Choose a reason for hiding this comment

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

func.im_class.__name__ but it was replaced with __qualname__ because __qualname__ is 'easier'

Copy link
Owner

Choose a reason for hiding this comment

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

Yeah I'm just sad so much parsing is needed on __qualname__

@graingert
Copy link
Contributor Author

@adamchainz worth splitting out the freevars stuff into a separate PR?

@graingert graingert force-pushed the methods-call-mangled branch 6 times, most recently from c3cf28c to 9087232 Compare March 11, 2017 12:53
@graingert graingert changed the title WIP: support patching methods that call mangled methods support patching methods that call mangled methods. Bonus: also support freevars Mar 11, 2017
@graingert
Copy link
Contributor Author

@adamchainz I think it's a good idea to release this as v2 just in case it breaks anyone

@graingert graingert force-pushed the methods-call-mangled branch 5 times, most recently from 036880f to 9087232 Compare March 11, 2017 14:45
tests/base.py Outdated

import patchy.api


class PatchyTestCase(unittest.TestCase):
def setUp(self):
class PatchyTestCase(object):
Copy link
Owner

Choose a reason for hiding this comment

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

can you put this unittest -> pytest stuff in a separate PR please, it's adding noise to this commit


assert Artist().method() == "Cheese on toast"

@unittest.skipUnless(six.PY3, "Python 3")
Copy link
Owner

Choose a reason for hiding this comment

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

the explanation should point out that it's super() that's Python 3 only

dont_inherit=True,
)

def _parse(code):
Copy link
Owner

Choose a reason for hiding this comment

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

this doesn't need to be an inner function

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It does to call _compile with the feature_flags freevar.

Copy link
Owner

Choose a reason for hiding this comment

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

so it does, I think I read it as calling compile, my bad

patchy/api.py Outdated
def _parse(code):
return _compile(code, flags=ast.PyCF_ONLY_AST)

class_name = _class_name(func)
Copy link
Owner

Choose a reason for hiding this comment

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

there is so much going on here now, i think we need it splitting into more functions and some comments added

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've split it into more functions and added doc strings.


assert sample()() == "Cheese on toast"

@pytest.mark.xfail(raises=NameError)
Copy link
Owner

Choose a reason for hiding this comment

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

I would be surprised if this could ever be made to work, but I guess never say never...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm pretty sure it could be done by digging around in the garbage collector. But it would be unreliable

@graingert graingert force-pushed the methods-call-mangled branch 3 times, most recently from cc4743d to 9087232 Compare March 13, 2017 10:05
@adamchainz adamchainz changed the title support patching methods that call mangled methods. Bonus: also support freevars Support freevars and methods that call mangled methods Mar 13, 2017
@graingert graingert force-pushed the methods-call-mangled branch 2 times, most recently from d98d403 to fd02557 Compare March 13, 2017 15:23
adamchainz pushed a commit that referenced this pull request Mar 13, 2017
@adamchainz
Copy link
Owner

Merged in 3de5de6, thanks!

@adamchainz adamchainz closed this Mar 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants