# Programmatic config

It is possible to extend and modify SnowDDL [<mark style="color:purple;">**config**</mark>](/advanced/architecture-overview/config.md) programmatically using pure Python.

A few examples of real business use cases which can be implemented with this technique:

* Get list of users dynamically from single sign-on data provider;
* Generate a view for each table in specific schemas;
* Generate masking policy for each table containing columns named "email" and "phone";
* Skip certain types of objects in DEV environment;

There are not restrictions. Any external data source and any Python package can be used.

### Implementation steps

1. Create a standard directory with [YAML config](/basic/yaml-configs.md). You may optionally fill it with YAML files.
2. Create a sub-directory with name `__custom` (starting with two underscores) in config directory.
3. Place one or more python modules (`.py` files) in `__custom` sub-directory.

During SnowDDL execution YAML configs are resolved first. After that Python modules are resolved one-by-one in alphanumeric order.

It is highly recommended to start module names with zero-padded numbers to make sure you have a precise control of resolution order, for example: `01_foo.py`, `02_bar.py`, `03_baz.py`.

### Module requirements

* Each module should have a function with name `handler`, which accepts instance of [`SnowDDLConfig`](/advanced/architecture-overview/config.md) as a single argument. This function does not return anything.
* In `handler` function you may build [<mark style="color:blue;">**blueprint**</mark>](/advanced/architecture-overview/blueprints.md) objects representing the desired state of objects in Snowflake, and use [<mark style="color:purple;">**config**</mark>](/advanced/architecture-overview/config.md) methods `.add_blueprint()` and `.remove_blueprint()` to manipulate the collection of blueprints.
* You may access existing [<mark style="color:blue;">**blueprints**</mark>](/advanced/architecture-overview/blueprints.md) using methods `.get_blueprints_by_type()` and `.get_blueprints_by_type_and_pattern()`.

### Examples

* Complete example of config with `__custom` sub-directory: <https://github.com/littleK0i/SnowDDL/tree/master/snowddl/_config/sample02_01>
* Example of Python module adding a few custom tables:

```python
from snowddl import DataType, Ident, TableBlueprint, TableColumn, SchemaObjectIdent, SnowDDLConfig


def handler(config: SnowDDLConfig):
    # Add custom tables
    for i in range(1, 5):
        bp = TableBlueprint(
            full_name=SchemaObjectIdent(config.env_prefix, "test_db", "test_schema", f"custom_table_{i}"),
            columns=[
                TableColumn(
                    name=Ident("id"),
                    type=DataType("NUMBER(38,0)"),
                ),
                TableColumn(
                    name=Ident("name"),
                    type=DataType("VARCHAR(255)"),
                ),
            ],
            is_transient=True,
            comment="This table was created programmatically",
        )

        config.add_blueprint(bp)
```

* Example of Python module which scans current config for custom tables and generates a consolidated view dynamically:

```python
from snowddl import SchemaObjectIdent, SnowDDLConfig, TableBlueprint, ViewBlueprint


def handler(config: SnowDDLConfig):
    # Add view combining all custom tables
    parts = []

    for full_name, bp in config.get_blueprints_by_type_and_pattern(TableBlueprint, "test_db.test_schema.custom_table_*").items():
        parts.append(f"SELECT id, name FROM {full_name}")

    bp = ViewBlueprint(
        full_name=SchemaObjectIdent(config.env_prefix, "test_db", "test_schema", "custom_view"),
        text="\nUNION ALL\n".join(parts),
        comment="This view was created programmatically",
    )

    config.add_blueprint(bp)
```


---

# 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.snowddl.com/advanced/programmatic-config.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.
