Skip to content

Commit 680364d

Browse files
dxxbPaul Sokolovsky
authored and
Paul Sokolovsky
committed
contextlib: depend on ucontextlib and fix tests
1 parent de39c24 commit 680364d

File tree

4 files changed

+11
-135
lines changed

4 files changed

+11
-135
lines changed

contextlib/contextlib.py

+1-95
Original file line numberDiff line numberDiff line change
@@ -8,101 +8,7 @@
88
99
"""
1010

11-
class ContextDecorator(object):
12-
"A base class or mixin that enables context managers to work as decorators."
13-
14-
def _recreate_cm(self):
15-
"""Return a recreated instance of self.
16-
17-
Allows an otherwise one-shot context manager like
18-
_GeneratorContextManager to support use as
19-
a decorator via implicit recreation.
20-
21-
This is a private interface just for _GeneratorContextManager.
22-
See issue #11647 for details.
23-
"""
24-
return self
25-
26-
def __call__(self, func):
27-
def inner(*args, **kwds):
28-
with self._recreate_cm():
29-
return func(*args, **kwds)
30-
return inner
31-
32-
33-
class _GeneratorContextManager(ContextDecorator):
34-
"""Helper for @contextmanager decorator."""
35-
36-
def __init__(self, func, *args, **kwds):
37-
self.gen = func(*args, **kwds)
38-
self.func, self.args, self.kwds = func, args, kwds
39-
40-
def _recreate_cm(self):
41-
# _GCM instances are one-shot context managers, so the
42-
# CM must be recreated each time a decorated function is
43-
# called
44-
return self.__class__(self.func, *self.args, **self.kwds)
45-
46-
def __enter__(self):
47-
try:
48-
return next(self.gen)
49-
except StopIteration:
50-
raise RuntimeError("generator didn't yield") from None
51-
52-
def __exit__(self, type, value, traceback):
53-
if type is None:
54-
try:
55-
next(self.gen)
56-
except StopIteration:
57-
return
58-
else:
59-
raise RuntimeError("generator didn't stop")
60-
else:
61-
if value is None:
62-
# Need to force instantiation so we can reliably
63-
# tell if we get the same exception back
64-
value = type()
65-
try:
66-
self.gen.throw(type, value, traceback)
67-
raise RuntimeError("generator didn't stop after throw()")
68-
except StopIteration as exc:
69-
# Suppress the exception *unless* it's the same exception that
70-
# was passed to throw(). This prevents a StopIteration
71-
# raised inside the "with" statement from being suppressed
72-
return exc is not value
73-
74-
75-
def contextmanager(func):
76-
"""@contextmanager decorator.
77-
78-
Typical usage:
79-
80-
@contextmanager
81-
def some_generator(<arguments>):
82-
<setup>
83-
try:
84-
yield <value>
85-
finally:
86-
<cleanup>
87-
88-
This makes this:
89-
90-
with some_generator(<arguments>) as <variable>:
91-
<body>
92-
93-
equivalent to this:
94-
95-
<setup>
96-
try:
97-
<variable> = <value>
98-
<body>
99-
finally:
100-
<cleanup>
101-
102-
"""
103-
def helper(*args, **kwds):
104-
return _GeneratorContextManager(func, *args, **kwds)
105-
return helper
11+
from ucontextlib import *
10612

10713

10814
class closing(object):

contextlib/metadata.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
srctype = cpython
22
type = module
3-
version = 3.4.2-1
3+
version = 3.4.2-2
44
long_desc = Port of contextlib for micropython
5+
depends = ucontextlib

contextlib/setup.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77

88
setup(name='micropython-contextlib',
9-
version='3.4.2-1',
9+
version='3.4.2-2',
1010
description='CPython contextlib module ported to MicroPython',
1111
long_description='This is a module ported from CPython standard library to be compatible with\nMicroPython interpreter. Usually, this means applying small patches for\nfeatures not supported (yet, or at all) in MicroPython. Sometimes, heavier\nchanges are required. Note that CPython modules are written with availability\nof vast resources in mind, and may not work for MicroPython ports with\nlimited heap. If you are affected by such a case, please help reimplement\nthe module from scratch.',
1212
url='https://github.com/micropython/micropython/issues/405',
@@ -15,4 +15,5 @@
1515
maintainer='MicroPython Developers',
1616
maintainer_email='[email protected]',
1717
license='Python',
18-
py_modules=['contextlib'])
18+
py_modules=['contextlib'],
19+
install_requires=['micropython-ucontextlib'])

contextlib/tests.py

+5-37
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,8 @@
1-
from unittest import TestCase, run_class
2-
from contextlib import contextmanager, closing, suppress
1+
import unittest
2+
from contextlib import closing, suppress
33

44

5-
class ContextManagerTestCase(TestCase):
6-
7-
def setUp(self):
8-
self._history = []
9-
10-
@contextmanager
11-
def manager(x):
12-
self._history.append('start')
13-
try:
14-
yield x
15-
finally:
16-
self._history.append('finish')
17-
18-
self._manager = manager
19-
20-
def test_context_manager(self):
21-
with self._manager(123) as x:
22-
self.assertEqual(x, 123)
23-
self.assertEqual(self._history, ['start', 'finish'])
24-
25-
def test_context_manager_on_error(self):
26-
exc = Exception()
27-
try:
28-
with self._manager(123) as x:
29-
raise exc
30-
except Exception as e:
31-
self.assertEqual(exc, e)
32-
self.assertEqual(self._history, ['start', 'finish'])
33-
34-
35-
class ClosingTestCase(TestCase):
5+
class ClosingTestCase(unittest.TestCase):
366

377
class Closable:
388
def __init__(self):
@@ -58,7 +28,7 @@ def test_closing_after_error(self):
5828
self.assertTrue(closable.closed)
5929

6030

61-
class SuppressTestCase(TestCase):
31+
class SuppressTestCase(unittest.TestCase):
6232

6333
def test_suppress(self):
6434
with suppress(ValueError, TypeError):
@@ -68,6 +38,4 @@ def test_suppress(self):
6838

6939

7040
if __name__ == '__main__':
71-
run_class(ContextManagerTestCase)
72-
run_class(ClosingTestCase)
73-
run_class(SuppressTestCase)
41+
unittest.main()

0 commit comments

Comments
 (0)