<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: viraj-sh</title>
    <description>The latest articles on DEV Community by viraj-sh (@virajsh).</description>
    <link>https://dev.to/virajsh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3534927%2F8774ab63-70c9-4b1f-b74a-6c5907b5fb5a.png</url>
      <title>DEV Community: viraj-sh</title>
      <link>https://dev.to/virajsh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/virajsh"/>
    <language>en</language>
    <item>
      <title>how to create flatpak package of python project</title>
      <dc:creator>viraj-sh</dc:creator>
      <pubDate>Sun, 25 Oct 2026 11:16:23 +0000</pubDate>
      <link>https://dev.to/virajsh/how-to-create-flatpak-package-of-python-project-104a</link>
      <guid>https://dev.to/virajsh/how-to-create-flatpak-package-of-python-project-104a</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Install required tools
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;flatpak flatpak-builder pipx appstream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flatpak &lt;span class="nb"&gt;install &lt;/span&gt;flathub org.kde.Platform//6.11 org.kde.Sdk//6.11 com.riverbankcomputing.PyQt.BaseApp//6.11 org.freedesktop.Sdk.Extension.node24//25.08
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;download pip generator&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/pip/flatpak-pip-generator.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;download and install node generator&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/flatpak/flatpak-builder-tools/archive/refs/heads/master.zip
unzip master.zip &lt;span class="s2"&gt;"flatpak-builder-tools-master/node/*"&lt;/span&gt;
pipx &lt;span class="nb"&gt;install&lt;/span&gt; ./flatpak-builder-tools-master/node/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify Python and QWebEngineView
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flatpak run &lt;span class="nt"&gt;--command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python3 org.kde.Sdk//6.11 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flatpak run &lt;span class="nt"&gt;--command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;python3 com.riverbankcomputing.PyQt.BaseApp//6.11 &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"from PyQt6.QtWebEngineWidgets import QWebEngineView; print('PyQt6 WebEngine OK')"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Packaging files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;make &lt;code&gt;packaging/flatpak dir&lt;/code&gt; in the root add the following files &lt;/p&gt;

&lt;p&gt;&lt;code&gt;io.github.user_name.project_name.desktop&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Desktop Entry]
Name=Uniclare Client
Exec=unigui
Icon=io.github.viraj_sh.UniclareClient
Terminal=false
Type=Application
Categories=Utility;
StartupWMClass=unigui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;io.github.user_name.project_name.metainfo.xml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;component&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"desktop-application"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;id&amp;gt;&lt;/span&gt;io.github.viraj_sh.uniclareclient&lt;span class="nt"&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Uniclare Client&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;View data that is hidden on the Uniclare App or Student Portal&lt;span class="nt"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;metadata_license&amp;gt;&lt;/span&gt;MIT&lt;span class="nt"&gt;&amp;lt;/metadata_license&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;project_license&amp;gt;&lt;/span&gt;MIT&lt;span class="nt"&gt;&amp;lt;/project_license&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Uniclare Client lets you view data that is hidden on the Uniclare App or Student Portal.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;launchable&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"desktop-id"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;io.github.viraj_sh.uniclareclient.desktop&lt;span class="nt"&gt;&amp;lt;/launchable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;developer&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"io.github.viraj_sh"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;viraj-sh&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/developer&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;url&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"homepage"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;https://github.com/viraj-sh/uniclare-client&lt;span class="nt"&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;content_rating&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"oars-1.1"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;releases&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;release&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"3.0.0"&lt;/span&gt; &lt;span class="na"&gt;date=&lt;/span&gt;&lt;span class="s"&gt;"2026-10-25"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/releases&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/component&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;io.github.user_name.project_name.svg&lt;/code&gt; or 512px png&lt;/p&gt;

&lt;p&gt;then to verify the metinfo.xml run this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;appstream
appstreamcli validate &lt;span class="nt"&gt;--pedantic&lt;/span&gt; packaging/flatpak/io.github.viraj_sh.UniclareClient.metainfo.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Dependencies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;now generate a requirements.txt and remove pyqt related packages do not remove qtpy its still needed remove pyqt related stuff&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv pip compile pyproject.toml &lt;span class="nt"&gt;--extra&lt;/span&gt; desktop &lt;span class="nt"&gt;-o&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-viE&lt;/span&gt; &lt;span class="s1"&gt;'^(pyqt6|pyqt6-qt6|pyqt6-sip|pyqt6-webengine|pyqt6-webengine-qt6)'&lt;/span&gt; requirements.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; requirements.clean.txt &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mv &lt;/span&gt;requirements.clean.txt requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then run this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSL_CERT_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; certifi&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# optional nixos&lt;/span&gt;

python3 flatpak-pip-generator.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--runtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'org.kde.Sdk//6.11'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--prefer-wheels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pydantic-core &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--requirements-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;requirements.txt &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; python3-deps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;move this &lt;code&gt;python3-deps.json&lt;/code&gt; into &lt;code&gt;/packaging/flatpak/*&lt;/code&gt; dir&lt;/p&gt;

&lt;p&gt;then generate the uv_build module (separate, because uv_build is a Rust/maturin sdist by default and must resolve to a manylinux wheel):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv pip &lt;span class="nb"&gt;install &lt;/span&gt;pip
python &lt;span class="nt"&gt;-m&lt;/span&gt; pip download &lt;span class="s2"&gt;"uv_build&amp;gt;=0.11.21,&amp;lt;0.12.0"&lt;/span&gt; &lt;span class="nt"&gt;--only-binary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;:all: &lt;span class="nt"&gt;--no-deps&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; /tmp/uvb
&lt;span class="nb"&gt;ls&lt;/span&gt; /tmp/uvb   &lt;span class="c"&gt;# confirm a .whl is present&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"uv_build==0.11.33"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; uvb.txt
python3 flatpak-pip-generator.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--runtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'org.kde.Sdk//6.11'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--prefer-wheels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;uv_build &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--requirements-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;uvb.txt &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; python3-uv-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;open &lt;code&gt;python3-uv-build.json&lt;/code&gt; and confirm the source URL ends with &lt;code&gt;.whl&lt;/code&gt; (not &lt;code&gt;.tar.gz&lt;/code&gt;). move &lt;code&gt;python3-uv-build.json&lt;/code&gt; into &lt;code&gt;/packaging/flatpak/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;then run this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flatpak-node-generator npm web/package-lock.json &lt;span class="nt"&gt;-o&lt;/span&gt; generated-sources.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;move this &lt;code&gt;generated-sources.json&lt;/code&gt; into &lt;code&gt;/packaging/flatpak/*/&lt;/code&gt; dir&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;now make a .yml file in /package/flatpak
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;io.github.viraj_sh.uniclare_client&lt;/span&gt;
&lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.kde.Platform&lt;/span&gt;
&lt;span class="na"&gt;runtime-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;6.11'&lt;/span&gt;
&lt;span class="na"&gt;sdk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;org.kde.Sdk&lt;/span&gt;
&lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.riverbankcomputing.PyQt.BaseApp&lt;/span&gt;
&lt;span class="na"&gt;base-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;6.11'&lt;/span&gt;
&lt;span class="na"&gt;sdk-extensions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;org.freedesktop.Sdk.Extension.node24&lt;/span&gt;
&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unigui&lt;/span&gt;

&lt;span class="na"&gt;cleanup-commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/app/cleanup-BaseApp.sh&lt;/span&gt;

&lt;span class="na"&gt;finish-args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--share=network&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--share=ipc&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--socket=wayland&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--socket=fallback-x11&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--device=dri&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--env=PYWEBVIEW_GUI=qt&lt;/span&gt;

&lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3-deps.json&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;python3-uv-build.json&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;uniclare-client&lt;/span&gt;
    &lt;span class="na"&gt;buildsystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;simple&lt;/span&gt;
    &lt;span class="na"&gt;build-options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;append-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/lib/sdk/node24/bin&lt;/span&gt;
    &lt;span class="na"&gt;build-commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ls&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cd web &amp;amp;&amp;amp; npm ci --offline --cache=$FLATPAK_BUILDER_BUILDDIR/flatpak-node/npm-cache &amp;amp;&amp;amp; npm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pip3 install --prefix=/app --no-deps --no-build-isolation .&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;install -Dm644 packaging/flatpak/io.github.viraj_sh.uniclare_client.desktop /app/share/applications/io.github.viraj_sh.uniclare_client.desktop&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;install -Dm644 packaging/flatpak/io.github.viraj_sh.uniclare_client.metainfo.xml /app/share/metainfo/io.github.viraj_sh.uniclare_client.metainfo.xml&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;install -Dm644 packaging/flatpak/io.github.viraj_sh.uniclare_client.svg /app/share/icons/hicolor/scalable/apps/io.github.viraj_sh.uniclare_client.svg&lt;/span&gt;
    &lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dir&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../..&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;generated-sources.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then run this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flatpak-builder &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="nt"&gt;--force-clean&lt;/span&gt; &lt;span class="nt"&gt;--install-deps-from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flathub build-dir io.github.viraj_sh.uniclare_client.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Build &amp;amp; Test&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;install app locally&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flatpak-builder &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="nt"&gt;--force-clean&lt;/span&gt; &lt;span class="nt"&gt;--install-deps-from&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flathub &lt;span class="nt"&gt;--install&lt;/span&gt; &lt;span class="nt"&gt;--repo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;repo build-dir io.github.viraj_sh.uniclare_client.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flatpak run io.github.viraj_sh.uniclare_client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>cli</category>
      <category>linux</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Running pywebview on NixOS with a single shell.nix</title>
      <dc:creator>viraj-sh</dc:creator>
      <pubDate>Sun, 25 Oct 2026 08:04:52 +0000</pubDate>
      <link>https://dev.to/virajsh/running-pywebview-on-nixos-with-a-single-shellnix-2dmg</link>
      <guid>https://dev.to/virajsh/running-pywebview-on-nixos-with-a-single-shellnix-2dmg</guid>
      <description>&lt;p&gt;How to run pywebview (Qt backend) on NixOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why
&lt;/h2&gt;

&lt;p&gt;pywebview's Qt backend uses prebuilt wheels (PyQt6 + QtWebEngine). On NixOS they can't find the shared libraries they expect, so the libraries have to be exposed through &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;shell.nix&lt;/code&gt; below includes everything QtWebEngine/Chromium needs, so it works on a fresh NixOS install with nothing else installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  shell.nix
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nix"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;nixpkgs&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt;
  &lt;span class="nv"&gt;runtimeLibs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kn"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c"&gt;# Base&lt;/span&gt;
    &lt;span class="nv"&gt;stdenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;lib&lt;/span&gt;
    &lt;span class="nv"&gt;zlib&lt;/span&gt;
    &lt;span class="nv"&gt;zstd&lt;/span&gt;
    &lt;span class="nv"&gt;brotli&lt;/span&gt;

    &lt;span class="c"&gt;# GL / graphics&lt;/span&gt;
    &lt;span class="nv"&gt;libGL&lt;/span&gt;
    &lt;span class="nv"&gt;libglvnd&lt;/span&gt; &lt;span class="c"&gt;# libEGL&lt;/span&gt;
    &lt;span class="nv"&gt;libgbm&lt;/span&gt;
    &lt;span class="nv"&gt;libdrm&lt;/span&gt;
    &lt;span class="nv"&gt;vulkan-loader&lt;/span&gt;

    &lt;span class="c"&gt;# Wayland / input&lt;/span&gt;
    &lt;span class="nv"&gt;wayland&lt;/span&gt;
    &lt;span class="nv"&gt;libxkbcommon&lt;/span&gt;

    &lt;span class="c"&gt;# X11&lt;/span&gt;
    &lt;span class="nv"&gt;libx11&lt;/span&gt;
    &lt;span class="nv"&gt;libxext&lt;/span&gt;
    &lt;span class="nv"&gt;libxrandr&lt;/span&gt;
    &lt;span class="nv"&gt;libxcomposite&lt;/span&gt;
    &lt;span class="nv"&gt;libxdamage&lt;/span&gt;
    &lt;span class="nv"&gt;libxfixes&lt;/span&gt;
    &lt;span class="nv"&gt;libxrender&lt;/span&gt;
    &lt;span class="nv"&gt;libxi&lt;/span&gt;
    &lt;span class="nv"&gt;libxcursor&lt;/span&gt;
    &lt;span class="nv"&gt;libxtst&lt;/span&gt;
    &lt;span class="nv"&gt;libxkbfile&lt;/span&gt;
    &lt;span class="nv"&gt;libxshmfence&lt;/span&gt;

    &lt;span class="c"&gt;# xcb&lt;/span&gt;
    &lt;span class="nv"&gt;libxcb&lt;/span&gt;
    &lt;span class="nv"&gt;libxcb-util&lt;/span&gt;
    &lt;span class="nv"&gt;libxcb-cursor&lt;/span&gt;
    &lt;span class="nv"&gt;libxcb-wm&lt;/span&gt;
    &lt;span class="nv"&gt;libxcb-image&lt;/span&gt;
    &lt;span class="nv"&gt;libxcb-keysyms&lt;/span&gt;
    &lt;span class="nv"&gt;libxcb-render-util&lt;/span&gt;

    &lt;span class="c"&gt;# GTK stack / fonts&lt;/span&gt;
    &lt;span class="nv"&gt;glib&lt;/span&gt;
    &lt;span class="nv"&gt;gtk3&lt;/span&gt;
    &lt;span class="nv"&gt;gdk-pixbuf&lt;/span&gt;
    &lt;span class="nv"&gt;pango&lt;/span&gt;
    &lt;span class="nv"&gt;cairo&lt;/span&gt;
    &lt;span class="nv"&gt;atk&lt;/span&gt;
    &lt;span class="nv"&gt;at-spi2-atk&lt;/span&gt;
    &lt;span class="nv"&gt;harfbuzz&lt;/span&gt;
    &lt;span class="nv"&gt;fontconfig&lt;/span&gt;
    &lt;span class="nv"&gt;freetype&lt;/span&gt;

    &lt;span class="c"&gt;# QtWebEngine / Chromium&lt;/span&gt;
    &lt;span class="nv"&gt;dbus&lt;/span&gt;
    &lt;span class="nv"&gt;expat&lt;/span&gt;
    &lt;span class="nv"&gt;nss&lt;/span&gt;
    &lt;span class="nv"&gt;nspr&lt;/span&gt;
    &lt;span class="nv"&gt;cups&lt;/span&gt;
    &lt;span class="nv"&gt;alsa-lib&lt;/span&gt;
    &lt;span class="nv"&gt;libpulseaudio&lt;/span&gt;
    &lt;span class="nv"&gt;krb5&lt;/span&gt;
    &lt;span class="nv"&gt;icu&lt;/span&gt;
    &lt;span class="nv"&gt;libpng&lt;/span&gt;
    &lt;span class="nv"&gt;libjpeg&lt;/span&gt;
    &lt;span class="nv"&gt;libwebp&lt;/span&gt;
    &lt;span class="nv"&gt;libxml2&lt;/span&gt;
    &lt;span class="nv"&gt;libxslt&lt;/span&gt;
    &lt;span class="nv"&gt;lcms2&lt;/span&gt;
    &lt;span class="nv"&gt;libopus&lt;/span&gt;
    &lt;span class="nv"&gt;libevent&lt;/span&gt;
    &lt;span class="nv"&gt;minizip&lt;/span&gt;
    &lt;span class="nv"&gt;snappy&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kn"&gt;in&lt;/span&gt;
&lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;mkShell&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;packages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;uv&lt;/span&gt; &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="nv"&gt;LD_LIBRARY_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;makeLibraryPath&lt;/span&gt; &lt;span class="nv"&gt;runtimeLibs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;# --pure sets this to a nonexistent file, which breaks httpx&lt;/span&gt;
  &lt;span class="nv"&gt;SSL_CERT_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;pkgs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;cacert&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/etc/ssl/certs/ca-bundle.crt"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nv"&gt;QTWEBENGINE_DISABLE_SANDBOX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;PYWEBVIEW_GUI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"qt"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the non-obvious bits do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt;: makes the libs above visible to the pip wheels&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SSL_CERT_FILE&lt;/code&gt;: only needed with &lt;code&gt;nix-shell --pure&lt;/code&gt;, otherwise httpx breaks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;QTWEBENGINE_DISABLE_SANDBOX&lt;/code&gt;: the Chromium sandbox doesn't work here, so it's disabled&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PYWEBVIEW_GUI=qt&lt;/code&gt;: forces the Qt backend&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nix-shell
uv init
uv add &lt;span class="s2"&gt;"pywebview[qt]"&lt;/span&gt;
uv run main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  main.py
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webview&lt;/span&gt;

&lt;span class="n"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_window&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;webview&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>nixos</category>
      <category>python</category>
      <category>pywebview</category>
      <category>linux</category>
    </item>
    <item>
      <title>Develop and Publish Python Packages to PyPI</title>
      <dc:creator>viraj-sh</dc:creator>
      <pubDate>Sat, 24 Oct 2026 22:20:49 +0000</pubDate>
      <link>https://dev.to/virajsh/develop-and-publish-python-packages-to-pypi-2mbn</link>
      <guid>https://dev.to/virajsh/develop-and-publish-python-packages-to-pypi-2mbn</guid>
      <description>&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pick a package name that isn't already taken on &lt;a href="https://pypi.org/project/" rel="noopener noreferrer"&gt;https://pypi.org/project/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Register an account on &lt;a href="https://pypi.org/" rel="noopener noreferrer"&gt;https://pypi.org/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://docs.astral.sh/uv/" rel="noopener noreferrer"&gt;uv&lt;/a&gt; and &lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;Python&lt;/a&gt; on your system&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Initialize the project
&lt;/h3&gt;

&lt;p&gt;Run this in the directory where you want the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init &lt;span class="nt"&gt;--package&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; project_name &lt;span class="nt"&gt;--build-backend&lt;/span&gt; uv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;code&gt;src/project_name&lt;/code&gt; package and a &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Write your code
&lt;/h3&gt;

&lt;p&gt;Start coding inside &lt;code&gt;./src/project_name&lt;/code&gt; — that's where the package source lives. All your modules go here.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Update the project metadata
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;pyproject.toml&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update description&lt;/li&gt;
&lt;li&gt;Add a license&lt;/li&gt;
&lt;li&gt;Update the author name and email&lt;/li&gt;
&lt;li&gt;Add your dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also update &lt;code&gt;README.md&lt;/code&gt; and &lt;code&gt;LICENSE&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. (Optional) Add entry points for a CLI app or MCP server
&lt;/h3&gt;

&lt;p&gt;If your app is a CLI or an MCP server, you can expose a command that gets installed on the user's system. Add an &lt;code&gt;entry.py&lt;/code&gt; under the relevant subpackage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CLI entry point&lt;/strong&gt; — &lt;code&gt;src/package_name/cli/entry.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# src/package_name/cli/entry.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;package_name.cli.main&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cli&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ModuleNotFoundError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;typer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keyring&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}:&lt;/span&gt;
            &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing CLI deps. Install: uv tool install &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;package_name[cli]&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;
    &lt;span class="nf"&gt;cli&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MCP server entry point&lt;/strong&gt; — &lt;code&gt;src/package_name/mcp_server/entry.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# src/package_name/mcp_server/entry.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;package_name.mcp_server.server&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ModuleNotFoundError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fastmcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing MCP deps. Install: uv tool install &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;package_name[mcp]&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then register the commands in &lt;code&gt;pyproject.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="k"&gt;[&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scripts&lt;/span&gt;&lt;span class="k"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;command_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"package_name.cli.entry:run"&lt;/span&gt;
&lt;span class="n"&gt;mcp_server_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"package_name.mcp_server.entry:run"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the &lt;code&gt;[cli]&lt;/code&gt; and &lt;code&gt;[mcp]&lt;/code&gt; extras used above must be defined under &lt;code&gt;[project.optional-dependencies]&lt;/code&gt; in &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. Update .gitignore and test locally
&lt;/h3&gt;

&lt;p&gt;Add any files that should not be committed (virtual environments, &lt;code&gt;dist/&lt;/code&gt;, secrets, etc.) to &lt;code&gt;.gitignore&lt;/code&gt;, then test the application locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Build the package
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a &lt;code&gt;.tar.gz&lt;/code&gt; (source distribution) and a &lt;code&gt;.whl&lt;/code&gt; (wheel) in &lt;code&gt;./dist&lt;/code&gt;. Extract the &lt;code&gt;.tar.gz&lt;/code&gt; and check its contents to make sure no unnecessary files are included.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Test the build locally
&lt;/h3&gt;

&lt;p&gt;Before publishing, install the wheel to confirm it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As a library&lt;/strong&gt; — install it into a virtual environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv pip &lt;span class="nb"&gt;install&lt;/span&gt; ./dist/package_name-x.x.x-py3-none-any.whl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;As a CLI or MCP server&lt;/strong&gt; — &lt;code&gt;uv tool install&lt;/code&gt; is meant for packages that expose a command (a CLI entry point or an MCP server entry point). Install the wheel with the relevant extra:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"package_name[cli] @ ./dist/package_name-x.x.x-py3-none-any.whl"&lt;/span&gt;
&lt;span class="c"&gt;# or&lt;/span&gt;
uv tool &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"package_name[mcp] @ ./dist/package_name-x.x.x-py3-none-any.whl"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  8. Publish to PyPI
&lt;/h3&gt;

&lt;p&gt;Log in at &lt;a href="https://pypi.org/manage/account/" rel="noopener noreferrer"&gt;https://pypi.org/manage/account/&lt;/a&gt; and create an API token.&lt;/p&gt;

&lt;p&gt;Use the token to publish:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;UV_PUBLISH_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;pypi-...
uv publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package is now live under your account, and anyone can install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;package_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; a new token can be scoped to your whole account only until the project exists. After the first upload, create a token scoped to that project and use it for future releases.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  9. Publish updates
&lt;/h3&gt;

&lt;p&gt;After making code changes:&lt;/p&gt;

&lt;p&gt;Bump the version in &lt;code&gt;pyproject.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv version &lt;span class="nt"&gt;--bump&lt;/span&gt; patch   &lt;span class="c"&gt;# or minor / major&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean old builds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; dist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Publish (with &lt;code&gt;UV_PUBLISH_TOKEN&lt;/code&gt; set):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also pass the token directly with &lt;code&gt;uv publish --token pypi-...&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; PyPI does not allow re-uploading a version that already exists, so always bump the version before publishing.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>python</category>
      <category>pypi</category>
    </item>
  </channel>
</rss>
