<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>danigm.net - linux</title><link>https://danigm.net/</link><description></description><lastBuildDate>Wed, 22 May 2024 00:00:00 +0200</lastBuildDate><item><title>Python 3.13 Beta 1</title><link>https://danigm.net/python313-beta1.html</link><description>&lt;p&gt;&lt;img src="/pictures/python-logo-master-v313-TM.png" width="100%" /&gt;&lt;/p&gt;
&lt;p&gt;Python &lt;a href="https://www.python.org/downloads/release/python-3130b1/"&gt;3.13 beta 1 is out&lt;/a&gt;, and I've been working on the openSUSE
Tumbleweed package to get it ready for the release.&lt;/p&gt;
&lt;h2&gt;Installing python 3.13 beta 1 in Tumbleweed&lt;/h2&gt;
&lt;p&gt;If you are adventurous enough to want to test the python 3.13 and you
are using openSUSE Tumbleweed, you can give it a try and install the
current devel package:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# zypper addrepo -p 1000 https://download.opensuse.org/repositories/devel:languages:python:Factory/openSUSE_Tumbleweed/devel:languages:python:Factory.repo&lt;/span&gt;
&lt;span class="c1"&gt;# zypper refresh&lt;/span&gt;
&lt;span class="c1"&gt;# zypper install python313&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;What's new in Python 3.13&lt;/h2&gt;
&lt;p&gt;Python interpreter is pretty stable nowadays and it doesn't change too
much to keep code compatible between versions, so if you are writing
modern Python, your code should continue working whit this new
version. But it's actively developed and new versions have cool new
functionalities.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3.13/whatsnew/3.13.html#a-better-interactive-interpreter"&gt;New and improved interactive interpreter&lt;/a&gt;, colorized prompts,
   multiline editing with history preservation, interactive help with
   &lt;code&gt;F1&lt;/code&gt;, history browsing with &lt;code&gt;F2&lt;/code&gt;, paste mode with &lt;code&gt;F3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A set of performance improvements.&lt;/li&gt;
&lt;li&gt;Removal of many deprecated modules: aifc, audioop, chunk, cgi,
   cgitb, crypt, imghdr, mailcap, msilib, nis, nntplib, ossaudiodev,
   pipes, sndhdr, spwd, sunau, telnetlib, uu, xdrlib, lib2to3.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Enabling Experimental JIT Compiler&lt;/h2&gt;
&lt;p&gt;The python 3.13 version will arrive with an &lt;a href="https://docs.python.org/3.13/whatsnew/3.13.html#experimental-jit-compiler"&gt;experimental functionality&lt;/a&gt;
to improve performance. We're building with the
&lt;code&gt;--enable-experimental-jit=yes-off&lt;/code&gt; so it's disabled by default but it
can be enabled with a virtualenv before launching:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PYTHON_JIT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python3.13
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Free-threaded CPython&lt;/h2&gt;
&lt;p&gt;The python 3.13 has another build option to disable the Global
Interpreter Lock (&lt;code&gt;--disable-gil&lt;/code&gt;), but we're not enabling it because
in this case it's not possible to keep the same behavior. Building
with &lt;code&gt;disabled-gil&lt;/code&gt; will break compatibility.&lt;/p&gt;
&lt;p&gt;In any case, maybe it's interesting to be able to provide another
version of the interpreter with the GIL disabled, for specific cases
where the performance is something critical, but that's something to
evaluate.&lt;/p&gt;
&lt;p&gt;We can think about having a &lt;code&gt;python313-nogil&lt;/code&gt; package, but it's not
something trivial to be able to have &lt;code&gt;python313&lt;/code&gt; and &lt;code&gt;python313-nogil&lt;/code&gt;
at the same time in the same system installation, so I'm not planning
to work on that for now.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Wed, 22 May 2024 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2024-05-22:/python313-beta1.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>linux</category><category>python</category></item><item><title>Where's my python code?</title><link>https://danigm.net/wheres-my-python-code.html</link><description>&lt;p&gt;&lt;img src="/pictures/python-logo-master-v3-TM.png" width="100%" /&gt;&lt;/p&gt;
&lt;p&gt;Python is a interpreted language, so the python code are just text
files with the &lt;code&gt;.py&lt;/code&gt; extension. For simple scripts it's really easy to
have your files located, but when you starts to use dependencies and
different projects with different requirements the thing starts to get
more complex.&lt;/p&gt;
&lt;h2&gt;PYTHONPATH&lt;/h2&gt;
&lt;p&gt;The Python interpreter uses a list of paths to try to locate python
modules, for example this is what you can get in a modern GNU/Linux
distribution by default:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Python&lt;/span&gt; &lt;span class="mf"&gt;3.11.7&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Dec&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="mi"&gt;2023&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;GCC&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;linux&lt;/span&gt;
&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;help&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;copyright&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;credits&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;license&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;information&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;/usr/lib64/python311.zip&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;/usr/lib64/python3.11&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;/usr/lib64/python3.11/lib-dynload&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;/usr/lib64/python3.11/site-packages&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;/usr/lib64/python3.11/_import_failed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="s1"&gt;&amp;#39;/usr/lib/python3.11/site-packages&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These are the default paths where the python modules are installed. If
you install any python module using your linux packaging tool, the
python code will be placed inside the &lt;code&gt;site-packages&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;So system installed python modules can be located in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/usr/lib/python3.11/site-packages&lt;/code&gt; for modules that are
   architecture independent (pure python, all &lt;code&gt;.py&lt;/code&gt; files)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr/lib64/python3.11/site-packages&lt;/code&gt; for modules that depends on
   the arquitecture, that's something that uses low level libraries
   and needs to build so there are some &lt;code&gt;.so&lt;/code&gt; files.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;pip&lt;/h2&gt;
&lt;p&gt;When you need a new python dependency you can try to install from your
GNU/Linux distribution using the default package manager like
&lt;code&gt;zypper&lt;/code&gt;, &lt;code&gt;dnf&lt;/code&gt; or &lt;code&gt;apt&lt;/code&gt;, and those python files will be placed in the
system paths that you can see above.&lt;/p&gt;
&lt;p&gt;But distributions doesn't pack all the python modules and even if they
do, you can require an specific version that's different from the one
packaged in your favourite distribution, so in python it's common to
install dependencies from the &lt;a href="https://pypi.org/"&gt;Python Package Index (PyPI)&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Python has a tool to install and manage Python packages that looks for
desired python modules in PyPI.&lt;/p&gt;
&lt;p&gt;You can install new dependencies with &lt;code&gt;pip&lt;/code&gt; just like:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;django
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that command looks for the &lt;code&gt;django&lt;/code&gt; python module in the PyPI,
downloads and install it, in your user
&lt;code&gt;$HOME/.local/lib/python3.11/site-packages&lt;/code&gt; folder if you
use &lt;code&gt;--user&lt;/code&gt;, or in a global system path like &lt;code&gt;/usr/local/lib&lt;/code&gt; or
&lt;code&gt;/usr/lib&lt;/code&gt; if you run pip as root.&lt;/p&gt;
&lt;p&gt;But the usage of &lt;code&gt;pip&lt;/code&gt; directly in the system is something &lt;strong&gt;not
recommended today&lt;/strong&gt;, and even &lt;a href="https://packaging.python.org/en/latest/specifications/externally-managed-environments/#externally-managed-environments"&gt;it's disabled&lt;/a&gt; in some
distributions, like openSUSE Tumbleweed.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;danigm&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;localhost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;django&lt;/span&gt;
&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;externally&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;managed&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;

&lt;span class="err"&gt;×&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;externally&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;managed&lt;/span&gt;
&lt;span class="err"&gt;╰─&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;wide&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;try&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;zypper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python311&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;xyz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xyz&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;trying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;rpm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;packaged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python3&lt;/span&gt;&lt;span class="m m-Double"&gt;.11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Then&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;pip&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;wish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;rpm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;packaged&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;may&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;easiest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nx"&gt;pipx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xyz&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;which&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;manage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;virtual&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pipx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;via&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nx"&gt;zypper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python311&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;pipx&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="nx"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;believe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mistake&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;please&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;contact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;installation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;distribution&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;You&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;at&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;risk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breaking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;installation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;OS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;passing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;See&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PEP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;668&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;detailed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;specification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;virtualenvs&lt;/h2&gt;
&lt;p&gt;Following the current recommendation, the correct way of installing
third party python modules is to use &lt;code&gt;virtualenvs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;virtualenvs&lt;/code&gt; are just specific folders where you install your
python modules and some scripts that make's easy to use it in
combination with your system libraries so you don't need to modify the
&lt;code&gt;PYTHONPATH&lt;/code&gt; manually.&lt;/p&gt;
&lt;p&gt;So if you've a custom project and want to install python modules you
can create your own virtualenv and use pip to install dependencies
there:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;danigm@localhost tmp&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;venv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myenv&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;danigm@localhost tmp&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;activate&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;danigm@localhost tmp&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;
&lt;span class="n"&gt;Collecting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;Successfully&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;installed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;asgiref&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;3.7.2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;5.0.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sqlparse&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.4.4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So all dependencies are installed in my new virtualenv folder and if I
use the python from the virtualenv it's using those paths, so all the
modules installed there are usable inside that virtualenv:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;danigm&lt;/span&gt;&lt;span class="nd"&gt;@localhost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ls&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="mf"&gt;.11&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="n"&gt;apps&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;contrib&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;shortcuts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;templatetags&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;
&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="n"&gt;dispatch&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;__pycache__&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="n"&gt;utils&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;danigm&lt;/span&gt;&lt;span class="nd"&gt;@localhost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;import django; print(django.__version__)&amp;quot;&lt;/span&gt;
&lt;span class="mf"&gt;5.0.1&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;danigm&lt;/span&gt;&lt;span class="nd"&gt;@localhost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deactivate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With virtualenvs you can have multiple python projects, with different
dependencies, isolated, so you use different dependencies when you
activate your desired virtualenv:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;activate &lt;code&gt;$ . ./myenv/bin/activate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;deactivate &lt;code&gt;$ deactivate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;High level tools to handle virtualenvs&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://docs.python.org/3/library/venv.html#module-venv"&gt;venv&lt;/a&gt; module is a default Python module and as you can see
above, it's really simple to use, but there are some tools that
provides some tooling around it, to make it easy for you, so usually
you don't need to use &lt;code&gt;venv&lt;/code&gt; directly.&lt;/p&gt;
&lt;h3&gt;pipx&lt;/h3&gt;
&lt;p&gt;For final python tools, that you are not going to use as dependencies
in your python code, the recommended tool to use is &lt;a href="https://github.com/pypa/pipx"&gt;pipx&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="/pictures/pipx_demo.gif" width="100%" /&gt;&lt;/p&gt;
&lt;p&gt;The tool creates virtualenv automatically and links the binaries so
you don't need to worry about anything, just use as a way to install
third party python applications and update/uninstall using it. The
&lt;code&gt;pipx&lt;/code&gt; won't mess your system libraries and each installation will use
a different virtualenv, so even tools with incompatible dependencies
will work nicely together in the same system.&lt;/p&gt;
&lt;h3&gt;Libraries, for Python developers&lt;/h3&gt;
&lt;p&gt;In the case of Python developers, when you need to manage dependencies
for your project, there are a lot of nice high level tools for
&lt;a href="https://packaging.python.org/en/latest/tutorials/managing-dependencies/#other-tools-for-application-dependency-management"&gt;managing dependencies&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pdm-project/pdm"&gt;PDM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pypa/hatch"&gt;hatch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/thoth-station/micropipenv"&gt;micropipenv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jazzband/pip-tools"&gt;pip-tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://packaging.python.org/en/latest/key_projects/#pipenv"&gt;pipenv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/python-poetry/poetry"&gt;poetry&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These tools provides different ways of managing dependencies, but all
of them relies in the use of &lt;code&gt;venv&lt;/code&gt;, creating the virtualenv in
different locations and providing tools to enable/disable and manage
dependencies inside those virtualenvs.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;poetry&lt;/code&gt; creates virtualenvs by default inside the
&lt;code&gt;.cache&lt;/code&gt; folder, in my case I can find all poetry created virtualenvs
in:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/home/danigm/.cache/pypoetry/virtualenvs/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Most of these tools add other utilities on top of the dependency
management. Just for installing python modules easily you can always
use default &lt;code&gt;venv&lt;/code&gt; and &lt;code&gt;pip&lt;/code&gt; modules, but for more complex projects
it's worth to investigate high level tools, because it'll make easy to
manage your project dependencies and virtualenvs.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There are a lot of python code inside any modern Linux distribution
and if you're a python developer it's possible to have a lot of python
code. Make sure to know the source of your modules and do not mix
different environments to avoid future headaches.&lt;/p&gt;
&lt;p&gt;As a final trick, if you don't know where's the actual code of some
python module in your running python script, you can always ask:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;django&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__file__&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;/tmp/myenv/lib64/python3.11/site-packages/django/__init__.py&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This could be even more complicated if you start to use containers
and different python versions, so keep you dependencies clean and up
to date and make sue that you know &lt;strong&gt;where is your Python code&lt;/strong&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 03 Feb 2024 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2024-02-03:/wheres-my-python-code.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>linux</category><category>python</category></item><item><title>Updating GNOME shell extensions to GNOME 45</title><link>https://danigm.net/gnome-45-extensions.html</link><description>&lt;p&gt;&lt;img src="/pictures/GNOME45.webp" width="100%" /&gt;&lt;/p&gt;
&lt;p&gt;The new version of the &lt;a href="https://www.gnome.org/"&gt;GNOME desktop&lt;/a&gt; was released &lt;a href="https://foundation.gnome.org/2023/09/20/introducing-gnome-45/"&gt;more than one month&lt;/a&gt;
ago. It takes some time to arrive to the final user, because distributions
should integrate, tests and release the new desktop, and that's not something
simple, and it should integrate in the distribution release planning.&lt;/p&gt;
&lt;p&gt;So right now, it's possible that there's just a few people with the latest
version of the desktop right now, just people with rolling release distros or
people using testing versions of mayor distributions.&lt;/p&gt;
&lt;p&gt;This is one of the reasons because a lot of gnome-shell extensions aren't
updated to work with the latest version of GNOME, even after a few months,
because even developers doesn't have the latest version of the desktop and
it's not something "easy" to install, without a virtual machine or something
like that. Even if the update is just a change in the metadata.json, there
should be someone to test the extension, and even someone to request this
update, and that will happen once the mayor distributions release a new
version.&lt;/p&gt;
&lt;p&gt;I'm using Tumbleweed, that's a rolling release and GNOME 45 is here just after
the official release, but of course, a lot of extensions are not working, and
in the infamous list of non working extensions there where the three that I'm
&lt;a href="https://extensions.gnome.org/accounts/profile/danigm"&gt;maintaining right now&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/danigm/spotify-ad-blocker"&gt;mute-spotify-ads&lt;/a&gt;, extension to mute the spotify app when it's playing ads.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/danigm/gnome-shell-calculator"&gt;calc&lt;/a&gt;, a simple calculator in the alt+F2 input.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/danigm/hide-minimized"&gt;hide-minimized&lt;/a&gt;, hide minimized windows from alt+tab and overview.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/GNOME45-desktop.webp" /&gt;
&lt;/p&gt;

&lt;h2&gt;The correct way&lt;/h2&gt;
&lt;p&gt;The correct way to maintain and update a gnome-shell extension should be to
test and update "before" the official release of GNOME. It should be something
easy for me, using Tumbleweed I can just add the &lt;a href="https://build.opensuse.org/project/show/GNOME:Next"&gt;GNOME Next&lt;/a&gt; repository,
install the new desktop when it's in beta stage, and update the extension
there.&lt;/p&gt;
&lt;p&gt;But that's something that require an active maintainership... And right now
what I do is to update the extensions when they are broken for me, so just when
I need them, and that's after I get the new desktop and I find some time to
update.&lt;/p&gt;
&lt;p&gt;I know that's not the correct way and this produces a bad experience for other
people using the extensions, but this is the easier thing to do for me. Maybe
in the future I can do it correctly, and provide a tested update before the
official release, maybe using snapper to be able to go back to stable, without
the need of using virtual machines.&lt;/p&gt;
&lt;h2&gt;Update your extension to GNOME 45&lt;/h2&gt;
&lt;p&gt;The update to GNOME 45 was a bit more complex than previous ones. This version
of the shell and gjs change a lot of things, so the migration it's not just to
add a new number to the metadata.json, but requires incompatible changes, so
extensions that works for GNOME 45 won't work for previous versions and
vice versa.&lt;/p&gt;
&lt;p&gt;But the people working in gnome-shell does a great work documenting and there's
a really nice guide about &lt;a href="https://gjs.guide/extensions/upgrading/gnome-shell-45.html"&gt;how to upgrade your extension&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The most important part is the import section, that now it has a different syntax.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GNOME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;
&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;imports&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GNOME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;resource:///org/gnome/shell/ui/main.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And some changes in the extension class, that now can inherit from existing
ones to provide common usage, like preferences window:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;Adw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gi://Adw&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ExtensionPreferences&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gettext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;MyExtensionPreferences&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ExtensionPreferences&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fillPreferencesWindow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getSettings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Adw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PreferencesPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Adw&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PreferencesGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Group Title&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &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;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 03 Nov 2023 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2023-11-03:/gnome-45-extensions.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>linux</category><category>javascript</category></item><item><title>One year of Tumbleweed</title><link>https://danigm.net/tumbleweed.html</link><description>&lt;p class="img"&gt;
    &lt;a target="_blank" href="https://www.opensuse.org/#Tumbleweed"&gt;
        &lt;img src="/pictures/tumbleweed.png" /&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;More than a year has passed since I switched to &lt;a href="https://www.opensuse.org/#Tumbleweed"&gt;openSUSE Tumbleweed&lt;/a&gt;
Linux distribution, in both, my work computer (for obvious reasons)
and in my personal computer and I can say that I'm really happy with
the change.&lt;/p&gt;
&lt;p&gt;Tumbleweed is a &lt;a href="https://en.wikipedia.org/wiki/Rolling_release"&gt;rolling release&lt;/a&gt; distribution, and in this kind of
distributions there are a lot of changes every week, if you want the
latest software, this kind of distribution is the way to go. But with
high update frequency you are exposed to some kind of instability,
it's impossible to have the latest changes without some broken program
here and there, because not everyone is able to follow upstream
changes without some weeks or months to update.&lt;/p&gt;
&lt;h2&gt;My distro history&lt;/h2&gt;
&lt;p&gt;I've been always a Linux user, since I get my first computer at 2003.
In those days I was using a &lt;a href="https://www.debian.org/"&gt;debian&lt;/a&gt; base distribution called
&lt;a href="https://www.knopper.net/knoppix/index-en.html"&gt;knoppix&lt;/a&gt;. Then I switched to &lt;a href="https://ubuntu.com/"&gt;ubuntu&lt;/a&gt; when it appeared around 2004.
But at that time I was a computer science student and I was exploring
the whole free software and Linux ecosystem, so I was changing my
distribution every time that I found a new one.&lt;/p&gt;
&lt;p&gt;Like a lot of distro-hoppers, at some point I landed at &lt;a href="https://archlinux.org/"&gt;ArchLinux&lt;/a&gt;
and there I discovered the rolling release concept. And that was my
home for some time, it was nice to have the latest available software
just after the release.&lt;/p&gt;
&lt;p&gt;At some point I bough a new computer and it was too new to work
correctly with the kernel distributed in ArchLinux, so I tried
different distributions and at that moment &lt;a href="https://fedoraproject.org/"&gt;Fedora&lt;/a&gt; was the distro
that works without too much complications with that computer, so I
picked that one.&lt;/p&gt;
&lt;p&gt;In 2019 I started to work at Endless and at that time I should try the
&lt;a href="https://www.endlessos.org/"&gt;EndlessOS&lt;/a&gt;, so I played a bit with &lt;a href="https://danigm.net/endlessos-dual-boot.html"&gt;the dual boot&lt;/a&gt;, having
Fedora and EndlessOS at the same time. That was the first time that I
get in contact with immutable distributions, something that's getting
more popular everyday, but this distributions rely a lot on containers
(flatpak, podman) and, even being something that could work, as a
software engineer, I don't feel comfortable enough needing a container
with another distribution to do something that could be in my system.&lt;/p&gt;
&lt;p&gt;In 2022 I started to &lt;a href="https://danigm.net/suse.html"&gt;work at SUSE&lt;/a&gt; and for the first time I tried
the openSUSE distribution until today.&lt;/p&gt;
&lt;h2&gt;The Tumbleweed&lt;/h2&gt;
&lt;p&gt;Today I've three different computers with Tumbleweed running. One for
work, Thinkpad T14s, one for personal usage, Dell inspiron 5490, and
another one as a personal media server, Libre computer &lt;a href="https://libre.computer/products/aml-s805x-ac/"&gt;La-frite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The best thing of having Tumbleweed for me is that I get the latest
&lt;strong&gt;GNOME&lt;/strong&gt; as soon as it's released. And another big thing for this
distribution is how easy it's to fix something upstream thanks to the
&lt;a href="https://build.opensuse.org/project/show/openSUSE:Factory"&gt;Open Build Service&lt;/a&gt;, but I work everyday with that, so I'm
biased. For sure, any other community distribution has different ways
to contribute, but I find this one easy enough.&lt;/p&gt;
&lt;p&gt;Even being a rolling release distro, Tumbleweed doesn't break a lot. I
can't say that it's stable, because the API of everything is broken
everyday, but the &lt;a href="https://openqa.opensuse.org/group_overview/1"&gt;distribution is tested&lt;/a&gt; for every release and
at least some level of package compatibility check is done. That makes
Tumbleweed a good distribution and I can update without fearing some
weird package breakage.&lt;/p&gt;
&lt;p&gt;I usually update my work and personal laptops once a week, and
la-frite not so often, maybe every 6 months.&lt;/p&gt;
&lt;p&gt;With the default installation, Tumbleweed uses btrfs with snapshots,
and it's really easy to go back and forward using the
&lt;a href="https://en.opensuse.org/openSUSE:Snapper_Tutorial"&gt;snapper tool&lt;/a&gt;. So it's really easy to go back to a good state if
the distribution is broken for some reason, and wait for a fix.&lt;/p&gt;
&lt;h2&gt;The problems that I found during this year&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Some problems with the NVidia graphic card in my Dell laptop, some
   times the kernel and the driver were not working correctly. I had
   to use snapper to get the NVidia working again, but fixed a few
   days later.&lt;/li&gt;
&lt;li&gt;Currently I'm having some random crashes because some bug with
   &lt;a href="https://bugzilla.suse.com/show_bug.cgi?id=1215695"&gt;amdgpu&lt;/a&gt; and wayland and mutter, but it's not too annoying for
   me to go back, so I didn't use snapper this time and I'm facing
   this random crashes waiting for the fix.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Long live the Tumbleweed&lt;/h2&gt;
&lt;p&gt;So far so good. Tumbleweed is a nice distribution that I'm enjoying.
It's not getting in the way and I can find almost anything that I need
for work, programming, gaming, media, etc. I'm really happy with this
distribution and it's the perfect distribution for people like me,
that want to have the latest things.&lt;/p&gt;
&lt;p&gt;I know that there are other openSUSE flavors that are interesting,
like the &lt;a href="https://en.opensuse.org/Portal:Aeon"&gt;immutable ones&lt;/a&gt;, &lt;a href="https://en.opensuse.org/openSUSE:Slowroll"&gt;Leap&lt;/a&gt; or the latest one
&lt;a href="https://en.opensuse.org/openSUSE:Slowroll"&gt;Slowroll&lt;/a&gt;, but Tumbleweed is the one for me.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 06 Oct 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-10-06:/tumbleweed.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>openSUSE</category><category>tumbleweed</category><category>linux</category><category>distribution</category></item></channel></rss>