{"id":52401,"date":"2024-04-29T14:13:58","date_gmt":"2024-04-29T12:13:58","guid":{"rendered":"https:\/\/www.inovex.de\/?p=52401"},"modified":"2024-04-29T14:15:54","modified_gmt":"2024-04-29T12:15:54","slug":"exploring-snowparks-capabilities-for-python-developers-on-snowflake","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/","title":{"rendered":"Exploring Snowpark&#8217;s Capabilities for Python Developers on Snowflake"},"content":{"rendered":"<p>Ever wondered how to leverage the scalable compute power of Snowflake&#8217;s virtual warehouses to empower your data applications using your favorite programming language? In this blog post, we will take a deeper look into the Snowpark API and explore how you can efficiently build scalable Python-based data applications including third-party and custom dependencies on the Snowflake Data Cloud.<!--more--><\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_82_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#What-is-Snowpark\" >What is Snowpark?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#Connect-to-Snowflake-with-a-Snowpark-Session\" >Connect to Snowflake with a Snowpark Session<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#User-defined-functions-UDFs\" >User-defined functions (UDFs)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#Third-party-packages-with-Snowpark\" >Third-party packages with Snowpark<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#Custom-libraries-Snowpark\" >Custom libraries &amp; Snowpark<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#Conclusion\" >Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"What-is-Snowpark\"><\/span>What is Snowpark?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>First of all, before we dive too deep into technical details, I want to give you a brief overview of what Snowpark is. Snowflake\u2019s Snowpark is essentially an API that allows you to query and process data at scale on the Snowflake Data Cloud. From a client perspective, it is a library available for Java, Scala, and Python. The core abstraction of Snowpark is a tabular representation of your data called DataFrame. This allows you to interact with or operate on your data intuitively through programmatic expressions. Any transformation or operation you might apply to your data will be pushed down to the Snowflake Data Cloud where the (potentially) heavy computing is happening on a virtual warehouse providing the server-side (Java, Scala, or Python) runtime. This all happens lazily, meaning that the moment you define a DataFrame, the data is not retrieved and transformations you might apply are delayed until you explicitly call for an action. This allows Snowpark to optimize your data pipeline and reduces data transfer between your application and the Snowflake Data Cloud. Now, this all might sound quite familiar to you if you have worked with PySpark before and yes, there are many similarities but also a few differences.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Connect-to-Snowflake-with-a-Snowpark-Session\"><\/span>Connect to Snowflake with a Snowpark Session<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>So let\u2019s get started and connect to Snowflake via Snowpark. All you need is a Snowflake account with credentials for appropriate access rights. For an initial connection, the following parameters are sufficient:<\/p>\n<ul>\n<li>account-identifier<\/li>\n<li>username<\/li>\n<li>password<\/li>\n<li>role<\/li>\n<li>warehouse<\/li>\n<\/ul>\n<blockquote><p><strong><em>Note: You might be required to acknowledge Snowflake\u2019s third-party usage terms. You can do this directly in the Snowsight-UI of your Snowflake account in the admin section. Details about this can be found in the <a href=\"https:\/\/docs.snowflake.com\/en\/developer-guide\/udf\/python\/udf-python-packages\">Snowflake documentation<\/a>.<\/em><\/strong><\/p><\/blockquote>\n<p>To establish a connection to the Snowflake Data Cloud within a Python application, we initially have to create a Snowpark Session. This requires us to set up a Python environment and install the <i><span style=\"font-weight: 400;\">snowflake-snowpark-python<\/span><\/i> library. Since Snowflake partnered with Anaconda, their server-side Python runtimes use a dedicated Snowflake-Anaconda channel to detail all third-party packages available in the Snowflake Data Cloud. So to efficiently align our local Python environment with the server-side runtime and to avoid dependency conflicts, it is recommended to also use <em>conda<\/em> to manage your local Python environment. A basic yaml-specification of our conda-environment looks like this:<\/p>\n<pre class=\"lang:yaml decode:true\">name: my-conda-env\r\nchannels:\r\n  - https:\/\/repo.anaconda.com\/pkgs\/snowflake\r\ndependencies:\r\n  - python=3.10\r\n  - snowflake-snowpark-python\r\n  - ...<\/pre>\n<blockquote><p><strong><em>Note, that we explicitly define the Snowflake-Anaconda channel to install dependencies like snowflake-snowpark-python and possibly others.<\/em><\/strong><\/p><\/blockquote>\n<p>With this, we can simply create and activate our environment with the following two commands executed in a terminal:<\/p>\n<pre class=\"lang:zsh decode:true\">conda env create --file conda-env.yaml\r\nconda activate my-conda-env<\/pre>\n<p>With our Python environment ready, we are finally able to connect to Snowflake by passing a dictionary containing the necessary connection properties to the <em>Session-Builder<\/em> class.<\/p>\n<pre class=\"lang:python decode:true\">from snowflake.snowpark import Session\r\n\r\n\r\nconnection_properties = {\r\n    \"account\": &lt;account-identifier&gt;,\r\n    \"user\": &lt;username&gt;,\r\n    \"password\": &lt;password&gt;,\r\n    \"role\": &lt;role&gt;,\r\n    \"warehouse\": &lt;warehouse&gt;,\r\n    \"database\": &lt;database&gt;,        # optional\r\n    \"schema\": &lt;schema&gt;,\u00a0 \u00a0 \u00a0       # optional\r\n}\r\n\r\nsession = Session.builder.configs(connection_properties).getOrCreate()\r\nprint(session._session_info)<\/pre>\n<p>Similar to PySpark, by calling <em>getOrCreate()<\/em>, Snowpark creates the <em>Session<\/em> object connected to Snowflake. The above print statement should provide you with basic information about your session in case everything worked out.<\/p>\n<p>Once connected, you can interact with the Snowflake Data Cloud by either executing SQL statements directly \u2026<\/p>\n<pre class=\"lang:python decode:true\">session.sql(\"SELECT CURRENT_VERSION()\").show()<\/pre>\n<p>\u2026 or by leveraging the DataFrame-API to create a simple DataFrame with one column and five rows<\/p>\n<pre class=\"lang:python decode:true\">from snowflake.snowpark import types as T\r\n\r\n\r\nschema = T.StructType([T.StructField(\"id\", T.IntegerType())])\r\n\r\ndf = session.createDataFrame(\r\n    data=[[1], [2], [3], [4], [5]],\r\n    schema=schema,\r\n)\r\n\r\ndf.show()<\/pre>\n<p>Notice that <em>show()<\/em> is the actual action that triggers the lazily defined DataFrame to be created using the compute of your remote virtual warehouse.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"User-defined-functions-UDFs\"><\/span>User-defined functions (UDFs)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Now that you have connected to Snowflake and created your first DataFrame, you might have already noticed that you can apply various transformations, all provided out-of-the-box by the Snowpark API (you can find an overview <a href=\"https:\/\/docs.snowflake.com\/en\/developer-guide\/snowpark\/reference\/python\/latest\/dataframe\">here<\/a>). But what if you need to apply custom logic to your data? Similar to (Py-)Spark, Snowpark lets you create user-defined functions (UDF) to express custom logic to be applied to your data. When a UDF is called, Snowpark pushes your code to the Data Cloud and executes it remotely. So this is cool as you do not have to copy and transfer the data to where your code is, but rather upload your application code to where your data resides!<\/p>\n<pre class=\"lang:python decode:true\">import random\r\nfrom snowflake.snowpark import functions as F, types as T\r\n\r\n\r\ndef name() -&gt; str:\r\n    \"\"\"Returns a random name.\"\"\"\r\n    return random.choice([\"Jack\", \"Julia\", \"Max\"])\r\n\r\n\r\nname_udf = F.udf(\r\n    func=name,\r\n    session=session,\r\n    return_type=T.StringType(),\r\n)\r\n\r\ndf = df.withColumn(\"name\", name_udf())\r\ndf.show()<\/pre>\n<p>In the above code sample, we define a simple Python method that randomly returns a name from a predefined list. To create an UDF from this method, we simply need to register it with the <em>udf-function<\/em> provided by Snowpark and pass the method, the current session, and specify the return type of the UDF. Since our Python method returns a string, the UDF\u2019s return type is <em>StringType()<\/em>. The resulting UDF can then be applied within a <em>withColumn()<\/em>\u00a0statement. Once executed, you should be presented with an output similar to the following:<\/p>\n<pre class=\"top-set:false bottom-set:false toolbar:2 show-lang:2 nums:false nums-toggle:false show-plain:3 lang:default decode:true\">---------------------\r\n| \"ID\" | \"NAME\"     |\r\n---------------------\r\n| 5    | Moritz     |\r\n| 3    | Jack       |\r\n| 2    | Julia      |\r\n| 4    | Jack       |\r\n| 1    | Moritz     |\r\n---------------------<\/pre>\n<p>Of course, this is a rather simple example, but it shows the principles of applying custom logic to your data and serves as a good starting point for writing more complex UDFs.<\/p>\n<p>Besides UDFs, Snowflake also offers stored p<em>rocedures<\/em> as a way to execute custom logic on the Snowflake Data Cloud. From a programmatic point-of-view, you can register a stored procedure in the very same way as we did with a UDF above. But there are a few key differences between UDFs and stored procedures and it depends on what you intend to do to decide which one to use. Since we could have a whole blog post about this topic, you will find all the differences detailed in the Snowflake <a href=\"https:\/\/docs.snowflake.com\/en\/developer-guide\/stored-procedures-vs-udfs\">documentation<\/a>. The most obvious ones are<\/p>\n<ul>\n<li>a stored procedure does not need to return a value, a UDF does<\/li>\n<li>the (python-) method used for a stored procedure always has the Snowpark Session as its first input parameter<\/li>\n<li>a UDF can be called in the context of another SQL-Statement:<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true\">SELECT my_udf(col_a) FROM table;<\/pre>\n<ul>\n<li>stored procedures are called independently:<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true\">CALL my_stored_procedure(arg_1);<\/pre>\n<p>A general rule of thumb would be to choose a stored procedure if you\u2019d like to perform several administrative tasks and\/or do not need your logic to evaluate a single value. However, if you need to return a value for each row in your DataFrame (as we do in our example above) you would want to wrap your logic into a UDF.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Third-party-packages-with-Snowpark\"><\/span>Third-party packages with Snowpark<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>You might end up rather quickly in a situation where you want to use third-party Python packages to enable your UDF or the entire data application. Since your code gets executed remotely, you also need to tell Snowflake which dependencies you will want to use. Based on Snowflake&#8217;s tight Anaconda integration, you can either pass this information once globally via the Snowpark Session object or on a UDF level. The only real difference between the two options is that passing this information on a UDF level requires you to place import statements of third-party packages into the UDF itself rather than on top of the whole Python module. You can find detailed information about this in the <a href=\"https:\/\/docs.snowflake.com\/en\/developer-guide\/snowpark\/python\/creating-udfs\">official Snowflake documentation<\/a>. Since it is more convenient to pass third-party packages in use only once to the Snowpark Session rather than to each UDF, we will only look at the former.<\/p>\n<p>To make sure the remote server-side runtime has all necessary dependencies available, you can either pass a list of packages along with their versions to the built-in <em>add_packages()<\/em> method or provide the path to your <em>conda-env.yaml<\/em> file to <em>add_requirements()<\/em>.<\/p>\n<pre class=\"lang:python decode:true\">session.add_packages([\"numpy==1.26.2\"])\r\nsession.add_requirements(\"conda-env.yaml\")<\/pre>\n<p>Having Snowpark instructed to load numpy, we now can create a separate UDF called age which returns a random age using numpy\u2019s <em>randint<\/em> method. The actual registration and application of the UDF do not differ compared to the previous example.<\/p>\n<pre class=\"lang:python decode:true\">import numpy as np\r\n\r\n\r\ndef age() -&gt; int:\r\n    \"\"\"Returns a random age.\"\"\"\r\n    return np.random.randint(low=18, high=85)\r\n\r\n\r\nage_udf = F.udf(\r\n    func=age,\r\n    session=session,\r\n    return_type=T.IntegerType(),\r\n)\r\n\r\ndf = df.withColumn(\"age\", age_udf())\r\ndf.show()<\/pre>\n<p>This will add an <em>age<\/em> column to our DataFrame and will look similar to the following after execution:<\/p>\n<pre class=\"top-set:false bottom-set:false nums:false nums-toggle:false lang:default decode:true\">--------------------------\r\n| \"ID\" | \"NAME\"\u00a0 | \"AGE\" |\r\n--------------------------\r\n| 5 \u00a0 \u00a0 | Julia \u00a0 | 38 \u00a0\u00a0|\r\n| 2 \u00a0 \u00a0 | Jack\u00a0 \u00a0 | 42 \u00a0\u00a0|\r\n| 4 \u00a0 \u00a0 | Julia \u00a0 | 77 \u00a0 |\r\n| 1 \u00a0 \u00a0 | Jack\u00a0 \u00a0 | 20 \u00a0 |\r\n| 3 \u00a0 \u00a0 | Max \u00a0 \u00a0 | 31 \u00a0 |\r\n--------------------------<\/pre>\n<p>By default, you are restricted to third-party packages available on the official Snowflake-Anaconda channel. However, with a little <a href=\"https:\/\/docs.snowflake.com\/en\/developer-guide\/snowpark\/reference\/python\/1.12.1\/api\/snowflake.snowpark.Session.custom_package_usage_config\">configuration<\/a>, you can use third-party packages not available on Snowflake:<\/p>\n<pre class=\"lang:python decode:true\">session.custom_package_usage_config = {\r\n    \"enabled\": True,\r\n    \"cache_path\": \"@some\/path\/to\/a\/stage\/directory\",\r\n}\r\n\r\nsession.add_packages([\"scikit-fuzzy\"])<\/pre>\n<p>Once enabled, packages that are not available on Snowflake will be installed locally via pip using the official PyPi index! You can even speed up this process by adding a cache path to reduce latency. Although this removes any potential dependency barrier you could face, it is worth mentioning that this feature is marked as experimental by Snowflake. So you might want to use this carefully.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Custom-libraries-Snowpark\"><\/span>Custom libraries &amp; Snowpark<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>So far, we have explored how to enable your data application with the Snowpark API and showed how to add custom logic that makes use of third-party libraries via a UDF. For the simple examples above, it might be sufficient to have everything in one single Python module\/file. But in reality, you most probably want to structure your application as a package consisting of multiple modules with different purposes and import objects (methods, classes, etc.) of these modules. A simple project structure for our custom Python package could look similar to this \u2026<\/p>\n<pre class=\"top-set:false bottom-set:false nums:false nums-toggle:false lang:default decode:true\">\/my-package\r\n|--src\r\n|  |--my_package\r\n|  |  |--__init__.py\r\n|  |  |--my_module.py\r\n|--conda-env.yaml\r\n|--script.py\r\n...<\/pre>\n<p>\u2026 with our well-known <em>conda-env.yaml<\/em>, a src folder containing the source code of our custom library, and a script.py file serving as the main entry point for our sample application. Our package shall for now consist of a single module <em>my_module.py<\/em> containing the UDFs we previously created and in <em>script.py<\/em> we import the UDFs and apply them to our DataFrame.<\/p>\n<pre class=\"lang:python decode:true\">### src\/my_package\/my_module.py\r\n\r\nimport random\r\nimport numpy\r\n\r\n\r\ndef name() -&gt; str:\r\n    \"\"\"Returns a random name.\"\"\"\r\n    return random.choice([\"Jack\", \"Julia\", \"Max\"])\r\n\r\n\r\ndef age() -&gt; int:\r\n    \"\"\"Returns a random age.\"\"\"\r\n    return numpy.random.randint(low=18, high=85)\r\n\r\n\r\n\r\n### script.py\r\n\r\nfrom my_package.my_module import name, age\r\n\r\n...\r\n\r\ndf = df.withColumn(\"name\", name_udf())\r\ndf = df.withColumn(\"age\", age_udf())\r\ndf.show()<\/pre>\n<p>If you would execute <em>script.py<\/em> right now, Snowpark will greet you with the following error:<\/p>\n<pre class=\"top-set:false bottom-set:false nums:false nums-toggle:false lang:default decode:true\">ModuleNotFoundError: No module named 'my_package'<\/pre>\n<p>This is kind of what we expected as we did not provide our package to Snowflake\u2019s remote runtime. Now, in the Python ecosystem, you would usually package your source code into a <em>wheel<\/em> file which is then installable on any system your application shall be executed on. However, on Snowflake, access to the underlying hardware\/infrastructure of your virtual warehouse is not granted at all. The only option available in terms of providing files is Snowflake Stages. So to provide our custom source code, we have to upload archived source code to a Snowflake Stage and instruct Snowpark to load the archive from the Stage location.<\/p>\n<p>Open a terminal window, direct to your package root, and execute the following command to create the archive <em>my-package.zip<\/em> containing the source code within the <em>src<\/em> folder.<\/p>\n<pre class=\"lang:zsh decode:true\">cd src &amp;&amp; zip -r ..\/my-package.zip . -x '*.pyc' -x '*\/__pycache__\/*'<\/pre>\n<p>As you will likely have more than one module in your package we can keep the archive a bit more lean by excluding unnecessary files\/directories with the <em>-x<\/em>\u00a0option. This <em>zip<\/em> file is all you need to provide to Snowflake.<\/p>\n<p>Snowflake can load files from internal stages. Since a stage is a schema-level object we need to create a database and a schema before creating the actual <em>dependencies<\/em> stage:<\/p>\n<pre class=\"lang:default decode:true\">CREATE DATABASE IF NOT EXISTS demo;\r\nUSE DATABASE demo;\r\n\r\nCREATE SCHEMA IF NOT EXISTS demo;\r\nUSE SCHEMA demo;\r\n\r\nCREATE STAGE IF NOT EXISTS dependencies;<\/pre>\n<p>You can execute these SQL statements from within a SQL worksheet in the Snowsight UI or via the SnowSQL CLI \u2013 whichever is more convenient for you! With the stage created, the upload of our custom library is as simple as executing a <em>PUT<\/em> command! Remember that you can\u2019t execute the <em>PUT <\/em>command via SQL-Worksheet, you need the SnowSQL-CLI for this.<\/p>\n<pre class=\"lang:default decode:true\">PUT file:\/\/my-package.zip @dependencies AUTO_COMPRESS=False;<\/pre>\n<p>Snowflake compresses all files by default so we have to disable this feature for our package upload. You can double-check the upload by listing the contents of our dependencies stage with<\/p>\n<pre class=\"lang:default decode:true\">LS @dependencies;<\/pre>\n<p>Now that we uploaded our custom library to Snowflake, the only thing left is to instruct Snowpark to load our library. This can be done by enabling a setting on our Snowflake Session called <em>custom_package_usage_config<\/em> and providing the path to our archive to the built-in method <em>add_import()<\/em>. I\u2019 will recommend you place these statements right at the beginning of your application after initially creating the Snowflake Session to make sure that everything is set up correctly before executing any application logic.<\/p>\n<pre class=\"lang:python decode:true\">session.custom_package_usage_config = {\r\n    \"enabled\": True,\r\n    \"cache_path\": \"@dependencies\/cache\",\r\n}\r\n\r\nsession.add_import(path=\"@dependencies\/my-package.zip\")<\/pre>\n<p>Since Snowflake will load the dependencies every time we create a Snowpark-Session, we also apply a second configuration called <em>cache_path<\/em>. This is just a path pointing to a directory on our dependencies stage and enables caching to speed up the load process of our dependencies.<\/p>\n<p>So <em>script.py<\/em> now looks similar to this<\/p>\n<pre class=\"lang:python decode:true\">from snowflake.snowpark import Session, functions as F, types as T\r\nfrom my_package.my_module import name, age\r\n\r\n...\r\n\r\nsession = Session.builder.configs(connection_properties).create()\r\n\r\nsession.custom_package_usage_config = {\r\n    \"enabled\": True,\r\n    \"cache_path\": \"@dependencies\/cache\",\r\n}\r\n\r\nsession.add_import(path=\"@dependencies\/my-package.zip\")\r\n\r\nsession.add_requirements(\"conda-env.yaml\")\r\n\r\n...\r\n\r\nname_udf = F.udf(func=name, session=session, return_type=T.StringType())\r\nage_udf = F.udf(func=age, session=session, return_type=T.IntegerType())\r\n\r\ndf = df.withColumn(\"name\", name_udf())\r\ndf = df.withColumn(\"age\", age_udf())\r\ndf.show()<\/pre>\n<p>If you execute this script now once again, you will not be greeted by a <em>ModuleNotFoundError<\/em> anymore, but instead, get a sample DataFrame printed!<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Congratulations, if you have closely followed our above examples you have just implemented your first data application using the Snowpark API for Python. It is a fairly small application, but we have also seen how to apply your custom logic to your data with user-defined functions and stored procedures, as well as incorporate third-party packages via Anaconda and your own custom libraries! This broadens your possibilities when building scalable data pipelines on the Snowflake Data Cloud.<\/p>\n<p>In case data engineering is not solely your focus, Snowflake also provides <em>snowpark-ml,<\/em> a machine-learning toolbox to pre-process data, and train and deploy machine-learning models, all on the Snowflake Data Cloud!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ever wondered how to leverage the scalable compute power of Snowflake&#8217;s virtual warehouses to empower your data applications using your favorite programming language? In this blog post, we will take a deeper look into the Snowpark API and explore how you can efficiently build scalable Python-based data applications including third-party and custom dependencies on the [&hellip;]<\/p>\n","protected":false},"author":110,"featured_media":53003,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[733,385,377,1108],"service":[411,431],"coauthors":[{"id":110,"display_name":"Dominik Sch\u00fcssele","user_nicename":"dschuessele"}],"class_list":["post-52401","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-cloud-en-2","tag-data-engineering","tag-development","tag-snowflake","service-data-engineering","service-data-science"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Exploring Snowpark&#039;s Capabilities for Python Developers on Snowflake - inovex GmbH<\/title>\n<meta name=\"description\" content=\"Learn how to efficiently build scalable Python-based data applications including third-party and custom dependencies on the Snowflake Data Cloud.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Exploring Snowpark&#039;s Capabilities for Python Developers on Snowflake - inovex GmbH\" \/>\n<meta property=\"og:description\" content=\"Learn how to efficiently build scalable Python-based data applications including third-party and custom dependencies on the Snowflake Data Cloud.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2024-04-29T12:13:58+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-04-29T12:15:54+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1500\" \/>\n\t<meta property=\"og:image:height\" content=\"880\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dominik Sch\u00fcssele\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake-1024x601.png\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dominik Sch\u00fcssele\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"13\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Dominik Sch\u00fcssele\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/\"},\"author\":{\"name\":\"Dominik Sch\u00fcssele\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/person\\\/859fb8c129d1ea2d1f72a318973a9653\"},\"headline\":\"Exploring Snowpark&#8217;s Capabilities for Python Developers on Snowflake\",\"datePublished\":\"2024-04-29T12:13:58+00:00\",\"dateModified\":\"2024-04-29T12:15:54+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/\"},\"wordCount\":2150,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Blogheader-snowflake.png\",\"keywords\":[\"Cloud\",\"Data Engineering\",\"Development\",\"Snowflake\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/\",\"name\":\"Exploring Snowpark's Capabilities for Python Developers on Snowflake - inovex GmbH\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Blogheader-snowflake.png\",\"datePublished\":\"2024-04-29T12:13:58+00:00\",\"dateModified\":\"2024-04-29T12:15:54+00:00\",\"description\":\"Learn how to efficiently build scalable Python-based data applications including third-party and custom dependencies on the Snowflake Data Cloud.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Blogheader-snowflake.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/Blogheader-snowflake.png\",\"width\":1500,\"height\":880,\"caption\":\"Grafik: Ein Snowboarder f\u00e4hrt einen Berg herab, neben ihm ein Python und ein Snowflake Logo.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Exploring Snowpark&#8217;s Capabilities for Python Developers on Snowflake\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#website\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\\\/\\\/www.inovex.de\\\/wp-content\\\/uploads\\\/2021\\\/03\\\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/inovexde\",\"https:\\\/\\\/x.com\\\/inovexgmbh\",\"https:\\\/\\\/www.instagram.com\\\/inovexlife\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/inovex\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/#\\\/schema\\\/person\\\/859fb8c129d1ea2d1f72a318973a9653\",\"name\":\"Dominik Sch\u00fcssele\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/e41818a0023fced0fde19ac5e2b2fa98c4609e5407b548542173f439414f9f3c?s=96&d=retro&r=g376c65faa210416c961583d0118158b4\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/e41818a0023fced0fde19ac5e2b2fa98c4609e5407b548542173f439414f9f3c?s=96&d=retro&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/e41818a0023fced0fde19ac5e2b2fa98c4609e5407b548542173f439414f9f3c?s=96&d=retro&r=g\",\"caption\":\"Dominik Sch\u00fcssele\"},\"url\":\"https:\\\/\\\/www.inovex.de\\\/de\\\/blog\\\/author\\\/dschuessele\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Exploring Snowpark's Capabilities for Python Developers on Snowflake - inovex GmbH","description":"Learn how to efficiently build scalable Python-based data applications including third-party and custom dependencies on the Snowflake Data Cloud.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/","og_locale":"de_DE","og_type":"article","og_title":"Exploring Snowpark's Capabilities for Python Developers on Snowflake - inovex GmbH","og_description":"Learn how to efficiently build scalable Python-based data applications including third-party and custom dependencies on the Snowflake Data Cloud.","og_url":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2024-04-29T12:13:58+00:00","article_modified_time":"2024-04-29T12:15:54+00:00","og_image":[{"width":1500,"height":880,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake.png","type":"image\/png"}],"author":"Dominik Sch\u00fcssele","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake-1024x601.png","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Dominik Sch\u00fcssele","Gesch\u00e4tzte Lesezeit":"13\u00a0Minuten","Written by":"Dominik Sch\u00fcssele"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/"},"author":{"name":"Dominik Sch\u00fcssele","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/859fb8c129d1ea2d1f72a318973a9653"},"headline":"Exploring Snowpark&#8217;s Capabilities for Python Developers on Snowflake","datePublished":"2024-04-29T12:13:58+00:00","dateModified":"2024-04-29T12:15:54+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/"},"wordCount":2150,"commentCount":0,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake.png","keywords":["Cloud","Data Engineering","Development","Snowflake"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/","url":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/","name":"Exploring Snowpark's Capabilities for Python Developers on Snowflake - inovex GmbH","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake.png","datePublished":"2024-04-29T12:13:58+00:00","dateModified":"2024-04-29T12:15:54+00:00","description":"Learn how to efficiently build scalable Python-based data applications including third-party and custom dependencies on the Snowflake Data Cloud.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/Blogheader-snowflake.png","width":1500,"height":880,"caption":"Grafik: Ein Snowboarder f\u00e4hrt einen Berg herab, neben ihm ein Python und ein Snowflake Logo."},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/exploring-snowparks-capabilities-for-python-developers-on-snowflake\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Exploring Snowpark&#8217;s Capabilities for Python Developers on Snowflake"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/859fb8c129d1ea2d1f72a318973a9653","name":"Dominik Sch\u00fcssele","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/e41818a0023fced0fde19ac5e2b2fa98c4609e5407b548542173f439414f9f3c?s=96&d=retro&r=g376c65faa210416c961583d0118158b4","url":"https:\/\/secure.gravatar.com\/avatar\/e41818a0023fced0fde19ac5e2b2fa98c4609e5407b548542173f439414f9f3c?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e41818a0023fced0fde19ac5e2b2fa98c4609e5407b548542173f439414f9f3c?s=96&d=retro&r=g","caption":"Dominik Sch\u00fcssele"},"url":"https:\/\/www.inovex.de\/de\/blog\/author\/dschuessele\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/52401","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/110"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=52401"}],"version-history":[{"count":5,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/52401\/revisions"}],"predecessor-version":[{"id":53305,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/52401\/revisions\/53305"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/53003"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=52401"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=52401"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=52401"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=52401"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}