# Python API

## Installation

{% content-ref url="/pages/xbHoaBtcgajPRYZQ1UoX" %}
[Soda Python Libraries](/deployment-options/soda-python-libraries.md)
{% endcontent-ref %}

## Publish a local Contract to Soda Cloud

{% hint style="warning" %}
Publishing a new version of a contract to Soda Cloud requires additional permissions in Soda Cloud.

* If you are publishing a new version for an **existing dataset**, you must have the **Managed contract** permission for that dataset.
* If you are publishing a **new dataset**, you must have the global permission **Create new datasets and data sources with Soda Library**.

Learn more about permissions in Soda Cloud [Global and Dataset Roles](/organization-and-admin-settings/global-and-dataset-roles.md)
{% endhint %}

Use `publish_contract` to publish a contract to Soda Cloud:

```python
from soda_core.contracts import publish_contract

result = publish_contract(
    contract_file_path="contract1.yaml",
    soda_cloud_file_path="path/to/soda_cloud.yml"
)
```

<table><thead><tr><th width="199.44921875">Parameter</th><th width="112.70703125">Required</th><th width="100.5234375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>contract_file_path</code></td><td>Yes</td><td>str</td><td>Path to local contract file</td></tr><tr><td><code>soda_cloud_file_path</code></td><td>yes</td><td>str</td><td>Path to Soda Cloud config file</td></tr></tbody></table>

### **Configure Logging**

To enable logging for contract operations, use:

```python
from soda_core import configure_logging

# Enable or disable verbose logging
configure_logging(verbose=True)
```

To access logs **after** a verification run:

```python
from soda_core.contracts import publish_contract

result = publish_contract(
    contract_file_path="contract1.yaml",
    soda_cloud_file_path="path/to/soda_cloud.yml"
)

result.get_logs()
```

### Publish Result Object

#### Publish Verification Session Result

Represents the overall publication session (may include multiple contracts).

**Attributes**

* `ContractPublicationResultList: list[ContractPublicationResult]` : all per-contract publication results. See [#contractpublicationresult](#contractpublicationresult "mention")

**Methods**

* `get_logs() -> list[str]` : publication logs across all contracts.
* `get_errors() -> list[str]` : publication errors across all contracts.

***

#### **ContractPublicationResult**

Immutable outcome for a **single** contract publishing.

**Attributes**

* `contract: Optional[Contract]` : See [#contract](#contract "mention")

***

#### Contract

Describes the published contract (dataset identity and source info).

**Attributes**

* `data_source_name str` : name of the data source (as configured in Soda).
* `dataset_prefix: str[]` : hierarchical prefix (e.g., db, schema).
* `dataset_name: str` : name of the dataset (table/view).
* `soda_qualified_dataset_name: str` : full qualified dataset identifier.
* `source: YamlFileContentInfo` : reference to YAML source definition. See [#yamlfilecontentinfo](#yamlfilecontentinfo "mention")
* `dataset_id: Optional[str]`: the unique identifier of the dataset (only filled in when results are sent to Soda Cloud).

#### YamlFileContentInfo

Describes the published YAML.

**Attributes**

* `source_content_str: Optional[str]` : YAML provided inline.
* `local_path: Optional[str]` : local file path to the YAML.

## Verify a Contract

{% hint style="info" %}
Soda Library can verify contracts either locally (Soda Core) or remotely (Soda Agent). The returned session result objects share a common structure, but log/diagnostics availability differs by execution context.
{% endhint %}

{% hint style="warning" %}
Publishing verification results to Soda Cloud with `publish=True` requires additional permissions in Soda Cloud.

* If you are publishing to an **existing dataset**, you must have the **Managed contract** permission for that dataset.
* If you are publishing a **new dataset**, you must have the global permission **Create new datasets and data sources with Soda Library**.

Learn more about permissions in Soda Cloud [Global and Dataset Roles](/organization-and-admin-settings/global-and-dataset-roles.md)
{% endhint %}

### With Soda Core

Use `verify_contract_locally` to run the verification using **local configuration and execution**:

```python
from soda_core.contracts import verify_contract_locally

result = verify_contract_locally(
    data_source_file_path="path/to/data_source.yml",
    contract_file_path="contract1.yaml", ## OR dataset_identifier="datasource/db/schema/dataset"
    soda_cloud_file_path="path/to/soda_cloud.yml",
    variables={"START_DATE": "2024-01-01"},
    publish=False,
)
```

<table><thead><tr><th width="199.44921875">Parameter</th><th width="236.28515625">Required</th><th width="85.89453125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>data_source_file_path</code></td><td>Yes (or <code>data_source_file_paths</code> is required)</td><td>str</td><td>Path to data source file <a data-mention href="/pages/Ovp9NbJpqBhQz07AImSa">/pages/Ovp9NbJpqBhQz07AImSa</a></td></tr><tr><td><code>data_source_file_paths</code></td><td>Yes (or <code>data_source_file_path</code> is required)</td><td>[str]</td><td><p>Paths to data source files <a data-mention href="/pages/Ovp9NbJpqBhQz07AImSa">/pages/Ovp9NbJpqBhQz07AImSa</a> .</p><p>Required when using reconciliation checks to compare with a source dataset located in another data source.</p></td></tr><tr><td><code>contract_file_path</code></td><td>Yes (or <code>dataset_identifier</code> is required)</td><td>str</td><td>Path to local contract file</td></tr><tr><td><code>dataset_identifier</code></td><td>Yes (or <code>contract_file_path</code> is required)</td><td>str</td><td>Dataset identifier to fetch contracts from Soda Cloud <a data-mention href="/pages/yB0XMIIob1nyTOjyZraz#dataset-fully-qualified-name">/pages/yB0XMIIob1nyTOjyZraz#dataset-fully-qualified-name</a></td></tr><tr><td><code>variables</code></td><td>No</td><td>dict</td><td>Variables to override in contract</td></tr><tr><td><code>publish</code></td><td>No</td><td>bool</td><td>Push results to Soda Cloud.</td></tr><tr><td><code>soda_cloud_file_path</code></td><td>No (unless publish is True)</td><td>str</td><td>Path to Soda Cloud config file</td></tr></tbody></table>

### With Soda Agent

Use `verify_contract_on_agent` to run verification **remotely via Soda Agent**.

```python
from soda_core.contracts import verify_contract_on_agent

result = verify_contract_on_agent(
    contract_file_path="path/to/contract.yaml", ## OR dataset_identifier="datasource/db/schema/dataset"
    soda_cloud_file_path="path/to/soda_cloud.yml",
    variables={"COUNTRY": "US"},
    publish=True,
)
```

<table><thead><tr><th width="199.44921875">Parameter</th><th width="207.40625">Required</th><th width="87.14453125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>contract_file_path</code></td><td>Yes (or <code>dataset_identifier</code> is required)</td><td>str</td><td>Path to local contract file</td></tr><tr><td><code>dataset_identifier</code></td><td>Yes (or <code>contract_file_path</code> is required)</td><td>str</td><td>Dataset identifier to fetch contract from Soda Cloud <a data-mention href="/pages/yB0XMIIob1nyTOjyZraz#dataset-fully-qualified-name">/pages/yB0XMIIob1nyTOjyZraz#dataset-fully-qualified-name</a></td></tr><tr><td><code>variables</code></td><td>No</td><td>dict</td><td>Variables to override in contract</td></tr><tr><td><code>publish</code></td><td>No</td><td>bool</td><td>Push results to Soda Cloud.</td></tr><tr><td><code>soda_cloud_file_path</code></td><td>Yes</td><td>str</td><td>Path to Soda Cloud config file</td></tr><tr><td><code>blocking_timeout_in_minutes</code></td><td>No</td><td>int</td><td>How long to wait for the agent to return results (default: 60 minutes)</td></tr></tbody></table>

***

### **Configure Logging**

To enable logging for contract operations, use:

```python
from soda_core import configure_logging

# Enable or disable verbose logging
configure_logging(verbose=True)
```

To access logs **after** a verification run:

```python
from soda_core.contracts import verify_contract_on_agent

result = verify_contract_on_agent(
    contract_file_path="path/to/contract.yaml", 
    soda_cloud_file_path="path/to/soda_cloud.yml",
)

result.get_logs()
```

{% hint style="warning" %}
If you call `verify_contract_locally(...)` or `verify_contract_on_agent(...)` in a loop, you should invoke `configure_logging(...)` **inside the loop before each verification call**.

The logging setup is not automatically reset between iterations, so placing `configure_logging(...)` only once outside the loop may lead to missing or inconsistent log output for subsequent runs.
{% endhint %}

### Verification Result Object

Running a verification returns a **`ContractVerificationSessionResult`** that aggregates results for one or more contracts verified in a single session. Use it to read logs and errors across contracts and to compute aggregate pass/fail counts. Each contract gets a **`ContractVerificationResult`** per-check **`CheckResult`** entries and derived counters.

***

#### Contract Verification Session Result

Represents the overall verification session (may include multiple contracts).

**Attributes available for Soda Core and Soda Agent scans**

* `contract_verification_results: list[ContractVerificationResult]` : all per-contract results. See [#contractverificationresult](#contractverificationresult "mention")
* `has_errors: bool` : true if any contract has execution errors.
* `has_excluded: bool` : true if any contract has any excluded checks.
* `is_failed: bool` : true if any contract has failed checks. Ignores execution errors.
* `is_passed: bool` : true if all contracts have no failed checks. Ignores execution errors.
* `is_warned: bool` : true if any contract has warned checks. Ignores execution errors.
* `is_ok: bool` : true if all contracts are both not failed and have no errors.

**Attributes only available for Soda Core scans**

* `number_of_checks: int` : sum across contract.
* `number_of_checks_excluded`: sum across contract.
* `number_of_checks_passed: int` : sum across contract.
* `number_of_checks_failed: int` : sum across contract.
* `started_timestamp: timestamp` : verification start timestamp
* `data_timestamp: timestamp` : Effective timestamp of the contract. In the future, It will be possible to overwrite the value for backfilling use case.
* `ended_timestamp: timestamp` : verification end timestamp

**Methods**

* `get_logs() -> list[str]` : concatenated logs from all contracts.
* `get_logs_str() -> str` : newline-joined logs.
* `get_errors() -> list[str]` / `get_errors_str() -> str` : aggregated error lines from logs.

***

#### ContractVerificationResult

Immutable outcome for a **single** contract: status, timing, measurements, and per-check results.

**Attributes available for Soda Core and Soda Agent scans**

* `contract: Contract` : See [#contract](#contract "mention")
* `status: ContractVerificationStatus` : `FAILED`, `PASSED`, `WARNED`, `ERROR`, or `UNKNOWN`. See [#contractverificationstatus](#contractverificationstatus "mention")
* `sending_results_to_soda_cloud_failed: bool` : whether publishing failed.
* `log_records: Optional[list[logging.LogRecord]]` : detailed logs.
* `has_errors: bool` : true if status is `ERROR`.
* `is_failed: bool` : true if status is `FAILED`. (Only checks, not execution errors.)
* `is_warned: bool` : true if status is `WARNED`. (Ignores execution errors.)
* `is_passed: bool` : true if status is `PASSED`. (Ignores execution errors.)
* `is_ok: bool` : not failed and not in error.
* `number_of_checks: int` / `number_of_checks_passed: int` / `number_of_checks_failed: int` : counts derived from `check_results`.

**Attributes only available for Soda Core scans**

* `data_source: DataSource` : See [#datasource](#datasource "mention")
* `data_timestamp: Optional[datetime]` : data time context (if any).
* `started_timestamp: datetime` / `ended_timestamp: datetime` : execution window.
* `measurements: list[Measurement]` — See [#measurement](#measurement "mention")
* `check_results: list[CheckResult]` — See [#checkresult](#checkresult "mention")
* `scan_id: Optional[str]`: the id of the scan (filled in when results are sent to soda-cloud)

**Methods**

* `get_logs() -> list[str]` / `get_logs_str() -> str` : pull message text from log records.
* `get_errors() -> list[str]` / `get_errors_str() -> str` : log lines at error level or higher.

***

#### CheckResult

Represents the outcome of a single check in the contract.

**Attributes**

* `check: Check` : See [#check](#check "mention")
* `outcome: CheckOutcome` : `PASSED`, `WARNED`, `FAILED`, or `NOT_EVALUATED`. See [#checkoutcome](#checkoutcome "mention")
* `threshold_value: Optional[float|int]` : threshold applied.
* `diagnostic_metric_values: Optional[dict[str, float|int|str]]` : diagnostic metrics.
* `is_passed: bool` / `is_failed: bool` / `is_not_evaluated: bool` : convenience flags.
* `outcome_emoticon: str` : Unicode for quick visual status.

**Methods**

* `log_table_row() -> dict` : compact, user-friendly log row (includes diagnostics).
* `log_table_row_diagnostics(verbose: bool=True) -> str` : formatted diagnostic string; uses `_log_console_format(...)` for short form.

***

#### CheckOutcome

`PASSED`, `WARNED`, `FAILED`, `NOT_EVALUATED`.

***

#### Measurement

Metric container captured during verification.

**Attributes**

* `metric_id: str` : unique identifier of the metric.
* `metric_name: Optional[str]` : name of the metric.
* `value: Any` : captured value of the metric.

***

#### ContractVerificationStatus

Execution status of a contract. Drives `is_failed`, `is_passed`, and `has_errors`.

**Values**

* `UNKNOWN` : status not determined.
* `FAILED` : contract executed and one or more checks failed.
* `WARNED`: contract executed and one or more checks warned.
* `PASSED` : contract executed and all checks passed.
* `ERROR` : execution error occurred.

***

#### Check

Represents the executed check definition (identity, type, threshold, etc.).

**Attributes**

* `type: str` : check type (e.g., `missing`, `row_count`).
* `name: Optional[str]` : ame of the check.
* `qualifier: Optional[str]` : string to distinguish multiple checks of same type.
* `identity: str` : unique identifier of the check, **used to correlate results in Soda Cloud**. It is **automatically generated based on the check path** in the contract.
* `column_name: Optional[str]` : column the check applies to (if applicable).
* `threshold: Optional[Threshold]` : threshold configuration for this check.
* `attributes: dict[str, Any]` : metadata attributes (for Soda Cloud, routing, etc.).
* `location: str` : where in the contract YAML the check is defined.

***

#### Threshold

Configured numeric boundaries for a check outcome.

**Attributes**

* `must_be: Optional[float|int]` : value must equal the configured number.
* `must_not_be: Optional[float|int]` : value must not equal the configured number.
* `must_be_greater_than: Optional[float|int]` : value must be strictly greater than.
* `must_be_greater_than_or_equal: Optional[float|int]` : value must be greater than or equal.
* `must_be_less_than: Optional[float|int]` : value must be strictly less than.
* `must_be_less_than_or_equal: Optional[float|int]` : value must be less than or equal.
* `must_be_between: Optional[dict]` : value must be within the specified range.
* `must_be_not_between: Optional[dict]` : value must not be within the specified range.

***

#### Contract

Describes the verified contract (dataset identity and source info).

**Attributes**

* `data_source_name str` : name of the data source (as configured in Soda).
* `dataset_prefix: str[]` : hierarchical prefix (e.g., db, schema).
* `dataset_name: str` : name of the dataset (table/view).
* `source: YamlFileContentInfo` : reference to YAML source definition. See [#yamlfilecontentinfo](#yamlfilecontentinfo "mention")
* `dataset_id: Optional[str]`: the unique identifier of the dataset (only filled in when results are sent to Soda Cloud).

***

#### YamlFileContentInfo

Describes where the YAML was loaded from.

**Attributes**

* `source_content_str: Optional[str]` : YAML provided inline.
* `local_path: Optional[str]` : local file path to the YAML.

***

#### DataSource

Represents the data source used for verification.

**Attributes**

* `name: str` : logical name of the data source.
* `type: str` : type of the data source (e.g., Postgres, Snowflake, BigQuery).

***

<br>

***

{% if (visitor.claims.plan === 'datasetStandard')%}
{% hint style="success" %}
You are **logged in to Soda** and seeing the **Free license** documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}

{% if (visitor.claims.plan === 'enterprise')%}
{% hint style="success" %}
You are **logged in to Soda** and seeing the **Team license** documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}

{% if (visitor.claims.plan === 'enterpriseUserBased')%}
{% hint style="success" %}
You are **logged in to Soda** and seeing the **Enterprise license** documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}

{% if !(visitor.claims.plan === 'enterprise' || visitor.claims.plan === 'enterpriseUserBased' || visitor.claims.plan === 'datasetStandard')%}
{% hint style="info" %}
You are **not logged in to Soda** and are viewing the default public documentation. Learn more about [Documentation access & licensing](/reference/documentation-access-and-licensing.md).
{% endhint %}
{% endif %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.soda.io/reference/python-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
