def test_patch_freevars_order(): def tastes_good(v): return v + ' tastes good' def tastes_bad(v): return v + ' tastes bad' def sample(): return ', '.join([ tastes_good('Cheese'), tastes_bad('Chalk'), ]) patchy.patch( sample, """\ @@ -1,4 +1,4 @@ def sample(): return ', '.join([ - tastes_good('Cheese'), - tastes_bad('Chalk'), + tastes_bad('Chalk'), + tastes_good('Cheese'), )] """) assert sample() == 'Chalk tastes bad, Cheese tastes good'
def test_patch_init_module_level(tmpdir): """ Module level classes do not have a freevar for their class name, whilst classes defined in a scope do... """ example_py = tmpdir.join('example.py') example_py.write( dedent('''\ class Person(object): def __init__(self): self.base_prop = 'yo' class Artist(Person): def __init__(self): super(Artist, self).__init__() self.prop = 'old' ''')) mod = example_py.pyimport() Artist = mod.Artist patchy.patch( Artist.__init__, """\ @@ -1,3 +1,3 @@ def __init__(self): super(Artist, self).__init__() - self.prop = 'old' + self.prop = 'new' """) a = Artist() assert a.base_prop == 'yo' assert a.prop == 'new'
def test_patch_unpatch(): def sample(): return 1 patch_text = """\ @@ -1,2 +1,2 @@ def sample(): - return 1 + return 9001 """ patchy.patch(sample, patch_text) assert sample() == 9001 # Check that we use the cache orig_mkdtemp = patchy.api.mkdtemp def mkdtemp(*args, **kwargs): raise AssertionError( "mkdtemp should not be called, the unpatch should be cached.") try: patchy.api.mkdtemp = mkdtemp patchy.unpatch(sample, patch_text) finally: patchy.api.mkdtemp = orig_mkdtemp assert sample() == 1 # Check that we use the cache going forwards again try: patchy.api.mkdtemp = mkdtemp patchy.patch(sample, patch_text) finally: patchy.api.mkdtemp = orig_mkdtemp assert sample() == 9001
def test_patch_invalid_hunk_2(self): """ We need to balk on patches that fail on application """ def sample(): if True: print("yes") if False: print("no") return 1 bad_patch = """\ @@ -1,2 +1,2 @@ def sample(): - if True: + if False: @@ -3,5 +3,5 @@ print("yes") - if Falsy: + if Truey: print("no") """ with pytest.raises(ValueError) as excinfo: patchy.patch(sample, bad_patch) print(excinfo.value) assert "Hunk #2 FAILED" in str(excinfo.value) assert sample() == 1
def test_patch_future_instancemethod_python_3_6(tmpdir): tmpdir.join("future_instancemethod.py").write( dedent("""\ from __future__ import generator_stop def f(x): raise StopIteration() class Sample(object): def meth(self): return list(f(x) for x in range(10)) """)) sys.path.insert(0, str(tmpdir)) try: from future_instancemethod import Sample finally: sys.path.pop(0) with pytest.raises(RuntimeError): Sample().meth() patchy.patch( Sample.meth, """\ @@ -1,2 +1,3 @@ def meth(self): + pass return list(f(x) for x in range(10)) """, ) with pytest.raises(RuntimeError): Sample().meth()
def test_patch_freevars_nested(): def free_func(v): return v + " on toast" def sample(): filling = "Chalk" def _inner_func(): return free_func(filling) return _inner_func patchy.patch( sample, """\ @@ -1,2 +1,2 @@ def sample(): - filling = "Chalk" + filling = "Cheese" def _inner_func(): """, ) assert sample()() == "Cheese on toast"
def test_patch_nonlocal_fails(tmpdir): # Put in separate file since it would SyntaxError on Python 2 tmpdir.join('py3_nonlocal.py').write(dedent("""\ variab = 20 def get_function(): variab = 15 def sample(): nonlocal variab multiple = 3 return variab * multiple return sample sample = get_function() """)) sys.path.insert(0, six.text_type(tmpdir)) try: from py3_nonlocal import sample with pytest.raises(SyntaxError) as excinfo: patchy.patch(sample, """\ @@ -2,3 +2,3 @@ nonlocal variab - multiple = 3 + multiple = 4 """) assert "no binding for nonlocal 'variab' found" in str(excinfo.value) finally: sys.path.pop()
def test_patch_future_instancemethod(tmpdir): tmpdir.join('future_instancemethod.py').write( dedent("""\ from __future__ import unicode_literals class Sample(object): def meth(self): return type('example string') """)) sys.path.insert(0, six.text_type(tmpdir)) try: from future_instancemethod import Sample finally: sys.path.pop(0) assert Sample().meth() is six.text_type patchy.patch( Sample.meth, """\ @@ -1,2 +1,3 @@ def meth(self): + pass return type('example string') """) assert Sample().meth() is six.text_type
def test_patch_future_doesnt_inherit(tmpdir): # This test module has 'division' imported, test file doesn't assert division tmpdir.join('no_future_division.py').write( dedent("""\ def sample(): return 1 / 2 """)) sys.path.insert(0, six.text_type(tmpdir)) try: from no_future_division import sample finally: sys.path.pop(0) assert sample() == 0 patchy.patch( sample, """\ @@ -1,2 +1,3 @@ def sample(): + pass return 1 / 2 """) assert sample() == 0
def test_patch_future(tmpdir): tmpdir.join('future_user.py').write( dedent("""\ from __future__ import unicode_literals def sample(): return type('example string') """)) sys.path.insert(0, six.text_type(tmpdir)) try: from future_user import sample finally: sys.path.pop(0) assert sample() is six.text_type patchy.patch( sample, """\ @@ -1,2 +1,3 @@ def sample(): + pass return type('example string') """) assert sample() is six.text_type
def _patch(self): import patchy import sage.rings.function_field.function_field_valuation patchy.patch( sage.rings.function_field.function_field_valuation. FunctionFieldValuationFactory. create_key_and_extra_args_from_valuation, r""" @@ -310,7 +320,7 @@ class FunctionFieldValuationFactory(UniqueFactory): # and easier pickling) we need to find a normal form of # valuation, i.e., the smallest approximant that describes this # valuation - approximants = vK.mac_lane_approximants(domain.polynomial()) + approximants = vK.mac_lane_approximants(domain.polynomial(), require_incomparability=True) approximant = vK.mac_lane_approximant(domain.polynomial(), valuation, approximants) return (domain, approximant), {'approximants': approximants} else: """) patchy.patch( sage.rings.function_field.function_field_valuation. DiscreteFunctionFieldValuation_base.extensions, r""" @@ -544,7 +554,7 @@ class DiscreteFunctionFieldValuation_base(DiscreteValuation): if type(y_to_u) == RingHomomorphism_im_gens and type(u_to_y) == RingHomomorphism_im_gens: return [L.valuation((w, L.hom([M(y_to_u(y_to_u.domain().gen()))]), M.hom([L(u_to_y(u_to_y.domain().gen()))]))) for w in H_extensions] raise NotImplementedError - return [L.valuation(w) for w in self.mac_lane_approximants(L.polynomial())] + return [L.valuation(w) for w in self.mac_lane_approximants(L.polynomial(), require_incomparability=True)] elif L.base() is not L and K.is_subring(L): # recursively call this method for the tower of fields from operator import add """)
def test_patch_freevars_order(): def tastes_good(v): return v + ' tastes good' def tastes_bad(v): return v + ' tastes bad' def sample(): return ', '.join([ tastes_good('Cheese'), tastes_bad('Chalk'), ]) patchy.patch(sample, """\ @@ -1,4 +1,4 @@ def sample(): return ', '.join([ - tastes_good('Cheese'), - tastes_bad('Chalk'), + tastes_bad('Chalk'), + tastes_good('Cheese'), )] """) assert sample() == 'Chalk tastes bad, Cheese tastes good'
def _patch(self): import patchy import sage.rings.valuation.inductive_valuation patchy.patch( sage.rings.valuation.inductive_valuation. NonFinalInductiveValuation.mac_lane_step, r""" @@ -771,18 +780,6 @@ class NonFinalInductiveValuation(FiniteInductiveValuation, DiscreteValuation): assert len(F) == 1 break - if phi == self.phi(): - # a factor phi in the equivalence decomposition means that we - # found an actual factor of G, i.e., we can set - # v(phi)=infinity - # However, this should already have happened in the last step - # (when this polynomial had -infinite slope in the Newton - # polygon.) - if self.is_gauss_valuation(): # unless in the first step - pass - else: - continue - verbose("Determining the augmentation of %s for %s"%(self, phi), level=11) old_mu = self(phi) w = self.augmentation(phi, old_mu, check=False) """)
def test_patch_future_twice(tmpdir): tmpdir.join('future_twice.py').write(dedent("""\ from __future__ import unicode_literals def sample(): return type('example string') """)) sys.path.insert(0, six.text_type(tmpdir)) try: from future_twice import sample finally: sys.path.pop(0) assert sample() is six.text_type patchy.patch(sample, """\ @@ -1,2 +1,3 @@ def sample(): + pass return type('example string 2') """) assert sample() is six.text_type patchy.patch(sample, """\ @@ -1,3 +1,4 @@ def sample(): pass + pass return type('example string 2') """) assert sample() is six.text_type
def test_patch_future_instancemethod(tmpdir): tmpdir.join('future_instancemethod.py').write(dedent("""\ from __future__ import unicode_literals class Sample(object): def meth(self): return type('example string') """)) sys.path.insert(0, six.text_type(tmpdir)) try: from future_instancemethod import Sample finally: sys.path.pop(0) assert Sample().meth() is six.text_type patchy.patch(Sample.meth, """\ @@ -1,2 +1,3 @@ def meth(self): + pass return type('example string') """) assert Sample().meth() is six.text_type
def test_patch_future_python_3_6(tmpdir): tmpdir.join("future_user.py").write( dedent("""\ from __future__ import generator_stop def f(x): raise StopIteration() def sample(): return list(f(x) for x in range(10)) """)) sys.path.insert(0, str(tmpdir)) try: from future_user import sample finally: sys.path.pop(0) with pytest.raises(RuntimeError): sample() patchy.patch( sample, """\ @@ -1,2 +1,3 @@ def sample(): + pass return list(f(x) for x in range(10)) """, ) with pytest.raises(RuntimeError): sample()
def test_patch_staticmethod_twice(): class Doge: @staticmethod def bark(): return "Woof" patchy.patch( Doge.bark, """\ @@ -1,3 +1,3 @@ @staticmethod def bark(): - return "Woof" + return "Wow\"""", ) patchy.patch( Doge.bark, """\ @@ -1,3 +1,3 @@ @staticmethod def bark(): - return "Wow" + return "Wowowow\"""", ) assert Doge.bark() == "Wowowow"
def test_patch_invalid_hunk_2(): """ We need to balk on patches that fail on application """ def sample(): if True: print("yes") if False: print("no") return 1 bad_patch = """\ @@ -1,2 +1,2 @@ def sample(): - if True: + if False: @@ -3,5 +3,5 @@ print("yes") - if Falsy: + if Truey: print("no") """ with pytest.raises(ValueError) as excinfo: patchy.patch(sample, bad_patch) assert "Hunk #2 FAILED" in str(excinfo.value) assert sample() == 1
def test_patch_invalid(): """ We need to balk on empty patches """ def sample(): return 1 bad_patch = """garbage """ with pytest.raises(ValueError) as excinfo: patchy.patch(sample, bad_patch) msg = str(excinfo.value) expected = dedent("""\ Could not apply the patch to 'sample'. The message from `patch` was: patch: **** Only garbage was found in the patch input. The code to patch was: def sample(): return 1 The patch was: garbage """) assert msg == expected assert sample() == 1
def test_patch_instancemethod_twice(): class Artist: def method(self): return "Chalk" patchy.patch( Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): - return "Chalk" + return "Cheese" """, ) patchy.patch( Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): - return "Cheese" + return "Crackers" """, ) assert Artist().method() == "Crackers"
def test_patch_future_instancemethod_python_3_7_plus(tmpdir): tmpdir.join("future_instancemethod.py").write( dedent("""\ from __future__ import annotations class Sample(object): def meth(self): pass """)) sys.path.insert(0, str(tmpdir)) try: from future_instancemethod import Sample finally: sys.path.pop(0) assert Sample.meth.__code__.co_flags & __future__.annotations.compiler_flag patchy.patch( Sample.meth, """\ @@ -1,2 +1,3 @@ def meth(self): + pass pass """, ) assert Sample.meth.__code__.co_flags & __future__.annotations.compiler_flag
def test_patch_instancemethod_mangled_tabs(tmpdir): tmpdir.join("tabs_mangled.py").write( dedent("""\ class Artist: \tdef __mangled_name(self, v): \t\treturn v + ' on toast' \tdef method(self): \t\tfilling = 'Chalk' \t\treturn self.__mangled_name(filling) """)) sys.path.insert(0, str(tmpdir)) try: from tabs_mangled import Artist finally: sys.path.pop(0) patchy.patch( Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): -\tfilling = 'Chalk' +\tfilling = 'Cheese' \treturn __mangled_name(filling) """, ) assert Artist().method() == "Cheese on toast"
def test_patch_recursive_module_level(tmpdir): """ Module level recursive functions do not have a freevar for their name, whilst functions defined in a scope do... """ example_py = tmpdir.join('patch_recursive_module_level.py') example_py.write(dedent("""\ def factorial(n): if n == 1: return 1 else: return n * factorial(n-1) """)) mod = example_py.pyimport() factorial = mod.factorial assert factorial(10) == 3628800 patchy.patch(factorial, """\ @@ -2,4 +2,4 @@ - if n == 1: - return 1 - else: - return n * factorial(n-1) + if n <= 1: + return n + else: + return factorial(n-1) + factorial(n-2) """) assert factorial(10) == 55 assert factorial == mod.factorial
def test_patch_init_module_level(tmpdir): """ Module level classes do not have a freevar for their class name, whilst classes defined in a scope do... """ example_py = tmpdir.join('patch_init_module_level.py') example_py.write(dedent('''\ class Person(object): def __init__(self): self.base_prop = 'yo' class Artist(Person): def __init__(self): super(Artist, self).__init__() self.prop = 'old' ''')) mod = example_py.pyimport() Artist = mod.Artist patchy.patch(Artist.__init__, """\ @@ -1,3 +1,3 @@ def __init__(self): super(Artist, self).__init__() - self.prop = 'old' + self.prop = 'new' """) a = Artist() assert mod.Artist == Artist assert a.base_prop == 'yo' assert a.prop == 'new'
def test_patch_by_path_already_imported(tmpdir): package = tmpdir.mkdir("patch_by_path_pkg2") package.join("__init__.py").ensure(file=True) package.join("mod.py").write( dedent("""\ class Foo(object): def sample(self): return 1 """)) sys.path.insert(0, str(tmpdir)) try: from patch_by_path_pkg2.mod import Foo assert Foo().sample() == 1 patchy.patch( "patch_by_path_pkg2.mod.Foo.sample", """\ @@ -2,2 +2,2 @@ - return 1 + return 2 """, ) finally: sys.path.pop(0) assert Foo().sample() == 2
def test_patch_nonlocal_fails(tmpdir): # Put in separate file since it would SyntaxError on Python 2 tmpdir.join('py3_nonlocal.py').write(dedent("""\ variab = 20 def get_function(): variab = 15 def sample(): nonlocal variab multiple = 3 return variab * multiple return sample sample = get_function() """)) sys.path.insert(0, six.text_type(tmpdir)) try: from py3_nonlocal import sample finally: sys.path.pop(0) assert sample() == 15 * 3 patchy.patch(sample, """\ @@ -2,3 +2,3 @@ nonlocal variab - multiple = 3 + multiple = 4 """) assert sample() == 15 * 4
def test_patch_classmethod_twice(self): class Emotion(object): def __init__(self, name): self.name = name @classmethod def create(cls, name): return cls(name) patchy.patch(Emotion.create, """\ @@ -1,2 +1,3 @@ @classmethod def create(cls, name): + name = name.title() return cls(name)""") patchy.patch(Emotion.create, """\ @@ -1,3 +1,3 @@ @classmethod def create(cls, name): - name = name.title() + name = name.lower() return cls(name)""") assert Emotion.create("happy").name == "happy" assert Emotion.create("Happy").name == "happy" assert Emotion.create("HAPPY").name == "happy"
def test_patch_classmethod_twice(): class Emotion: def __init__(self, name): self.name = name @classmethod def create(cls, name): return cls(name) patchy.patch( Emotion.create, """\ @@ -1,2 +1,3 @@ @classmethod def create(cls, name): + name = name.title() return cls(name)""", ) patchy.patch( Emotion.create, """\ @@ -1,3 +1,3 @@ @classmethod def create(cls, name): - name = name.title() + name = name.lower() return cls(name)""", ) assert Emotion.create("happy").name == "happy" assert Emotion.create("Happy").name == "happy" assert Emotion.create("HAPPY").name == "happy"
def test_patch_instancemethod_mangled_tabs(tmpdir): tmpdir.join('tabs_mangled.py').write(dedent("""\ class Artist: \tdef __mangled_name(self, v): \t\treturn v + ' on toast' \tdef method(self): \t\tfilling = 'Chalk' \t\treturn self.__mangled_name(filling) """)) sys.path.insert(0, six.text_type(tmpdir)) try: from tabs_mangled import Artist finally: sys.path.pop(0) patchy.patch(Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): -\tfilling = 'Chalk' +\tfilling = 'Cheese' \treturn __mangled_name(filling) """) assert Artist().method() == "Cheese on toast"
def test_patch_future_python_3_7_plus(tmpdir): tmpdir.join("future_user.py").write( dedent("""\ from __future__ import annotations def sample(): pass """)) sys.path.insert(0, str(tmpdir)) try: from future_user import sample finally: sys.path.pop(0) assert sample.__code__.co_flags & __future__.annotations.compiler_flag patchy.patch( sample, """\ @@ -1,2 +1,3 @@ def sample(): + pass pass """, ) assert sample.__code__.co_flags & __future__.annotations.compiler_flag
def _patch(self): import patchy import sage.rings.function_field.function_field_valuation patchy.patch( sage.rings.function_field.function_field.RationalFunctionField. _factor_univariate_polynomial, r""" @@ -2580,7 +2574,10 @@ class RationalFunctionField(FunctionField): if old_variable_name != a.variable_name(): a = a.change_variable_name(old_variable_name) unit *= (c**e) - w.append((a,e)) + if a.is_unit(): + unit *= a**e + else: + w.append((a,e)) from sage.structure.factorization import Factorization return Factorization(w, unit=unit) """) import sage.rings.polynomial.multi_polynomial_element patchy.patch( sage.rings.polynomial.multi_polynomial_element. MPolynomial_polydict.factor, r""" @@ -1715,6 +1729,10 @@ class MPolynomial_polydict(Polynomial_singular_repr, MPolynomial_element): F = base_ring(self).factor() return Factorization([(R(f),m) for f,m in F], unit=F.unit()) + base_ring = self.base_ring() + if hasattr(base_ring, '_factor_multivariate_polynomial'): + return base_ring._factor_multivariate_polynomial(self, proof=proof) + # try to use univariate factoring try: F = self.univariate_polynomial().factor() """) import sage.rings.polynomial.polynomial_quotient_ring def PolynomialQuotientRing_generic__factor_multivariate_polynomial( self, f, proof=True): from sage.structure.factorization import Factorization if f.is_zero(): raise ValueError("factorization of 0 not defined") from_isomorphic_ring, to_isomorphic_ring, isomorphic_ring = self._isomorphic_ring( ) g = f.map_coefficients(to_isomorphic_ring) F = g.factor() unit = f.parent( from_isomorphic_ring(F.unit().constant_coefficient())) return Factorization( [(factor.map_coefficients(from_isomorphic_ring), e) for factor, e in F], unit=unit) sage.rings.polynomial.polynomial_quotient_ring.PolynomialQuotientRing_generic._factor_multivariate_polynomial = PolynomialQuotientRing_generic__factor_multivariate_polynomial
def test_patch_simple_no_newline(self): def sample(): return 1 patchy.patch(sample, """\ @@ -2,2 +2,2 @@ - return 1 + return 2""") assert sample() == 2
def test_patch_simple_no_newline(): def sample(): return 1 patchy.patch( sample, """\ @@ -2,2 +2,2 @@ - return 1 + return 2""") assert sample() == 2
def test_patch(self): def sample(): return 1 patchy.patch(sample, """\ @@ -1,2 +1,2 @@ def sample(): - return 1 + return 9001 """) assert sample() == 9001
def patch_Query(): patchy.patch(Query.add_extra, """\ @@ -13,7 +13,7 @@ param_iter = iter(select_params) else: param_iter = iter([]) - for name, entry in select.items(): + for name, entry in sorted(select.items()): entry = force_text(entry) entry_params = [] pos = entry.find("%s") """)
def test_patch(): def sample(): return 1 patchy.patch( sample, """\ @@ -1,2 +1,2 @@ def sample(): - return 1 + return 9001 """) assert sample() == 9001
def test_patch_nonlocal_fails(self): # Kept in separate file since it would SyntaxError on Python 2 from py3_nonlocal import sample with pytest.raises(SyntaxError) as excinfo: patchy.patch(sample, """\ @@ -2,3 +2,3 @@ nonlocal variab - multiple = 3 + multiple = 4 """) assert "no binding for nonlocal 'variab' found" in str(excinfo.value)
def patch_QuerySet(): patchy.patch(QuerySet.annotate, """\ @@ -17,7 +17,7 @@ except (AttributeError, TypeError): raise TypeError("Complex annotations require an alias") annotations[arg.default_alias] = arg - annotations.update(kwargs) + annotations.update(sorted(kwargs.items())) clone = self._clone() names = self._fields """)
def test_patch_instancemethod(self): class Artist(object): def method(self): return 'Chalk' patchy.patch(Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): - return 'Chalk' + return 'Cheese' """) assert Artist().method() == "Cheese"
def test_patch_future(self): from python2_future import sample assert sample() is unicode patchy.patch(sample, """\ @@ -1,2 +1,3 @@ def sample(): + pass return type('example string') """) assert sample() is unicode
def test_patch_init(): class Artist(object): def __init__(self): self.prop = 'old' patchy.patch(Artist.__init__, """\ @@ -1,2 +1,2 @@ def __init__(self): - self.prop = 'old' + self.prop = 'new'""") a = Artist() assert a.prop == 'new'
def test_patch_future_instancemethod(self): from python2_future import Sample assert Sample().meth() is unicode patchy.patch(Sample.meth, """\ @@ -1,2 +1,3 @@ def meth(self): + pass return type('example string') """) assert Sample().meth() is unicode
def test_patch_init(): class Artist(object): def __init__(self): self.prop = 'old' patchy.patch( Artist.__init__, """\ @@ -1,2 +1,2 @@ def __init__(self): - self.prop = 'old' + self.prop = 'new'""") a = Artist() assert a.prop == 'new'
def test_patch_init_change_arg(): class Artist(object): def __init__(self): self.prop = 'old' patchy.patch(Artist.__init__, """\ @@ -1,2 +1,2 @@ -def __init__(self): - self.prop = 'old' +def __init__(self, arg): + self.prop = arg""") a = Artist('new') assert a.prop == 'new'
def _patch(self): import patchy import sage.rings.valuation.inductive_valuation patchy.patch( sage.rings.valuation.inductive_valuation. NonFinalInductiveValuation.equivalence_decomposition, r""" @@ -1209,7 +1209,7 @@ class NonFinalInductiveValuation(FiniteInductiveValuation, DiscreteValuation): v = self.extension(domain) ret = v.equivalence_decomposition(v.domain()(f)) return Factorization([(self._eliminate_denominators(g), e) - for (g,e) in ret], unit=self._eliminate_denominators(ret.unit())) + for (g,e) in ret], unit=self._eliminate_denominators(ret.unit()), sort=False) """)
def test_patch_staticmethod(self): class Doge(object): @staticmethod def bark(): return "Woof" patchy.patch(Doge.bark, """\ @@ -1,3 +1,3 @@ @staticmethod def bark(): - return "Woof" + return "Wow\"""") assert Doge.bark() == "Wow"
def test_patch_instancemethod(): class Artist(object): def method(self): return 'Chalk' patchy.patch( Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): - return 'Chalk' + return 'Cheese' """) assert Artist().method() == "Cheese"
def test_patch_staticmethod(): class Doge(object): @staticmethod def bark(): return "Woof" patchy.patch( Doge.bark, """\ @@ -1,3 +1,3 @@ @staticmethod def bark(): - return "Woof" + return "Wow\"""") assert Doge.bark() == "Wow"
def test_patch_init_change_arg(): class Artist(object): def __init__(self): self.prop = 'old' patchy.patch( Artist.__init__, """\ @@ -1,2 +1,2 @@ -def __init__(self): - self.prop = 'old' +def __init__(self, arg): + self.prop = arg""") a = Artist('new') assert a.prop == 'new'
def test_patch_future_doesnt_inherit(self): # This test module has 'division' imported, but python2_future doesn't assert division from python2_future import sample3 assert sample3() == 0 patchy.patch(sample3, """\ @@ -1,2 +1,3 @@ def sample3(): + pass return 1 / 2 """) assert sample3() == 0
def test_patch_invalid(self): """ We need to balk on empty patches """ def sample(): return 1 bad_patch = """ """ with pytest.raises(ValueError) as excinfo: patchy.patch(sample, bad_patch) msg = str(excinfo.value) assert msg.startswith("Could not apply the patch to 'sample'.") assert "Only garbage was found in the patch input." assert sample() == 1
def test_patch_unpatch(self): def sample(): return 1 patch_text = """\ @@ -1,2 +1,2 @@ def sample(): - return 1 + return 9001 """ patchy.patch(sample, patch_text) assert sample() == 9001 patchy.unpatch(sample, patch_text) assert sample() == 1
def test_patch_invalid_hunk(self): """ We need to balk on patches that fail on application """ def sample(): return 1 bad_patch = """\ @@ -1,2 +1,2 @@ def sample(): - return 2 + return 23""" with pytest.raises(ValueError) as excinfo: patchy.patch(sample, bad_patch) assert "Hunk #1 FAILED" in str(excinfo.value) assert sample() == 1
def test_patch_freevars(): def free_func(v): return v + ' on toast' def sample(): filling = 'Chalk' return free_func(filling) patchy.patch(sample, """\ @@ -1,2 +1,2 @@ def method(): - filling = 'Chalk' + filling = 'Cheese' return free_func(filling) """) assert sample() == "Cheese on toast"
def test_patch_twice(self): def sample(): return 1 patchy.patch(sample, """\ @@ -1,2 +1,2 @@ def sample(): - return 1 + return 2""") patchy.patch(sample, """\ @@ -1,2 +1,2 @@ def sample(): - return 2 + return 3 """) assert sample() == 3
def test_patch_old_class_instancemethod_mangled(): class Artist: def __mangled_name(self, v): return v + ' on toast' def method(self): filling = 'Chalk' return self.__mangled_name(filling) patchy.patch(Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): - filling = 'Chalk' + filling = 'Cheese' return self.__mangled_name(filling) """) assert Artist().method() == "Cheese on toast"
def test_patch_instancemethod_freevars(): def free_func(v): return v + ' on toast' class Artist: def method(self): filling = 'Chalk' return free_func(filling) patchy.patch(Artist.method, """\ @@ -1,2 +1,2 @@ def method(self): - filling = 'Chalk' + filling = 'Cheese' return free_func(filling) """) assert Artist().method() == "Cheese on toast"
def test_patch_freevars_re_close(): def nasty_filling(v): return 'Chalk' def nice_filling(v): return 'Cheese' def sample(): filling = nasty_filling() return filling + ' on toast' patchy.patch(sample, """\ @@ -1,2 +1,2 @@ def sample(): - filling = nasty_filling() + filling = nice_filling() return filling + ' on toast' """) assert sample() == "Cheese on toast"
def test_patch_by_path(tmpdir): package = tmpdir.mkdir('patch_by_path_pkg') package.join('__init__.py').ensure(file=True) package.join('mod.py').write(dedent("""\ class Foo(object): def sample(self): return 1 """)) sys.path.insert(0, six.text_type(tmpdir)) try: patchy.patch('patch_by_path_pkg.mod.Foo.sample', """\ @@ -2,2 +2,2 @@ - return 1 + return 2 """) from patch_by_path_pkg.mod import Foo finally: sys.path.pop(0) assert Foo().sample() == 2