Skip to main content

deferrable-py

A lightweight pure-Python implementation of Go's "defer"

Features

  • The developers can defer operations, dubbed deferred operations.
    • Only a deferrable async callable object can take both sync and async callables as deferred operations.
  • The deferred operations will be run in the LIFO order.

Example

Suppose we have a deferrable function.

from deferrable import defer, deferrable


@deferrable
def do_something():
    print('in-1')
    defer(lambda: print('out-1'))
    print('in-2')
    defer(lambda: print('out-2'))

do_something()

The output would be:

in-1
in-2
out-2
out-1

Why it matters?

Suppose that you want to close a file after a chain of operations. Generally, you can do this.

def func():
    with open('foo.txt', 'r') as fp:
        fp.write('abcdef123456')
    # NOTE: fp is now closed as the code exits the context of "open()".
    # NOTE: At this point, fp is no longer useful.
# end of def

However, what if fp is still needed later in the same method.

With this library, you can simply defer fp.close() to the end of callable invocation.

from deferrable import defer, deferrable


@deferrable
def func():
    fp = open('foo.txt', 'r')
    defer(lambda: fp.close())  # <-- Define a deferred operation
    # NOTE: You can also simply write:
    #
    #         defer(functools.partial(lambda fp: fp.close(), fp))
    #
    #       if you want to deal with the late binding problem right away.

    fp.write('abcdef123456')

    ...

    # NOTE: No more code here
# end of def

When the invocation of func() completes successfully or ends with error, the deferred operation will be invoked.

Please note that the deferred operation will not alter the returned value of the deferrable callable.

Example Use Cases

  • Flexible cleanup for each test case
    from unittest import TestCase
    
    from deferrable import defer, deferrable
    
    def create_obj(id):
      ...
    
    def delete_obj(id):
      ...
    
    class UnitTest(TestCase):
      @deferrable
      def test_happy_path(self):
        o = create_obj('alpha')  # <-- create a test obj
        defer(lambda: delete_obj('alpha'))  # <-- defer the test obj deletion to the end 
        ... # <-- the rest of the test
    

    Some test frameworks provide this mechanism. This is all about being framework-agnostic.

  • Handle the data temporarily.
    from os import unlink
    from typing import Iterator
    from deferrable import defer, deferrable
    
    def load_blob(url) -> Iterator[bytes]:
      ...
    
    def upload_blob(local_file_path):
      ...
    
    @deferrable
    def transfer(source_url, destination_url):
      tmp_file_path = ...
      with open(tmp_file_path, 'wb') as f:
        for b in load_blob(source_url):
          f.write(b)
      defer(lambda: unlink(tmp_file_path))
      upload_blob(tmp_file_path)
    

API Reference

Decorator deferrable.deferrable(func: Callable)

Make the wrapped callable capable of having deferred operations.

The func parameter must be callable.

from deferrable import deferrable

@deferrable
def func_a():
    ...

@deferrable
async def func_b():
    ...

Function deferrable.defer(op: Callable[[], None]|Callable[[], Awaitable[None]])

Defer the given operation to be executed at the end of the callable invocation,i.e., on the call exit.

The op parameter must be a callable which takes no parameters. Any returning values will be disregarded.

from deferrable import deferrable, defer

@deferrable
def func_a():
    ...
    defer(lambda: ...)

@deferrable
def func_b():
    ...
    defer(lambda: ...)  # A normal function can be used as a deferred operation.
    defer(lambda: ...)  # A normal function can be used as a deferred operation.

Metadata

Release files for deferrable-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for deferrable-py 0.1.0
File Size Uploaded Provenance Actions
deferrable_py-0.1.0.tar.gz 8.8 kB With provenance Details for deferrable_py-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for deferrable-py 0.1.0
File Interpreter ABI Platform Actions
deferrable_py-0.1.0-py3-none-any.whl Python 3 none any Details for deferrable_py-0.1.0-py3-none-any.whl

Total release size: 16.9 kB

Release files / deferrable_py-0.1.0.tar.gz

Download URL deferrable_py-0.1.0.tar.gz
Size 8.8 kB
Tags Source
SHA-256 checksum
How to use checksums
ef4ce4340a58f0fa9caaf855a50af3a0503d03eb269897eac9ecc9dec283d15b
BLAKE2b-256 checksum
How to use checksums
3800c61161f446938179e60346efd4d5b5749dc4a2033d00e3298cbf7e3a7e56
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 5, 2025.

Transparency log

Release files / deferrable_py-0.1.0-py3-none-any.whl

Download URL deferrable_py-0.1.0-py3-none-any.whl
Size 8.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
87da40db91d906ed3c73329dfcf239ef3a04765ef55a62765304366be6302bcd
BLAKE2b-256 checksum
How to use checksums
ec21ddfb164420f624e70b9e15cd449770f18940ee23597a27fcbfd909943a19
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 5, 2025.

Transparency log

Security for deferrable-py 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for deferrable_py-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 5, 2025.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page