Metadata-Version: 2.5
Name: cloud-proxy-hub
Version: 0.2.0
Summary: Multi-provider proxy pool with geo/performance validation (Proxy-Seller, SmartProxy, pingnetwork).
License: Proprietary
Requires-Python: >=3.11
Requires-Dist: aiohttp>=3.9
Requires-Dist: countryinfo>=0.1.2
Requires-Dist: pycountry>=23.12
Requires-Dist: requests>=2.31
Description-Content-Type: text/markdown

# cloud-proxy-hub

Multi-provider proxy pool with geo and performance validation. Wraps
Proxy-Seller (datacenter + residential), pingnetwork.io (residential) and
SmartProxy (residential) behind a single class:

```python
from cloud_proxy_hub import ProxyHub, ProxyHubConfig

config = ProxyHubConfig(
    # provider credentials — or leave unset and export the same-named
    # env vars (PROXY_API_KEY, SMARTPROXY_LOGIN, SMARTPROXY_PASS, ...)
    proxy_api_key="...",
    proxy_seller_res_login="...",
    proxy_seller_res_pass="...",
    proxy_pingnetwork_res_login="...",
    proxy_pingnetwork_res_pass="...",
    smartproxy_login="...",
    smartproxy_pass="...",

    # extra static datacenter proxies per ISO-3166 alpha-2 country code
    # (used to be hardcoded in the library — now it's yours to supply)
    additional_datacenter_proxies={
        "ZA": ["http://user:pass@host:port", ...],
        "BR": ["http://user:pass@host:port", ...],
    },

    # which providers are active, and in what order (default shown here —
    # SmartProxy is OFF by default; add it back with any key/priority to
    # re-enable, e.g. provider_priority={"Proxy-Seller": 1, "pingnetwork": 2, "SmartProxy": 3}).
    # Drop "pingnetwork" if you don't want the pingnetwork.io fallback.
    # Providers are tried in order, the first one that returns proxies wins,
    # and SmartProxy is always tried last whatever number you give it.
    provider_priority={"Proxy-Seller": 1, "pingnetwork": 2},

    # smartproxy_retries / smartproxy_backoff_factor / smartproxy_timeout
    # also exist (defaults 5 / 1.5 / 10) — omitted here since SmartProxy is
    # off by default above; only relevant once you add "SmartProxy" back to
    # provider_priority.
)

proxy_hub = ProxyHub(validate_proxies=True, config=config)

proxy = proxy_hub.provide_valid_proxies(
    proxy_type="residential",
    country_code="DE",
    neighbor_geo_enable=False,
    reverse_proxy=is_last_attempt,  # try pingnetwork.io first on the last retry
)
```

Everything you need to tune lives on `ProxyHubConfig` — construct it once,
pass it to `ProxyHub`, and call `provide_valid_proxies()`. No need to reach
into `cloud_proxy_hub.providers` / `cloud_proxy_hub.geo` /
`cloud_proxy_hub.performance` unless you're extending the library itself.

## Why a config object

The original script read paths and provider credentials from an internal
`src.settings` module, and had a dict of extra datacenter proxies (with real
login/password pairs) hardcoded in the class body. Both made the code
impossible to hand to anyone outside that one codebase, and unsafe to publish
anywhere public. `ProxyHubConfig` replaces both: every credential is either
passed explicitly or read from an environment variable of the same name, and
`additional_datacenter_proxies` is supplied by the caller instead of baked
into the source.

## Install

```bash
pip install cloud-proxy-hub
```

Published on public PyPI. No credentials are embedded anywhere in the
source — every secret is supplied by the consumer via `ProxyHubConfig` or
environment variables, as shown above.

### Publishing a new version

```bash
python -m pip install --upgrade build twine
python -m build          # produces dist/*.whl and dist/*.tar.gz
python -m twine upload dist/*
```

Requires a PyPI account with 2FA enabled and an API token (`__token__` as
username, the token as password).

## What changed in 0.2.0

**pingnetwork.io is a real provider now.** Up to 0.1.1 it was generated from
inside `ProxySeller.generate_resident_proxy_by_proxy_seller`: its proxies were
appended to the proxy-seller list and one of the two was picked with the 90/10
`proxy_seller_weight` / `pingnetwork_weight` split. That also meant dropping
`"Proxy-Seller"` from `provider_priority` silently disabled pingnetwork.io,
and a failure reading proxy-seller's `geo_proxy.json` took pingnetwork down
with it — the two shared one `try/except`.

It is now a `PingNetwork` class dispatched by `ProxyHub` like any other
provider:

- providers are tried in order and the **first one that returns proxies
  wins** — the weighted split is gone;
- default order is `Proxy-Seller` → `pingnetwork`, so proxy-seller.com serves
  traffic and pingnetwork.io is the fallback;
- `provide_valid_proxies(..., reverse_proxy=True)` flips the first two:
  pingnetwork.io first, proxy-seller.com as the fallback;
- `SmartProxy` is always tried last, whatever priority number it is given;
- `provider_priority={"pingnetwork": 1}` finally works on its own, with no
  proxy-seller.com account involved.

`ProxySeller.generate_resident_proxy_by_proxy_seller` returns proxy-seller
proxies only; `PingNetwork.generate_resident_proxy_by_pingnetwork` is its
pingnetwork counterpart. Both default to 10 proxies per call
(`proxy_count=10`) when called directly — `ProxyHub` passes its own
`proxy_count` (default 20) instead.

Also in 0.2.0: three more geo-check services (`country.is`, `geojs.io`,
`ip.sb`) replace `reallyfreegeoip` in `geo.get_geo_services()`.

## Migrating from the old `updated_proxy_hub.py`

- `from src.settings import settings` → build a `ProxyHubConfig(...)` once
  (from your own private settings) and pass it to `ProxyHub(config=...)`.
- The hardcoded `ADDITIONAL_DATACENTER_PROXIES` dict → pass it as
  `ProxyHubConfig(additional_datacenter_proxies={...})`.
- The hardcoded `proxy_priority` module dict (which providers run, and in
  what order) → `ProxyHubConfig(provider_priority={...})`. Default is
  `{"Proxy-Seller": 1, "pingnetwork": 2}` — SmartProxy is off by default
  (still fully implemented in the library, just excluded from the default
  dict); add an `"SmartProxy": <n>` key to turn it back on, or drop
  `"pingnetwork"` to disable that too. Same membership check for all three —
  drop any key to disable that provider at startup instead of commenting it
  out in library source.
- The hardcoded 90/10 provider split → gone as of 0.2.0, see
  "What changed in 0.2.0" below. `proxy_seller_weight` / `pingnetwork_weight`
  still exist on `ProxyHubConfig` so old call sites keep working, but nothing
  reads them any more.
- SmartProxy's hardcoded `retries=5, backoff_factor=1.5, timeout=10` →
  `smartproxy_retries` / `smartproxy_backoff_factor` / `smartproxy_timeout`
  on `ProxyHubConfig` (same defaults).
- `ProxyHub(validate_proxies=...)` and `provide_valid_proxies(...)` keep
  their original signature and behavior.
