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
CupScript is a simple programing language made with python

CupScript CupScript is a simple programming language made with python It includes some basic functions, variables, loops, and some other built in func

FUSEN 23 Dec 29, 2022
Our product DrLeaf which not only makes the work easier but also reduces the effort and expenditure of the farmer to identify the disease and its treatment methods.

Our product DrLeaf which not only makes the work easier but also reduces the effort and expenditure of the farmer to identify the disease and its treatment methods. We have to upload the image of an

Aniruddha Jana 2 Feb 02, 2022
A StarkNet project template based on a Pythonic environment

StarkNet Project Template This is an opinionated StarkNet project template. It is based around the Python's ecosystem and best practices. tox to manag

Francesco Ceccon 5 Apr 21, 2022
An interactive course to git

OperatorEquals' Sandbox Git Course! Preface This Git course is an ongoing project containing use cases that I've met (and still meet) while working in

John Torakis 62 Sep 19, 2022
A Way to Use Python, Easier.

PyTools A Way to Use Python, Easier. How to Install Just copy this code, then make a new file in your project directory called PyTools.py, then paste

Kamran 2 Aug 15, 2022
A lightweight and unlocked launcher for Lunar Client made in Python.

LCLPy LCL's Python Port of Lunar Client Lite. Releases: https://github.com/Aetopia/LCLPy/releases Build Install PyInstaller. pip install PyInstaller

21 Aug 03, 2022
Repls goes to sleep due to inactivity, but to keep it awake, simply host a webserver and ping it.

Repls goes to sleep due to inactivity, but to keep it awake, simply host a webserver and ping it. This repo will help you make a webserver with a bit of console controls.

2 Mar 01, 2022
Traffic flow test platform, especially for reinforcement learning

Traffic Flow Test Platform Traffic flow test platform, especially for reinforcement learning, named TFTP. A traffic signal control framework that can

4 Nov 07, 2022
This is an API to get user details for competitive coding platforms - Codeforces, Codechef, SPOJ, Interviewbit. More Platform will be Added Soon.

Competitive-Programming-Score-API An API to get user details for competitive coding platforms - Codeforces, Codechef, SPOJ, Interviewbit Platforms Ava

Aaditya Prakash 3 Jan 17, 2022
Test reproducibility of leiden/umap on different systems

Demonstrate that UMAP and Leiden analysis is not reproducible between different cpu architectures.

Gregor Sturm 2 Oct 16, 2021
Pydesy package description (EN)

Pydesy package description (EN) Last version: 0.0.2 Geodetic library, which includes the following tasks: 1. Calculation of theodolite traverse (tachy

1 Feb 03, 2022
Runs macOS on linux with qemu.

mac-on-linux-with-qemu Runs macOS on linux with qemu. Pre-requisites qemu-system-x86_64 dmg2img pulseaudio python[click] Usage After cloning the repos

Arindam Das 177 Dec 26, 2022
Density is a open-sourced multi-purpose tool for ROBLOX with some cool

Density is a open-sourced multi-purpose tool for ROBLOX with some cool

ssl 5 Jul 16, 2022
1000+ ready code templates to kickstart your next AI experiment

AI Seed Projects Start with ready code for your next AI experiment. Choose from 1000+ code templates, across a wide variety of use cases. All examples

BlobCity, Inc 98 Jan 03, 2023
*考研学习利器,玩电脑控制不住自己时,可以使用该程序定日期锁屏,同时有精美壁纸锁屏显示,也不会枯燥。

LockscreenbyTime_win10 A python program in win10. You can set the time to lock the computer(by setting year, month, day), Fullscreen pictures will sho

PixianDouban 4 Jul 10, 2022
PyGo custom language, New but similar language programming

New but similar language programming. Now we are capable to program in a very similar language to Python but at the same time get the efficiency of Go.

Fernando Perez 4 Nov 19, 2022
A Brainfuck interpreter written in Python.

A Brainfuck interpreter written in Python.

Ethan Evans 1 Dec 05, 2021
Cross-platform .NET Core pre-commit hooks

dotnet-core-pre-commit Cross-platform .NET Core pre-commit hooks How to use Add this to your .pre-commit-config.yaml - repo: https://github.com/juan

Juan Odicio 5 Jul 20, 2021
A compilation of useful scripts to automate common tasks

Scripts-To-Automate-This A compilation of useful scripts for common tasks Name What it does Type Add file extensions Adds ".png" to a list of file nam

0 Nov 05, 2021
A command line interface tool converting starknet warp transpiled outputs into readable cairo contracts.

warp-to-cairo warp-to-cairo is a simple tool converting starknet warp outputs (NethermindEth/warp) outputs into readable cairo contracts. The warp out

Michael K 5 Jun 10, 2022