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
Platform Tree for Xiaomi Redmi Note 7/7S (lavender)

The Xiaomi Redmi Note 7 (codenamed "lavender") is a mid-range smartphone from Xiaomi announced in January 2019. Device specifications Device Xiaomi Re

MUHAMAD KHOIRON 2 Dec 20, 2021
A script to download all the challenges and files from the CTFd instance.

Python CTFd Downloader A script to download all the challenges and files from the CTFd instance. Installation Clone this repo: git clone https://githu

Jacob Elliott 19 Dec 16, 2022
It's an .exe file that can notify your chia profit and warning message every time automatically.

chia-Notify-with-Line 警示程式 It's an .exe file that can notify your chia profit and warning message every time automatically. 這是我自行設計的小程式,有轉成.exe檔了,可以在沒

You,Yu 1 Oct 28, 2021
Adansons Base is a data management tool that organizes metadata of unstructured data and creates and organizes datasets.

Adansons Base is a data management tool that organizes metadata of unstructured data and creates and organizes datasets. It makes dataset creation more effective and helps find essential insights fro

Adansons Inc 27 Oct 22, 2022
Python with the scientific stack, compiled to WebAssembly.

Pyodide may be used in any context where you want to run Python inside a web browser.

9.5k Jan 09, 2023
An implementation of multimap with per-item expiration backed up by Redis.

MultiMapWithTTL An implementation of multimap with per-item expiration backed up by Redis. Documentation: https://loggi.github.io/python-multimapwitht

Loggi 2 Jan 17, 2022
Social reading and reviewing, decentralized with ActivityPub

BookWyrm Social reading and reviewing, decentralized with ActivityPub Contents Joining BookWyrm Contributing About BookWyrm What it is and isn't The r

BookWyrm 1.4k Jan 08, 2023
Nimbus - Open Source Cloud Computing Software - 100% Apache2 licensed

⚠️ The Nimbus infrastructure project is no longer under development. ⚠️ For more information, please read the news announcement. If you are interested

Nimbus 194 Jun 30, 2022
A Powerful Tool For Making Combo List(All possible modes)

ComboMaker A Powerful Tool For Making Combo List Introduction Check out all possible Combo list build modes with this tool =) How to Install Open the

MasterBurnt 7 Jan 07, 2023
log4shell pwner for vulnerable minecraft servers

Log4-hell name supposed to be Log4$hell but oh well log4shell pwner for vulnerable minecraft servers install all reqs python + a minecraft client for

1 Jan 05, 2022
Mines all the moneys and stuff and things.

NFT Miner NFT Miner - Version 1.1.0 - Quick Fix Since the whole NFT thing started booming on Twitter it's been hard not to see one of those ugly ass m

8w8 1 Dec 13, 2021
Software for visualization of RTStruct structures on CT images

This script is responsible for the operation of the program, it is responsible for both creating the GUI and the process of processing images from dicom files. The program is based on the use of the

Adam Piszczek 0 Jun 29, 2022
Simple package to make requests throughout Tor with circuit renewal.

AutoTor Table of Contents About the Project Contents Dependencies Getting Started Installation Coding Contributing About the Project Simple package to

Salvador Belenguer 6 Jan 01, 2023
ChainJacking is a tool to find which of your Go lang direct GitHub dependencies is susceptible to ChainJacking attack.

ChainJacking is a tool to find which of your Go lang direct GitHub dependencies is susceptible to ChainJacking attack.

Checkmarx 36 Nov 02, 2022
A python tool that creates issues in your repos based on TODO comments in your code

Krypto A neat little sidekick python script to create issues on your repo based on comments left in the code on your behalf Convert todo comments in y

Alex Antoniou 4 Oct 26, 2021
Este script añade la config de s4vitar a bspwm automaticamente!

Se ha testeado este script en ParrotOS, Kali y Ubuntu. Funciona para todos los sistemas operativos basados en Debian. Instalación git clone https://gi

yorkox 201 Dec 30, 2022
OTP-Bomber - An otp from MPL ID app, which can be spammed

OTP-Bomber An otp from MPL ID app, which can be spammed Note: Only available on

5 Oct 29, 2022
Jannik Ramrath 1 Feb 05, 2022
Class XII computer science project.

Computer Science Project — Class XII Kshitij Srivastava (XI – A) Introduction The aim of this project is to create a fully operational system for a me

Kshitij Srivastava 2 Jul 21, 2022
Providing a working, flexible, easier and faster installer than the one officially provided by Arch Linux

Purpose The purpose is to bring more people to Arch Linux by providing a working, flexible, easier and faster installer than the one officially provid

André Luís 0 Nov 09, 2022