zope.hookable 6.0__tar.gz → 7.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.

Potentially problematic release.


This version of zope.hookable might be problematic. Click here for more details.

Files changed (46) hide show
  1. {zope.hookable-6.0 → zope_hookable-7.0}/.manylinux-install.sh +7 -7
  2. zope_hookable-7.0/.pre-commit-config.yaml +28 -0
  3. {zope.hookable-6.0 → zope_hookable-7.0}/CHANGES.rst +14 -0
  4. {zope.hookable-6.0 → zope_hookable-7.0}/MANIFEST.in +1 -2
  5. {zope.hookable-6.0 → zope_hookable-7.0}/PKG-INFO +17 -3
  6. {zope.hookable-6.0 → zope_hookable-7.0}/docs/_build/doctest/output.txt +1 -1
  7. zope_hookable-7.0/docs/conf.py +37 -0
  8. zope_hookable-7.0/pyproject.toml +25 -0
  9. {zope.hookable-6.0 → zope_hookable-7.0}/setup.cfg +0 -3
  10. {zope.hookable-6.0 → zope_hookable-7.0}/setup.py +3 -4
  11. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope/hookable/__init__.py +7 -3
  12. zope_hookable-7.0/src/zope/hookable/_zope_hookable.c +285 -0
  13. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope/hookable/tests/test_hookable.py +6 -1
  14. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope.hookable.egg-info/PKG-INFO +17 -3
  15. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope.hookable.egg-info/SOURCES.txt +2 -2
  16. {zope.hookable-6.0 → zope_hookable-7.0}/tox.ini +28 -22
  17. zope.hookable-6.0/.coveragerc +0 -29
  18. zope.hookable-6.0/appveyor.yml +0 -49
  19. zope.hookable-6.0/docs/conf.py +0 -248
  20. zope.hookable-6.0/src/zope/hookable/_zope_hookable.c +0 -264
  21. {zope.hookable-6.0 → zope_hookable-7.0}/.manylinux.sh +0 -0
  22. {zope.hookable-6.0 → zope_hookable-7.0}/.readthedocs.yaml +0 -0
  23. {zope.hookable-6.0 → zope_hookable-7.0}/CONTRIBUTING.md +0 -0
  24. {zope.hookable-6.0 → zope_hookable-7.0}/COPYRIGHT.txt +0 -0
  25. {zope.hookable-6.0 → zope_hookable-7.0}/LICENSE.txt +0 -0
  26. {zope.hookable-6.0 → zope_hookable-7.0}/README.rst +0 -0
  27. {zope.hookable-6.0 → zope_hookable-7.0}/buildout.cfg +0 -0
  28. {zope.hookable-6.0 → zope_hookable-7.0}/docs/Makefile +0 -0
  29. {zope.hookable-6.0 → zope_hookable-7.0}/docs/_build/html/_sources/api.rst.txt +0 -0
  30. {zope.hookable-6.0 → zope_hookable-7.0}/docs/_build/html/_sources/hacking.rst.txt +0 -0
  31. {zope.hookable-6.0 → zope_hookable-7.0}/docs/_build/html/_sources/index.rst.txt +0 -0
  32. {zope.hookable-6.0 → zope_hookable-7.0}/docs/_build/html/_sources/narr.rst.txt +0 -0
  33. {zope.hookable-6.0 → zope_hookable-7.0}/docs/api.rst +0 -0
  34. {zope.hookable-6.0 → zope_hookable-7.0}/docs/hacking.rst +0 -0
  35. {zope.hookable-6.0 → zope_hookable-7.0}/docs/index.rst +0 -0
  36. {zope.hookable-6.0 → zope_hookable-7.0}/docs/make.bat +0 -0
  37. {zope.hookable-6.0 → zope_hookable-7.0}/docs/narr.rst +0 -0
  38. {zope.hookable-6.0 → zope_hookable-7.0}/docs/requirements.txt +0 -0
  39. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope/__init__.py +0 -0
  40. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope/hookable/tests/__init__.py +0 -0
  41. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope/hookable/tests/test_compile_flags.py +0 -0
  42. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope.hookable.egg-info/dependency_links.txt +0 -0
  43. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope.hookable.egg-info/namespace_packages.txt +0 -0
  44. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope.hookable.egg-info/not-zip-safe +0 -0
  45. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope.hookable.egg-info/requires.txt +0 -0
  46. {zope.hookable-6.0 → zope_hookable-7.0}/src/zope.hookable.egg-info/top_level.txt +0 -0
@@ -28,12 +28,12 @@ yum -y install libffi-devel
28
28
 
29
29
  tox_env_map() {
30
30
  case $1 in
31
- *"cp37"*) echo 'py37';;
32
31
  *"cp38"*) echo 'py38';;
33
32
  *"cp39"*) echo 'py39';;
34
33
  *"cp310"*) echo 'py310';;
35
34
  *"cp311"*) echo 'py311';;
36
35
  *"cp312"*) echo 'py312';;
36
+ *"cp313"*) echo 'py313';;
37
37
  *) echo 'py';;
38
38
  esac
39
39
  }
@@ -41,12 +41,12 @@ tox_env_map() {
41
41
  # Compile wheels
42
42
  for PYBIN in /opt/python/*/bin; do
43
43
  if \
44
- [[ "${PYBIN}" == *"cp311"* ]] || \
45
- [[ "${PYBIN}" == *"cp312"* ]] || \
46
- [[ "${PYBIN}" == *"cp37"* ]] || \
47
- [[ "${PYBIN}" == *"cp38"* ]] || \
48
- [[ "${PYBIN}" == *"cp39"* ]] || \
49
- [[ "${PYBIN}" == *"cp310"* ]] ; then
44
+ [[ "${PYBIN}" == *"cp38/"* ]] || \
45
+ [[ "${PYBIN}" == *"cp39/"* ]] || \
46
+ [[ "${PYBIN}" == *"cp310/"* ]] || \
47
+ [[ "${PYBIN}" == *"cp311/"* ]] || \
48
+ [[ "${PYBIN}" == *"cp312/"* ]] || \
49
+ [[ "${PYBIN}" == *"cp313/"* ]] ; then
50
50
  "${PYBIN}/pip" install -e /io/
51
51
  "${PYBIN}/pip" wheel /io/ -w wheelhouse/
52
52
  if [ `uname -m` == 'aarch64' ]; then
@@ -0,0 +1,28 @@
1
+ # Generated from:
2
+ # https://github.com/zopefoundation/meta/tree/master/config/c-code
3
+ minimum_pre_commit_version: '3.6'
4
+ repos:
5
+ - repo: https://github.com/pycqa/isort
6
+ rev: "5.13.2"
7
+ hooks:
8
+ - id: isort
9
+ - repo: https://github.com/hhatto/autopep8
10
+ rev: "v2.3.1"
11
+ hooks:
12
+ - id: autopep8
13
+ args: [--in-place, --aggressive, --aggressive]
14
+ - repo: https://github.com/asottile/pyupgrade
15
+ rev: v3.17.0
16
+ hooks:
17
+ - id: pyupgrade
18
+ args: [--py38-plus]
19
+ - repo: https://github.com/isidentical/teyit
20
+ rev: 0.4.3
21
+ hooks:
22
+ - id: teyit
23
+ - repo: https://github.com/PyCQA/flake8
24
+ rev: "7.1.1"
25
+ hooks:
26
+ - id: flake8
27
+ additional_dependencies:
28
+ - flake8-debugger == 4.1.2
@@ -2,6 +2,20 @@
2
2
  Changes
3
3
  =========
4
4
 
5
+ 7.0 (2024-09-17)
6
+ ================
7
+
8
+ - C extension now enables multi-phase module initialization (PEP 489).
9
+ For CPython >= 3.11, the ``hookable`` type is now a heap-allocated
10
+ type. See:
11
+ https://docs.python.org/3.13/howto/isolating-extensions.html
12
+
13
+ - Drop support for Python 3.7.
14
+
15
+ - Add support for Python 3.13.
16
+
17
+ - Build windows wheels on GHA.
18
+
5
19
  6.0 (2023-10-05)
6
20
  ================
7
21
 
@@ -5,8 +5,7 @@ include *.rst
5
5
  include *.txt
6
6
  include buildout.cfg
7
7
  include tox.ini
8
- include appveyor.yml
9
- include .coveragerc
8
+ include .pre-commit-config.yaml
10
9
 
11
10
  recursive-include docs *.py
12
11
  recursive-include docs *.rst
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zope.hookable
3
- Version: 6.0
3
+ Version: 7.0
4
4
  Summary: Zope hookable
5
5
  Home-page: http://github.com/zopefoundation/zope.hookable
6
6
  Author: Zope Foundation and Contributors
@@ -13,17 +13,17 @@ Classifier: License :: OSI Approved :: Zope Public License
13
13
  Classifier: Operating System :: OS Independent
14
14
  Classifier: Programming Language :: Python
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.7
17
16
  Classifier: Programming Language :: Python :: 3.8
18
17
  Classifier: Programming Language :: Python :: 3.9
19
18
  Classifier: Programming Language :: Python :: 3.10
20
19
  Classifier: Programming Language :: Python :: 3.11
21
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Programming Language :: Python :: Implementation :: CPython
23
23
  Classifier: Programming Language :: Python :: Implementation :: PyPy
24
24
  Classifier: Framework :: Zope :: 3
25
25
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
- Requires-Python: >=3.7
26
+ Requires-Python: >=3.8
27
27
  License-File: LICENSE.txt
28
28
  Requires-Dist: setuptools
29
29
  Provides-Extra: docs
@@ -75,6 +75,20 @@ Documentation is hosted at https://zopehookable.readthedocs.io
75
75
  Changes
76
76
  =========
77
77
 
78
+ 7.0 (2024-09-17)
79
+ ================
80
+
81
+ - C extension now enables multi-phase module initialization (PEP 489).
82
+ For CPython >= 3.11, the ``hookable`` type is now a heap-allocated
83
+ type. See:
84
+ https://docs.python.org/3.13/howto/isolating-extensions.html
85
+
86
+ - Drop support for Python 3.7.
87
+
88
+ - Add support for Python 3.13.
89
+
90
+ - Build windows wheels on GHA.
91
+
78
92
  6.0 (2023-10-05)
79
93
  ================
80
94
 
@@ -1,4 +1,4 @@
1
- Results of doctest builder run on 2023-10-05 13:43:00
1
+ Results of doctest builder run on 2024-09-17 08:22:56
2
2
  =====================================================
3
3
 
4
4
  Document: narr
@@ -0,0 +1,37 @@
1
+ # Configuration file for the Sphinx documentation builder.
2
+ #
3
+ # For the full list of built-in configuration values, see the documentation:
4
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html
5
+
6
+ import datetime
7
+
8
+
9
+ # -- Project information -----------------------------------------------------
10
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
11
+ year = datetime.datetime.now().year
12
+
13
+ project = 'zope.hookable'
14
+ copyright = f'2012-{year}, Zope Foundation and contributors'
15
+ author = 'Zope Foundation and contributors'
16
+
17
+ # -- General configuration ---------------------------------------------------
18
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
19
+
20
+ extensions = [
21
+ 'sphinx.ext.autodoc',
22
+ 'sphinx.ext.doctest',
23
+ 'sphinx.ext.intersphinx',
24
+ ]
25
+
26
+ templates_path = ['_templates']
27
+ exclude_patterns = []
28
+
29
+
30
+ # -- Options for HTML output -------------------------------------------------
31
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
32
+
33
+ html_theme = 'sphinx_rtd_theme'
34
+ html_static_path = ['_static']
35
+
36
+ # Example configuration for intersphinx: refer to the Python standard library.
37
+ intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)}
@@ -0,0 +1,25 @@
1
+ #
2
+ # Generated from:
3
+ # https://github.com/zopefoundation/meta/tree/master/config/c-code
4
+
5
+ [build-system]
6
+ requires = ["setuptools<74"]
7
+ build-backend = "setuptools.build_meta"
8
+
9
+ [tool.coverage.run]
10
+ branch = true
11
+ source = ["zope.hookable"]
12
+ relative_files = true
13
+
14
+ [tool.coverage.report]
15
+ fail_under = 98
16
+ precision = 2
17
+ ignore_errors = true
18
+ show_missing = true
19
+ exclude_lines = ["pragma: no cover", "pragma: nocover", "except ImportError:", "raise NotImplementedError", "if __name__ == '__main__':", "self.fail", "raise AssertionError", "raise unittest.Skip"]
20
+
21
+ [tool.coverage.html]
22
+ directory = "parts/htmlcov"
23
+
24
+ [tool.coverage.paths]
25
+ source = ["src/", ".tox/*/lib/python*/site-packages/", ".tox/pypy*/site-packages/"]
@@ -1,6 +1,3 @@
1
- [bdist_wheel]
2
- universal = 0
3
-
4
1
  [zest.releaser]
5
2
  create-wheel = no
6
3
 
@@ -85,7 +85,7 @@ TESTS_REQUIRE = [
85
85
  ]
86
86
 
87
87
  setup(name='zope.hookable',
88
- version='6.0',
88
+ version='7.0',
89
89
  url='http://github.com/zopefoundation/zope.hookable',
90
90
  license='ZPL 2.1',
91
91
  description='Zope hookable',
@@ -101,12 +101,12 @@ setup(name='zope.hookable',
101
101
  "Operating System :: OS Independent",
102
102
  "Programming Language :: Python",
103
103
  "Programming Language :: Python :: 3",
104
- "Programming Language :: Python :: 3.7",
105
104
  "Programming Language :: Python :: 3.8",
106
105
  "Programming Language :: Python :: 3.9",
107
106
  "Programming Language :: Python :: 3.10",
108
107
  "Programming Language :: Python :: 3.11",
109
108
  "Programming Language :: Python :: 3.12",
109
+ "Programming Language :: Python :: 3.13",
110
110
  "Programming Language :: Python :: Implementation :: CPython",
111
111
  "Programming Language :: Python :: Implementation :: PyPy",
112
112
  "Framework :: Zope :: 3",
@@ -124,11 +124,10 @@ setup(name='zope.hookable',
124
124
  ],
125
125
  include_package_data=True,
126
126
  zip_safe=False,
127
- test_suite='zope.hookable.tests.test_hookable.test_suite',
128
127
  extras_require={
129
128
  'docs': ['Sphinx', 'sphinx_rtd_theme'],
130
129
  'testing': TESTS_REQUIRE + ['coverage'],
131
130
  'test': TESTS_REQUIRE,
132
131
  },
133
- python_requires='>=3.7',
132
+ python_requires='>=3.8',
134
133
  )
@@ -17,8 +17,12 @@ import os
17
17
  import platform
18
18
 
19
19
 
20
- _PYPY = platform.python_implementation() in ('PyPy', 'Jython')
21
- _PURE_PYTHON = os.environ.get('PURE_PYTHON', _PYPY)
20
+ # Keep these two flags separate: we want the `_PURE_PYTHON` one
21
+ # to represent that the flag is explicitly set to '1' in the environment,
22
+ # since our 'tox.ini' sets it to '0' for its environments which expect
23
+ # to test the C extension.
24
+ _PYPY_OR_JAVA = platform.python_implementation() in ('PyPy', 'Jython')
25
+ _PURE_PYTHON = os.environ.get('PURE_PYTHON') == '1'
22
26
 
23
27
 
24
28
  class _py_hookable:
@@ -69,7 +73,7 @@ try:
69
73
  except ImportError: # pragma: no cover
70
74
  _c_hookable = None
71
75
 
72
- if _PURE_PYTHON or _c_hookable is None:
76
+ if _PYPY_OR_JAVA or _PURE_PYTHON or _c_hookable is None:
73
77
  hookable = _py_hookable
74
78
  else: # pragma: no cover
75
79
  hookable = _c_hookable
@@ -0,0 +1,285 @@
1
+ /*############################################################################
2
+ #
3
+ # Copyright (c) 2003 Zope Foundation and Contributors.
4
+ # All Rights Reserved.
5
+ #
6
+ # This software is subject to the provisions of the Zope Public License,
7
+ # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
8
+ # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
9
+ # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10
+ # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
11
+ # FOR A PARTICULAR PURPOSE.
12
+ #
13
+ ############################################################################*/
14
+
15
+ static char module__doc__[] = (
16
+ "Provide an efficient implementation for hookable objects"
17
+ );
18
+
19
+ #include "Python.h"
20
+ #include "structmember.h"
21
+
22
+ typedef struct
23
+ {
24
+ PyObject_HEAD
25
+ PyObject* original;
26
+ PyObject* implementation;
27
+ } hookable;
28
+
29
+ static int
30
+ hookable_init(hookable* self, PyObject* args, PyObject* kwds)
31
+ {
32
+ static char* kwlist[] = { "implementation", NULL };
33
+ PyObject* implementation;
34
+
35
+ if (!PyArg_ParseTupleAndKeywords(
36
+ args, kwds, "O:hookable", kwlist, &implementation))
37
+ return -1;
38
+
39
+ /* Both 'self->original' and 'self->implementation' are originally
40
+ * set to the passed-in 'implementation', hence the need for
41
+ * two increfs.
42
+ */
43
+ Py_INCREF(implementation);
44
+ Py_XDECREF(self->original);
45
+ self->original = implementation;
46
+
47
+ Py_INCREF(implementation);
48
+ Py_XDECREF(self->implementation);
49
+ self->implementation = implementation;
50
+
51
+ return 0;
52
+ }
53
+
54
+ static int
55
+ hookable_traverse(hookable* self, visitproc visit, void* arg)
56
+ {
57
+ #if PY_VERSION_HEX >= 0x03090000
58
+ Py_VISIT(Py_TYPE(self));
59
+ #endif
60
+ Py_VISIT(self->implementation);
61
+ Py_VISIT(self->original);
62
+ return 0;
63
+ }
64
+
65
+ static int
66
+ hookable_clear(hookable* self)
67
+ {
68
+ Py_XDECREF(self->original);
69
+ self->original = NULL;
70
+
71
+ Py_XDECREF(self->implementation);
72
+ self->implementation = NULL;
73
+
74
+ return 0;
75
+ }
76
+
77
+ static void
78
+ hookable_dealloc(hookable* self)
79
+ {
80
+ PyObject_GC_UnTrack((PyObject*)self);
81
+ PyTypeObject* tp = Py_TYPE(self);
82
+
83
+ Py_XDECREF(self->original);
84
+ Py_XDECREF(self->implementation);
85
+
86
+ tp->tp_free((PyObject*)self);
87
+
88
+ /* heap types must decref their type when dealloc'ed */
89
+ Py_DECREF(tp);
90
+ }
91
+
92
+ static PyObject*
93
+ hookable_call(hookable* self, PyObject* args, PyObject* kw)
94
+ {
95
+ if (self->implementation != NULL)
96
+ return PyObject_Call(self->implementation, args, kw);
97
+
98
+ PyErr_SetString(PyExc_TypeError, "Hookable has no implementation");
99
+ return NULL;
100
+ }
101
+
102
+ static PyObject*
103
+ hookable_getattro(hookable* self, PyObject* name)
104
+ {
105
+ PyObject* result = NULL;
106
+ const char* name_as_string;
107
+ int maybe_special_name;
108
+
109
+ name_as_string = PyUnicode_AsUTF8(name);
110
+ if (name_as_string == NULL) { return NULL; }
111
+
112
+ maybe_special_name = name_as_string[0] == '_' && name_as_string[1] == '_';
113
+
114
+ if (maybe_special_name) {
115
+ /* pass through __doc__ to the original implementation */
116
+ if (strcmp("__doc__", name_as_string) == 0) {
117
+ return PyObject_GetAttr(self->original, name);
118
+ }
119
+ /* synthesize __bases__ and __dict__ if the original fails */
120
+ if (strcmp("__bases__", name_as_string) == 0) {
121
+ result = PyObject_GetAttr(self->original, name);
122
+ if (result == NULL) {
123
+ PyErr_Clear();
124
+ result = PyTuple_New(0);
125
+ }
126
+ return result;
127
+ }
128
+ if (strcmp("__dict__", name_as_string) == 0) {
129
+ result = PyObject_GetAttr(self->original, name);
130
+ if (result == NULL) {
131
+ PyErr_Clear();
132
+ result = PyDict_New();
133
+ }
134
+ return result;
135
+ }
136
+ }
137
+
138
+ return PyObject_GenericGetAttr((PyObject*)self, name);
139
+ }
140
+
141
+ static char hookable_sethook__doc__[] = (
142
+ "Set the hook implementation for the hookable object\n\n"
143
+ "Return the previous hook implementation, or None."
144
+ );
145
+
146
+ static PyObject*
147
+ hookable_sethook(hookable* self, PyObject* implementation)
148
+ {
149
+ PyObject* current;
150
+
151
+ current = self->implementation;
152
+ Py_INCREF(implementation);
153
+ self->implementation = implementation;
154
+
155
+ if (current == NULL) {
156
+ Py_INCREF(Py_None);
157
+ return Py_None;
158
+ }
159
+
160
+ return current;
161
+ }
162
+
163
+ static char hookable_reset__doc__[] = (
164
+ "Reset the hook to the original value"
165
+ );
166
+
167
+ static PyObject*
168
+ hookable_reset(hookable* self)
169
+ {
170
+ Py_XINCREF(self->original);
171
+ Py_XDECREF(self->implementation);
172
+
173
+ self->implementation = self->original;
174
+
175
+ Py_INCREF(Py_None);
176
+ return Py_None;
177
+ }
178
+
179
+ static struct PyMethodDef hookable_methods[] = {
180
+ { "sethook",
181
+ (PyCFunction)hookable_sethook, METH_O, hookable_sethook__doc__ },
182
+ { "reset",
183
+ (PyCFunction)hookable_reset, METH_NOARGS, hookable_reset__doc__},
184
+ { NULL, NULL } /* sentinel */
185
+ };
186
+
187
+ static PyMemberDef hookable_members[] = {
188
+ { "original",
189
+ T_OBJECT_EX, offsetof(hookable, original), READONLY },
190
+ { "implementation",
191
+ T_OBJECT_EX, offsetof(hookable, implementation), READONLY },
192
+ { NULL } /* Sentinel */
193
+ };
194
+
195
+ static char hookable__name__[] = "zope.hookable.hookable";
196
+ static char hookable__doc__[] =
197
+ "Callable objects that support being overridden";
198
+
199
+
200
+ /*
201
+ * Heap type: hookable
202
+ */
203
+ static PyType_Slot hookable_type_slots[] = {
204
+ {Py_tp_doc, hookable__doc__},
205
+ {Py_tp_init, hookable_init},
206
+ {Py_tp_call, hookable_call},
207
+ {Py_tp_getattro, hookable_getattro},
208
+ {Py_tp_traverse, hookable_traverse},
209
+ {Py_tp_clear, hookable_clear},
210
+ {Py_tp_dealloc, hookable_dealloc},
211
+ {Py_tp_members, hookable_members},
212
+ {Py_tp_methods, hookable_methods},
213
+ {0, NULL}
214
+ };
215
+
216
+ static PyType_Spec hookable_type_spec = {
217
+ .name = hookable__name__,
218
+ .basicsize = sizeof(hookable),
219
+ .flags = Py_TPFLAGS_DEFAULT |
220
+ Py_TPFLAGS_BASETYPE |
221
+ #if PY_VERSION_HEX >= 0x030c0000
222
+ Py_TPFLAGS_MANAGED_WEAKREF |
223
+ #endif
224
+ Py_TPFLAGS_HAVE_GC,
225
+ .slots = hookable_type_slots
226
+ };
227
+
228
+ /*
229
+ * Module initialization
230
+ */
231
+
232
+ static struct PyMethodDef hookable_module_methods[] = {
233
+ { NULL, NULL } /* sentinel */
234
+ };
235
+
236
+
237
+ /* Handler for the 'execute' phase of multi-phase initialization
238
+ *
239
+ * See: https://docs.python.org/3/c-api/module.html#multi-phase-initialization
240
+ * and: https://peps.python.org/pep-0489/#module-execution-phase
241
+ */
242
+ static int
243
+ hookable_module_exec(PyObject* module)
244
+ {
245
+ PyObject* hookable_type;
246
+
247
+ hookable_type = PyType_FromSpec(&hookable_type_spec);
248
+ if (hookable_type == NULL) { return -1; }
249
+
250
+ if (PyModule_AddObject(module, "hookable", hookable_type) < 0)
251
+ return -1;
252
+
253
+ return 0;
254
+ }
255
+
256
+
257
+ /* Slot definitions for multi-phase initialization
258
+ *
259
+ * See: https://docs.python.org/3/c-api/module.html#multi-phase-initialization
260
+ * and: https://peps.python.org/pep-0489
261
+ */
262
+ static PyModuleDef_Slot hookable_module_slots[] = {
263
+ {Py_mod_exec, hookable_module_exec},
264
+ {0, NULL}
265
+ };
266
+
267
+ static struct PyModuleDef hookable_module_def = {
268
+ PyModuleDef_HEAD_INIT,
269
+ .m_name = "_zope_hookable",
270
+ .m_doc = module__doc__,
271
+ .m_methods = hookable_module_methods,
272
+ .m_slots = hookable_module_slots
273
+ };
274
+
275
+ static PyObject*
276
+ init(void)
277
+ {
278
+ return PyModuleDef_Init(&hookable_module_def);
279
+ }
280
+
281
+ PyMODINIT_FUNC
282
+ PyInit__zope_hookable(void)
283
+ {
284
+ return init();
285
+ }
@@ -50,10 +50,15 @@ class PyHookableTests(PyHookableMixin,
50
50
 
51
51
  def test_pure_python(self):
52
52
  from zope.hookable import _PURE_PYTHON
53
+ from zope.hookable import _PYPY_OR_JAVA
53
54
  from zope.hookable import _c_hookable
54
55
  from zope.hookable import _py_hookable
55
56
  from zope.hookable import hookable
56
- self.assertIs(hookable, _py_hookable if _PURE_PYTHON else _c_hookable)
57
+
58
+ if _PYPY_OR_JAVA or _PURE_PYTHON:
59
+ self.assertIs(hookable, _py_hookable)
60
+ else:
61
+ self.assertIs(hookable, _c_hookable)
57
62
 
58
63
  def test_before_hook(self):
59
64
  hooked = self._callFUT(return_foo)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zope.hookable
3
- Version: 6.0
3
+ Version: 7.0
4
4
  Summary: Zope hookable
5
5
  Home-page: http://github.com/zopefoundation/zope.hookable
6
6
  Author: Zope Foundation and Contributors
@@ -13,17 +13,17 @@ Classifier: License :: OSI Approved :: Zope Public License
13
13
  Classifier: Operating System :: OS Independent
14
14
  Classifier: Programming Language :: Python
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.7
17
16
  Classifier: Programming Language :: Python :: 3.8
18
17
  Classifier: Programming Language :: Python :: 3.9
19
18
  Classifier: Programming Language :: Python :: 3.10
20
19
  Classifier: Programming Language :: Python :: 3.11
21
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Programming Language :: Python :: Implementation :: CPython
23
23
  Classifier: Programming Language :: Python :: Implementation :: PyPy
24
24
  Classifier: Framework :: Zope :: 3
25
25
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
- Requires-Python: >=3.7
26
+ Requires-Python: >=3.8
27
27
  License-File: LICENSE.txt
28
28
  Requires-Dist: setuptools
29
29
  Provides-Extra: docs
@@ -75,6 +75,20 @@ Documentation is hosted at https://zopehookable.readthedocs.io
75
75
  Changes
76
76
  =========
77
77
 
78
+ 7.0 (2024-09-17)
79
+ ================
80
+
81
+ - C extension now enables multi-phase module initialization (PEP 489).
82
+ For CPython >= 3.11, the ``hookable`` type is now a heap-allocated
83
+ type. See:
84
+ https://docs.python.org/3.13/howto/isolating-extensions.html
85
+
86
+ - Drop support for Python 3.7.
87
+
88
+ - Add support for Python 3.13.
89
+
90
+ - Build windows wheels on GHA.
91
+
78
92
  6.0 (2023-10-05)
79
93
  ================
80
94
 
@@ -1,6 +1,6 @@
1
- .coveragerc
2
1
  .manylinux-install.sh
3
2
  .manylinux.sh
3
+ .pre-commit-config.yaml
4
4
  .readthedocs.yaml
5
5
  CHANGES.rst
6
6
  CONTRIBUTING.md
@@ -8,8 +8,8 @@ COPYRIGHT.txt
8
8
  LICENSE.txt
9
9
  MANIFEST.in
10
10
  README.rst
11
- appveyor.yml
12
11
  buildout.cfg
12
+ pyproject.toml
13
13
  setup.cfg
14
14
  setup.py
15
15
  tox.ini