> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anomalyarmor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Great Expectations

> Convert a Great Expectations project into an AnomalyArmor data contract

<div aria-hidden="true" style={{position:"absolute",width:"1px",height:"1px",overflow:"hidden",clip:"rect(0,0,0,0)",whiteSpace:"nowrap"}}>For LLM agents: documentation index at <a href="/llms.txt" tabIndex={-1}>/llms.txt</a>, full text at <a href="/llms-full.txt" tabIndex={-1}>/llms-full.txt</a>. Append .md to any page URL for plain markdown.</div>
The `armor migrate-from great-expectations` command converts a Great Expectations project on disk into an [ODCS](/guides/contracts) YAML document. Pipe the output straight into `armor contract apply` to port your expectation suites into AnomalyArmor validity rules.

<Frame>
  <img src="https://mintcdn.com/anomalyarmor/C0RY1-Hrje4r-_Nv/images/diagrams/contracts-ge-migration-flow-light.svg?fit=max&auto=format&n=C0RY1-Hrje4r-_Nv&q=85&s=1ff2d403f9bc321366e0447b505c9aa5" alt="Great Expectations suites translated to ODCS YAML and applied to AnomalyArmor" className="block dark:hidden" width="980" height="472" data-path="images/diagrams/contracts-ge-migration-flow-light.svg" />

  <img src="https://mintcdn.com/anomalyarmor/C0RY1-Hrje4r-_Nv/images/diagrams/contracts-ge-migration-flow-dark.svg?fit=max&auto=format&n=C0RY1-Hrje4r-_Nv&q=85&s=2017ad9dd191847989efc281f89748a4" alt="Great Expectations suites translated to ODCS YAML and applied to AnomalyArmor" className="hidden dark:block" width="980" height="472" data-path="images/diagrams/contracts-ge-migration-flow-dark.svg" />
</Frame>

```bash theme={null}
armor migrate-from great-expectations ./great_expectations/ | armor contract apply --asset <asset-uuid> -f -
```

The adapter is file-based: it reads `great_expectations.yml` and the expectation-suite JSON files directly. You do not need the `great_expectations` pip package installed to run the migration.

## What gets mapped

### Native ODCS fields

These expectations land on the standard ODCS property surface so they round-trip through any ODCS tool, not just AnomalyArmor.

| Great Expectations                    | ODCS field                              |
| ------------------------------------- | --------------------------------------- |
| `expect_column_values_to_not_be_null` | `schema[].properties[].required = true` |
| `expect_column_values_to_be_unique`   | `schema[].properties[].unique = true`   |

### AnomalyArmor validity rules

These expectations map to validity rules under `customProperties.anomalyarmor.validity`.

| Great Expectations                              | AnomalyArmor `rule_type` | Notes                                                         |
| ----------------------------------------------- | ------------------------ | ------------------------------------------------------------- |
| `expect_column_values_to_be_in_set`             | `allowed_values`         | `value_set` → `values`                                        |
| `expect_column_values_to_match_regex`           | `regex_match`            | `regex` → `pattern`                                           |
| `expect_column_values_to_be_between`            | `range_bounds`           | `min_value` / `max_value` → `min` / `max`                     |
| `expect_column_value_lengths_to_be_between`     | `length_bounds`          | `min_value` / `max_value` → `min_length` / `max_length`       |
| `expect_column_values_to_match_strftime_format` | `format`                 | `%Y-%m-%d` → `iso_date`; `%Y-%m-%dT%H:%M:%S` → `iso_datetime` |

### Unmapped expectations

Anything not in the table above surfaces as a warning in the command summary rather than being silently dropped. The common ones that land in warnings today:

* `expect_column_pair_*` and `expect_multicolumn_*` (cross-column logic)
* `expect_column_kl_divergence_*` and other statistical distribution checks
* Custom expectations (`dbt_expectations.*`, user-defined subclasses)
* `expect_column_values_to_be_of_type` (type-system translation is its own problem)
* Table-scoped expectations like `expect_table_row_count_to_be_between` (row-count monitoring needs its own follow-up wiring)

For expectations without a native AnomalyArmor equivalent, author a custom SQL check after the migration rather than trying to force them through the validity-rule shape.

## Project shapes supported

The adapter auto-detects whether you have a legacy (pre-v1) project or a v1 project using Fluent Datasources.

* **Legacy projects.** Expectation suites live as JSON under `{project_root}/expectations/*.json`. The adapter walks that tree directly.
* **v1 Fluent Datasources projects.** The adapter reads the `fluent_datasources` block from `great_expectations.yml` to pull per-column type hints into `schema[].properties[].physicalType`. Suites still need to live under `expectations/`. If your project uses a non-default suite store (a database, S3, etc.), export the suites to disk before migrating:

  ```python theme={null}
  import great_expectations as gx
  context = gx.get_context()
  for name in context.list_expectation_suite_names():
      suite = context.get_expectation_suite(name)
      with open(f"expectations/{name}.json", "w") as f:
          f.write(suite.to_json_dict())
  ```

The adapter emits a warning with a pointer to this snippet when it detects a project shape it cannot walk via files alone.

## Suite-to-table resolution

Great Expectations organizes suites by suite name, not by table. AnomalyArmor scopes every validity rule to a `table_path`. The adapter resolves the mapping in this order:

1. `meta.anomalyarmor.table_path` inside the suite JSON (the explicit escape hatch).
2. The suite's `expectation_suite_name` field (GE's canonical source of truth for the suite's logical name).
3. The suite filename without the `.json` extension (final fallback).

If your suite names already match your target table names, you don't need to touch anything. When they don't, set the escape hatch inside the suite:

```json theme={null}
{
  "expectation_suite_name": "orders_v2_suite",
  "meta": {
    "anomalyarmor": {
      "table_path": "warehouse.public.orders"
    }
  },
  "expectations": [...]
}
```

## Worked example

Given this legacy project layout:

```
great_expectations/
├── great_expectations.yml
└── expectations/
    └── orders.json
```

...where `orders.json` contains:

```json theme={null}
{
  "expectation_suite_name": "public.orders",
  "expectations": [
    {
      "expectation_type": "expect_column_values_to_not_be_null",
      "kwargs": {"column": "order_id"}
    },
    {
      "expectation_type": "expect_column_values_to_be_unique",
      "kwargs": {"column": "order_id"}
    },
    {
      "expectation_type": "expect_column_values_to_be_in_set",
      "kwargs": {"column": "status", "value_set": ["pending", "shipped", "delivered"]}
    },
    {
      "expectation_type": "expect_column_values_to_match_regex",
      "kwargs": {"column": "email", "regex": "^[^@]+@[^@]+\\.[^@]+$"}
    }
  ]
}
```

Running:

```bash theme={null}
armor migrate-from great-expectations ./great_expectations/ --output contract.yaml
```

...produces:

```yaml theme={null}
apiVersion: v3.1.0
kind: DataContract
id: <stable UUID5 derived from project path>
name: great_expectations
version: 1.0.0
status: active
schema:
  - name: public.orders
    properties:
      - name: order_id
        required: true
        unique: true
      - name: status
      - name: email
customProperties:
  - property: anomalyarmor
    value:
      validity:
        - table_path: public.orders
          column_name: status
          rule_type: allowed_values
          rule_config:
            values: [pending, shipped, delivered]
          severity: error
          treat_null_as_valid: true
          check_interval: daily
        - table_path: public.orders
          column_name: email
          rule_type: regex_match
          rule_config:
            pattern: "^[^@]+@[^@]+\\.[^@]+$"
          severity: error
          treat_null_as_valid: true
          check_interval: daily
```

Then validate and apply:

```bash theme={null}
armor contract validate -f contract.yaml
armor contract plan --asset <asset-uuid> -f contract.yaml
armor contract apply --asset <asset-uuid> -f contract.yaml
```

Re-running the migration is safe: the command produces a deterministic `id` seeded from the project path, so re-applying the same contract will dedupe rather than create duplicates.

## Common Questions

### How do I migrate from Great Expectations to AnomalyArmor?

Run `armor migrate-from great-expectations ./great_expectations/` to translate your expectation suites into ODCS YAML, then pipe it into `armor contract apply --asset <uuid> -f -`. The adapter is file-based and reads suite JSON directly, so you don't need the `great_expectations` pip package installed on the migration host.

### Which Great Expectations expectations are supported?

`not_null` and `unique` map to native ODCS `required` / `unique`. Six more map to AnomalyArmor validity rules: `be_in_set`, `match_regex`, `be_between`, `value_lengths_between`, and `match_strftime_format`. See the full [mapping tables](#what-gets-mapped) for exact field translations.

### What happens to expectations the adapter can't map?

They surface as warnings in the CLI summary, never silent drops. Common unsupported cases are `expect_column_pair_*`, `expect_multicolumn_*`, KL-divergence / distribution checks, custom subclasses, and type checks. Re-author those as custom SQL checks after the migration rather than forcing them through the validity-rule shape.

### Does the adapter work with Great Expectations v1 Fluent Datasources?

Yes. The adapter auto-detects v1 projects and reads the `fluent_datasources` block from `great_expectations.yml` to pull per-column type hints into `physicalType`. Suites still need to live on disk under `expectations/`, so if you use a non-default store (database, S3), export them to disk first. See [Project shapes supported](#project-shapes-supported).

### How does AnomalyArmor know which table an expectation suite belongs to?

The adapter resolves the suite-to-table mapping in this order: `meta.anomalyarmor.table_path` inside the suite JSON, then the suite's `expectation_suite_name` field, then the filename. Use the `meta.anomalyarmor.table_path` escape hatch when suite names don't match your target table paths. See [Suite-to-table resolution](#suite-to-table-resolution).

### Is it safe to re-run the migration?

Yes. The command produces a deterministic contract `id` seeded from the project path, so re-applying the same contract deduplicates instead of creating duplicates. Combine with `armor contract plan` first to preview the diff before `apply`.

## See also

* [Data Contracts (ODCS export/import)](/guides/contracts)
* [Migrate from dbt](/guides/migrate-from-dbt)
