testcontainers-python icon indicating copy to clipboard operation
testcontainers-python copied to clipboard

feat(core): Add `run_containers` function in utils.py to run several containers

Open surister opened this issue 2 months ago • 6 comments

This utils method runs containers on the same context manager. This ensures that the passed containers are run in order and cleaned up.

The main use case is to be able to run code after all containers have started. I need this to create CrateDB clusters.

Practical example: run containers inside a network and clean up the network (network can only be cleaned up after all containers using it are stopped)

network = Network()
network.create()

with run_containers(
        PostgresContainer(network=network),
        PostgresContainer(image='postgres:16', network=network),
) as containers:
    c1, c2 = containers
    conn1 = sqlalchemy.engine.create_engine(c1.get_connection_url()).connect()
    conn2 = sqlalchemy.engine.create_engine(c2.get_connection_url()).connect()

    result1 = conn1.execute(sqlalchemy.text("select version()")).fetchone()
    result2 = conn2.execute(sqlalchemy.text("select version()")).fetchone()

    print(result1, result2, sep='\n')

# The network gets removed only when containers are stopped.
network.remove()

surister avatar Oct 05 '25 12:10 surister

if we add this can we name it consistently with any one of the other implementations, thanks

alexanderankin avatar Oct 07 '25 22:10 alexanderankin

if we add this can we name it consistently with any one of the other implementations, thanks

Hm, could you like any of the other implementations? Can't find them @alexanderankin

surister avatar Oct 08 '25 09:10 surister

I'm admittedly not sure this should be part of the library, when the caller can achieve the same result explicitly with the same amount of code.

with run_containers(
        PostgresContainer(network=network),
        PostgresContainer(image='postgres:16', network=network),
) as containers:
    c1, c2 = containers

Becomes

with contextlib.ExitStack() as stack:
    c1, c2 = stack.enter_context(container) for container in (
        PostgresContainer(network=network),
        PostgresContainer(image='postgres:16', network=network)
    )

rhoban13 avatar Oct 13 '25 21:10 rhoban13

https://www.javadoc.io/doc/org.testcontainers/testcontainers/1.12.1/org/testcontainers/lifecycle/Startables.html

On Mon, Oct 13, 2025 at 5:23 PM Ryan Hoban @.***> wrote:

rhoban13 left a comment (testcontainers/testcontainers-python#896) https://github.com/testcontainers/testcontainers-python/pull/896#issuecomment-3399108721

I'm admittedly not sure this should be part of the library, when the caller can achieve the same result explicitly with the same amount of code.

with run_containers( PostgresContainer(network=network), PostgresContainer(image='postgres:16', network=network), ) as containers: c1, c2 = containers

Becomes

with contextlib.ExitStack() as stack: c1, c2 = stack.enter_context(container) for container in ( PostgresContainer(network=network), PostgresContainer(image='postgres:16', network=network) )

— Reply to this email directly, view it on GitHub https://github.com/testcontainers/testcontainers-python/pull/896#issuecomment-3399108721, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACECGJEPB3G3BZVLOQQEFKT3XQJ3PAVCNFSM6AAAAACIKPW4UOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGOJZGEYDQNZSGE . You are receiving this because you were mentioned.Message ID: @.***>

alexanderankin avatar Oct 15 '25 00:10 alexanderankin

https://java.testcontainers.org/features/advanced_options/#parallel-container-startup

On Tue, Oct 14, 2025 at 8:23 PM David Ankin @.***> wrote:

https://www.javadoc.io/doc/org.testcontainers/testcontainers/1.12.1/org/testcontainers/lifecycle/Startables.html

On Mon, Oct 13, 2025 at 5:23 PM Ryan Hoban @.***> wrote:

rhoban13 left a comment (testcontainers/testcontainers-python#896) https://github.com/testcontainers/testcontainers-python/pull/896#issuecomment-3399108721

I'm admittedly not sure this should be part of the library, when the caller can achieve the same result explicitly with the same amount of code.

with run_containers( PostgresContainer(network=network), PostgresContainer(image='postgres:16', network=network), ) as containers: c1, c2 = containers

Becomes

with contextlib.ExitStack() as stack: c1, c2 = stack.enter_context(container) for container in ( PostgresContainer(network=network), PostgresContainer(image='postgres:16', network=network) )

— Reply to this email directly, view it on GitHub https://github.com/testcontainers/testcontainers-python/pull/896#issuecomment-3399108721, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACECGJEPB3G3BZVLOQQEFKT3XQJ3PAVCNFSM6AAAAACIKPW4UOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTGOJZGEYDQNZSGE . You are receiving this because you were mentioned.Message ID: @.***>

alexanderankin avatar Oct 15 '25 00:10 alexanderankin

Ahhhh, I see what you're looking to achieve. I could definitely see the parallel container startup being a really useful feature. In it's current form, that's not what this PR proposes.

I suspect such an implementation and would warrant some discussion on which of python's plethora of ways to achieve parallelism makes most sense here.

rhoban13 avatar Oct 15 '25 17:10 rhoban13