twisted / twisted/twisted

twisted.python.monkey.MonkeyPatcher can't patch staticmethods

Open
#9,331 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug new priority-normal trial
Dominant language
Python
Stars
6k
Forks
1.2k
Avg merge
2d 10h
Merged PRs (30d)
10

Description

markrwilliams's avatar @markrwilliams reported
Trac ID trac#9331
Type defect
Created 2017-11-20 23:05:32Z

Sometimes it's convenient to attach a staticmethod to a class and then patch it out in a test, like so:

from twisted.trial import unittest

def free():
    print("A free function.")

class _ClassToTest(object):
    _someMethod = staticmethod(free)
    def api(self):
        self._someMethod()


class TestClass(unittest.SynchronousTestCase):
    def test_api(self):
        def fake(self):
            print("A fake.")
        self.patch(_ClassToTest, "_someMethod", fake)
    def test_broken(self):
        _ClassToTest.api()

But test_api breaks test_broken:

broken
  TestClass
    test_api ...                                                           [OK]
    test_broken ...                                                     [ERROR]

===============================================================================
[ERROR]
Traceback (most recent call last):
  File "broken.py", line 18, in test_broken
    _ClassToTest().api()
  File "broken.py", line 9, in api
    self._someMethod()
exceptions.TypeError: free() takes no arguments (1 given)

f.TestClass.test_broken
-------------------------------------------------------------------------------
Ran 2 tests in 0.015s

Because twisted.python.monkey.MonkeyPatcher.addPatch retrieves the original object with getattr and staticmethod descriptors return their wrapped free function when accessed on a class, patch can't patch staticmethods.

One solution would be to MonkeyPatch's use of getattr and setattr with __dict__ munging.

Searchable metadata
trac-id__9331 9331
type__defect defect
reporter__markrwilliams markrwilliams
priority__normal normal
milestone__None None
branch__ 
branch_author__ 
status__new new
resolution__None None
component__trial trial
keywords__None None
time__1511219132801019 1511219132801019
changetime__1511219568721385 1511219568721385
version__None None
owner__None None

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at twisted.python.monkey.MonkeyPatcher.addPatch and reproduce the staticmethod example from the issue. Check how the original attribute is retrieved and restored, then add coverage for patching a staticmethod while preserving existing patch behavior. Done means the shown test scenario no longer receives an unexpected argument.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing-qa
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.