pytest-unused-port


Namepytest-unused-port JSON
Version 0.2 PyPI version JSON
download
home_pageNone
Summarypytest fixture finding an unused local port
upload_time2025-10-22 21:54:04
maintainerNone
docs_urlNone
authorSimon Willison
requires_python>=3.10
licenseNone
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pytest-unused-port

[![PyPI](https://img.shields.io/pypi/v/pytest-unused-port.svg)](https://pypi.org/project/pytest-unused-port/)
[![Tests](https://github.com/simonw/pytest-unused-port/actions/workflows/test.yml/badge.svg)](https://github.com/simonw/pytest-unused-port/actions/workflows/test.yml)
[![Changelog](https://img.shields.io/github/v/release/simonw/pytest-unused-port?include_prereleases&label=changelog)](https://github.com/simonw/pytest-unused-port/releases)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/pytest-unused-port/blob/main/LICENSE)

pytest fixture finding an unused local port, built [using Claude Code](https://gistpreview.github.io/?9ffa45bc69a545427009ca6283e2e672)

## Installation

Install this library using `pip`:
```bash
pip install pytest-unused-port
```
## Usage

### Command-line Interface

You can use pytest-unused-port as a standalone tool to serve a directory on an unused port:

```bash
# Serve a specific directory
pytest-unused-port /tmp/blah

# Or use the shorter alias
uport /tmp/blah

# Or using uvx
uvx pytest-unused-port /tmp/blah

# Or as a Python module
python -m pytest_unused_port /tmp/blah

# Serve the current directory (default)
pytest-unused-port
uport
```

This will start Python's `http.server` serving the specified directory on an automatically-selected unused port. The server will print the URL and run until you press Ctrl+C.

### Pytest Fixtures

This pytest plugin provides a `unused_port` fixture that returns an available TCP port on localhost that your tests can use.

### Basic Example

```python
def test_my_server(unused_port):
    # unused_port is an integer containing an available port number
    server = start_my_server(port=unused_port)
    assert server.is_running()
```

### Starting an HTTP Server

```python
import http.server

def test_http_server(unused_port):
    handler = http.server.SimpleHTTPRequestHandler
    server = http.server.HTTPServer(('127.0.0.1', unused_port), handler)
    # Now you can test your server on the unused port
    assert server.server_port == unused_port
```

### Using with Socket Programming

```python
import socket

def test_socket_server(unused_port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('127.0.0.1', unused_port))
    sock.listen(1)
    # Your test code here
    sock.close()
```

The fixture automatically finds an available port by binding to port 0 (which tells the OS to assign any available port), getting the assigned port number, and then releasing it for your test to use.

### The `unused_port_server` fixture

For convenience, this plugin also provides an `unused_port_server` fixture that manages an HTTP server for you. This is especially useful for testing applications that need to fetch content from a local server.

#### Basic Example

```python
def test_fetch_from_server(unused_port_server, tmp_path):
    # Create a test file
    test_file = tmp_path / "index.html"
    test_file.write_text("<h1>Hello</h1>")

    # Start the server serving the directory
    unused_port_server.start(tmp_path)

    # Make requests to http://127.0.0.1:{unused_port_server.port}/
    # Server automatically stops at the end of the test
```

#### Features

- **Automatic cleanup**: The server automatically stops when the test ends
- **Explicit control**: Call `.stop()` to stop the server manually if needed
- **Port access**: Access the port number via `unused_port_server.port`
- **Method chaining**: `.start()` returns self for convenience

#### Example with explicit stop

```python
def test_server_lifecycle(unused_port_server, tmp_path):
    unused_port_server.start(tmp_path)

    # Do some testing...

    # Explicitly stop the server
    unused_port_server.stop()

    # Server is now stopped
```

#### Example fetching a file

```python
from urllib.request import urlopen

def test_fetch_file(unused_port_server, tmp_path):
    # Create a test file
    (tmp_path / "data.txt").write_text("test data")

    # Start server
    unused_port_server.start(tmp_path)

    # Fetch the file
    url = f"http://127.0.0.1:{unused_port_server.port}/data.txt"
    response = urlopen(url)
    assert response.read().decode() == "test data"
```

#### Using as a context manager

You can also use `StaticServer` directly as a context manager if you need more control:

```python
from pytest_unused_port import StaticServer

def test_with_context_manager(unused_port, tmp_path):
    with StaticServer(unused_port) as server:
        server.start(tmp_path)
        # Server runs here
        # ... your test code ...
    # Server automatically stops when exiting the context
```

The server runs `python -m http.server` in a subprocess, serving static files from the specified directory.

## Development

To contribute to this library, first checkout the code. Then install the dependencies using `uv`:
```bash
cd pytest-unused-port
uv pip install -e '.[test]'
```
To run the tests:
```bash
uv run pytest
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pytest-unused-port",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Simon Willison",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/61/27/96e530adc51b7d3106d5e4223317b99586d74765a0201e828e52ca34700c/pytest_unused_port-0.2.tar.gz",
    "platform": null,
    "description": "# pytest-unused-port\n\n[![PyPI](https://img.shields.io/pypi/v/pytest-unused-port.svg)](https://pypi.org/project/pytest-unused-port/)\n[![Tests](https://github.com/simonw/pytest-unused-port/actions/workflows/test.yml/badge.svg)](https://github.com/simonw/pytest-unused-port/actions/workflows/test.yml)\n[![Changelog](https://img.shields.io/github/v/release/simonw/pytest-unused-port?include_prereleases&label=changelog)](https://github.com/simonw/pytest-unused-port/releases)\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/simonw/pytest-unused-port/blob/main/LICENSE)\n\npytest fixture finding an unused local port, built [using Claude Code](https://gistpreview.github.io/?9ffa45bc69a545427009ca6283e2e672)\n\n## Installation\n\nInstall this library using `pip`:\n```bash\npip install pytest-unused-port\n```\n## Usage\n\n### Command-line Interface\n\nYou can use pytest-unused-port as a standalone tool to serve a directory on an unused port:\n\n```bash\n# Serve a specific directory\npytest-unused-port /tmp/blah\n\n# Or use the shorter alias\nuport /tmp/blah\n\n# Or using uvx\nuvx pytest-unused-port /tmp/blah\n\n# Or as a Python module\npython -m pytest_unused_port /tmp/blah\n\n# Serve the current directory (default)\npytest-unused-port\nuport\n```\n\nThis will start Python's `http.server` serving the specified directory on an automatically-selected unused port. The server will print the URL and run until you press Ctrl+C.\n\n### Pytest Fixtures\n\nThis pytest plugin provides a `unused_port` fixture that returns an available TCP port on localhost that your tests can use.\n\n### Basic Example\n\n```python\ndef test_my_server(unused_port):\n    # unused_port is an integer containing an available port number\n    server = start_my_server(port=unused_port)\n    assert server.is_running()\n```\n\n### Starting an HTTP Server\n\n```python\nimport http.server\n\ndef test_http_server(unused_port):\n    handler = http.server.SimpleHTTPRequestHandler\n    server = http.server.HTTPServer(('127.0.0.1', unused_port), handler)\n    # Now you can test your server on the unused port\n    assert server.server_port == unused_port\n```\n\n### Using with Socket Programming\n\n```python\nimport socket\n\ndef test_socket_server(unused_port):\n    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    sock.bind(('127.0.0.1', unused_port))\n    sock.listen(1)\n    # Your test code here\n    sock.close()\n```\n\nThe fixture automatically finds an available port by binding to port 0 (which tells the OS to assign any available port), getting the assigned port number, and then releasing it for your test to use.\n\n### The `unused_port_server` fixture\n\nFor convenience, this plugin also provides an `unused_port_server` fixture that manages an HTTP server for you. This is especially useful for testing applications that need to fetch content from a local server.\n\n#### Basic Example\n\n```python\ndef test_fetch_from_server(unused_port_server, tmp_path):\n    # Create a test file\n    test_file = tmp_path / \"index.html\"\n    test_file.write_text(\"<h1>Hello</h1>\")\n\n    # Start the server serving the directory\n    unused_port_server.start(tmp_path)\n\n    # Make requests to http://127.0.0.1:{unused_port_server.port}/\n    # Server automatically stops at the end of the test\n```\n\n#### Features\n\n- **Automatic cleanup**: The server automatically stops when the test ends\n- **Explicit control**: Call `.stop()` to stop the server manually if needed\n- **Port access**: Access the port number via `unused_port_server.port`\n- **Method chaining**: `.start()` returns self for convenience\n\n#### Example with explicit stop\n\n```python\ndef test_server_lifecycle(unused_port_server, tmp_path):\n    unused_port_server.start(tmp_path)\n\n    # Do some testing...\n\n    # Explicitly stop the server\n    unused_port_server.stop()\n\n    # Server is now stopped\n```\n\n#### Example fetching a file\n\n```python\nfrom urllib.request import urlopen\n\ndef test_fetch_file(unused_port_server, tmp_path):\n    # Create a test file\n    (tmp_path / \"data.txt\").write_text(\"test data\")\n\n    # Start server\n    unused_port_server.start(tmp_path)\n\n    # Fetch the file\n    url = f\"http://127.0.0.1:{unused_port_server.port}/data.txt\"\n    response = urlopen(url)\n    assert response.read().decode() == \"test data\"\n```\n\n#### Using as a context manager\n\nYou can also use `StaticServer` directly as a context manager if you need more control:\n\n```python\nfrom pytest_unused_port import StaticServer\n\ndef test_with_context_manager(unused_port, tmp_path):\n    with StaticServer(unused_port) as server:\n        server.start(tmp_path)\n        # Server runs here\n        # ... your test code ...\n    # Server automatically stops when exiting the context\n```\n\nThe server runs `python -m http.server` in a subprocess, serving static files from the specified directory.\n\n## Development\n\nTo contribute to this library, first checkout the code. Then install the dependencies using `uv`:\n```bash\ncd pytest-unused-port\nuv pip install -e '.[test]'\n```\nTo run the tests:\n```bash\nuv run pytest\n```\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "pytest fixture finding an unused local port",
    "version": "0.2",
    "project_urls": {
        "CI": "https://github.com/simonw/pytest-unused-port/actions",
        "Changelog": "https://github.com/simonw/pytest-unused-port/releases",
        "Homepage": "https://github.com/simonw/pytest-unused-port",
        "Issues": "https://github.com/simonw/pytest-unused-port/issues"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "7f6533d0be055b30b8a3cfadfe8fe722105b72ec6e45971e15e86b1d3ee57e88",
                "md5": "1a36a42a1671924f41e3ef7739b24cd6",
                "sha256": "ca5bcf00cdf516a372f3a3e0f651bcf9dfdb1c4ac44ad0d7cdfc950a9cbfefed"
            },
            "downloads": -1,
            "filename": "pytest_unused_port-0.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "1a36a42a1671924f41e3ef7739b24cd6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 9629,
            "upload_time": "2025-10-22T21:54:03",
            "upload_time_iso_8601": "2025-10-22T21:54:03.298814Z",
            "url": "https://files.pythonhosted.org/packages/7f/65/33d0be055b30b8a3cfadfe8fe722105b72ec6e45971e15e86b1d3ee57e88/pytest_unused_port-0.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "612796e530adc51b7d3106d5e4223317b99586d74765a0201e828e52ca34700c",
                "md5": "08957f2a686057844a4f38a14ceeb084",
                "sha256": "3d443b9b8d25506fa2b627d35dfdc94148a611ab7cefb9c65428daef2146395c"
            },
            "downloads": -1,
            "filename": "pytest_unused_port-0.2.tar.gz",
            "has_sig": false,
            "md5_digest": "08957f2a686057844a4f38a14ceeb084",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 10498,
            "upload_time": "2025-10-22T21:54:04",
            "upload_time_iso_8601": "2025-10-22T21:54:04.594124Z",
            "url": "https://files.pythonhosted.org/packages/61/27/96e530adc51b7d3106d5e4223317b99586d74765a0201e828e52ca34700c/pytest_unused_port-0.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-22 21:54:04",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "simonw",
    "github_project": "pytest-unused-port",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pytest-unused-port"
}
        
Elapsed time: 2.78926s