patchy 2.9.0__tar.gz → 3.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {patchy-2.9.0/src/patchy.egg-info → patchy-3.0.0}/PKG-INFO +18 -23
- {patchy-2.9.0 → patchy-3.0.0}/README.rst +5 -13
- patchy-3.0.0/pyproject.toml +112 -0
- patchy-3.0.0/pyproject.toml.orig +120 -0
- {patchy-2.9.0 → patchy-3.0.0}/src/patchy/api.py +38 -59
- patchy-2.9.0/CHANGELOG.rst +0 -131
- patchy-2.9.0/MANIFEST.in +0 -6
- patchy-2.9.0/PKG-INFO +0 -369
- patchy-2.9.0/pirate.png +0 -0
- patchy-2.9.0/pyproject.toml +0 -86
- patchy-2.9.0/setup.cfg +0 -4
- patchy-2.9.0/src/patchy.egg-info/SOURCES.txt +0 -20
- patchy-2.9.0/src/patchy.egg-info/dependency_links.txt +0 -1
- patchy-2.9.0/src/patchy.egg-info/top_level.txt +0 -1
- patchy-2.9.0/tests/test_cache.py +0 -36
- patchy-2.9.0/tests/test_patch.py +0 -953
- patchy-2.9.0/tests/test_patch_then_unpatch.py +0 -45
- patchy-2.9.0/tests/test_replace.py +0 -153
- patchy-2.9.0/tests/test_temp_patch.py +0 -74
- patchy-2.9.0/tests/test_unpatch.py +0 -76
- {patchy-2.9.0 → patchy-3.0.0}/LICENSE +0 -0
- {patchy-2.9.0 → patchy-3.0.0}/src/patchy/__init__.py +0 -0
- {patchy-2.9.0 → patchy-3.0.0}/src/patchy/cache.py +0 -0
- {patchy-2.9.0 → patchy-3.0.0}/src/patchy/py.typed +0 -0
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: patchy
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: Patch the inner source of python functions at runtime.
|
|
5
|
-
Author-email: Adam Johnson <me@adamj.eu>
|
|
6
|
-
Project-URL: Changelog, https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst
|
|
7
|
-
Project-URL: Funding, https://adamj.eu/books/
|
|
8
|
-
Project-URL: Repository, https://github.com/adamchainz/patchy
|
|
9
5
|
Keywords: patchy
|
|
6
|
+
Author: Adam Johnson
|
|
7
|
+
Author-email: Adam Johnson <me@adamj.eu>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
10
|
Classifier: Development Status :: 5 - Production/Stable
|
|
11
11
|
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
12
|
Classifier: Natural Language :: English
|
|
14
13
|
Classifier: Operating System :: OS Independent
|
|
15
14
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
16
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
17
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
18
|
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
|
-
Requires-
|
|
22
|
+
Requires-Dist: unipatch
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Project-URL: Changelog, https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst
|
|
25
|
+
Project-URL: Funding, https://adamj.eu/books/
|
|
26
|
+
Project-URL: Repository, https://github.com/adamchainz/patchy
|
|
23
27
|
Description-Content-Type: text/x-rst
|
|
24
|
-
License-File: LICENSE
|
|
25
28
|
|
|
26
29
|
======
|
|
27
30
|
Patchy
|
|
@@ -90,7 +93,7 @@ Use **pip**:
|
|
|
90
93
|
|
|
91
94
|
python -m pip install patchy
|
|
92
95
|
|
|
93
|
-
Python 3.
|
|
96
|
+
Python 3.10 to 3.15 supported.
|
|
94
97
|
|
|
95
98
|
Why?
|
|
96
99
|
====
|
|
@@ -105,7 +108,7 @@ I found this with some small but important patches to Django for a project.
|
|
|
105
108
|
Since it takes a lot of energy to maintain a fork, writing monkey patches was
|
|
106
109
|
the chosen quick solution, but then writing actual patches would be better.
|
|
107
110
|
|
|
108
|
-
The patches are applied with the
|
|
111
|
+
The patches are applied in-memory by `unipatch <https://pypi.org/project/unipatch/>`__, a pure-Python implementation of unified diff patching, compatible with the behaviour of the GNU ``patch`` commandline utility.
|
|
109
112
|
|
|
110
113
|
|
|
111
114
|
Why not?
|
|
@@ -113,8 +116,6 @@ Why not?
|
|
|
113
116
|
|
|
114
117
|
There are of course a lot of reasons against:
|
|
115
118
|
|
|
116
|
-
* It’s (relatively) slow (since it writes the source to disk and calls the
|
|
117
|
-
``patch`` command)
|
|
118
119
|
* If you have a patch file, why not just fork the library and apply it?
|
|
119
120
|
* At least with monkey-patching you know what end up with, rather than having
|
|
120
121
|
the changes being done at runtime to source that may have changed.
|
|
@@ -126,16 +127,10 @@ solution.
|
|
|
126
127
|
How?
|
|
127
128
|
====
|
|
128
129
|
|
|
129
|
-
The standard library function ``inspect.getsource()`` is used to retrieve the
|
|
130
|
-
|
|
131
|
-
``patch``, the code is recompiled, and the function’s code object is replaced
|
|
132
|
-
the new one. Because nothing tends to poke around at code objects apart from
|
|
133
|
-
dodgy hacks like this, you don’t need to worry about chasing any references
|
|
134
|
-
that may exist to the function, unlike ``mock.patch``.
|
|
130
|
+
The standard library function ``inspect.getsource()`` is used to retrieve the source code of the function, the patch is applied in-memory with `unipatch <https://pypi.org/project/unipatch/>`__, the code is recompiled, and the function’s code object is replaced the new one.
|
|
131
|
+
Because nothing tends to poke around at code objects apart from dodgy hacks like this, you don’t need to worry about chasing any references that may exist to the function, unlike ``mock.patch``.
|
|
135
132
|
|
|
136
|
-
A little special treatment is given to ``instancemethod``, ``classmethod``, and
|
|
137
|
-
``staticmethod`` objects to make sure the underlying function is what gets
|
|
138
|
-
patched and that you don't have to worry about the details.
|
|
133
|
+
A little special treatment is given to ``instancemethod``, ``classmethod``, and ``staticmethod`` objects to make sure the underlying function is what gets patched and that you don't have to worry about the details.
|
|
139
134
|
|
|
140
135
|
|
|
141
136
|
API
|
|
@@ -65,7 +65,7 @@ Use **pip**:
|
|
|
65
65
|
|
|
66
66
|
python -m pip install patchy
|
|
67
67
|
|
|
68
|
-
Python 3.
|
|
68
|
+
Python 3.10 to 3.15 supported.
|
|
69
69
|
|
|
70
70
|
Why?
|
|
71
71
|
====
|
|
@@ -80,7 +80,7 @@ I found this with some small but important patches to Django for a project.
|
|
|
80
80
|
Since it takes a lot of energy to maintain a fork, writing monkey patches was
|
|
81
81
|
the chosen quick solution, but then writing actual patches would be better.
|
|
82
82
|
|
|
83
|
-
The patches are applied with the
|
|
83
|
+
The patches are applied in-memory by `unipatch <https://pypi.org/project/unipatch/>`__, a pure-Python implementation of unified diff patching, compatible with the behaviour of the GNU ``patch`` commandline utility.
|
|
84
84
|
|
|
85
85
|
|
|
86
86
|
Why not?
|
|
@@ -88,8 +88,6 @@ Why not?
|
|
|
88
88
|
|
|
89
89
|
There are of course a lot of reasons against:
|
|
90
90
|
|
|
91
|
-
* It’s (relatively) slow (since it writes the source to disk and calls the
|
|
92
|
-
``patch`` command)
|
|
93
91
|
* If you have a patch file, why not just fork the library and apply it?
|
|
94
92
|
* At least with monkey-patching you know what end up with, rather than having
|
|
95
93
|
the changes being done at runtime to source that may have changed.
|
|
@@ -101,16 +99,10 @@ solution.
|
|
|
101
99
|
How?
|
|
102
100
|
====
|
|
103
101
|
|
|
104
|
-
The standard library function ``inspect.getsource()`` is used to retrieve the
|
|
105
|
-
|
|
106
|
-
``patch``, the code is recompiled, and the function’s code object is replaced
|
|
107
|
-
the new one. Because nothing tends to poke around at code objects apart from
|
|
108
|
-
dodgy hacks like this, you don’t need to worry about chasing any references
|
|
109
|
-
that may exist to the function, unlike ``mock.patch``.
|
|
102
|
+
The standard library function ``inspect.getsource()`` is used to retrieve the source code of the function, the patch is applied in-memory with `unipatch <https://pypi.org/project/unipatch/>`__, the code is recompiled, and the function’s code object is replaced the new one.
|
|
103
|
+
Because nothing tends to poke around at code objects apart from dodgy hacks like this, you don’t need to worry about chasing any references that may exist to the function, unlike ``mock.patch``.
|
|
110
104
|
|
|
111
|
-
A little special treatment is given to ``instancemethod``, ``classmethod``, and
|
|
112
|
-
``staticmethod`` objects to make sure the underlying function is what gets
|
|
113
|
-
patched and that you don't have to worry about the details.
|
|
105
|
+
A little special treatment is given to ``instancemethod``, ``classmethod``, and ``staticmethod`` objects to make sure the underlying function is what gets patched and that you don't have to worry about the details.
|
|
114
106
|
|
|
115
107
|
|
|
116
108
|
API
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "uv_build"
|
|
3
|
+
requires = ["uv-build>=0.12.1,<0.13"]
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "patchy"
|
|
7
|
+
version = "3.0.0"
|
|
8
|
+
description = "Patch the inner source of python functions at runtime."
|
|
9
|
+
readme = "README.rst"
|
|
10
|
+
keywords = ["patchy"]
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
requires-python = ">=3.10"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"Natural Language :: English",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Programming Language :: Python :: 3.15",
|
|
26
|
+
"Typing :: Typed",
|
|
27
|
+
]
|
|
28
|
+
dependencies = ["unipatch"]
|
|
29
|
+
|
|
30
|
+
[[project.authors]]
|
|
31
|
+
name = "Adam Johnson"
|
|
32
|
+
email = "me@adamj.eu"
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Changelog = "https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst"
|
|
36
|
+
Funding = "https://adamj.eu/books/"
|
|
37
|
+
Repository = "https://github.com/adamchainz/patchy"
|
|
38
|
+
|
|
39
|
+
[dependency-groups]
|
|
40
|
+
test = [
|
|
41
|
+
"coverage[toml]",
|
|
42
|
+
"pkgutil-resolve-name; python_version<'3.9'",
|
|
43
|
+
"pytest>=9",
|
|
44
|
+
"pytest-randomly",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.ruff.lint]
|
|
48
|
+
select = [
|
|
49
|
+
"B",
|
|
50
|
+
"C4",
|
|
51
|
+
"E",
|
|
52
|
+
"F",
|
|
53
|
+
"I",
|
|
54
|
+
"SIM",
|
|
55
|
+
"TID",
|
|
56
|
+
"UP",
|
|
57
|
+
"W",
|
|
58
|
+
]
|
|
59
|
+
ignore = [
|
|
60
|
+
"B9",
|
|
61
|
+
"E501",
|
|
62
|
+
"SIM105",
|
|
63
|
+
"SIM108",
|
|
64
|
+
]
|
|
65
|
+
extend-safe-fixes = ["UP006"]
|
|
66
|
+
|
|
67
|
+
[tool.ruff.lint.isort]
|
|
68
|
+
required-imports = ["from __future__ import annotations"]
|
|
69
|
+
|
|
70
|
+
[tool.pyproject-fmt]
|
|
71
|
+
max_supported_python = "3.15"
|
|
72
|
+
|
|
73
|
+
[tool.mypy]
|
|
74
|
+
mypy_path = "src/"
|
|
75
|
+
namespace_packages = false
|
|
76
|
+
warn_unreachable = true
|
|
77
|
+
enable_error_code = [
|
|
78
|
+
"ignore-without-code",
|
|
79
|
+
"redundant-expr",
|
|
80
|
+
"truthy-bool",
|
|
81
|
+
]
|
|
82
|
+
strict = true
|
|
83
|
+
|
|
84
|
+
[[tool.mypy.overrides]]
|
|
85
|
+
module = "tests.*"
|
|
86
|
+
allow_untyped_defs = true
|
|
87
|
+
|
|
88
|
+
[tool.pytest]
|
|
89
|
+
strict = true
|
|
90
|
+
|
|
91
|
+
[tool.coverage.run]
|
|
92
|
+
branch = true
|
|
93
|
+
data_file = ".coverage/cov"
|
|
94
|
+
parallel = true
|
|
95
|
+
source = [
|
|
96
|
+
"patchy",
|
|
97
|
+
"tests",
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
[tool.coverage.paths]
|
|
101
|
+
source = [
|
|
102
|
+
"src",
|
|
103
|
+
".tox/**/site-packages",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
[tool.coverage.report]
|
|
107
|
+
show_missing = true
|
|
108
|
+
skip_covered = true
|
|
109
|
+
skip_empty = true
|
|
110
|
+
|
|
111
|
+
[tool.rstcheck]
|
|
112
|
+
report_level = "ERROR"
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "uv_build"
|
|
3
|
+
requires = [
|
|
4
|
+
"uv-build>=0.12.1,<0.13",
|
|
5
|
+
]
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "patchy"
|
|
9
|
+
version = "3.0.0"
|
|
10
|
+
description = "Patch the inner source of python functions at runtime."
|
|
11
|
+
readme = "README.rst"
|
|
12
|
+
keywords = [
|
|
13
|
+
"patchy",
|
|
14
|
+
]
|
|
15
|
+
license = "MIT"
|
|
16
|
+
license-files = [ "LICENSE" ]
|
|
17
|
+
authors = [
|
|
18
|
+
{ name = "Adam Johnson", email = "me@adamj.eu" },
|
|
19
|
+
]
|
|
20
|
+
requires-python = ">=3.10"
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 5 - Production/Stable",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Natural Language :: English",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
27
|
+
"Programming Language :: Python :: 3.10",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
"Programming Language :: Python :: 3.14",
|
|
32
|
+
"Programming Language :: Python :: 3.15",
|
|
33
|
+
"Typing :: Typed",
|
|
34
|
+
]
|
|
35
|
+
dependencies = [
|
|
36
|
+
"unipatch",
|
|
37
|
+
]
|
|
38
|
+
urls = { Changelog = "https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst", Funding = "https://adamj.eu/books/", Repository = "https://github.com/adamchainz/patchy" }
|
|
39
|
+
|
|
40
|
+
[dependency-groups]
|
|
41
|
+
test = [
|
|
42
|
+
"coverage[toml]",
|
|
43
|
+
"pkgutil-resolve-name; python_version<'3.9'",
|
|
44
|
+
"pytest>=9",
|
|
45
|
+
"pytest-randomly",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
lint.select = [
|
|
50
|
+
# flake8-bugbear
|
|
51
|
+
"B",
|
|
52
|
+
# flake8-comprehensions
|
|
53
|
+
"C4",
|
|
54
|
+
# pycodestyle
|
|
55
|
+
"E",
|
|
56
|
+
# Pyflakes errors
|
|
57
|
+
"F",
|
|
58
|
+
# isort
|
|
59
|
+
"I",
|
|
60
|
+
# flake8-simplify
|
|
61
|
+
"SIM",
|
|
62
|
+
# flake8-tidy-imports
|
|
63
|
+
"TID",
|
|
64
|
+
# pyupgrade
|
|
65
|
+
"UP",
|
|
66
|
+
# Pyflakes warnings
|
|
67
|
+
"W",
|
|
68
|
+
]
|
|
69
|
+
lint.ignore = [
|
|
70
|
+
# flake8-bugbear opinionated rules
|
|
71
|
+
"B9",
|
|
72
|
+
# line-too-long
|
|
73
|
+
"E501",
|
|
74
|
+
# suppressible-exception
|
|
75
|
+
"SIM105",
|
|
76
|
+
# if-else-block-instead-of-if-exp
|
|
77
|
+
"SIM108",
|
|
78
|
+
]
|
|
79
|
+
lint.extend-safe-fixes = [
|
|
80
|
+
# non-pep585-annotation
|
|
81
|
+
"UP006",
|
|
82
|
+
]
|
|
83
|
+
lint.isort.required-imports = [ "from __future__ import annotations" ]
|
|
84
|
+
|
|
85
|
+
[tool.pyproject-fmt]
|
|
86
|
+
max_supported_python = "3.15"
|
|
87
|
+
|
|
88
|
+
[tool.mypy]
|
|
89
|
+
mypy_path = "src/"
|
|
90
|
+
namespace_packages = false
|
|
91
|
+
warn_unreachable = true
|
|
92
|
+
enable_error_code = [
|
|
93
|
+
"ignore-without-code",
|
|
94
|
+
"redundant-expr",
|
|
95
|
+
"truthy-bool",
|
|
96
|
+
]
|
|
97
|
+
strict = true
|
|
98
|
+
overrides = [ { module = "tests.*", allow_untyped_defs = true } ]
|
|
99
|
+
|
|
100
|
+
[tool.pytest]
|
|
101
|
+
strict = true
|
|
102
|
+
|
|
103
|
+
[tool.coverage]
|
|
104
|
+
run.branch = true
|
|
105
|
+
run.data_file = ".coverage/cov"
|
|
106
|
+
run.parallel = true
|
|
107
|
+
run.source = [
|
|
108
|
+
"patchy",
|
|
109
|
+
"tests",
|
|
110
|
+
]
|
|
111
|
+
paths.source = [
|
|
112
|
+
"src",
|
|
113
|
+
".tox/**/site-packages",
|
|
114
|
+
]
|
|
115
|
+
report.show_missing = true
|
|
116
|
+
report.skip_covered = true
|
|
117
|
+
report.skip_empty = true
|
|
118
|
+
|
|
119
|
+
[tool.rstcheck]
|
|
120
|
+
report_level = "ERROR"
|
|
@@ -2,20 +2,15 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import ast
|
|
4
4
|
import inspect
|
|
5
|
-
import
|
|
6
|
-
import shutil
|
|
7
|
-
import subprocess
|
|
5
|
+
from collections.abc import Callable
|
|
8
6
|
from functools import wraps
|
|
9
|
-
from tempfile import mkdtemp
|
|
10
7
|
from textwrap import dedent
|
|
11
|
-
from types import CodeType
|
|
12
|
-
from
|
|
13
|
-
from typing import Any
|
|
14
|
-
from typing import Callable
|
|
15
|
-
from typing import TypeVar
|
|
16
|
-
from typing import cast
|
|
8
|
+
from types import CodeType, TracebackType
|
|
9
|
+
from typing import Any, TypeVar, cast
|
|
17
10
|
from weakref import WeakKeyDictionary
|
|
18
11
|
|
|
12
|
+
from unipatch import HunkApplyError, PatchError, apply_patch
|
|
13
|
+
|
|
19
14
|
from .cache import PatchingCache
|
|
20
15
|
|
|
21
16
|
if True:
|
|
@@ -115,44 +110,34 @@ def _apply_patch(
|
|
|
115
110
|
except KeyError:
|
|
116
111
|
pass
|
|
117
112
|
|
|
118
|
-
# Write out files
|
|
119
|
-
tempdir = mkdtemp(prefix="patchy")
|
|
120
113
|
try:
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
source, patch_text
|
|
149
|
-
)
|
|
150
|
-
raise ValueError(msg)
|
|
151
|
-
|
|
152
|
-
with open(source_path) as source_file:
|
|
153
|
-
new_source = source_file.read()
|
|
154
|
-
finally:
|
|
155
|
-
shutil.rmtree(tempdir)
|
|
114
|
+
new_source = apply_patch(source, patch_text, forwards=forwards)
|
|
115
|
+
except PatchError as exc:
|
|
116
|
+
detail = str(exc)
|
|
117
|
+
if isinstance(exc, HunkApplyError):
|
|
118
|
+
try:
|
|
119
|
+
apply_patch(source, patch_text, forwards=not forwards)
|
|
120
|
+
except PatchError:
|
|
121
|
+
pass
|
|
122
|
+
else:
|
|
123
|
+
if forwards:
|
|
124
|
+
detail += (
|
|
125
|
+
" Applying it in reverse succeeds, so it looks like"
|
|
126
|
+
+ " the patch has already been applied."
|
|
127
|
+
)
|
|
128
|
+
else:
|
|
129
|
+
detail += (
|
|
130
|
+
" Applying it forwards succeeds, so it looks like the"
|
|
131
|
+
+ " patch is unreversed and has not been applied yet."
|
|
132
|
+
)
|
|
133
|
+
msg = "Could not {action} the patch {prep} '{name}'. {detail}".format(
|
|
134
|
+
action=("apply" if forwards else "unapply"),
|
|
135
|
+
prep=("to" if forwards else "from"),
|
|
136
|
+
name=name,
|
|
137
|
+
detail=detail,
|
|
138
|
+
)
|
|
139
|
+
msg += f"\n\nThe code to patch was:\n{source}\nThe patch was:\n{patch_text}"
|
|
140
|
+
raise ValueError(msg) from None
|
|
156
141
|
|
|
157
142
|
_patching_cache.store(source, patch_text, forwards, new_source)
|
|
158
143
|
|
|
@@ -271,12 +256,8 @@ def _set_source(func: Callable[..., Any], func_source: str) -> None:
|
|
|
271
256
|
if class_name in func.__code__.co_freevars
|
|
272
257
|
else f" global {class_name}\n"
|
|
273
258
|
)
|
|
274
|
-
class_src = "{_global} class {
|
|
275
|
-
|
|
276
|
-
)
|
|
277
|
-
ret = " return {class_name}.{name}".format(
|
|
278
|
-
class_name=class_name, name=func.__name__
|
|
279
|
-
)
|
|
259
|
+
class_src = f"{_global} class {class_name}(object):\n pass"
|
|
260
|
+
ret = f" return {class_name}.{func.__name__}"
|
|
280
261
|
to_parse = "\n".join([_def] + fv_body + [class_src, ret])
|
|
281
262
|
new_source = _parse(to_parse)
|
|
282
263
|
new_source.body[0].body[-2].body[0] = _ast # type: ignore [attr-defined]
|
|
@@ -330,12 +311,10 @@ def _get_real_func(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
|
330
311
|
def _assert_ast_equal(current_source: str, expected_source: str, name: str) -> None:
|
|
331
312
|
current_ast = ast.parse(current_source)
|
|
332
313
|
expected_ast = ast.parse(expected_source)
|
|
333
|
-
if
|
|
314
|
+
if ast.dump(current_ast) != ast.dump(expected_ast):
|
|
334
315
|
msg = (
|
|
335
|
-
"The code of '{name}' has changed from expected.\n"
|
|
336
|
-
"The current code is:\n{current_source}\n"
|
|
337
|
-
"The expected code is:\n{expected_source}"
|
|
338
|
-
).format(
|
|
339
|
-
name=name, current_source=current_source, expected_source=expected_source
|
|
316
|
+
f"The code of '{name}' has changed from expected.\n"
|
|
317
|
+
f"The current code is:\n{current_source}\n"
|
|
318
|
+
f"The expected code is:\n{expected_source}"
|
|
340
319
|
)
|
|
341
320
|
raise ValueError(msg)
|
patchy-2.9.0/CHANGELOG.rst
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
=========
|
|
2
|
-
Changelog
|
|
3
|
-
=========
|
|
4
|
-
|
|
5
|
-
2.9.0 (2024-10-25)
|
|
6
|
-
------------------
|
|
7
|
-
|
|
8
|
-
* Drop Python 3.8 support.
|
|
9
|
-
|
|
10
|
-
* Support Python 3.13.
|
|
11
|
-
|
|
12
|
-
2.8.0 (2023-07-10)
|
|
13
|
-
------------------
|
|
14
|
-
|
|
15
|
-
* Drop Python 3.7 support.
|
|
16
|
-
|
|
17
|
-
2.7.0 (2023-06-16)
|
|
18
|
-
------------------
|
|
19
|
-
|
|
20
|
-
* Support Python 3.12.
|
|
21
|
-
|
|
22
|
-
2.6.1 (2023-01-16)
|
|
23
|
-
------------------
|
|
24
|
-
|
|
25
|
-
* Use the ``--force`` flag to ``patch``, so it doesn’t hang waiting input for invalid reverse patches.
|
|
26
|
-
This seems to happen with the new version on macOS.
|
|
27
|
-
|
|
28
|
-
2.6.0 (2022-05-11)
|
|
29
|
-
------------------
|
|
30
|
-
|
|
31
|
-
* Support Python 3.11.
|
|
32
|
-
|
|
33
|
-
2.5.0 (2022-01-10)
|
|
34
|
-
------------------
|
|
35
|
-
|
|
36
|
-
* Drop Python 3.6 support.
|
|
37
|
-
|
|
38
|
-
2.4.0 (2021-08-11)
|
|
39
|
-
------------------
|
|
40
|
-
|
|
41
|
-
* Add type hints.
|
|
42
|
-
|
|
43
|
-
2.3.0 (2021-05-10)
|
|
44
|
-
------------------
|
|
45
|
-
|
|
46
|
-
* Support Python 3.10.
|
|
47
|
-
|
|
48
|
-
* Stop distributing tests to reduce package size. Tests are not intended to be
|
|
49
|
-
run outside of the tox setup in the repository. Repackagers can use GitHub's
|
|
50
|
-
tarballs per tag.
|
|
51
|
-
|
|
52
|
-
2.2.0 (2020-12-13)
|
|
53
|
-
------------------
|
|
54
|
-
|
|
55
|
-
* Drop Python 3.5 support.
|
|
56
|
-
* Move license from BSD to MIT License.
|
|
57
|
-
|
|
58
|
-
2.1.0 (2020-02-20)
|
|
59
|
-
------------------
|
|
60
|
-
|
|
61
|
-
* Support Python 3.9.
|
|
62
|
-
* Use Python 3.9's ``pkgutil.resolve_name()``
|
|
63
|
-
(`docs <https://docs.python.org/3.9/library/pkgutil.html#pkgutil.resolve_name>`__)
|
|
64
|
-
to import names by strings, and depend on the
|
|
65
|
-
`backport package <https://pypi.org/project/pkgutil_resolve_name/>`__ on
|
|
66
|
-
older Python versions.
|
|
67
|
-
|
|
68
|
-
2.0.0 (2019-11-15)
|
|
69
|
-
------------------
|
|
70
|
-
|
|
71
|
-
* Drop Python 2 support, only Python 3.5-3.8 is supported now. Python 3.4 was
|
|
72
|
-
dropped as it has reached its end of life.
|
|
73
|
-
* Converted setuptools metadata to configuration file. This meant removing the
|
|
74
|
-
``__version__`` attribute from the package. If you want to inspect the
|
|
75
|
-
installed version, use
|
|
76
|
-
``importlib.metadata.version("patchy")``
|
|
77
|
-
(`docs <https://docs.python.org/3.8/library/importlib.metadata.html#distribution-versions>`__ /
|
|
78
|
-
`backport <https://pypi.org/project/importlib-metadata/>`__).
|
|
79
|
-
|
|
80
|
-
1.5.0 (2019-02-15)
|
|
81
|
-
------------------
|
|
82
|
-
|
|
83
|
-
* Support cases where the function or class name is not in the freevars. This
|
|
84
|
-
allows patching ``__init__`` of a class, or patching a recursive module-level
|
|
85
|
-
function.
|
|
86
|
-
* Support patching objects provided by dotted path string.
|
|
87
|
-
|
|
88
|
-
1.4.0 (2017-05-13)
|
|
89
|
-
------------------
|
|
90
|
-
|
|
91
|
-
* Added new function ``patchy.replace()``, that can be used to directly assign
|
|
92
|
-
new source code to a function, without having to make a patch.
|
|
93
|
-
|
|
94
|
-
1.3.2 (2017-03-13)
|
|
95
|
-
------------------
|
|
96
|
-
|
|
97
|
-
* Support freevars and methods that call mangled methods.
|
|
98
|
-
|
|
99
|
-
1.3.1 (2016-05-24)
|
|
100
|
-
------------------
|
|
101
|
-
|
|
102
|
-
* Fixed ``setup.py`` to not fix the version of ``six`` required.
|
|
103
|
-
* Fixed install instruction in README.
|
|
104
|
-
* Added ``patchy.mc_patchface()`` as an alias for ``patchy.patch()`` because
|
|
105
|
-
memes.
|
|
106
|
-
|
|
107
|
-
1.3.0 (2015-12-09)
|
|
108
|
-
------------------
|
|
109
|
-
|
|
110
|
-
* Remove dependency on ``pylru`` by using a simpler caching strategy
|
|
111
|
-
|
|
112
|
-
1.2.0 (2015-07-23)
|
|
113
|
-
------------------
|
|
114
|
-
|
|
115
|
-
* Pirate mascot!
|
|
116
|
-
* Patching caches the patched and unpatched versions, so unpatching and repeat
|
|
117
|
-
patching/unpatching are both faster
|
|
118
|
-
* Patching doesn't attach an attribute to the function object any more
|
|
119
|
-
|
|
120
|
-
1.1.0 (2015-06-16)
|
|
121
|
-
------------------
|
|
122
|
-
|
|
123
|
-
* Fixed code compilation to use the ``__future__`` flags from the function that
|
|
124
|
-
is being patched
|
|
125
|
-
* Added ``unpatch`` method
|
|
126
|
-
* Added ``temp_patch`` context manager/decorator
|
|
127
|
-
|
|
128
|
-
1.0.0 (2015-06-09)
|
|
129
|
-
---------------------
|
|
130
|
-
|
|
131
|
-
* First release on PyPI, featuring ``patch`` function.
|