Metadata-Version: 2.5
Name: protoncloud-sdk
Version: 5.1.0
Summary: Proton Cloud SDK para Python: execução de automações, ambientes, logs, parâmetros e recursos.
Project-URL: Homepage, https://protoncloud.com.br
Author: Atomic Solutions
License: Proprietary
License-File: LICENSE
Keywords: automation,proton,qa,rpa,testing
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
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: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Requires-Dist: requests>=2.31
Description-Content-Type: text/markdown

# Proton Cloud SDK (Python)

SDK Python da plataforma [Proton](https://protoncloud.com.br). A automação usa
esta biblioteca para reportar ao Proton o progresso, o status, os logs, os
parâmetros e os recursos de cada execução.

Distribuição: `protoncloud-sdk`. Import: `proton`.

```python
from proton.proton_automation import start_component, end_component, update_run_status
from proton.run_status import RunStatus
```

## Instalação

```bash
pip install protoncloud-sdk
```

ou, com [uv](https://docs.astral.sh/uv/):

```bash
uv add protoncloud-sdk
```

## Configuração

Host e token são resolvidos nesta ordem, a mesma convenção da SDK Java do Proton:

1. **Variável de ambiente**: `PROTON_HOST`, `PROTON_TOKEN`
2. **`proton.ini`** no diretório de execução

Quando a automação roda pelo Proton Runner, ele injeta no processo o
`PROTON_HOST`, apontando para o servidor de onde a execução nasceu, e o id da
execução (`idDatasetRun`). É isso que permite o mesmo projeto rodar em qualquer
servidor sem editar arquivo.

O runner não injeta o token. Ele vem da variável `PROTON_TOKEN` da máquina do
runner ou do `proton.ini`.

O arquivo continua válido e é a única fonte quando se roda a automação fora do
runner:

```ini
[server]
hostname = https://app.protoncloud.com.br/api
token = <token>

[reports]
video_record = false
video_upload = true
```

O token pode vir com ou sem o prefixo `Bearer `; a biblioteca normaliza e nunca
o duplica.

Não versione o `proton.ini` com o token preenchido: deixe-o fora do controle de
versão e, na máquina do runner, prefira a variável `PROTON_TOKEN`.

### Fixando o servidor do projeto

Para um teste apontado a outro servidor, ou um projeto que precise ignorar o que
o runner injeta:

```ini
[server]
config_precedence = file
```

Sem isso, quando o valor injetado difere do arquivo, a biblioteca imprime uma
linha dizendo qual venceu. O valor do token nunca é impresso, porque a saída da
automação sobe como log da execução no Proton.

## Contexto da execução

| variável | origem | uso |
|---|---|---|
| `idDatasetRun` | runner | identifica a execução; sem ela a biblioteca fica inerte (`is_proton_execution()` é `False`) |
| `PROTON_HOST` | runner ou `proton.ini` | base da API |
| `PROTON_TOKEN` | variável da máquina ou `proton.ini` (o runner não injeta) | autenticação |
| `idRunProgress` | definida pela própria biblioteca em `start_component()` | componente em andamento |
| ambiente da execução | Proton, lido uma vez por execução em `start_component()` | variáveis do ambiente (`get_environment_value`); só em memória, nunca vira variável do processo |

Fora de uma execução do Proton, `is_proton_execution()` é `False` e as chamadas
viram no-op: o mesmo teste roda localmente sem falar com o servidor.

## Ambiente da execução

No Proton 5, cada execução roda num **ambiente** (Homologação, Produção...): o
escolhido no disparo ou, sem escolha, o ambiente padrão do dataset. O ambiente
tem variáveis (endereço, usuário, senha), cadastradas no Proton, e o script as lê
pelo nome:

```python
from proton.proton_automation import start_component, end_component
from proton.proton_environment import get_environment_value, get_environment_name, is_production
from proton.proton_logs import set_log

start_component()  # já lê o ambiente da execução, uma vez

url = get_environment_value("SAP_URL")
usuario = get_environment_value("SAP_USUARIO")
senha = get_environment_value("SAP_SENHA")

set_log(f"Ambiente: {get_environment_name()}")
if is_production():
    set_log("Execução em produção: sem gravar documento de teste")

end_component()
```

| função (`proton.proton_environment`) | o que faz |
|---|---|
| `get_environment_value(nome, allow_empty=False)` | valor da variável; erro se ela não existir ou estiver vazia (`allow_empty=True` aceita `""`) |
| `get_environment_variables()` | cópia de todas as variáveis; `{}` sem ambiente ou fora do Proton |
| `get_environment_name()` | nome do ambiente; `None` sem ambiente ou fora do Proton |
| `is_production()` | `True` quando o ambiente tem a marca de produção; `False` sem ambiente ou fora do Proton |
| `mask_environment_values(texto)` | o texto com os valores do ambiente trocados por `••••••` |
| `load_environment(force=False)` | lê o ambiente; o `start_component()` já chama, e `force=True` lê de novo |

O nome da variável é comparado exatamente, com maiúsculas e minúsculas. Nos
ambientes, use os **mesmos nomes** de variáveis (`SISTEMA_URL` em Homologação e em
Produção): o script lê sempre o mesmo nome, e o ambiente decide o valor. Só o que
muda de comportamento em produção usa `is_production()`.

### Uma leitura por execução

Os valores são lidos **uma vez por execução**: no `start_component()` ou, se o
script não o chamar, no primeiro acesso ao ambiente. As leituras seguintes usam o
que já está em memória, e a execução inteira usa os mesmos valores, mesmo que
alguém altere o ambiente no meio. Se o id da execução mudar no mesmo processo
(`set_id_dataset_run`), a biblioteca lê de novo.

Os valores nunca são gravados em disco, em log ou em variáveis do processo
(`os.environ` passa para processos filhos e aparece em dumps). A biblioteca
imprime uma linha só com o nome do ambiente e a quantidade de variáveis:

```
[proton] Ambiente da execução: Produção (produção), 3 variáveis
```

### Erros

As leituras levantam `ProtonEnvironmentError` (subclasse de `RuntimeError`), com
`reason`, `variable` e `environment`. A mensagem nunca traz o valor de uma
variável nem o corpo da resposta do servidor.

| `reason` | quando |
|---|---|
| `notProtonExecution` | leitura por nome fora de uma execução do Proton |
| `runWithoutEnvironment` | a execução não tem ambiente: defina o ambiente padrão do dataset ou escolha um ambiente no disparo |
| `environmentVariableNotFound` | o ambiente não tem a variável pedida |
| `emptyVariable` | a variável existe, mas está vazia (`allow_empty=True` aceita) |
| `runAlreadyFinished` | a execução já terminou: o ambiente só é entregue enquanto ela roda |
| `datasetRunNotFound` | a execução não existe na organização do token |
| `httpError` | sem acesso (HTTP 401 ou 403: confira o token e a permissão `automation.datasetRun.read`), outro status ou sem resposta |

Uma falha na leitura feita pelo `start_component()` não derruba o componente: a
automação que não usa ambiente segue normalmente, e o erro volta no primeiro
acesso ao ambiente, inclusive em `get_environment_name()` e `is_production()`,
para o script não concluir "não é produção" por causa de uma falha de rede.

### Máscara nos logs

O Proton não diz quais variáveis são segredo, então a biblioteca mascara **todos**
os valores do ambiente, trocando-os por `••••••` em tudo o que ela imprime e envia
ao log da execução (`set_log`, `set_error_log`, `set_log_from_exception`):

```python
set_log(f"url={url} senha={senha}")  # no log: url=•••••• senha=••••••
```

- Valores com **menos de 4 caracteres não são mascarados**, senão o log fica
  ilegível (um `1` ou um `sim` sumiria do texto todo). Não guarde segredo com
  menos de 4 caracteres.
- A troca vai do valor mais longo para o mais curto.
- O parâmetro de saída (`set_proton_value`) é gravado como veio: ele é escrito de
  propósito.
- `print(get_environment_variables())` mostra só os nomes, com os valores
  mascarados.
- Para os logs próprios do script, use `mask_environment_values(texto)`.

### Categoria do dataset (Proton 4)

No Proton 5 o dataset não tem categoria. `get_dataset_category()` e
`get_dataset_category_name()` estão obsoletas: emitem `DeprecationWarning` e, na
primeira chamada, uma linha `[proton]` no log; `get_dataset_category_name()`
devolve vazio. Em vez de decidir endereço, usuário e senha pela categoria, leia os
valores do ambiente:

```python
# Antes (Proton 4)
if get_dataset_category_name() == "PRD":
    url = "https://sistema.empresa.com.br"
else:
    url = "https://sistema-hml.empresa.com.br"

# Depois (Proton 5)
url = get_environment_value("SISTEMA_URL")
```

## Status da execução

```python
from proton.proton_automation import update_run_status
from proton.run_status import RunStatus

update_run_status(RunStatus.FAILED)
```

O Proton 5 aceita `RUNNING`, `PASSED` e `FAILED`. Os status do Proton 4
(`FAILED_DATA`, `FAILED_ENVIRONMENT` e `IN_PROCESS`) não existem mais: o servidor
os recusa, e a biblioteca envia `FAILED` no lugar dos dois primeiros e `RUNNING`
no lugar do último, com um `DeprecationWarning` e uma linha `[proton]` no log na
primeira vez. Para separar falha de dados de falha de ambiente, registre o
motivo no log da execução.

## Migrando de uma cópia local da pasta `proton/`

Projetos que carregam esta biblioteca como uma pasta `proton/` copiada migram em
dois passos:

1. adicione `protoncloud-sdk` às dependências;
2. **apague a pasta `proton/` do projeto.**

O segundo passo não é opcional: a pasta local tem precedência sobre o pacote
instalado, e enquanto ela existir o projeto continua executando a cópia antiga.
