{"id":396,"date":"2026-04-30T14:31:25","date_gmt":"2026-04-30T12:31:25","guid":{"rendered":"https:\/\/dataguide.tech\/?p=396"},"modified":"2026-04-30T14:31:26","modified_gmt":"2026-04-30T12:31:26","slug":"build-fabric-notebooks-library","status":"publish","type":"post","link":"https:\/\/dataguide.tech\/index.php\/2026\/04\/30\/build-fabric-notebooks-library\/","title":{"rendered":"Build Your Own Python Library for Microsoft Fabric Notebooks"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">When you&#8217;ve got more than one data engineer building things in Microsoft Fabric, you&#8217;ve probably hit the same little annoyance I did: everyone is quietly rewriting the same helper functions. Same string concat. Same date parser. Same five-line utility nobody can find when they actually need it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are a few ways to tackle this &#8211; sharing notebooks, dropping things into a &#8220;shared tools&#8221; workspace, or pinning best practices into team docs. They all sort of work. But honestly, the cleanest way I&#8217;ve found is to package your code into a proper Python library and install it through your custom Environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This post builds on top of my previous one: <a href=\"https:\/\/dataguide.tech\/index.php\/2026\/02\/24\/custom-environment-whats-that-what-is-the-reason\/\">Custom Environment &#8211; what&#8217;s that, what is the reason<\/a>. If you haven&#8217;t read that yet, give it a quick look first &#8211; I&#8217;ll skip over the Environment basics here and focus only on the library part.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">How It Works in Fabric<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Quick mental model before we touch any code: you build your own Python package, compile it into a <code>.whl<\/code> (wheel) file, and upload that wheel to your Fabric Environment as a custom library. Any notebook that uses that Environment gets your code as a normal import &#8211; no <code>pip install<\/code> cells, no copy-pasting helpers between notebooks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For this post I built a tiny library that just concatenates strings. Nothing exciting on its own, but the structure scales &#8211; once you&#8217;ve got the wheel pipeline working, you can drop in date helpers, file utilities, ingestion patterns, whatever your team keeps reinventing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s what it looks like once it&#8217;s uploaded into the Environment:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/Pasted-image-20260429225546.png\" alt=\"Pasted image 20260429225546.png\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And here&#8217;s the same library being imported and used in a notebook:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/Pasted-image-20260429225942-scaled.png\" alt=\"Pasted image 20260429225942.png\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Clean. Reusable. Your team stops duplicating logic across the tenant.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Ok, now the actual build.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Setting Up the Project Structure<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">I&#8217;m using VS Code for this. Any Python-friendly editor works, but the screenshots will be from VS Code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The folder layout I use for a small library:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#252937;color:#969dc4\">Python<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#a6accd;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>dataguide_demolibrary\/\n\u251c\u2500\u2500 dataguide_demolibrary\/\n\u2502   \u251c\u2500\u2500 __init__.py          \u2190 package front door\n\u2502   \u251c\u2500\u2500 stringtools.py       \u2190 string functions (one of many modules)\n\u2502   \u251c\u2500\u2500 datetools.py         \u2190 future: date helpers\n\u2502   \u251c\u2500\u2500 filetools.py         \u2190 future: file helpers\n\u2502   \u2514\u2500\u2500 ...                  \u2190 keep adding modules here\n\u251c\u2500\u2500 pyproject.toml\n\u2514\u2500\u2500 README.md\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki poimandres\" style=\"background-color: #1b1e28\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #A6ACCD\">dataguide_demolibrary<\/span><span style=\"color: #91B4D5\">\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u251c\u2500\u2500 dataguide_demolibrary<\/span><span style=\"color: #91B4D5\">\/<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u2502   \u251c\u2500\u2500 __init__.py          \u2190 package front door<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u2502   \u251c\u2500\u2500 stringtools.py       \u2190 string functions (one of many modules)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u2502   \u251c\u2500\u2500 datetools.py         \u2190 future: date helpers<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u2502   \u251c\u2500\u2500 filetools.py         \u2190 future: file helpers<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u2502   \u2514\u2500\u2500 ...                  \u2190 keep adding modules here<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u251c\u2500\u2500 pyproject.toml<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">\u2514\u2500\u2500 README.md<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">What each piece is doing:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>dataguide_demolibrary\/__init__.py<\/code> &#8211; the front door of the package. Python looks here first when someone imports the library.<\/li>\n\n\n\n<li><code>dataguide_demolibrary\/stringtools.py<\/code> &#8211; the actual logic lives here. You don&#8217;t strictly need separate module files, but it pays off the moment your library grows past a couple of functions.<\/li>\n\n\n\n<li><code>pyproject.toml<\/code> &#8211; the library&#8217;s ID card. It tells <code>pip<\/code> what this thing is, how to build it, and what it needs to run.<\/li>\n\n\n\n<li><code>README.md<\/code> &#8211; short doc covering what the library does and how to install\/use it.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">In VS Code I just create the same structure manually:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/Pasted-image-20260429215523-scaled.png\" alt=\"Pasted image 20260429215523.png\"\/><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\">Writing the Code<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s start with the heart of the library &#8211; <code>stringtools.py<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#252937;color:#969dc4\">Python<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#a6accd;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\"\"\"String concatenation helpers.\"\"\"\n\n\ndef concat(*args: str, sep: str = \"\") -> str:\n    \"\"\"Concatenate strings without a separator.\n\n    >>> concat(\"hello\", \"world\")\n    'helloworld'\n    \"\"\"\n    return sep.join(args)\n\n\ndef concat_sep(*args: str, sep: str = \"_\") -> str:\n    \"\"\"Concatenate strings with a separator (default: underscore).\n\n    >>> concat_sep(\"hello\", \"world\")\n    'hello_world'\n    >>> concat_sep(\"a\", \"b\", \"c\", sep=\"-\")\n    'a-b-c'\n    \"\"\"\n    return sep.join(args)\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki poimandres\" style=\"background-color: #1b1e28\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><span style=\"color: #5DE4C7\">String concatenation helpers.<\/span><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #91B4D5\">def<\/span><span style=\"color: #A6ACCD\"> <\/span><span style=\"color: #ADD7FF\">concat<\/span><span style=\"color: #A6ACCD\">(<\/span><span style=\"color: #91B4D5\">*<\/span><span style=\"color: #E4F0FB\">args<\/span><span style=\"color: #A6ACCD\">: <\/span><span style=\"color: #A6ACCDC0\">str<\/span><span style=\"color: #A6ACCD\">, <\/span><span style=\"color: #E4F0FB\">sep<\/span><span style=\"color: #A6ACCD\">: <\/span><span style=\"color: #A6ACCDC0\">str<\/span><span style=\"color: #A6ACCD\"> <\/span><span style=\"color: #91B4D5\">=<\/span><span style=\"color: #A6ACCD\"> <\/span><span style=\"color: #A6ACCD\">&quot;&quot;<\/span><span style=\"color: #A6ACCD\">) -&gt; <\/span><span style=\"color: #A6ACCDC0\">str<\/span><span style=\"color: #A6ACCD\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">    <\/span><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><span style=\"color: #5DE4C7\">Concatenate strings without a separator.<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    <\/span><span style=\"color: #5DE4C7C0\">&gt;&gt;&gt; <\/span><span style=\"color: #5DE4C7\">concat(&quot;hello&quot;, &quot;world&quot;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    &#39;helloworld&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    <\/span><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">    <\/span><span style=\"color: #5DE4C7C0\">return<\/span><span style=\"color: #A6ACCD\"> sep.join(args)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #91B4D5\">def<\/span><span style=\"color: #A6ACCD\"> <\/span><span style=\"color: #ADD7FF\">concat_sep<\/span><span style=\"color: #A6ACCD\">(<\/span><span style=\"color: #91B4D5\">*<\/span><span style=\"color: #E4F0FB\">args<\/span><span style=\"color: #A6ACCD\">: <\/span><span style=\"color: #A6ACCDC0\">str<\/span><span style=\"color: #A6ACCD\">, <\/span><span style=\"color: #E4F0FB\">sep<\/span><span style=\"color: #A6ACCD\">: <\/span><span style=\"color: #A6ACCDC0\">str<\/span><span style=\"color: #A6ACCD\"> <\/span><span style=\"color: #91B4D5\">=<\/span><span style=\"color: #A6ACCD\"> <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">_<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #A6ACCD\">) -&gt; <\/span><span style=\"color: #A6ACCDC0\">str<\/span><span style=\"color: #A6ACCD\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">    <\/span><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><span style=\"color: #5DE4C7\">Concatenate strings with a separator (default: underscore).<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    <\/span><span style=\"color: #5DE4C7C0\">&gt;&gt;&gt; <\/span><span style=\"color: #5DE4C7\">concat_sep(&quot;hello&quot;, &quot;world&quot;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    &#39;hello_world&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    <\/span><span style=\"color: #5DE4C7C0\">&gt;&gt;&gt; <\/span><span style=\"color: #5DE4C7\">concat_sep(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, sep=&quot;-&quot;)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    &#39;a-b-c&#39;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">    <\/span><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">    <\/span><span style=\"color: #5DE4C7C0\">return<\/span><span style=\"color: #A6ACCD\"> sep.join(args)<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Two functions, doctests in the docstrings, type hints &#8211; nothing fancy, but it gives you a feel for what a &#8220;real&#8221; library looks like.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next, <code>__init__.py<\/code>. This is what makes the package importable and exposes the functions you want available at the top level:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#252937;color:#969dc4\">Python<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#a6accd;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>\"\"\"dataguide_demolibrary - personal utility toolkit by \u0141ukasz.\"\"\"\n\n__version__ = \"0.1.0\"\n\nfrom dataguide_demolibrary.stringtools import concat, concat_sep\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki poimandres\" style=\"background-color: #1b1e28\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><span style=\"color: #5DE4C7\">dataguide_demolibrary - personal utility toolkit by \u0141ukasz.<\/span><span style=\"color: #A6ACCD\">&quot;&quot;&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">__version__ <\/span><span style=\"color: #91B4D5\">=<\/span><span style=\"color: #A6ACCD\"> <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">0.1.0<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">from<\/span><span style=\"color: #A6ACCD\"> dataguide_demolibrary.stringtools <\/span><span style=\"color: #5DE4C7\">import<\/span><span style=\"color: #A6ACCD\"> concat, concat_sep<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Then <code>pyproject.toml<\/code> &#8211; the build configuration:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(1 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#252937;color:#969dc4\">TOML<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#a6accd;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>&#91;build-system&#93;\nrequires = &#91;\"setuptools>=68.0\", \"wheel\"&#93;\nbuild-backend = \"setuptools.build_meta\"\n\n&#91;project&#93;\nname = \"dataguide-demolibrary\"\nversion = \"0.1.0\"\ndescription = \"Personal utility toolkit - string, date, and file helpers.\"\nrequires-python = \">=3.10\"<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki poimandres\" style=\"background-color: #1b1e28\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #A6ACCD\">&#91;<\/span><span style=\"color: #91B4D5\">build-system<\/span><span style=\"color: #A6ACCD\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #E4F0FB\">requires<\/span><span style=\"color: #A6ACCD\"> = &#91;<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">setuptools&gt;=68.0<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #A6ACCD\">, <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">wheel<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #A6ACCD\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #E4F0FB\">build-backend<\/span><span style=\"color: #A6ACCD\"> = <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">setuptools.build_meta<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">&#91;<\/span><span style=\"color: #91B4D5\">project<\/span><span style=\"color: #A6ACCD\">&#93;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #E4F0FB\">name<\/span><span style=\"color: #A6ACCD\"> = <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">dataguide-demolibrary<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #E4F0FB\">version<\/span><span style=\"color: #A6ACCD\"> = <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">0.1.0<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #E4F0FB\">description<\/span><span style=\"color: #A6ACCD\"> = <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">Personal utility toolkit - string, date, and file helpers.<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #E4F0FB\">requires-python<\/span><span style=\"color: #A6ACCD\"> = <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">&gt;=3.10<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">And finally a minimal <code>README.md<\/code>:<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#a6accd;--cbp-line-number-width:calc(2 * 0.6 * .875rem);line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#252937;color:#969dc4\">Python<\/span><span role=\"button\" tabindex=\"0\" style=\"color:#a6accd;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly># dataguide-demolibrary\n\nPersonal utility toolkit.\n\n## Install\n\npip install -e .\n\n## Usage\n\nfrom dataguide_demolibrary.stringtools import concat, concat_sep\n\nconcat(\"hello\", \"world\")            # \"helloworld\"\nconcat_sep(\"hello\", \"world\")        # \"hello_world\"\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki poimandres\" style=\"background-color: #1b1e28\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #767C9DB0; font-style: italic\"># dataguide-demolibrary<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">Personal utility toolkit.<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #767C9DB0; font-style: italic\">## Install<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">pip install <\/span><span style=\"color: #91B4D5\">-<\/span><span style=\"color: #A6ACCD\">e .<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #767C9DB0; font-style: italic\">## Usage<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #5DE4C7\">from<\/span><span style=\"color: #A6ACCD\"> dataguide_demolibrary.stringtools <\/span><span style=\"color: #5DE4C7\">import<\/span><span style=\"color: #A6ACCD\"> concat, concat_sep<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">concat(<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">hello<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #A6ACCD\">, <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">world<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #A6ACCD\">)            <\/span><span style=\"color: #767C9DB0; font-style: italic\"># &quot;helloworld&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #A6ACCD\">concat_sep(<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">hello<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #A6ACCD\">, <\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #5DE4C7\">world<\/span><span style=\"color: #A6ACCD\">&quot;<\/span><span style=\"color: #A6ACCD\">)        <\/span><span style=\"color: #767C9DB0; font-style: italic\"># &quot;hello_world&quot;<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s the whole project. Four files.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Building the Wheel<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Save everything first. Then open the integrated terminal in VS Code (<code>Terminal \u2192 New Terminal<\/code> if it isn&#8217;t already open):<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/Pasted-image-20260429221634.png\" alt=\"Pasted image 20260429221634.png\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Install the <code>build<\/code> package:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Windows: <code>pip install build<\/code><\/li>\n\n\n\n<li>Mac: <code>python3 -m pip install build<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This gives you the tooling to build your library into a <code>.whl<\/code> file:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/Pasted-image-20260429222416.png\" alt=\"Pasted image 20260429222416.png\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Now build the wheel:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Windows: <code>python -m build --wheel<\/code><\/li>\n\n\n\n<li>Mac: <code>python3 -m build --wheel<\/code><\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/Pasted-image-20260429222813.png\" alt=\"Pasted image 20260429222813.png\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Heads up:<\/strong> you have to run this from the root folder of your project. If your terminal opened somewhere else, <code>cd<\/code> into it first:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/Pasted-image-20260429223002.png\" alt=\"Pasted image 20260429223002.png\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">When the build finishes, you&#8217;ll see two new folders:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>dist\/<\/code> &#8211; your <code>.whl<\/code> file lives here. This is what you&#8217;ll upload to Fabric.<\/li>\n\n\n\n<li><code>dataguide_demolibrary.egg-info\/<\/code> &#8211; metadata setuptools generates during the build (package name, version, dependencies, file list). Python uses it internally to track what&#8217;s installed.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Quick note: both folders are build artifacts, so add them to <code>.gitignore<\/code>. No reason to commit them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The full code is also on my repo if you&#8217;d rather copy and adapt: <a href=\"https:\/\/github.com\/LukaszLubinaDataGuide\/DataGuide-Blog\/tree\/main\/dataguide_demolibrary\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Wrapping Up<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">That&#8217;s the whole flow. Folder structure, four files, one build command, one <code>.whl<\/code>. From here, follow the steps in <a href=\"https:\/\/dataguide.tech\/index.php\/2026\/02\/24\/custom-environment-whats-that-what-is-the-reason\/\">Custom Environment &#8211; what&#8217;s that, what is the reason<\/a> to upload the wheel as a custom library, share it across your team, and stop rewriting helpers every other notebook.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Quick recap:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Standard Python package layout with <code>__init__.py<\/code>, your modules, <code>pyproject.toml<\/code>, and a README<\/li>\n\n\n\n<li><code>python -m build --wheel<\/code> (or <code>python3 -m build --wheel<\/code> on Mac) compiles the <code>.whl<\/code><\/li>\n\n\n\n<li>The wheel goes into your Fabric Environment under custom libraries<\/li>\n\n\n\n<li>Every connected notebook gets the helpers as a normal import<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Have you already built something like this for your team? Curious what kinds of helpers you&#8217;re packaging! I&#8217;m preparing one more post on how to deploy it and maintain in Fabric environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you&#8217;ve got more than one data engineer building things in Microsoft Fabric, you&#8217;ve probably hit the same little annoyance I did: everyone is quietly rewriting the same helper functions. Same string concat. Same date parser. Same five-line utility nobody can find when they actually need it. There are a few ways to tackle this&#8230;<\/p>\n","protected":false},"author":1,"featured_media":399,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_kadence_starter_templates_imported_post":false,"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[9],"tags":[],"class_list":["post-396","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microsoft-fabric"],"jetpack_featured_media_url":"https:\/\/dataguide.tech\/wp-content\/uploads\/2026\/04\/image.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/posts\/396","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/comments?post=396"}],"version-history":[{"count":2,"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/posts\/396\/revisions"}],"predecessor-version":[{"id":398,"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/posts\/396\/revisions\/398"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/media\/399"}],"wp:attachment":[{"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/media?parent=396"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/categories?post=396"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dataguide.tech\/index.php\/wp-json\/wp\/v2\/tags?post=396"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}