contextlib2 is a backport of the standard library's contextlib module to earlier Python versions.

Overview
Jazzband Tests Coverage Latest Docs

contextlib2 is a backport of the standard library's contextlib module to earlier Python versions.

It also sometimes serves as a real world proving ground for possible future enhancements to the standard library version.

Licensing

As a backport of Python standard library software, the implementation, test suite and other supporting files for this project are distributed under the Python Software License used for the CPython reference implementation.

The one exception is the included type hints file, which comes from the typeshed project, and is hence distributed under the Apache License 2.0.

Development

contextlib2 has no runtime dependencies, but requires setuptools and wheel at build time to generate universal wheel archives.

Local testing is a matter of running:

python3 -m unittest discover -t . -s test

You can test against multiple versions of Python with tox:

pip install tox
tox

Versions currently tested in both tox and GitHub Actions are:

  • CPython 3.6
  • CPython 3.7
  • CPython 3.8
  • CPython 3.9
  • CPython 3.10
  • PyPy3

Updating to a new stdlib reference version

As of Python 3.10, 4 files needed to be copied from the CPython reference implementation to contextlib2:

  • Doc/contextlib.rst -> docs/contextlib2.rst
  • Lib/contextlib.py -> contextlib2/__init__.py
  • Lib/test/test_contextlib.py -> test/test_contextlib.py
  • Lib/test/test_contextlib_async.py -> test/test_contextlib_async.py

The corresponding version of contextlib2/__init__.pyi also needs to be retrieved from the typeshed project:

wget https://raw.githubusercontent.com/python/typeshed/master/stdlib/contextlib.pyi

For the 3.10 sync, the only changes needed to the test files were to import from contextlib2 rather than contextlib. The test directory is laid out so that the test suite's imports from test.support work the same way they do in the main CPython test suite.

The following patch files are saved in the dev directory:

  • changes made to contextlib2/__init__.py to get it to run on the older versions (and to add back in the deprecated APIs that never graduated to the standard library version)
  • changes made to contextlib2/__init__.pyi to make the Python version guards unconditional (since the contextlib2 API is the same on all supported versions)
  • changes made to docs/contextlib2.rst to use contextlib2 version numbers in the version added/changed notes and to integrate the module documentation with the rest of the project documentation
Comments
  • Decide how to backport 3.7 async context management support

    Decide how to backport 3.7 async context management support

    Python 3.7 added async/await support to the contextlib module (e.g. asyncontextmanager and AsyncExitStack), and then Python 3.10 added more (e.g. aclosing).

    This raised the question of how to backport those features to 3.6+ (the first version with support for yield inside async def).

    The answer turned out to be "procrastinate on the question for 4+ years, so it became feasible to simply drop support for Python 3.5 and earlier, and use the async generator code as-is".

    (Issue description updated Jun 2021 to describe what actually happened, rather than the more complicated alternatives I was considering to allow adding the new async features without dropping support for Python 3.5 and earlier)

    opened by ncoghlan 16
  • 0.6.0.post1: pytest is failing

    0.6.0.post1: pytest is failing

    Just normal build, install and test cycle used on building package from non-root account:

    • "setup.py build"
    • "setup.py install --root </install/prefix>"
    • "pytest with PYTHONPATH pointing to setearch and sitelib inside </install/prefix>
    + PYTHONPATH=/home/tkloczko/rpmbuild/BUILDROOT/python-contextlib2-0.6.0.post1-2.fc35.x86_64/usr/lib64/python3.8/site-packages:/home/tkloczko/rpmbuild/BUILDROOT/python-contextlib2-0.6.0.post1-2.fc35.x86_64/usr/lib/python3.8/site-packages
    + PYTHONDONTWRITEBYTECODE=1
    + /usr/bin/pytest -ra
    =========================================================================== test session starts ============================================================================
    platform linux -- Python 3.8.9, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
    benchmark: 3.4.1 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
    rootdir: /home/tkloczko/rpmbuild/BUILD/contextlib2-0.6.0.post1
    plugins: forked-1.3.0, shutil-1.7.0, virtualenv-1.7.0, expect-1.1.0, httpbin-1.0.0, flake8-1.0.7, timeout-1.4.2, betamax-0.8.1, freezegun-0.4.2, case-1.5.3, isort-1.3.0, aspectlib-1.5.2, asyncio-0.15.1, toolbox-0.5, xprocess-0.17.1, aiohttp-0.3.0, checkdocs-2.7.0, mock-3.6.1, rerunfailures-9.1.1, requests-mock-1.9.3, cov-2.12.1, pyfakefs-4.5.0, cases-3.6.1, flaky-3.7.0, hypothesis-6.14.0, benchmark-3.4.1, xdist-2.3.0, Faker-8.8.1
    collected 81 items
    
    . .                                                                                                                                                                  [  1%]
    test_contextlib2.py ...............................................FFFFFFF.........................                                                                  [100%]
    
    ================================================================================= FAILURES =================================================================================
    __________________________________________________________________ TestRedirectStream.test_instance_docs ___________________________________________________________________
    
    self = <test_contextlib2.TestRedirectStream object at 0x7ff603109fd0>
    
        @requires_docstrings
        def test_instance_docs(self):
            # Issue 19330: ensure context manager instances have good docstrings
            cm_docstring = self.redirect_stream.__doc__
    >       obj = self.redirect_stream(None)
    E       TypeError: 'NoneType' object is not callable
    
    test_contextlib2.py:842: TypeError
    _______________________________________________________________ TestRedirectStream.test_no_redirect_in_init ________________________________________________________________
    
    self = <test_contextlib2.TestRedirectStream object at 0x7ff6028e6d00>
    
        def test_no_redirect_in_init(self):
    >       orig_stdout = getattr(sys, self.orig_stream)
    E       TypeError: getattr(): attribute name must be string
    
    test_contextlib2.py:846: TypeError
    ______________________________________________________________ TestRedirectStream.test_redirect_to_string_io _______________________________________________________________
    
    self = <test_contextlib2.TestRedirectStream object at 0x7ff602845340>
    
        def test_redirect_to_string_io(self):
            f = io.StringIO()
            msg = "Consider an API like help(), which prints directly to stdout"
    >       orig_stdout = getattr(sys, self.orig_stream)
    E       TypeError: getattr(): attribute name must be string
    
    test_contextlib2.py:853: TypeError
    ______________________________________________________________ TestRedirectStream.test_enter_result_is_target ______________________________________________________________
    
    self = <test_contextlib2.TestRedirectStream object at 0x7ff602645520>
    
        def test_enter_result_is_target(self):
            f = io.StringIO()
    >       with self.redirect_stream(f) as enter_result:
    E       TypeError: 'NoneType' object is not callable
    
    test_contextlib2.py:862: TypeError
    __________________________________________________________________ TestRedirectStream.test_cm_is_reusable __________________________________________________________________
    
    self = <test_contextlib2.TestRedirectStream object at 0x7ff602845760>
    
        def test_cm_is_reusable(self):
            f = io.StringIO()
    >       write_to_f = self.redirect_stream(f)
    E       TypeError: 'NoneType' object is not callable
    
    test_contextlib2.py:867: TypeError
    _________________________________________________________________ TestRedirectStream.test_cm_is_reentrant __________________________________________________________________
    
    self = <test_contextlib2.TestRedirectStream object at 0x7ff6021ed070>
    
        def test_cm_is_reentrant(self):
            f = io.StringIO()
    >       write_to_f = self.redirect_stream(f)
    E       TypeError: 'NoneType' object is not callable
    
    test_contextlib2.py:879: TypeError
    ____________________________________________________________ TestRedirectStream.test_cm_is_exitstack_compatible ____________________________________________________________
    
    self = <test_contextlib2.TestRedirectStream object at 0x7ff6028667f0>
    
        def test_cm_is_exitstack_compatible(self):
            with ExitStack() as stack:
                # This shouldn't raise an exception.
    >           stack.enter_context(self.redirect_stream(io.StringIO()))
    E           TypeError: 'NoneType' object is not callable
    
    test_contextlib2.py:892: TypeError
    ========================================================================= short test summary info ==========================================================================
    FAILED test_contextlib2.py::TestRedirectStream::test_instance_docs - TypeError: 'NoneType' object is not callable
    FAILED test_contextlib2.py::TestRedirectStream::test_no_redirect_in_init - TypeError: getattr(): attribute name must be string
    FAILED test_contextlib2.py::TestRedirectStream::test_redirect_to_string_io - TypeError: getattr(): attribute name must be string
    FAILED test_contextlib2.py::TestRedirectStream::test_enter_result_is_target - TypeError: 'NoneType' object is not callable
    FAILED test_contextlib2.py::TestRedirectStream::test_cm_is_reusable - TypeError: 'NoneType' object is not callable
    FAILED test_contextlib2.py::TestRedirectStream::test_cm_is_reentrant - TypeError: 'NoneType' object is not callable
    FAILED test_contextlib2.py::TestRedirectStream::test_cm_is_exitstack_compatible - TypeError: 'NoneType' object is not callable
    ======================================================================= 7 failed, 73 passed in 7.07s =======================================================================
    
    opened by kloczek 9
  • dropped python 2.6 support, updated travis config, pep8 compliance

    dropped python 2.6 support, updated travis config, pep8 compliance

    Dropped support for Python 2.6 as it reached EOL in 2013 and not supported by both tox and setuptools anymore Enabled back Travis CI testing in pypy3 env, using stable python 3.7 Updated setup.py according to all the changes Fixed several formatting issues to better comply with PEP8

    opened by likeon 7
  • asynccontextmanager as decorator

    asynccontextmanager as decorator

    The contextmanager decorated function can be used as decorator for sync functions. But asynccontextmanager decorated function cannot be used as decorator for async function. It would be nice to allow it

    opened by Fak3 5
  • ExitStack fails with StreamReader / StreamWriter

    ExitStack fails with StreamReader / StreamWriter

    In Python 2.7, StreamReader and StreamWriter are context managers that wrap around a stream and handle encoding issue. However, the type of one of these objects is instance, not file. As a result, ExitStack.enter_context with AttributeError when one of these is added to the stack:

    MWE:

    # -*- coding: utf-8 -*-
    from contextlib2 import ExitStack
    from codecs import getreader
    
    with open('test_file', 'wb') as f:
        f.write(u'いちりきつくっ'.encode('UTF-8'))
    
    reader = getreader('utf-8')
    with reader(open('test_file', 'r')) as f:
        print(f.read())  # いちりきつくっ
    
    try:
        with ExitStack() as stack:
            f = stack.enter_context(reader(open('test_file', 'r'))) # Error
            print(f.read())
    finally:
        import os
        os.unlink('test_file')    # Delete the file
    

    Here is the result:

    AttributeError: type object 'instance' has no attribute '__exit__'
    

    Not sure what happens on Python 3, since Python 3's native unicode support obviates the need for the StreamReader in the first place as far as I can tell.

    I don't know if this is a good solution, but if you use cm.__class__ instead of type(cm), it seems to work OK:

        def enter_context(self, cm):
            """Enters the supplied context manager
    
            If successful, also pushes its __exit__ method as a callback and
            returns the result of the __enter__ method.
            """
            # We look up the special methods on the type to match the with statement
            for _cm_type in type(cm), cm.__class__:
                try:
                    _exit = _cm_type.__exit__
                    result = _cm_type.__enter__(cm)
                except AttributeError as e:
                    error = e
                    continue
    
                error = None
                break
    
            if error is not None:
                raise error        
    
            self._push_cm_exit(cm, _exit)
            return result
    
    opened by pganssle 5
  • Use mypy.stubtest in CI

    Use mypy.stubtest in CI

    (Derived from https://github.com/python/mypy/issues/5028#issuecomment-869001339)

    The current mypy CI check just tests that the stub file is well formed, it doesn't test that the module API actually matches the type hinted stub API. Running mypy.stubcheck instead will fix that testing gap, but the failures need to be fixed first:

    [[email protected] contextlib2]$ python3 -m mypy.stubtest contextlib2
    error: contextlib2.ContextDecorator.refresh_cm is not present in stub
    Stub:
    MISSING
    Runtime: at line 76 in file /home/ncoghlan/devel/contextlib2/contextlib2/__init__.py
    <function ContextDecorator.refresh_cm at 0x7fd497b61dc0>
    
    error: contextlib2.ContextStack is not present in stub
    Stub:
    MISSING
    Runtime: at line 783 in file /home/ncoghlan/devel/contextlib2/contextlib2/__init__.py
    <class 'contextlib2.ContextStack'>
    
    error: contextlib2.nullcontext is not a function
    Stub: at line 122
    Overload(def [_T] (enter_result: _T`-1) -> typing.ContextManager[_T`-1], def () -> typing.ContextManager[None])
    Runtime: at line 755 in file /home/ncoghlan/devel/contextlib2/contextlib2/__init__.py
    <class 'contextlib2.nullcontext'>
    
    opened by ncoghlan 3
  • Not up-to-date changelog

    Not up-to-date changelog

    v0.6.0 has been released in https://github.com/jazzband/contextlib2/tree/v0.6.0 and https://pypi.org/project/contextlib2/0.6.0/ but https://github.com/jazzband/contextlib2/blob/v0.6.0/NEWS.rst#060-unreleased makes it seems otherwise.

    opened by xavfernandez 3
  • Do not build universal wheels.

    Do not build universal wheels.

    Hi,

    Thanks for your work on contextlib2 and Python in general!

    Now that contextlib2 has only supported Python 3.x for a while, what do you think about this change that stops it from building universal wheels? It ought to be harmless, since there is a python_require specification, but still it might confuse some tools that see both "python_version": "py2.py3" and "requires_python": ">=3.6" in the PyPI metadata :)

    Thanks for your time, and keep up the great work!

    G'luck, Peter

    opened by ppentchev 2
  • Issue #12:  sync module from CPython 3.10

    Issue #12: sync module from CPython 3.10

    • Sync module and test suite from CPython 3.10
    • Switch test suite over to using unittest autodiscovery (since there are now two test files)
    • Capture the differences from the Python 3.10 version as a patch file
    • Ship the tox config (and other dev files) in the sdist
    opened by ncoghlan 2
  • setup.py does not fallback to using distutils.core import setup

    setup.py does not fallback to using distutils.core import setup

    In all of the setup.py scripts I have used before, the import for setup is like this:

    try: from setuptools import setup except ImportError: from distutils.core import setup

    Which allows it to fall back to distutils.core if setuptools is not available.

    Is there a reason that this is missing from this projects setup.py?

    Thanks.

    opened by allanhaywood 2
  • python3.11 support?

    python3.11 support?

    Hello,

    The next stable release of Debian includes Python 3.11 (and might make Python 3.11 the default version)

    Running the unit tests from version 0.6.0 or version 21.6.0 under Python 3.11 produces the following errors:

    ======================================================================
    ERROR: test_typo_enter (test.test_contextlib.TestContextDecorator.test_typo_enter)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/tmp/autopkgtest.oVLsYe/build.IvE/src/test/test_contextlib.py", line 498, in test_typo_enter
        with mycontext():
    TypeError: 'mycontext' object does not support the context manager protocol
    
    ======================================================================
    ERROR: test_typo_exit (test.test_contextlib.TestContextDecorator.test_typo_exit)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/tmp/autopkgtest.oVLsYe/build.IvE/src/test/test_contextlib.py", line 510, in test_typo_exit
        with mycontext():
    TypeError: 'mycontext' object does not support the context manager protocol (missed __exit__ method)
    
    ----------------------------------------------------------------------
    

    Any guidance on how we can patch contextlib2 version 21.6.0 to fix this?

    Thanks!

    opened by mr-c 1
  • backport contextlib from python 3.11

    backport contextlib from python 3.11

    https://github.com/python/cpython/commit/6cb145d23f5cf69b6d7414877d142747cd3d134c

    A TypeError is now raised instead of an AttributeError in contextlib.ExitStack.enter_context() and contextlib.AsyncExitStack.enter_async_context() for objects which do not support the context manager or asynchronous context manager protocols correspondingly. (Contributed by Serhiy Storchaka in bpo-44471.)

    however this is only to match the change in behaviour of the async with and with statements in 3.11:

    A TypeError is now raised instead of an AttributeError in with and async with statements for objects which do not support the context manager or asynchronous context manager protocols correspondingly. (Contributed by Serhiy Storchaka in bpo-12022.)

    so would need conditional checking.

    perhaps:

    if sys.version_info >= (3, 11):
        from contextlib import ExitStack, AsyncExitStack
    else:
        class ExitStack(...):
            ...
    
        class AsyncExitStack(...):
            ...
    

    would be best?

    opened by graingert 5
Releases(21.6.0)
  • 21.6.0(Jun 27, 2021)

    • Module API aligned with Python 3.10 (including all asynchronous APIs)
    • Dropped support for Python 3.5 and earlier due to lack of async generator support
    • Added API type hinting
    • Switched to calendar based versioning
    Source code(tar.gz)
    Source code(zip)
Owner
Jazzband
We are all part of this
Jazzband
Simple Assembler with python

Assembler with python converts assembly source code to machine code Requirements Python 3 🐍 Usage python main.py [source] [output] [source] : Path t

Amir mohammad 1 Dec 24, 2021
This program is meant to take the pain out of generating nice bash PS1 prompts.

TOC PS1 Installation / Quickstart License Other Docs Examples PS1 Command Help PS1 ↑ This program is meant to take the pain out of generating nice bas

Steven Hollingsworth 6 Jun 19, 2022
Team Curie is a group of people working together to achieve a common aim

Team Curie is a group of people working together to achieve a common aim. We are enthusiasts!.... We are setting the pace!.... We offer encouragement and motivation....And we believe TeamWork makes t

4 Aug 07, 2021
Structured Exceptions for Python

XC: Structured exceptions for Python XC encourages a structured, disciplined approach to use of exceptions: it reduces the overhead of declaring excep

Bob Gautier 2 May 28, 2021
Automated Content Feed Curator

Gathers posts from content feeds, filters, formats, delivers to you.

Alper S. Soylu 2 Jan 22, 2022
Example teacher bot for deployment to Chai app.

Create and share your own chatbot Here is the code for uploading the popular "Ms Harris (Teacher)" chatbot to the Chai app. You can tweak the config t

Chai 1 Jan 10, 2022
tidevice can be used to communicate with iPhone device

h 该工具能够用于与iOS设备进行通信, 提供以下功能 截图 获取手机信息 ipa包的安装和卸载 根据bundleID 启动和停止应用 列出安装应用信息 模拟Xcode运行XCTest,常用的如启动WebDriverAgent测试

Alibaba 1.8k Dec 30, 2022
A simple armature retargeting tool for Blender

Simple-Retarget-Tool-Blender A simple armature retargeting tool for Blender Update V2: Set Rest Pose to easily apply rest pose. Preset Import/Export.

Fahad Hasan Pathik 74 Jan 04, 2023
A deployer and package manager for OceanBase open-source software.

OceanBase Deploy OceanBase Deploy (简称 OBD)是 OceanBase 开源软件的安装部署工具。OBD 同时也是包管理器,可以用来管理 OceanBase 所有的开源软件。本文介绍如何安装 OBD、使用 OBD 和 OBD 的命令。 安装 OBD 您可以使用以下方

OceanBase 59 Dec 27, 2022
Automator anble you to create automations on your system

WELCOME TO AUTOMATOR BETA This programm is able to create automations on your system. This programm is only an experimantal release; infact it works v

Davide 1 Jan 12, 2022
Metal Gear Rising: Revengeance's DAT archive (un)packer

DOOMP Metal Gear Rising: Revengeance's DAT archive (un)packer

Christopher Holzmann Pérez 5 Sep 02, 2022
Python library for ODE integration via Taylor's method and LLVM

heyoka.py Modern Taylor's method via just-in-time compilation Explore the docs » Report bug · Request feature · Discuss The heyókȟa [...] is a kind of

Francesco Biscani 45 Dec 21, 2022
PORTSCANNING-IN-PYTHON - A python threaded portscanner to scan websites and ipaddresses

PORTSCANNING-IN-PYTHON This is a python threaded portscanner to scan websites an

1 Feb 16, 2022
A Python version of Canvacord

A copy of canvacord made in python! Installation Run any of these commands in terminal: Mac / Linux pip install canvacord Windows python -m pip insta

10 Mar 28, 2022
For Tok-k passages that have passed through the Bi-Encoder Retrival, ReRank is performed using CrossEncoder.

Cross-Encoder-with-Bi-Encoder For Tok-k passages that have passed through the Bi-Encoder Retrival, ReRank is performed using CrossEncoder. Data Data u

7 Feb 09, 2022
flake8 plugin which forbids match statements (PEP 634)

flake8-match flake8 plugin which forbids match statements (PEP 634)

Anthony Sottile 25 Nov 01, 2022
Improving the Transferability of Adversarial Examples with Resized-Diverse-Inputs, Diversity-Ensemble and Region Fitting

Improving the Transferability of Adversarial Examples with Resized-Diverse-Inputs, Diversity-Ensemble and Region Fitting

Junhua Zou 7 Oct 20, 2022
Python Cheat Sheet

Introduction Pysheeet was created with intention of collecting python code snippets for reducing coding hours and making life easier and faster. Any c

CHANG-NING TSAI 7.5k Dec 30, 2022
Solves Maths24 problems for you!

maths24-solver Solves Maths24 problems for you! Enjoy this open scource project! You can edit modify and share! My wishes is for you to use this proje

6 Nov 07, 2021
A Python wrapper API for operating and working with the Neo4j Graph Data Science (GDS) library

gdsclient NOTE: This is a work in progress and many GDS features are known to be missing or not working properly. This repo hosts the sources for gdsc

Neo4j 100 Dec 20, 2022