Metadata-Version: 2.4
Name: python-proxy-provider
Version: 0.1.1
Summary: Provider/plugin framework for dynamic reverse proxy configuration (Traefik-like providers in Python).
Author: Kubenew
License: MIT
License-File: LICENSE
Keywords: asyncio,dynamic-config,provider,reverse-proxy,traefik
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: System :: Networking
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.7.0
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: typer>=0.12.3
Requires-Dist: watchfiles>=0.22.0
Provides-Extra: dev
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-localserver>=0.8; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Provides-Extra: test
Requires-Dist: httpx>=0.27.0; extra == 'test'
Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
Requires-Dist: pytest-localserver>=0.8; extra == 'test'
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# python-proxy-provider

[![PyPI](https://img.shields.io/pypi/v/python-proxy-provider)](https://pypi.org/project/python-proxy-provider/)
[![Python Versions](https://img.shields.io/pypi/pyversions/python-proxy-provider)](https://pypi.org/project/python-proxy-provider/)
[![License](https://img.shields.io/pypi/l/python-proxy-provider)](https://github.com/Kubenew/python-proxy-provider/blob/main/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/Kubenew/python-proxy-provider?style=flat&logo=github)](https://github.com/Kubenew/python-proxy-provider)
[![Downloads](https://img.shields.io/pepy.tech/dt/python-proxy-provider)](https://pepy.tech/project/python-proxy-provider)

A Traefik-like **provider framework** for dynamic proxy configuration in Python.

This project is not a full reverse proxy by itself. It is a provider engine that watches multiple sources (files, HTTP APIs, Docker, Consul, etc.) and produces a normalized routing configuration.

## Use cases

- Build a Python Traefik-like router
- Build an edge gateway that reloads routes dynamically
- Implement Kubernetes/Docker providers in Python
- Provide unified routing config for multiple systems

## Features

- **Provider plugin interface** (`ProviderBase`) with `start()` / `stop()` / `current_config()`
- **Provider manager** — loads providers, merges configs, tracks background tasks
- **File provider** — watches YAML files for live changes via `watchfiles`
- **HTTP provider** — polls JSON routes from a remote endpoint with connection pooling
- **Event bus** — async pub/sub for config update notifications
- **Graceful shutdown** — signal handlers (SIGINT/SIGTERM) stop all providers cleanly
- **Configurable logging** — `--log-level` CLI option (DEBUG, INFO, WARNING, ERROR)
- **Merge conflict detection** — logs warnings when multiple providers define the same router or service

## Quickstart

### Install

```bash
pip install python-proxy-provider
```

### Run demo

```bash
proxy-provider run --file examples/routes.yml
```

Then edit `examples/routes.yml` and see live reload output.

Combine multiple providers:

```bash
proxy-provider run --file examples/routes.yml --http http://localhost:8000/routes --log-level DEBUG
```

## Architecture

```
                    ┌─────────────────┐
                    │   EventBus      │
                    │  (async Queue)  │
                    └──────┬──────────┘
          ┌────────────────┼────────────────┐
          ▼                ▼                ▼
   FileProvider      HttpProvider     (future providers)
   (watch YAML)     (poll JSON)       Docker, Consul, K8s
          │                │                │
          └────────────────┼────────────────┘
                           ▼
                    ProviderManager
                    ┌──────────┐
                    │  merge() │
                    └────┬─────┘
                         ▼
                   DynamicConfig
              (routers + services)
```

## Provider API

Implement a custom provider by subclassing `ProviderBase`:

```python
from python_proxy_provider.providers.base import ProviderBase
from python_proxy_provider.models import DynamicConfig
from python_proxy_provider.events import ConfigEvent

class MyProvider(ProviderBase):
    name = "my"

    async def start(self):
        cfg = DynamicConfig(...)
        await self.bus.publish(ConfigEvent(provider=self.name, config=cfg))

    async def current_config(self) -> DynamicConfig:
        return self._config
```

## Roadmap

- Docker provider (watch containers)
- Consul provider
- Kubernetes provider
- Plugin discovery via `entry_points`
- Conflict resolution policies
- Distributed config cache

## Changelog

### 0.1.1

- **Graceful shutdown**: Signal handlers (SIGINT/SIGTERM) stop all providers cleanly.
- **Connection pooling**: Shared `httpx.AsyncClient` singleton (was creating a client per request).
- **Logging**: Replaced `print()` with structured `logging` throughout; added `--log-level` CLI option.
- **Merge conflict detection**: Warns when multiple providers define the same router/service key.
- **EventBus close**: `EventBus.close()` prevents publishing after shutdown; subscribe loop exits cleanly.
- **Task tracking**: `ProviderBase` tracks background task for proper cancellation via `stop()`.
- **Bare except fixes**: All `except Exception` blocks re-raise `asyncio.CancelledError`.
- **Build system**: Migrated from `setuptools` to `hatchling`. Added classifiers, keywords, optional dev/test deps, ruff/pytest config.
- **Tests**: Expanded from 1 test to 20 tests covering models, events, manager, file provider, and HTTP provider.

### 0.1.0

- Initial release: Provider plugin interface, file provider, HTTP provider, event bus, CLI demo.

## License

MIT
