Skip to content

Snowflake integration#722

Merged
gee-senbong merged 33 commits intomainfrom
feat/snowflake-v2
Feb 4, 2026
Merged

Snowflake integration#722
gee-senbong merged 33 commits intomainfrom
feat/snowflake-v2

Conversation

@gee-senbong
Copy link
Collaborator

@gee-senbong gee-senbong commented Jan 3, 2026

This PR revises previous PR (#648) to add snowflake integration support.

Command to trigger the script to install Snowflake stored procedure:

python -m nixtla.scripts.snowflake_install_nixtla

@CLAassistant
Copy link

CLAassistant commented Jan 3, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ gee-senbong
❌ senbong


senbong seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 3, 2026

Experiment Results

Experiment 1: air-passengers

Description:

variable experiment
h 12
season_length 12
freq MS
level None
n_windows 1

Results:

metric timegpt-1 timegpt-1-long-horizon SeasonalNaive Naive
mae 12.6793 11.0623 47.8333 76
mape 0.027 0.0232 0.0999 0.1425
mse 213.936 199.132 2571.33 10604.2
total_time 1.5605 0.6944 0.0046 0.0036

Plot:

Experiment 2: air-passengers

Description:

variable experiment
h 24
season_length 12
freq MS
level None
n_windows 1

Results:

metric timegpt-1 timegpt-1-long-horizon SeasonalNaive Naive
mae 58.1031 58.4587 71.25 115.25
mape 0.1257 0.1267 0.1552 0.2358
mse 4040.21 4110.79 5928.17 18859.2
total_time 0.6584 0.6448 0.0037 0.0041

Plot:

Experiment 3: electricity-multiple-series

Description:

variable experiment
h 24
season_length 24
freq H
level None
n_windows 1

Results:

metric timegpt-1 timegpt-1-long-horizon SeasonalNaive Naive
mae 178.293 268.13 269.23 1331.02
mape 0.0234 0.0311 0.0304 0.1692
mse 121589 219485 213677 4.68961e+06
total_time 0.7406 1.1659 0.005 0.0045

Plot:

Experiment 4: electricity-multiple-series

Description:

variable experiment
h 168
season_length 24
freq H
level None
n_windows 1

Results:

metric timegpt-1 timegpt-1-long-horizon SeasonalNaive Naive
mae 465.497 346.972 398.956 1119.26
mape 0.062 0.0436 0.0512 0.1583
mse 835021 403760 656723 3.17316e+06
total_time 0.9005 0.6468 0.0052 0.0046

Plot:

Experiment 5: electricity-multiple-series

Description:

variable experiment
h 336
season_length 24
freq H
level None
n_windows 1

Results:

metric timegpt-1 timegpt-1-long-horizon SeasonalNaive Naive
mae 558.673 459.757 602.926 1340.95
mape 0.0697 0.0565 0.0787 0.17
mse 1.22723e+06 739114 1.61572e+06 6.04619e+06
total_time 0.8129 0.7469 0.0049 0.0044

Plot:

MOD(HASH(unique_id), :MAX_BATCHES) AS gp,
unique_id,
ds,
OBJECT_CONSTRUCT_KEEP_NULL(*) AS data_obj
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OBJECT_CONSTRUCT_KEEP_NULL is used here to handle the case when the historical exog variable has null value. Previous implementation:

(SELECT MOD(HASH(unique_id), :MAX_BATCHES) AS gp, unique_id, ds, y, object_construct(*) AS obj FROM TABLE(:INPUT_DATA)) a,


╔══════════════════════════════════════════════════════════════════════════════╗
║ 🎉 Ready to start forecasting! ║
╚══════════════════════════════════════════════════════════════════════════════╝
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sample scripts are generated to show user how to call the stored procedures using the generated sample tables.

Copy link
Collaborator

@JQGoh JQGoh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great to know that your demo video replicates the earlier behavior, a good start!

Makefile Outdated

format:
@echo "Running black formatter on staged files..."
@git diff --cached --name-only --diff-filter=ACMR | grep '\.py$$' | xargs -r uv run black No newline at end of file
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Deployment execution command like
python -m nixtla.scripts.snowflake_install_nixtla can be registered as part of Makefile command.

CREATE OR REPLACE NETWORK RULE {ds_prefix}nixtla_network_rule
MODE = EGRESS
TYPE = HOST_PORT
VALUE_LIST = ('api.nixtla.io');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please help to make this an option that user can customize the domain name, in case we want to use a value other than 'api.nixtla.io'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point

```
"""

PACKAGES = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest that the essential packages can be read from the pyproject.toml and on top of that, we add the additional snowflake required dependencies.

The objective is that if Nixtla client has newly introduced dependency, we can automatically consider them than updating this manually for snowflake integration.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly the thing that didn't work in snowflake. Snowflake running environment is extremely picky on libraries, it doesn't support many of them, so we have to carefully pick the ones. I spent the most time to figure out this list when I worked on this. But @gee-senbong feel free to try what @JQGoh suggests. Maybe it's much easier to work with now.

Makefile Outdated

format:
@echo "Running black formatter on staged files..."
@git diff --cached --name-only --diff-filter=ACMR | grep '\.py$$' | xargs -r uv run black No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should move to uv format but these two new commands are good to add.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update this to use uv format.

dependencies = [
"annotated-types",
"httpx[zstd]",
"narwhals>=2.11.0",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update this to fix the new integration test error when running in python 3.9 environment:

>       sf_df, client_df = self._execute_and_compare(
            snowflake_session,
            deployed_with_api_endpoint,
            example_dataframes,
            "evaluation_metrics",
            compare_evaluate,
        )

nixtla_tests/snowflake/test_snowflake_deployment.py:379: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
nixtla_tests/snowflake/test_snowflake_deployment.py:218: in _execute_and_compare
    client_df = comparison_fn(test_case, example_data[test_case.input_table])
nixtla_tests/snowflake/test_snowflake_deployment.py:364: in compare_evaluate
    result = evaluate(data, metrics=metrics, models=forecasters, train_df=data)
.venv/lib/python3.9/site-packages/utilsforecast/evaluation.py:314: in evaluate
    result = metric(**kwargs)
.venv/lib/python3.9/site-packages/utilsforecast/losses.py:331: in mape
    return _nw_agg_expr(
.venv/lib/python3.9/site-packages/utilsforecast/losses.py:76: in _nw_agg_expr
    nw.from_native(df)
.venv/lib/python3.9/site-packages/narwhals/dataframe.py:1519: in select
    return super().select(*exprs, **named_exprs)
.venv/lib/python3.9/site-packages/narwhals/dataframe.py:232: in select
    return self._with_compliant(self._compliant_frame.select(*compliant_exprs))
.venv/lib/python3.9/site-packages/narwhals/_pandas_like/dataframe.py:421: in select
    new_series = self._evaluate_into_exprs(*exprs)
.venv/lib/python3.9/site-packages/narwhals/_compliant/dataframe.py:360: in _evaluate_into_exprs
    return tuple(
.venv/lib/python3.9/site-packages/narwhals/_compliant/dataframe.py:361: in <genexpr>
    chain.from_iterable(self._evaluate_into_expr(expr) for expr in exprs)  # pyright: ignore[reportArgumentType]
.venv/lib/python3.9/site-packages/narwhals/_compliant/dataframe.py:375: in _evaluate_into_expr
    result = expr(self)
.venv/lib/python3.9/site-packages/narwhals/_compliant/expr.py:236: in __call__
    return self._call(df)
.venv/lib/python3.9/site-packages/narwhals/_compliant/expr.py:675: in <lambda>
    lambda df: [series.alias(name) for series in self(df)],
.venv/lib/python3.9/site-packages/narwhals/_compliant/expr.py:236: in __call__
    return self._call(df)
.venv/lib/python3.9/site-packages/narwhals/_compliant/expr.py:375: in _reuse_series_inner
    **{
.venv/lib/python3.9/site-packages/narwhals/_compliant/expr.py:376: in <dictcomp>
    name: df._evaluate_expr(value) if self._is_expr(value) else value
.venv/lib/python3.9/site-packages/narwhals/_compliant/dataframe.py:352: in _evaluate_expr
    result: Sequence[EagerSeriesT] = expr(self)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = PandasThen(depth=0, function_name=whenthen)
df = <narwhals._pandas_like.dataframe.PandasLikeDataFrame object at 0x137e37730>

    def __call__(self, df: EagerDataFrameT) -> Sequence[EagerSeriesT]:
>       return self._call(df)
E       AttributeError: 'PandasThen' object has no attribute '_call'

@review-notebook-app
Copy link

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beautiful!

Copy link
Contributor

@goodwanghan goodwanghan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have had a lot of offline discussion, and the PR reflects the design decisions based on our discussion.

@gee-senbong gee-senbong merged commit da7bbb9 into main Feb 4, 2026
17 of 18 checks passed
@gee-senbong gee-senbong deleted the feat/snowflake-v2 branch February 4, 2026 05:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants