kopia lustrzana https://github.com/micropython/micropython-lib
contextlib: depend on ucontextlib and fix tests
rodzic
de39c2417c
commit
680364d20c
|
@ -8,101 +8,7 @@ Not implemented:
|
|||
|
||||
"""
|
||||
|
||||
class ContextDecorator(object):
|
||||
"A base class or mixin that enables context managers to work as decorators."
|
||||
|
||||
def _recreate_cm(self):
|
||||
"""Return a recreated instance of self.
|
||||
|
||||
Allows an otherwise one-shot context manager like
|
||||
_GeneratorContextManager to support use as
|
||||
a decorator via implicit recreation.
|
||||
|
||||
This is a private interface just for _GeneratorContextManager.
|
||||
See issue #11647 for details.
|
||||
"""
|
||||
return self
|
||||
|
||||
def __call__(self, func):
|
||||
def inner(*args, **kwds):
|
||||
with self._recreate_cm():
|
||||
return func(*args, **kwds)
|
||||
return inner
|
||||
|
||||
|
||||
class _GeneratorContextManager(ContextDecorator):
|
||||
"""Helper for @contextmanager decorator."""
|
||||
|
||||
def __init__(self, func, *args, **kwds):
|
||||
self.gen = func(*args, **kwds)
|
||||
self.func, self.args, self.kwds = func, args, kwds
|
||||
|
||||
def _recreate_cm(self):
|
||||
# _GCM instances are one-shot context managers, so the
|
||||
# CM must be recreated each time a decorated function is
|
||||
# called
|
||||
return self.__class__(self.func, *self.args, **self.kwds)
|
||||
|
||||
def __enter__(self):
|
||||
try:
|
||||
return next(self.gen)
|
||||
except StopIteration:
|
||||
raise RuntimeError("generator didn't yield") from None
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
if type is None:
|
||||
try:
|
||||
next(self.gen)
|
||||
except StopIteration:
|
||||
return
|
||||
else:
|
||||
raise RuntimeError("generator didn't stop")
|
||||
else:
|
||||
if value is None:
|
||||
# Need to force instantiation so we can reliably
|
||||
# tell if we get the same exception back
|
||||
value = type()
|
||||
try:
|
||||
self.gen.throw(type, value, traceback)
|
||||
raise RuntimeError("generator didn't stop after throw()")
|
||||
except StopIteration as exc:
|
||||
# Suppress the exception *unless* it's the same exception that
|
||||
# was passed to throw(). This prevents a StopIteration
|
||||
# raised inside the "with" statement from being suppressed
|
||||
return exc is not value
|
||||
|
||||
|
||||
def contextmanager(func):
|
||||
"""@contextmanager decorator.
|
||||
|
||||
Typical usage:
|
||||
|
||||
@contextmanager
|
||||
def some_generator(<arguments>):
|
||||
<setup>
|
||||
try:
|
||||
yield <value>
|
||||
finally:
|
||||
<cleanup>
|
||||
|
||||
This makes this:
|
||||
|
||||
with some_generator(<arguments>) as <variable>:
|
||||
<body>
|
||||
|
||||
equivalent to this:
|
||||
|
||||
<setup>
|
||||
try:
|
||||
<variable> = <value>
|
||||
<body>
|
||||
finally:
|
||||
<cleanup>
|
||||
|
||||
"""
|
||||
def helper(*args, **kwds):
|
||||
return _GeneratorContextManager(func, *args, **kwds)
|
||||
return helper
|
||||
from ucontextlib import *
|
||||
|
||||
|
||||
class closing(object):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
srctype = cpython
|
||||
type = module
|
||||
version = 3.4.2-1
|
||||
version = 3.4.2-2
|
||||
long_desc = Port of contextlib for micropython
|
||||
depends = ucontextlib
|
||||
|
|
|
@ -6,7 +6,7 @@ from setuptools import setup
|
|||
|
||||
|
||||
setup(name='micropython-contextlib',
|
||||
version='3.4.2-1',
|
||||
version='3.4.2-2',
|
||||
description='CPython contextlib module ported to MicroPython',
|
||||
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.',
|
||||
url='https://github.com/micropython/micropython/issues/405',
|
||||
|
@ -15,4 +15,5 @@ setup(name='micropython-contextlib',
|
|||
maintainer='MicroPython Developers',
|
||||
maintainer_email='micro-python@googlegroups.com',
|
||||
license='Python',
|
||||
py_modules=['contextlib'])
|
||||
py_modules=['contextlib'],
|
||||
install_requires=['micropython-ucontextlib'])
|
||||
|
|
|
@ -1,38 +1,8 @@
|
|||
from unittest import TestCase, run_class
|
||||
from contextlib import contextmanager, closing, suppress
|
||||
import unittest
|
||||
from contextlib import closing, suppress
|
||||
|
||||
|
||||
class ContextManagerTestCase(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self._history = []
|
||||
|
||||
@contextmanager
|
||||
def manager(x):
|
||||
self._history.append('start')
|
||||
try:
|
||||
yield x
|
||||
finally:
|
||||
self._history.append('finish')
|
||||
|
||||
self._manager = manager
|
||||
|
||||
def test_context_manager(self):
|
||||
with self._manager(123) as x:
|
||||
self.assertEqual(x, 123)
|
||||
self.assertEqual(self._history, ['start', 'finish'])
|
||||
|
||||
def test_context_manager_on_error(self):
|
||||
exc = Exception()
|
||||
try:
|
||||
with self._manager(123) as x:
|
||||
raise exc
|
||||
except Exception as e:
|
||||
self.assertEqual(exc, e)
|
||||
self.assertEqual(self._history, ['start', 'finish'])
|
||||
|
||||
|
||||
class ClosingTestCase(TestCase):
|
||||
class ClosingTestCase(unittest.TestCase):
|
||||
|
||||
class Closable:
|
||||
def __init__(self):
|
||||
|
@ -58,7 +28,7 @@ class ClosingTestCase(TestCase):
|
|||
self.assertTrue(closable.closed)
|
||||
|
||||
|
||||
class SuppressTestCase(TestCase):
|
||||
class SuppressTestCase(unittest.TestCase):
|
||||
|
||||
def test_suppress(self):
|
||||
with suppress(ValueError, TypeError):
|
||||
|
@ -68,6 +38,4 @@ class SuppressTestCase(TestCase):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_class(ContextManagerTestCase)
|
||||
run_class(ClosingTestCase)
|
||||
run_class(SuppressTestCase)
|
||||
unittest.main()
|
||||
|
|
Ładowanie…
Reference in New Issue