Skip to main content

“UnBind” -- frees occupied ports by detecting and unbinding blocking processes

Project description

ub

"UnBind" - Frees occupied ports by detecting and unbinding blocking processes.

Never struggle with "port already in use" errors again! ub automatically detects what's using your ports, shows you the processes with their PIDs, and gives you options to kill them or find alternative ports.

🚀 Installation

pip install ub

✨ Quick Start

For FastAPI/Uvicorn servers:

from fastapi import FastAPI
from ub import start_uvicorn_with_port_handling

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

# This will handle port conflicts automatically
start_uvicorn_with_port_handling(app, host="0.0.0.0", port=8000, reload=True)

For Flask servers:

from flask import Flask
from ub import start_flask_with_port_handling

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

# This will handle port conflicts automatically  
start_flask_with_port_handling(app, host="0.0.0.0", port=5000, debug=True)

For any server:

from ub import start_server_with_port_handling
import uvicorn

def my_server_starter(host, port, **kwargs):
    # Your server startup logic here
    uvicorn.run(my_app, host=host, port=port, **kwargs)

start_server_with_port_handling(
    my_server_starter,
    host="0.0.0.0", 
    port=8000,
    service_name="My Custom Server"
)

🎭 Context Managers

ub now provides powerful context managers for automatic port management and server lifecycle control:

Basic Port Management

from ub import port_context

with port_context("0.0.0.0", 8000, "My API") as port:
    # Port conflict automatically resolved
    uvicorn.run(app, host="0.0.0.0", port=port)
    # Automatic cleanup on exit

Managed Server Lifecycle

from ub import managed_server

def my_server(host, port, app):
    uvicorn.run(app, host=host, port=port)

with managed_server(my_server, port=8000, app=my_app) as port:
    print(f"Server running on port {port}")
    # Do other work while server runs
    time.sleep(10)
# Server automatically shut down here

Framework-Specific Context Managers

# FastAPI
from ub import fastapi_context
with fastapi_context(app, port=8000, reload=True) as port:
    print(f"FastAPI running on port {port}")
    # Server runs in background, auto-cleanup on exit

# Flask  
from ub import flask_context
with flask_context(app, port=5000, debug=True) as port:
    print(f"Flask running on port {port}")
    # Server runs in background, auto-cleanup on exit

Port Reservation

from ub import reserve_port

# Reserve multiple consecutive ports
with reserve_port("0.0.0.0", 8000, count=3) as ports:
    print(f"Reserved ports: {ports}")  # e.g., [8000, 8001, 8002]
    start_service_1(port=ports[0])
    start_service_2(port=ports[1]) 
    start_service_3(port=ports[2])
# Ports automatically released

Temporary Process Management

from ub import temporary_kill

# Temporarily clear a port
with temporary_kill(8000) as killed_processes:
    print(f"Temporarily killed {len(killed_processes)} processes")
    # Port 8000 is now free for your use
    start_my_server(port=8000)
# Processes info available, optional restoration

🔧 What It Does

When you try to start a server and the port is already in use, ub will:

  1. Detect the conflict - Immediately identifies when a port is occupied
  2. Show process details - Lists all processes using the port with PIDs, names, and full command lines
  3. Offer clear options:
    • Kill the conflicting processes
    • Find and use an alternative port
    • Exit gracefully

Example interaction:

🚨 Port 8000 is already in use!

Processes using port 8000:
--------------------------------------------------------------------------------
1. PID: 1234 | Name: python
   Command: python my_old_server.py

2. PID: 5678 | Name: node  
   Command: node server.js

What would you like to do for FastAPI Server?
1. Kill the conflicting process(es)
2. Use a different port
3. Exit

Enter your choice (1-3): 

📚 API Reference

Core Functions

handle_port_conflict(host, port, service_name=None)

Handles port conflicts interactively. Returns the port to use (either original after cleanup or a new one).

from ub import handle_port_conflict

port = handle_port_conflict("0.0.0.0", 8000, "My API")
# Now use 'port' to start your server

check_port_available(host, port)

Check if a port is available.

from ub import check_port_available

if check_port_available("localhost", 8000):
    print("Port 8000 is free!")

get_processes_using_port(port)

Get detailed information about processes using a port.

from ub import get_processes_using_port

processes = get_processes_using_port(8000)
for proc in processes:
    print(f"PID: {proc['pid']}, Name: {proc['name']}, Command: {proc['command']}")

find_available_port(start_port, host="0.0.0.0", max_attempts=100)

Find the next available port starting from a given port.

from ub import find_available_port

available_port = find_available_port(8000)
print(f"Next available port: {available_port}")

Convenience Wrappers

start_uvicorn_with_port_handling(app, host="0.0.0.0", port=8000, **kwargs)

Start a Uvicorn/FastAPI server with automatic port conflict handling.

start_flask_with_port_handling(app, host="0.0.0.0", port=5000, **kwargs)

Start a Flask server with automatic port conflict handling.

start_server_with_port_handling(server_func, host="0.0.0.0", port=8000, service_name=None, **server_kwargs)

Generic wrapper for any server startup function.

Context Managers

port_context(host="0.0.0.0", port=8000, service_name=None, auto_kill=False)

Context manager for handling port conflicts. Yields the port to use.

from ub import port_context

with port_context("0.0.0.0", 8000, "My API", auto_kill=True) as port:
    uvicorn.run(app, host="0.0.0.0", port=port)

managed_server(server_func, host="0.0.0.0", port=8000, service_name=None, auto_kill=False, **server_kwargs)

Context manager that starts a server and ensures cleanup. Yields the port number.

fastapi_context(app, host="0.0.0.0", port=8000, auto_kill=False, **uvicorn_kwargs)

Context manager specifically for FastAPI applications.

flask_context(app, host="0.0.0.0", port=5000, auto_kill=False, **flask_kwargs)

Context manager specifically for Flask applications.

reserve_port(host="0.0.0.0", start_port=8000, count=1)

Context manager to reserve consecutive ports. Yields list of reserved port numbers.

temporary_kill(port, restore=False)

Context manager to temporarily kill processes using a port. Yields list of killed process info.

🎯 Usage Patterns

Pattern 1: Drop-in replacement (Recommended)

Replace your existing server startup with the ub equivalent:

# Before
uvicorn.run(app, host="0.0.0.0", port=8000)

# After  
from ub import start_uvicorn_with_port_handling
start_uvicorn_with_port_handling(app, host="0.0.0.0", port=8000)

Pattern 2: Manual conflict handling

Handle conflicts yourself with full control:

from ub import handle_port_conflict
import uvicorn

desired_port = 8000
final_port = handle_port_conflict("0.0.0.0", desired_port, "My Custom API")

print(f"Starting server on port {final_port}")
uvicorn.run(app, host="0.0.0.0", port=final_port)

Pattern 3: Port checking utilities

Use individual utility functions:

from ub import check_port_available, get_processes_using_port, find_available_port

port = 8000

if not check_port_available("localhost", port):
    print(f"Port {port} is busy!")
    
    # See what's using it
    processes = get_processes_using_port(port)
    for proc in processes:
        print(f"Process: {proc['name']} (PID: {proc['pid']})")
    
    # Find alternative
    alt_port = find_available_port(port + 1)
    print(f"Try port {alt_port} instead")

Pattern 4: Custom server integration

Integrate with any server framework:

from ub import start_server_with_port_handling
import http.server
import socketserver

def start_simple_server(host="0.0.0.0", port=8080):
    Handler = http.server.SimpleHTTPRequestHandler
    with socketserver.TCPServer((host, port), Handler) as httpd:
        print(f"Serving at http://{host}:{port}")
        httpd.serve_forever()

start_server_with_port_handling(
    start_simple_server,
    host="0.0.0.0", 
    port=8080,
    service_name="Simple HTTP Server"
)

Pattern 5: Context manager for testing

Perfect for tests that need temporary servers:

from ub import fastapi_context

def test_my_api():
    with fastapi_context(my_app, auto_kill=True) as port:
        # Server runs in background with auto-cleanup
        response = requests.get(f"http://localhost:{port}/health")
        assert response.status_code == 200
    # Server automatically cleaned up after test

Pattern 6: Multi-service development

Run multiple services with automatic port management:

from ub import reserve_port, fastapi_context

with reserve_port(start_port=8000, count=3) as ports:
    with fastapi_context(auth_service, port=ports[0]) as auth_port:
        with fastapi_context(api_service, port=ports[1]) as api_port:
            with fastapi_context(ui_service, port=ports[2]) as ui_port:
                # All services running, do integration work
                run_integration_tests(auth_port, api_port, ui_port)
# All services automatically cleaned up

🌍 Cross-Platform Support

ub works seamlessly across platforms:

  • macOS/Linux: Uses lsof and ps for detailed process information
  • Windows: Uses netstat and tasklist for process detection
  • Fallbacks: Gracefully handles missing system tools

🔐 Process Management

When killing processes, ub:

  1. Tries graceful termination first (SIGTERM on Unix, standard termination on Windows)
  2. Falls back to force kill if needed (SIGKILL on Unix, /F flag on Windows)
  3. Waits and verifies process termination
  4. Reports success/failure clearly

⚡ Benefits

  • 🚫 No more "address already in use" mysteries - See exactly what's blocking your port
  • ⚡ One-click process cleanup - Kill conflicting processes safely with a single choice
  • 🔄 Automatic port discovery - Find alternative ports instantly
  • 🔧 Framework agnostic - Works with FastAPI, Flask, Django, custom servers, anything
  • 🖥️ Cross-platform - Same experience on macOS, Linux, and Windows
  • 👥 User-friendly - Clear messages, safe defaults, graceful error handling
  • 📦 Zero dependencies - Uses only Python standard library
  • 🎭 Context manager support - Automatic cleanup and resource management
  • 🧪 Perfect for testing - Temporary servers with guaranteed cleanup
  • 🔄 Exception safe - Resources properly released even when errors occur

🤝 Contributing

Issues and pull requests welcome! This tool aims to eliminate the frustration of port conflicts for all developers.

📄 License

MIT License - Use freely in your projects!


Stop fighting port conflicts. Start using ub. 🎯 “UnBind”: Frees occupied ports by detecting and unbinding blocking processes.

To install: pip install ub

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ub-0.0.10.tar.gz (15.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ub-0.0.10-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

Details for the file ub-0.0.10.tar.gz.

File metadata

  • Download URL: ub-0.0.10.tar.gz
  • Upload date:
  • Size: 15.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.18

File hashes

Hashes for ub-0.0.10.tar.gz
Algorithm Hash digest
SHA256 caaf684c041db0da85bf5fb31eaa2dab672bbd558d362789e7ddf111d9974271
MD5 4e2b8a132a42ad0624b6de651017b830
BLAKE2b-256 6702b11d103cf8140cc8427f80ae23dc8061d66859d4aeb4f20c93e826fe6656

See more details on using hashes here.

File details

Details for the file ub-0.0.10-py3-none-any.whl.

File metadata

  • Download URL: ub-0.0.10-py3-none-any.whl
  • Upload date:
  • Size: 13.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.10.18

File hashes

Hashes for ub-0.0.10-py3-none-any.whl
Algorithm Hash digest
SHA256 b66362f1dcbe179eef42ea0c3a19ffa5b69ef3cf3477356070f3db6cc391fc64
MD5 06b7bf0acdd289b9b0e582a2e4de205a
BLAKE2b-256 0e8c8b4cc47c0dee24996fcd604d74134712ba5327f293a5099b321b4af182d6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page