• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zopefoundation / zope.hookable / 16098872535

17 Feb 2025 07:53AM UTC coverage: 100.0%. Remained the same
16098872535

push

github

web-flow
Update supported Python versions. (#43)

* Drop support for Python 3.8.
* Add preliminary support for Python 3.14.

51 of 51 branches covered (100.0%)

Branch coverage included in aggregate %.

173 of 173 relevant lines covered (100.0%)

6.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/zope/hookable/tests/test_hookable.py
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
"""Test the hookable support Extension
7✔
15
"""
16
import unittest
7✔
17

18

19
def return_foo():
7✔
20
    return 'FOO'
7✔
21

22

23
def return_bar():
7✔
24
    return 'BAR'
7✔
25

26

27
def not_called():
7✔
28
    raise AssertionError("This should not be called")
29

30

31
class PyHookableMixin:
7✔
32

33
    def _callFUT(self, *args, **kw):
7✔
34
        from zope.hookable import _py_hookable
7✔
35
        return _py_hookable(*args, **kw)
7✔
36

37

38
class HookableMixin:
7✔
39

40
    def _callFUT(self, *args, **kw):
7✔
41
        from zope.hookable import _py_hookable
7✔
42
        from zope.hookable import hookable
7✔
43
        if hookable is _py_hookable:
7✔
44
            raise unittest.SkipTest("Hookable and PyHookable are the same")
45
        return hookable(*args, **kw)  # pragma: no cover
46

47

48
class PyHookableTests(PyHookableMixin,
7✔
49
                      unittest.TestCase):
50

51
    def test_pure_python(self):
7✔
52
        from zope.hookable import _PURE_PYTHON
7✔
53
        from zope.hookable import _PYPY_OR_JAVA
7✔
54
        from zope.hookable import _c_hookable
7✔
55
        from zope.hookable import _py_hookable
7✔
56
        from zope.hookable import hookable
7✔
57

58
        if _PYPY_OR_JAVA or _PURE_PYTHON:
7✔
59
            self.assertIs(hookable, _py_hookable)
7✔
60
        else:
61
            self.assertIs(hookable, _c_hookable)
6✔
62

63
    def test_before_hook(self):
7✔
64
        hooked = self._callFUT(return_foo)
7✔
65
        self.assertIs(hooked.original, return_foo)
7✔
66
        self.assertIs(hooked.implementation, return_foo)
7✔
67
        self.assertEqual(hooked(), 'FOO')
7✔
68

69
    def test_after_hook(self):
7✔
70
        hooked = self._callFUT(not_called)
7✔
71
        old = hooked.sethook(return_bar)
7✔
72
        self.assertIs(old, not_called)
7✔
73
        self.assertIs(hooked.original, not_called)
7✔
74
        self.assertIs(hooked.implementation, return_bar)
7✔
75
        self.assertEqual(hooked(), 'BAR')
7✔
76

77
    def test_after_hook_and_reset(self):
7✔
78
        hooked = self._callFUT(return_foo)
7✔
79
        old = hooked.sethook(not_called)
7✔
80
        hooked.reset()
7✔
81
        self.assertIs(old, return_foo)
7✔
82
        self.assertIs(hooked.original, return_foo)
7✔
83
        self.assertIs(hooked.implementation, return_foo)
7✔
84
        self.assertEqual(hooked(), 'FOO')
7✔
85

86
    def test_original_cannot_be_deleted(self):
7✔
87
        hooked = self._callFUT(not_called)
7✔
88
        with self.assertRaises((TypeError, AttributeError)):
7✔
89
            del hooked.original
7✔
90

91
    def test_implementation_cannot_be_deleted(self):
7✔
92
        hooked = self._callFUT(not_called)
7✔
93
        with self.assertRaises((TypeError, AttributeError)):
7✔
94
            del hooked.implementation
7✔
95

96
    def test_no_args(self):
7✔
97
        with self.assertRaises(TypeError):
7✔
98
            self._callFUT()
7✔
99

100
    def test_too_many_args(self):
7✔
101
        with self.assertRaises(TypeError):
7✔
102
            self._callFUT(not_called, not_called)
7✔
103

104
    def test_w_implementation_kwarg(self):
7✔
105
        hooked = self._callFUT(implementation=return_foo)
7✔
106
        self.assertIs(hooked.original, return_foo)
7✔
107
        self.assertIs(hooked.implementation, return_foo)
7✔
108
        self.assertEqual(hooked(), 'FOO')
7✔
109

110
    def test_w_unknown_kwarg(self):
7✔
111
        with self.assertRaises(TypeError):
7✔
112
            self._callFUT(nonesuch=42)
7✔
113

114
    def test_class(self):
7✔
115
        class C:
7✔
116
            pass
7✔
117

118
        hooked = self._callFUT(C)
7✔
119
        self.assertIsInstance(hooked(), C)
7✔
120

121
        hooked.sethook(return_bar)
7✔
122
        self.assertEqual(hooked(), 'BAR')
7✔
123

124

125
class TestIssue6Py(PyHookableMixin,
7✔
126
                   unittest.TestCase):
127
    # Make sphinx docs for hooked objects work.
128
    # https://github.com/zopefoundation/zope.hookable/issues/6
129
    # We need to proxy __doc__ to the original,
130
    # and synthesize an empty __bases__ and a __dict__ attribute
131
    # if they're not present.
132

133
    def _check_preserves_doc(self, docs):
7✔
134
        self.assertEqual("I have some docs", docs.__doc__)
7✔
135

136
        hooked = self._callFUT(docs)
7✔
137
        self.assertEqual(hooked.__doc__, docs.__doc__)
7✔
138

139
    def test_preserves_doc_function(self):
7✔
140
        def docs():
7✔
141
            """I have some docs"""
142
        self._check_preserves_doc(docs)
7✔
143

144
    def test_preserves_doc_class(self):
7✔
145
        class Docs:
7✔
146
            """I have some docs"""
147

148
        self._check_preserves_doc(Docs)
7✔
149

150
    def test_empty_bases_function(self):
7✔
151
        hooked = self._callFUT(return_foo)
7✔
152
        self.assertEqual((), hooked.__bases__)
7✔
153

154
    def test_empty_dict_function(self):
7✔
155
        hooked = self._callFUT(return_foo)
7✔
156
        self.assertEqual({}, hooked.__dict__)
7✔
157

158
    def test_bases_class(self):
7✔
159
        class C:
7✔
160
            pass
7✔
161
        self.assertEqual(C.__bases__, (object,))
7✔
162
        hooked = self._callFUT(C)
7✔
163
        self.assertEqual(hooked.__bases__, (object,))
7✔
164

165
    def test_dict_class(self):
7✔
166
        class C:
7✔
167
            pass
7✔
168

169
        hooked = self._callFUT(C)
7✔
170
        self.assertEqual(hooked.__dict__, C.__dict__)
7✔
171

172
    def test_non_string_attr_name(self):
7✔
173
        # Specifically for the C implementation, which has to deal with this
174
        hooked = self._callFUT(return_foo)
7✔
175
        with self.assertRaises(TypeError):
7✔
176
            getattr(hooked, 42)
7✔
177

178
        with self.assertRaises(TypeError):
7✔
179
            hooked.__getattribute__(42)
7✔
180

181
    def test_unicode_attribute_name(self):
7✔
182
        # Specifically for the C implementation, which has to deal with this
183
        hooked = self._callFUT(return_foo)
7✔
184
        result = hooked.__getattribute__('__bases__')
7✔
185
        self.assertEqual(result, ())
7✔
186

187
    def test_short_name(self):
7✔
188
        # Specifically for the C implementation, which has to deal with this
189
        hooked = self._callFUT(return_foo)
7✔
190
        with self.assertRaises(AttributeError):
7✔
191
            hooked.__getattribute__('')
7✔
192

193

194
class HookableTests(HookableMixin, PyHookableTests):
7✔
195
    pass
7✔
196

197

198
class TestIssue6(HookableMixin, TestIssue6Py):
7✔
199
    pass
7✔
200

201

202
def test_suite():
7✔
203
    return unittest.defaultTestLoader.loadTestsFromName(__name__)
7✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc