mirror of
https://github.com/docker/docs.git
synced 2026-03-27 22:38:54 +07:00
## Description Migrate 17 Testcontainers guides from testcontainers.com into the Docker docs site, covering Java (14 guides), .NET (2 guides), and Node.js (1 guide). This follows up on PR #24450 which added the initial Go and Python guides. Each guide is converted from AsciiDoc to Hugo Markdown, split into multi-chapter stepper navigation, updated to the latest Testcontainers API, and verified with passing tests running in containers. Java guides use testcontainers-java 2.0.4 with the new 2.x Maven coordinates and package names (e.g., `testcontainers-postgresql`, `org.testcontainers.postgresql.PostgreSQLContainer`). The Quarkus guide uses Quarkus 3.22.3 with TC 1.x managed by the Quarkus BOM, since no released Quarkus version ships TC 2.x yet. ## How to test All code snippets have been verified by running each guide's source repository tests inside Docker containers with the Docker socket mounted. To re-run the verification, use the `/testcontainers-guides-migrator` skill included in this PR (`.claude/skills/testcontainers-guides-migrator/SKILL.md`). The skill's Step 6 documents the exact container commands and macOS Docker Desktop workarounds (host override, docker-java API version, etc.) needed to run each language's tests: ``` /testcontainers-guides-migrator I want you to verify all the guides in this branch. Do a full review, verifying that all code snippets compile, the code is executable, and ALL the tests pass. Run them as docker containers, never locally. ``` ## Related issues or tickets Supersedes #24450 (expanded from 2 guides to all 19) ## Reviews - [ ] Technical review - [ ] Editorial review - [ ] Product review --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
131 lines
3.7 KiB
Markdown
131 lines
3.7 KiB
Markdown
---
|
|
title: Create the Python project
|
|
linkTitle: Create the project
|
|
description: Set up a Python project with a PostgreSQL-backed customer service.
|
|
weight: 10
|
|
---
|
|
|
|
## Initialize the project
|
|
|
|
Start by creating a Python project with a virtual environment:
|
|
|
|
```console
|
|
$ mkdir tc-python-demo
|
|
$ cd tc-python-demo
|
|
$ python3 -m venv venv
|
|
$ source venv/bin/activate
|
|
```
|
|
|
|
This guide uses [psycopg3](https://www.psycopg.org/psycopg3/) to interact
|
|
with the Postgres database, [pytest](https://pytest.org/) for testing, and
|
|
[testcontainers-python](https://testcontainers-python.readthedocs.io/) for
|
|
running a PostgreSQL database in a container.
|
|
|
|
Install the dependencies:
|
|
|
|
```console
|
|
$ pip install "psycopg[binary]" pytest testcontainers[postgres]
|
|
$ pip freeze > requirements.txt
|
|
```
|
|
|
|
The `pip freeze` command generates a `requirements.txt` file so that others
|
|
can install the same package versions using `pip install -r requirements.txt`.
|
|
|
|
## Create the database helper
|
|
|
|
Create a `db/connection.py` file with a function to get a database connection:
|
|
|
|
```python
|
|
import os
|
|
|
|
import psycopg
|
|
|
|
|
|
def get_connection():
|
|
host = os.getenv("DB_HOST", "localhost")
|
|
port = os.getenv("DB_PORT", "5432")
|
|
username = os.getenv("DB_USERNAME", "postgres")
|
|
password = os.getenv("DB_PASSWORD", "postgres")
|
|
database = os.getenv("DB_NAME", "postgres")
|
|
return psycopg.connect(f"host={host} dbname={database} user={username} password={password} port={port}")
|
|
```
|
|
|
|
Instead of hard-coding the database connection parameters, the function uses
|
|
environment variables. This makes it possible to run the application in
|
|
different environments without changing code.
|
|
|
|
## Create the business logic
|
|
|
|
Create a `customers/customers.py` file and define the `Customer` class:
|
|
|
|
```python
|
|
class Customer:
|
|
def __init__(self, cust_id, name, email):
|
|
self.id = cust_id
|
|
self.name = name
|
|
self.email = email
|
|
|
|
def __str__(self):
|
|
return f"Customer({self.id}, {self.name}, {self.email})"
|
|
```
|
|
|
|
Add a `create_table()` function to create the `customers` table:
|
|
|
|
```python
|
|
from db.connection import get_connection
|
|
|
|
|
|
def create_table():
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute("""
|
|
CREATE TABLE customers (
|
|
id serial PRIMARY KEY,
|
|
name varchar not null,
|
|
email varchar not null unique)
|
|
""")
|
|
conn.commit()
|
|
```
|
|
|
|
The function obtains a database connection using `get_connection()` and creates
|
|
the `customers` table. The `with` statement automatically closes the connection
|
|
when done.
|
|
|
|
Add the remaining CRUD functions:
|
|
|
|
```python
|
|
def create_customer(name, email):
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(
|
|
"INSERT INTO customers (name, email) VALUES (%s, %s)", (name, email))
|
|
conn.commit()
|
|
|
|
|
|
def get_all_customers() -> list[Customer]:
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute("SELECT * FROM customers")
|
|
return [Customer(cid, name, email) for cid, name, email in cur]
|
|
|
|
|
|
def get_customer_by_email(email) -> Customer:
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute("SELECT id, name, email FROM customers WHERE email = %s", (email,))
|
|
(cid, name, email) = cur.fetchone()
|
|
return Customer(cid, name, email)
|
|
|
|
|
|
def delete_all_customers():
|
|
with get_connection() as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute("DELETE FROM customers")
|
|
conn.commit()
|
|
```
|
|
|
|
> [!NOTE]
|
|
> To keep it straightforward for this guide, each function creates a new
|
|
> connection. In a real-world application, use a connection pool to reuse
|
|
> connections.
|