Metadata-Version: 2.4
Name: nano-wait
Version: 7.2.0
Summary: Adaptive waiting and execution engine — replaces time.sleep() with system-aware, predictable waiting.
Author: Luiz Filipe Seabra de Marco
Author-email: luizfilipeseabra@icloud.com
License: MIT
Keywords: automation,adaptive wait,smart wait,execution engine,system-aware,deterministic automation,rpa,testing,selenium,playwright,performance,psutil,sleep replacement,polling,retry
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Utilities
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: psutil
Provides-Extra: wifi
Requires-Dist: pywifi; extra == "wifi"
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-mock; extra == "dev"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# NanoWait 7.2

> Esperas previsíveis e retries resilientes para automação Python.

O **NanoWait** reúne espera adaptativa, polling de condições e execução com retentativas em uma API pequena. A versão 7.2 acrescenta backoff exponencial, jitter e limite de intervalo ao executor `execute()`. Esses recursos reduzem rajadas de requisições quando uma API, conexão ou serviço externo oscila.

## Instalação

```bash
pip install nano-wait
```

Para desenvolvimento:

```bash
pip install nano-wait[dev]
```

O suporte opcional à leitura de sinal Wi-Fi continua disponível em plataformas compatíveis:

```bash
pip install nano-wait[wifi]
```

## Uso rápido

```python
from nano_wait import wait, wait_until

wait(2)                         # nunca fica abaixo de 2 segundos
wait(2, smart=True)             # pode ser menor quando for apenas uma cortesia
wait(lambda: page.is_loaded(), timeout=10)
wait_until(
    lambda: api_is_ready(),
    timeout=15,
    msg="A API não ficou pronta",
)
```

## Retry para rede instável

Use `execute()` quando uma operação pode falhar temporariamente. Por padrão, o intervalo cresce após cada falha, recebe uma pequena variação aleatória e não ultrapassa `max_interval`.

```python
import requests
from nano_wait import execute

result = execute(
    lambda: requests.get(url, timeout=3).json(),
    timeout=30,
    interval=0.5,
    backoff=2.0,
    max_interval=8.0,
    jitter=0.20,
    max_attempts=8,
    expected_exceptions=(requests.RequestException,),
)

if result.success:
    payload = result.result
else:
    result.raise_if_failed()
```

A sequência de espera do exemplo cresce aproximadamente como `0.5s`, `1s`, `2s`, `4s` e `8s`. O jitter evita que várias instâncias que falharam juntas repitam simultaneamente. O timeout é total e inclui a execução da função e os intervalos entre tentativas.

### Parâmetros de `execute`

| Parâmetro | Padrão | Finalidade |
| --- | --- | --- |
| `fn` | — | Função sem argumentos a executar. |
| `timeout` | `10.0` | Tempo total máximo em segundos. |
| `interval` | `0.2` | Intervalo inicial entre tentativas. |
| `backoff` | `2.0` | Multiplicador do intervalo a cada falha; deve ser `>= 1`. |
| `max_interval` | `30.0` | Teto do intervalo calculado. |
| `jitter` | `0.1` | Variação aleatória entre `0` e o percentual informado. |
| `max_attempts` | `None` | Limite opcional de tentativas. |
| `expected_exceptions` | `(Exception,)` | Exceções transitórias que podem ser capturadas. |
| `on_error` | `None` | Callback chamado como `on_error(exception, attempt)`. |
| `profile` | `None` | Perfil NanoWait usado durante a espera. |
| `smart` | `True` | Adapta o intervalo ao estado do sistema. |

Retornos truthy e o valor `0` representam sucesso. Outros retornos falsy geram nova tentativa. Exceções que não pertençam a `expected_exceptions` não são escondidas.

## Espera síncrona

```python
from nano_wait import wait

wait(1.5)
wait(1.5, speed="fast")
wait(1.5, profile="safe")
report = wait(1.5, explain=True)
```

No modo padrão (`smart=False`), `wait(t)` preserva um piso real de `t` segundos. O sistema pode aumentar a espera quando estiver sobrecarregado. No modo `smart=True`, a espera pode ser reduzida quando o sistema estiver saudável.

## Espera assíncrona

```python
import asyncio
from nano_wait import wait_async

async def main():
    await wait_async(1, smart=True)
    await wait_async(lambda: check_ready(), timeout=10)

asyncio.run(main())
```

A função assíncrona usa `asyncio.sleep()` e executa condições síncronas em uma thread para não bloquear o event loop.

## Polling e timeout

```python
from nano_wait import wait_until, WaitTimeoutError

try:
    wait_until(
        lambda: driver.title == "Home",
        timeout=15,
        msg="A página Home não carregou",
    )
except WaitTimeoutError as error:
    print(error)
```

`wait(condition)` retorna `True` quando a condição é satisfeita e `False` quando o timeout termina. Com `raise_on_timeout=True`, ele lança `WaitTimeoutError`.

## Decorator de retry

O decorator usa o mesmo motor resiliente de `execute()`.

```python
from nano_wait import retry

@retry(
    timeout=30,
    interval=0.5,
    backoff=2,
    max_attempts=6,
    max_interval=10,
    jitter=0.15,
)
def fetch_data():
    return client.fetch()

result = fetch_data()
if result.success:
    print(result.result)
```

O decorator retorna `ExecutionResult`, permitindo consultar `success`, `result`, `attempts`, `duration` e `error`.

## Perfis

| Perfil | Uso recomendado |
| --- | --- |
| `ci` | Pipelines rápidos e execução contínua. |
| `testing` | Testes locais e QA. |
| `default` | Uso geral. |
| `rpa` | Automação de interfaces lentas. |
| `turbo` | Cortesia mínima entre ações. |
| `safe` | Hardware fraco, serviços lentos e conexões frágeis. |

```python
wait(2, profile="safe")
execute(fetch_data, profile="safe", timeout=30)
```

## Utilitários de rede

```python
from nano_wait import has_internet

if has_internet(timeout=1):
    execute(fetch_data, timeout=20)
else:
    wait(2, profile="safe")
```

`has_internet()` faz uma tentativa simples de conexão TCP. Ela é um diagnóstico pontual, não uma garantia de que uma API específica esteja disponível. Para a operação real, prefira `execute()` com `expected_exceptions` restrito às exceções de rede da biblioteca cliente.

## Aprendizado e telemetria

O NanoWait mantém um ajuste de aprendizado por perfil em `~/.nano_wait_learning.json`. Esse ajuste influencia esperas adaptativas, mas não remove o piso de `wait(t)` no modo padrão. Telemetria e explicações podem ser ativadas pelas opções da API.

## Migração da versão 7.1

Nenhuma chamada existente precisa ser alterada. O comportamento anterior de `execute()` continua disponível com `interval`, `timeout`, `max_attempts`, `on_error` e `expected_exceptions`. Para aproveitar a melhoria, adicione `backoff`, `max_interval` e `jitter`.

A versão também corrige um caso em que o aprendizado acumulado ou um perfil agressivo podia fazer `wait(t)` ficar abaixo do valor solicitado apesar da garantia documentada.

## Desenvolvimento e testes

```bash
pytest -q
```

A versão 7.2 inclui testes para crescimento de backoff, jitter configurável, limite de tentativas, validação de parâmetros e propagação de exceções inesperadas.

## Licença

Este projeto é distribuído sob a licença MIT. Consulte [LICENSE](LICENSE).
