Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snow 1761248 introduce notebook entity #2007

Open
wants to merge 30 commits into
base: main
Choose a base branch
from

Conversation

sfc-gh-pczajka
Copy link
Contributor

@sfc-gh-pczajka sfc-gh-pczajka commented Jan 20, 2025

Pre-review checklist

  • I've confirmed that instructions included in README.md are still correct after my changes in the codebase.
  • I've added or updated automated unit tests to verify correctness of my new code.
  • I've added or updated integration tests to verify correctness of my new code.
  • I've confirmed that my changes are working by executing CLI's commands manually on MacOS.
  • I've confirmed that my changes are working by executing CLI's commands manually on Windows.
  • I've confirmed that my changes are up-to-date with the target branch.
  • I've described my changes in the release notes.
  • I've described my changes in the section below.

Changes description

Introduce notebook entity and add command snow notebook deploy based on entities

@sfc-gh-pczajka sfc-gh-pczajka requested review from a team as code owners January 20, 2025 17:02

@functools.cached_property
def _connection(self) -> SnowflakeConnection:
return get_cli_context().connection
Copy link
Contributor

Choose a reason for hiding this comment

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

These two overwrite properties from parent class without any change. Are they needed?

Copy link
Contributor Author

@sfc-gh-pczajka sfc-gh-pczajka Jan 24, 2025

Choose a reason for hiding this comment

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

Nice catch!
I was basing on streamlit_entity implementation, removed

try:
self._sql_executor.execute_query(
f"DESCRIBE NOTEBOOK {self._fqn.sql_identifier}"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

The SQL here could be extracted to get_describe_sql method - would be useful, when adding more actions
Also, maybe action_describe is the way to go?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

return self._sql_executor.execute_query(queries)

def action_deploy(
self,
Copy link
Contributor

Choose a reason for hiding this comment

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

If we have action_deploy - we probably should have an action_drop

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It currently won't be used by any command - should we implement it in this PR?

Copy link
Contributor

Choose a reason for hiding this comment

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

If we introduce an entity- i think we should at least make some dummy methods to show, what is left to implement

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added placeholders

stage_path = self._notebook_file_stage_path
cli_console.step("Creating notebook")
create_str = "CREATE OR REPLACE" if replace else "CREATE"
queries = dedent(
Copy link
Contributor

Choose a reason for hiding this comment

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

Please extract to get_create_sql - will be useful for creating more actions and if notebooks will be used as native apps children

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

return get_cli_context().connection

@functools.cached_property
def _fqn(self) -> FQN:
Copy link
Contributor

Choose a reason for hiding this comment

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

You can use self.fqn as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed


class NotebookEntity(EntityBase[NotebookEntityModel]):
"""
A notebook.
Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed 😺

RELEASE-NOTES.md Outdated Show resolved Hide resolved
replace: bool = ReplaceOption(
help="Replace existing Notebook if it already exists.",
),
if_not_exists: bool = IfNotExistsOption(help="Skip if Notebook already exists."),
Copy link
Contributor

Choose a reason for hiding this comment

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

Current approach was to fail if object exists. Do we plan to add this flag to other commands as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For some reason I was sure I've seen that in streamlit; removed

**options,
) -> CommandResult:
"""Uploads a notebook to a stage and creates a notebook. If entity_id is not provided,
deploys all notebooks defined in the project definition."""
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
deploys all notebooks defined in the project definition."""
deploys all notebooks defined in the project definition."""

See how streamlit works. Also consider borrowing this helper:

streamlit: StreamlitEntityModel = get_entity_for_operation(
cli_context=cli_context,
entity_id=entity_id,
project_definition=pd,
entity_type="streamlit",
)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed, nice helper!

stage_path: Optional[str] = Field(
title="Stage directory in which the notebook file will be stored", default=None
)
notebook_file: Path = Field(title="Notebook file")
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we consider using artifact approach with notbeook_file being a pointer (similar to streamlit main file)? In this way you can upload more than one file, for example .py file with scripts or a .csv data. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, added

return False

def _upload_artifacts(self):
stage_fqn = FQN.from_stage(self._stage_path.stage)
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we have _stage.path.get_fqn()? If not wdyt about adding it?

*args,
**kwargs,
) -> str:
with cli_console.phase(f"Deploying notebook {self.fqn}"):
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider splitting this into two phases:

  1. Uploading artifacts
  2. Creating notebook

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.

3 participants