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
Google Foobar challenge solutions from my experience and other's on the web.

Google Foobar challenge Google Foobar challenge solutions from my experience and other's on the web. Note: Problems indicated with "Mine" are tested a

Islam Ayman 6 Jan 20, 2022
Flask-built web application that simulates a time and cost calculator for charging Electric Vehicles.

ev_charging_calculator Flask-built web application that simulates a time and cost calculator for charging Electric Vehicles. The project aims to simul

1 Nov 03, 2021
A simple python project which control paint brush in microsoft paint app

Paint Buddy In Python A simple python project which control paint brush in micro

Ordinary Pythoneer 1 Dec 27, 2021
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
Enjoyable scripting experience with Python

Enjoyable scripting experience with Python

8 Jun 08, 2022
A community-driven python bot that aims to be as simple as possible to serve humans with their everyday tasks

JARVIS on Messenger Just A Rather Very Intelligent System, now on Messenger! Messenger is now used by 1.2 billion people every month. With the launch

Swapnil Agarwal 1.3k Jan 07, 2023
Fisherman is a free open source fishing bot written in python.

Fisherman is a free open source fishing bot written in python.

Pure | Cody 33 Jan 29, 2022
Create or join a private chatroom without any third-party middlemen in less than 30 seconds, available through an AES encrypted password protected link.

PY-CHAT Create or join a private chatroom without any third-party middlemen in less than 30 seconds, available through an AES encrypted password prote

1 Nov 24, 2021
Beancount Importers for DKB (Deutsche Kredit Bank) CSV Exports

Beancount DKB Importer beancount-dkb provides an Importer for converting CSV exports of DKB (Deutsche Kreditbank) account summaries to the Beancount f

Siddhant Goel 24 Aug 06, 2022
This is a repository containing the backend and the frontend of a simple pokédex.

Pokémon This is a repository containing the backend and the frontend of a simple pokédex. This is a work in progress project! Project Structure 🗂 pok

André Rato 1 Nov 28, 2021
SEH-Helper - Binary Ninja plugin for exploring Structured Exception Handlers

SEH Helper Author: EliseZeroTwo A Binary Ninja helper for exploring structured e

Elise 74 Dec 26, 2022
MinimalGearDisplay, Assetto Corsa app

MinimalGearDisplay MinimalGearDisplay, Assetto Corsa app. Just displays the current gear you are on. Download and Install To use this app, clone or do

1 Jan 10, 2022
Ontario-Covid-Screening - An automated Covid-19 School Screening Tool for Ontario

Ontario-Covid19-Screening An automated Covid-19 School Screening Tool for Ontari

Rayan K 0 Feb 20, 2022
Ellipitical Curve Table Generator

Ellipitical-Curve-Table-Generator This script generates a table of elliptical po

Nishaant Goswamy 1 Jan 02, 2022
Online-update est un programme python permettant de mettre a jour des dossier et de fichier depuis une adresse web.

Démarrage rapide Online-update est un programme python permettant de mettre a jour des dossier et de fichier depuis une adresse web. Mode préconfiguré

pf4 2 Nov 26, 2021
El Niño - Southern Oscillation analysis compared to minimum flow rates of rivers in northeast Brazil

ENSO (El Niño - Southern Oscillation) analysis in northeast Brazil É comprovada a influência dos fenômenos El Niño e La Niña nas secas no nordesde bra

Weyder Freire 1 Jan 13, 2022
万能通用对象池,可以池化任意自定义类型的对象。

pip install universal_object_pool 此包能够将一切任意类型的python对象池化,是万能池,适用范围远大于单一用途的mysql连接池 http连接池等。 框架使用对象池包,自带实现了4个对象池。可以直接开箱用这四个对象池,也可以作为例子学习对象池用法。

12 Dec 15, 2022
Change ACLs for QNAP LXD unprivileged container.

qnaplxdunpriv If Advanced Folder Permissions is enabled in QNAP NAS, unprivileged LXD containers won't start. qnaplxdunpriv changes ACLs of some Conta

1 Jan 10, 2022
Oregon State University grade distributions from Fall 2018 through Summer 2021

Oregon State University Grades Oregon State University grade distributions from Fall 2018 through Summer 2021 obtained through a Freedom Of Informatio

Melanie Gutzmann 5 May 02, 2022
Compress .dds file in ggpk to boost fps. This is a python rewrite of PoeTexureResizer.

PoeBooster Compress .dds file in ggpk to boost fps. This is a python rewrite of PoeTexureResizer. Setup Install ImageMagick-7.1.0. Download and unzip

3 Sep 30, 2022