patchy 2.8.0__tar.gz → 2.10.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.
@@ -2,6 +2,18 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ 2.10.0 (2025-09-09)
6
+ -------------------
7
+
8
+ * Support Python 3.14.
9
+
10
+ 2.9.0 (2024-10-25)
11
+ ------------------
12
+
13
+ * Drop Python 3.8 support.
14
+
15
+ * Support Python 3.13.
16
+
5
17
  2.8.0 (2023-07-10)
6
18
  ------------------
7
19
 
@@ -1,37 +1,35 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: patchy
3
- Version: 2.8.0
3
+ Version: 2.10.0
4
4
  Summary: Patch the inner source of python functions at runtime.
5
- Home-page: https://github.com/adamchainz/patchy
6
- Author: Adam Johnson
7
- Author-email: me@adamj.eu
8
- License: MIT
5
+ Author-email: Adam Johnson <me@adamj.eu>
6
+ License-Expression: MIT
9
7
  Project-URL: Changelog, https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst
10
- Project-URL: Mastodon, https://fosstodon.org/@adamchainz
11
- Project-URL: Twitter, https://twitter.com/adamchainz
8
+ Project-URL: Funding, https://adamj.eu/books/
9
+ Project-URL: Repository, https://github.com/adamchainz/patchy
12
10
  Keywords: patchy
13
11
  Classifier: Development Status :: 5 - Production/Stable
14
12
  Classifier: Intended Audience :: Developers
15
- Classifier: License :: OSI Approved :: MIT License
16
13
  Classifier: Natural Language :: English
17
14
  Classifier: Operating System :: OS Independent
18
- Classifier: Programming Language :: Python :: 3
19
15
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Classifier: Programming Language :: Python :: 3.8
21
16
  Classifier: Programming Language :: Python :: 3.9
22
17
  Classifier: Programming Language :: Python :: 3.10
23
18
  Classifier: Programming Language :: Python :: 3.11
24
19
  Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
25
22
  Classifier: Typing :: Typed
26
- Requires-Python: >=3.8
23
+ Requires-Python: >=3.9
27
24
  Description-Content-Type: text/x-rst
28
25
  License-File: LICENSE
26
+ Dynamic: license-file
29
27
 
30
28
  ======
31
29
  Patchy
32
30
  ======
33
31
 
34
- .. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/patchy/main.yml?branch=main&style=for-the-badge
32
+ .. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/patchy/main.yml.svg?branch=main&style=for-the-badge
35
33
  :target: https://github.com/adamchainz/patchy/actions?workflow=CI
36
34
 
37
35
  .. image:: https://img.shields.io/badge/Coverage-100%25-success?style=for-the-badge
@@ -78,6 +76,12 @@ function object itself the same. It's thus more versatile than monkey patching,
78
76
  since if the function has been imported in multiple places they'll also call
79
77
  the new behaviour.
80
78
 
79
+ ----
80
+
81
+ **Hacking on a Django project?**
82
+ Check out my book `Boost Your Django DX <https://adamchainz.gumroad.com/l/byddx>`__ which covers many ways to improve your development experience.
83
+
84
+ ----
81
85
 
82
86
  Installation
83
87
  ============
@@ -88,14 +92,7 @@ Use **pip**:
88
92
 
89
93
  python -m pip install patchy
90
94
 
91
- Python 3.8 to 3.12 supported.
92
-
93
- ----
94
-
95
- **Hacking on a Django project?**
96
- Check out my book `Boost Your Django DX <https://adamchainz.gumroad.com/l/byddx>`__ which covers many ways to improve your development experience.
97
-
98
- ----
95
+ Python 3.9 to 3.14 supported.
99
96
 
100
97
  Why?
101
98
  ====
@@ -2,7 +2,7 @@
2
2
  Patchy
3
3
  ======
4
4
 
5
- .. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/patchy/main.yml?branch=main&style=for-the-badge
5
+ .. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/patchy/main.yml.svg?branch=main&style=for-the-badge
6
6
  :target: https://github.com/adamchainz/patchy/actions?workflow=CI
7
7
 
8
8
  .. image:: https://img.shields.io/badge/Coverage-100%25-success?style=for-the-badge
@@ -49,6 +49,12 @@ function object itself the same. It's thus more versatile than monkey patching,
49
49
  since if the function has been imported in multiple places they'll also call
50
50
  the new behaviour.
51
51
 
52
+ ----
53
+
54
+ **Hacking on a Django project?**
55
+ Check out my book `Boost Your Django DX <https://adamchainz.gumroad.com/l/byddx>`__ which covers many ways to improve your development experience.
56
+
57
+ ----
52
58
 
53
59
  Installation
54
60
  ============
@@ -59,14 +65,7 @@ Use **pip**:
59
65
 
60
66
  python -m pip install patchy
61
67
 
62
- Python 3.8 to 3.12 supported.
63
-
64
- ----
65
-
66
- **Hacking on a Django project?**
67
- Check out my book `Boost Your Django DX <https://adamchainz.gumroad.com/l/byddx>`__ which covers many ways to improve your development experience.
68
-
69
- ----
68
+ Python 3.9 to 3.14 supported.
70
69
 
71
70
  Why?
72
71
  ====
@@ -0,0 +1,126 @@
1
+ [build-system]
2
+ build-backend = "setuptools.build_meta"
3
+ requires = [
4
+ "setuptools>=77",
5
+ ]
6
+
7
+ [project]
8
+ name = "patchy"
9
+ version = "2.10.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.9"
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.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ "Programming Language :: Python :: 3.12",
31
+ "Programming Language :: Python :: 3.13",
32
+ "Programming Language :: Python :: 3.14",
33
+ "Typing :: Typed",
34
+ ]
35
+ dependencies = [ ]
36
+ urls = { Changelog = "https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst", Funding = "https://adamj.eu/books/", Repository = "https://github.com/adamchainz/patchy" }
37
+
38
+ [dependency-groups]
39
+ test = [
40
+ "coverage[toml]",
41
+ "pkgutil-resolve-name; python_version<'3.9'",
42
+ "pytest",
43
+ "pytest-randomly",
44
+ ]
45
+
46
+ [tool.ruff]
47
+ lint.select = [
48
+ # flake8-bugbear
49
+ "B",
50
+ # flake8-comprehensions
51
+ "C4",
52
+ # pycodestyle
53
+ "E",
54
+ # Pyflakes errors
55
+ "F",
56
+ # isort
57
+ "I",
58
+ # flake8-simplify
59
+ "SIM",
60
+ # flake8-tidy-imports
61
+ "TID",
62
+ # pyupgrade
63
+ "UP",
64
+ # Pyflakes warnings
65
+ "W",
66
+ ]
67
+ lint.ignore = [
68
+ # flake8-bugbear opinionated rules
69
+ "B9",
70
+ # line-too-long
71
+ "E501",
72
+ # suppressible-exception
73
+ "SIM105",
74
+ # if-else-block-instead-of-if-exp
75
+ "SIM108",
76
+ ]
77
+ lint.extend-safe-fixes = [
78
+ # non-pep585-annotation
79
+ "UP006",
80
+ ]
81
+ lint.isort.required-imports = [ "from __future__ import annotations" ]
82
+
83
+ [tool.pyproject-fmt]
84
+ max_supported_python = "3.14"
85
+
86
+ [tool.pytest.ini_options]
87
+ addopts = """\
88
+ --strict-config
89
+ --strict-markers
90
+ """
91
+ xfail_strict = true
92
+
93
+ [tool.coverage.run]
94
+ branch = true
95
+ parallel = true
96
+ source = [
97
+ "patchy",
98
+ "tests",
99
+ ]
100
+
101
+ [tool.coverage.paths]
102
+ source = [
103
+ "src",
104
+ ".tox/**/site-packages",
105
+ ]
106
+
107
+ [tool.coverage.report]
108
+ show_missing = true
109
+
110
+ [tool.mypy]
111
+ enable_error_code = [
112
+ "ignore-without-code",
113
+ "redundant-expr",
114
+ "truthy-bool",
115
+ ]
116
+ mypy_path = "src/"
117
+ namespace_packages = false
118
+ strict = true
119
+ warn_unreachable = true
120
+
121
+ [[tool.mypy.overrides]]
122
+ module = "tests.*"
123
+ allow_untyped_defs = true
124
+
125
+ [tool.rstcheck]
126
+ report_level = "ERROR"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -5,17 +5,11 @@ import inspect
5
5
  import os
6
6
  import shutil
7
7
  import subprocess
8
- import sys
9
8
  from functools import wraps
10
9
  from tempfile import mkdtemp
11
10
  from textwrap import dedent
12
- from types import CodeType
13
- from types import TracebackType
14
- from typing import Any
15
- from typing import Callable
16
- from typing import cast
17
- from typing import Dict
18
- from typing import TypeVar
11
+ from types import CodeType, TracebackType
12
+ from typing import Any, Callable, TypeVar, cast
19
13
  from weakref import WeakKeyDictionary
20
14
 
21
15
  from .cache import PatchingCache
@@ -23,10 +17,7 @@ from .cache import PatchingCache
23
17
  if True:
24
18
  import __future__
25
19
 
26
- if sys.version_info >= (3, 9):
27
- from pkgutil import resolve_name as pkgutil_resolve_name
28
- else:
29
- from pkgutil_resolve_name import resolve_name as pkgutil_resolve_name
20
+ from pkgutil import resolve_name as pkgutil_resolve_name
30
21
 
31
22
  __all__ = ("patch", "mc_patchface", "unpatch", "replace", "temp_patch")
32
23
 
@@ -146,12 +137,8 @@ def _apply_patch(
146
137
  prep=("to" if forwards else "from"),
147
138
  name=name,
148
139
  )
149
- msg += " The message from `patch` was:\n{}\n{}".format(
150
- result.stdout, result.stderr
151
- )
152
- msg += "\nThe code to patch was:\n{}\nThe patch was:\n{}".format(
153
- source, patch_text
154
- )
140
+ msg += f" The message from `patch` was:\n{result.stdout}\n{result.stderr}"
141
+ msg += f"\nThe code to patch was:\n{source}\nThe patch was:\n{patch_text}"
155
142
  raise ValueError(msg)
156
143
 
157
144
  with open(source_path) as source_file:
@@ -175,11 +162,7 @@ FEATURE_MASK = _get_flags_mask()
175
162
 
176
163
 
177
164
  # Stores the source of functions that have had their source changed
178
- # Bad type hints because WeakKeyDictionary only indexable on Python 3.9+
179
- _source_map: dict[Callable[..., Any], str] = cast(
180
- Dict[Callable[..., Any], str],
181
- WeakKeyDictionary(),
182
- )
165
+ _source_map: WeakKeyDictionary[Callable[..., Any], str] = WeakKeyDictionary()
183
166
 
184
167
 
185
168
  def _get_source(func: Callable[..., Any]) -> str:
@@ -280,12 +263,8 @@ def _set_source(func: Callable[..., Any], func_source: str) -> None:
280
263
  if class_name in func.__code__.co_freevars
281
264
  else f" global {class_name}\n"
282
265
  )
283
- class_src = "{_global} class {name}(object):\n pass".format(
284
- _global=_global, name=class_name
285
- )
286
- ret = " return {class_name}.{name}".format(
287
- class_name=class_name, name=func.__name__
288
- )
266
+ class_src = f"{_global} class {class_name}(object):\n pass"
267
+ ret = f" return {class_name}.{func.__name__}"
289
268
  to_parse = "\n".join([_def] + fv_body + [class_src, ret])
290
269
  new_source = _parse(to_parse)
291
270
  new_source.body[0].body[-2].body[0] = _ast # type: ignore [attr-defined]
@@ -339,12 +318,10 @@ def _get_real_func(func: Callable[..., Any]) -> Callable[..., Any]:
339
318
  def _assert_ast_equal(current_source: str, expected_source: str, name: str) -> None:
340
319
  current_ast = ast.parse(current_source)
341
320
  expected_ast = ast.parse(expected_source)
342
- if not ast.dump(current_ast) == ast.dump(expected_ast):
321
+ if ast.dump(current_ast) != ast.dump(expected_ast):
343
322
  msg = (
344
- "The code of '{name}' has changed from expected.\n"
345
- "The current code is:\n{current_source}\n"
346
- "The expected code is:\n{expected_source}"
347
- ).format(
348
- name=name, current_source=current_source, expected_source=expected_source
323
+ f"The code of '{name}' has changed from expected.\n"
324
+ f"The current code is:\n{current_source}\n"
325
+ f"The expected code is:\n{expected_source}"
349
326
  )
350
327
  raise ValueError(msg)
@@ -1,37 +1,35 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: patchy
3
- Version: 2.8.0
3
+ Version: 2.10.0
4
4
  Summary: Patch the inner source of python functions at runtime.
5
- Home-page: https://github.com/adamchainz/patchy
6
- Author: Adam Johnson
7
- Author-email: me@adamj.eu
8
- License: MIT
5
+ Author-email: Adam Johnson <me@adamj.eu>
6
+ License-Expression: MIT
9
7
  Project-URL: Changelog, https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst
10
- Project-URL: Mastodon, https://fosstodon.org/@adamchainz
11
- Project-URL: Twitter, https://twitter.com/adamchainz
8
+ Project-URL: Funding, https://adamj.eu/books/
9
+ Project-URL: Repository, https://github.com/adamchainz/patchy
12
10
  Keywords: patchy
13
11
  Classifier: Development Status :: 5 - Production/Stable
14
12
  Classifier: Intended Audience :: Developers
15
- Classifier: License :: OSI Approved :: MIT License
16
13
  Classifier: Natural Language :: English
17
14
  Classifier: Operating System :: OS Independent
18
- Classifier: Programming Language :: Python :: 3
19
15
  Classifier: Programming Language :: Python :: 3 :: Only
20
- Classifier: Programming Language :: Python :: 3.8
21
16
  Classifier: Programming Language :: Python :: 3.9
22
17
  Classifier: Programming Language :: Python :: 3.10
23
18
  Classifier: Programming Language :: Python :: 3.11
24
19
  Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
25
22
  Classifier: Typing :: Typed
26
- Requires-Python: >=3.8
23
+ Requires-Python: >=3.9
27
24
  Description-Content-Type: text/x-rst
28
25
  License-File: LICENSE
26
+ Dynamic: license-file
29
27
 
30
28
  ======
31
29
  Patchy
32
30
  ======
33
31
 
34
- .. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/patchy/main.yml?branch=main&style=for-the-badge
32
+ .. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/patchy/main.yml.svg?branch=main&style=for-the-badge
35
33
  :target: https://github.com/adamchainz/patchy/actions?workflow=CI
36
34
 
37
35
  .. image:: https://img.shields.io/badge/Coverage-100%25-success?style=for-the-badge
@@ -78,6 +76,12 @@ function object itself the same. It's thus more versatile than monkey patching,
78
76
  since if the function has been imported in multiple places they'll also call
79
77
  the new behaviour.
80
78
 
79
+ ----
80
+
81
+ **Hacking on a Django project?**
82
+ Check out my book `Boost Your Django DX <https://adamchainz.gumroad.com/l/byddx>`__ which covers many ways to improve your development experience.
83
+
84
+ ----
81
85
 
82
86
  Installation
83
87
  ============
@@ -88,14 +92,7 @@ Use **pip**:
88
92
 
89
93
  python -m pip install patchy
90
94
 
91
- Python 3.8 to 3.12 supported.
92
-
93
- ----
94
-
95
- **Hacking on a Django project?**
96
- Check out my book `Boost Your Django DX <https://adamchainz.gumroad.com/l/byddx>`__ which covers many ways to improve your development experience.
97
-
98
- ----
95
+ Python 3.9 to 3.14 supported.
99
96
 
100
97
  Why?
101
98
  ====
@@ -4,7 +4,6 @@ MANIFEST.in
4
4
  README.rst
5
5
  pirate.png
6
6
  pyproject.toml
7
- setup.cfg
8
7
  src/patchy/__init__.py
9
8
  src/patchy/api.py
10
9
  src/patchy/cache.py
@@ -12,8 +11,6 @@ src/patchy/py.typed
12
11
  src/patchy.egg-info/PKG-INFO
13
12
  src/patchy.egg-info/SOURCES.txt
14
13
  src/patchy.egg-info/dependency_links.txt
15
- src/patchy.egg-info/not-zip-safe
16
- src/patchy.egg-info/requires.txt
17
14
  src/patchy.egg-info/top_level.txt
18
15
  tests/test_cache.py
19
16
  tests/test_patch.py
@@ -862,13 +862,13 @@ def test_patch_future_instancemethod(tmp_path):
862
862
 
863
863
 
864
864
  def test_patch_nonlocal_fails():
865
- variab = 20
865
+ variab = 20 # noqa: F841
866
866
 
867
867
  def get_function() -> Callable[[], int]:
868
868
  variab = 15
869
869
 
870
870
  def sample() -> int:
871
- nonlocal variab
871
+ nonlocal variab # noqa: F824
872
872
  multiple = 3
873
873
  return variab * multiple
874
874
 
@@ -882,7 +882,7 @@ def test_patch_nonlocal_fails():
882
882
  sample,
883
883
  """\
884
884
  @@ -2,3 +2,3 @@
885
- nonlocal variab
885
+ nonlocal variab # noqa: F824
886
886
  - multiple = 3
887
887
  + multiple = 4
888
888
  """,
@@ -30,7 +30,7 @@ def test_patch_unpatch():
30
30
  )
31
31
 
32
32
  try:
33
- patchy.api.mkdtemp = mkdtemp # type: ignore [attr-defined]
33
+ patchy.api.mkdtemp = mkdtemp # type: ignore [attr-defined,assignment]
34
34
  patchy.unpatch(sample, patch_text)
35
35
  finally:
36
36
  patchy.api.mkdtemp = orig_mkdtemp # type: ignore [attr-defined]
@@ -38,7 +38,7 @@ def test_patch_unpatch():
38
38
 
39
39
  # Check that we use the cache going forwards again
40
40
  try:
41
- patchy.api.mkdtemp = mkdtemp # type: ignore [attr-defined]
41
+ patchy.api.mkdtemp = mkdtemp # type: ignore [attr-defined,assignment]
42
42
  patchy.patch(sample, patch_text)
43
43
  finally:
44
44
  patchy.api.mkdtemp = orig_mkdtemp # type: ignore [attr-defined]
@@ -1,29 +0,0 @@
1
- [build-system]
2
- build-backend = "setuptools.build_meta"
3
- requires = [
4
- "setuptools",
5
- ]
6
-
7
- [tool.black]
8
- target-version = ['py38']
9
-
10
- [tool.pytest.ini_options]
11
- addopts = """\
12
- --strict-config
13
- --strict-markers
14
- """
15
- xfail_strict = true
16
-
17
- [tool.mypy]
18
- mypy_path = "src/"
19
- namespace_packages = false
20
- show_error_codes = true
21
- strict = true
22
- warn_unreachable = true
23
-
24
- [[tool.mypy.overrides]]
25
- module = "tests.*"
26
- allow_untyped_defs = true
27
-
28
- [tool.rstcheck]
29
- report_level = "ERROR"
patchy-2.8.0/setup.cfg DELETED
@@ -1,67 +0,0 @@
1
- [metadata]
2
- name = patchy
3
- version = 2.8.0
4
- description = Patch the inner source of python functions at runtime.
5
- long_description = file: README.rst
6
- long_description_content_type = text/x-rst
7
- url = https://github.com/adamchainz/patchy
8
- author = Adam Johnson
9
- author_email = me@adamj.eu
10
- license = MIT
11
- license_files = LICENSE
12
- classifiers =
13
- Development Status :: 5 - Production/Stable
14
- Intended Audience :: Developers
15
- License :: OSI Approved :: MIT License
16
- Natural Language :: English
17
- Operating System :: OS Independent
18
- Programming Language :: Python :: 3
19
- Programming Language :: Python :: 3 :: Only
20
- Programming Language :: Python :: 3.8
21
- Programming Language :: Python :: 3.9
22
- Programming Language :: Python :: 3.10
23
- Programming Language :: Python :: 3.11
24
- Programming Language :: Python :: 3.12
25
- Typing :: Typed
26
- keywords = patchy
27
- project_urls =
28
- Changelog = https://github.com/adamchainz/patchy/blob/main/CHANGELOG.rst
29
- Mastodon = https://fosstodon.org/@adamchainz
30
- Twitter = https://twitter.com/adamchainz
31
-
32
- [options]
33
- packages = find:
34
- install_requires =
35
- pkgutil-resolve-name;python_version < "3.9"
36
- python_requires = >=3.8
37
- include_package_data = True
38
- package_dir =
39
- =src
40
- zip_safe = False
41
-
42
- [options.packages.find]
43
- where = src
44
-
45
- [coverage:run]
46
- branch = True
47
- parallel = True
48
- source =
49
- patchy
50
- tests
51
-
52
- [coverage:paths]
53
- source =
54
- src
55
- .tox/**/site-packages
56
-
57
- [coverage:report]
58
- show_missing = True
59
-
60
- [flake8]
61
- max-line-length = 88
62
- extend-ignore = E203
63
-
64
- [egg_info]
65
- tag_build =
66
- tag_date = 0
67
-
@@ -1 +0,0 @@
1
-
@@ -1,3 +0,0 @@
1
-
2
- [:python_version < "3.9"]
3
- pkgutil-resolve-name
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes