<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>danigm.net - suse</title><link>https://danigm.net/</link><description></description><lastBuildDate>Fri, 05 Jun 2026 12:00:00 +0200</lastBuildDate><item><title>Take it easy. A guide to avoid burnown during the Vulnpocalypse</title><link>https://danigm.net/take-it-easy.html</link><description>&lt;p&gt;Do not let the AI to remove the fun part from software development.
We shouldn't allow gen AI to write software just because it "can".
First, we must ask if it "should" do it, and even then, we should ask
if we &lt;strong&gt;want&lt;/strong&gt; to delegate the fun part, the thinking, the writing,
the learning.&lt;/p&gt;
&lt;p&gt;Remember what's important, journey before destination, &lt;strong&gt;we are the
Code&lt;/strong&gt;:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/mb3uK-_QkOo" title="We are the art" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Do not let AI to destroy the community, do not let it destroy the
&lt;a href="https://linguacelta.com/blog/2026/05/LLMs.html"&gt;technological knowledge commons&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;tl;dr&lt;/h2&gt;
&lt;p&gt;Open Source maintainers are dealing with a lot of new reports and
pressure to "fix" the project due to generative AI.&lt;/p&gt;
&lt;p&gt;We need to find a way of stopping this and get back to something
maintainable before all maintainers get burned out and look for a job
in a farm:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;100% secure software doesn't exists, so there will be always a
   possible CVE there. As &lt;a href="https://en.wikiquote.org/wiki/Gene_Spafford"&gt;Spaf said in 1989&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;The only truly secure system is one that is powered off, cast in a
block of concrete and sealed in a lead-lined room with armed guards
- and even then I have my doubts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Fixing bugs, adds new bugs, and if you need to fix something quick,
   the probability of new bugs will be higher. Do not forget about the
   First Law of Programming:&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;If it works, don't touch it&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The amount of CVE reports is lowering the CVE credibility and
   quality, so if everything is a &lt;em&gt;"high"&lt;/em&gt; security issue, we can't
   prioritize now and these reports are not different from random
   issues in github. Do not listen to &lt;a href="https://en.wikipedia.org/wiki/The_Boy_Who_Cried_Wolf"&gt;The Boy Who Cried Wolf&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stable software is sable because it doesn't change too much. It's
   something that we are willing to loose trying to reach the
   impossible of 100% secure software?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The actual problem&lt;/h2&gt;
&lt;p&gt;There's a lot of money in AI tech right now, and everyone is trying to
make the best gen AI tool or just pretend that their tool is the best.&lt;/p&gt;
&lt;p&gt;In relation with the software analysis and writing, targeting the
open source is the obvious strategy.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It's interesting to scrap every line of code, patch, pull request,
   issue and discussion around software to train your model, so AI
   scrappers are DDoSing open source projects infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To promote their tools or themselves, &lt;em&gt;Security Researches&lt;/em&gt; are
   using AI to target any project, reporting &lt;em&gt;High security
   vulnerabilities&lt;/em&gt;, with the only goal of getting a CVE number to say
   how good they are.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This second point is affecting maintainers, because now you are
receiving a lot of poor quality security reports, that are generated
with AI and that looks plausible and are hard to read. You need to
spend a lot of time to check if there's an actual wolf there or if
it's again this boy that's tricking me.&lt;/p&gt;
&lt;p&gt;This is burning the energy of maintainers, that instead of doing
something productive are wasting their limited time talking with a
&lt;a href="https://en.wikipedia.org/wiki/Stochastic_parrot"&gt;Stocatic Parrot&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Do not let the AI Bros to use classic manipulation techniques on you!&lt;/h2&gt;
&lt;p&gt;A lot of open source projects are maintained by volunteers that do the
work with passion and love. And even if it's the job that paid your
bills, the maintainer can feel the &lt;a href="https://daniel.haxx.se/blog/2026/05/26/the-pressure/"&gt;pressure&lt;/a&gt;. When someone put a
lot of love in something and work on it during years, it's part of his
identity, so attacking the software is like attacking the person
behind it.&lt;/p&gt;
&lt;p&gt;This is nothing new, and a lot of people take advantage of this
emotional link to manipulate the maintainer to do something that he
do not want to do.&lt;/p&gt;
&lt;p&gt;AI bros are using these techniques, do not let them to manipulate you
and define your project agenda.&lt;/p&gt;
&lt;p&gt;Here's a (not complete) list of known manipulation techniques that you
can detect (and disarm!) in your daily community work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flooding the queue&lt;/strong&gt;. Just create so many new issues that the
   actual maintainers can't deal with it. You feel responsible for the
   project and feel bad because &lt;em&gt;your TO-DO list&lt;/em&gt; is growing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This software is not secure (doesn't do what I want), I will use
   this other one instead that's better&lt;/strong&gt;. The classic, "GNOME doesn't
   allow me to change this specific preference, I'll use KDE from now
   on".&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This software is low quality, it doesn't follow the (my random)
   quality standards&lt;/strong&gt;. Direct attack to the maintainer self-esteem.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Gaslighting software development&lt;/strong&gt;. LLM are expert at this and
   people that uses it just copy the tactic. When the maintainer
   detects something weird and just tries to blame the other person
   for reporting nonsense and wasting all people time, it starts to
   invent new arguments and ignore the previous interaction.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, take it easy, and remember the best clause in almost any software
project, &lt;strong&gt;THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
PROGRAM IS WITH YOU&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;Disclaimer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Warranty&lt;/span&gt;.

&lt;span class="nv"&gt;THERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;NO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WARRANTY&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="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EXTENT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PERMITTED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BY&lt;/span&gt;
&lt;span class="nv"&gt;APPLICABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LAW&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EXCEPT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OTHERWISE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;STATED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WRITING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;COPYRIGHT&lt;/span&gt;
&lt;span class="nv"&gt;HOLDERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AND&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OTHER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PARTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROVIDE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;“&lt;span class="nv"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IS&lt;/span&gt;”&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WITHOUT&lt;/span&gt;
&lt;span class="nv"&gt;WARRANTY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ANY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;KIND&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EITHER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;EXPRESSED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IMPLIED&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;INCLUDING&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;NOT&lt;/span&gt;
&lt;span class="nv"&gt;LIMITED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IMPLIED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WARRANTIES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MERCHANTABILITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;FITNESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;
&lt;span class="nv"&gt;A&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PARTICULAR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PURPOSE&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ENTIRE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;RISK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;QUALITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;AND&lt;/span&gt;
&lt;span class="nv"&gt;PERFORMANCE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;YOU&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;SHOULD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROGRAM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PROVE&lt;/span&gt;
&lt;span class="nv"&gt;DEFECTIVE&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;YOU&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ASSUME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;THE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;COST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;NECESSARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;SERVICING&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;REPAIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OR&lt;/span&gt;
&lt;span class="nv"&gt;CORRECTION&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Is the software more insecure in 2026?&lt;/h2&gt;
&lt;p&gt;No. Anyone old enough could remember how insecure old software was. Do
you remember windows 98? Do you remember the internet when everything
was http (without that little s at the end), when people use ftp
to logging into their server and modify the php code directly on
production?&lt;/p&gt;
&lt;p&gt;It's true that today we have more dependency on technology, but it's
also true that everything is more secure, we have more and better
cryptography, we have different levels of isolation, virtual
environments, containers, virtual machines...&lt;/p&gt;
&lt;p&gt;But we have the feeling that since AI can analyse all the software and
look for vulnerabilities, we are doomed, because any stupid kid can
hack my over engineered GNU/Linux machine!&lt;/p&gt;
&lt;p&gt;First, that's not true, you need to know about security to get
something useful from any AI tool. But even if it was true, what can
you do about it? We need to be practical and find a balance between
risk and usefulness, so do not &lt;strong&gt;overestimate the risk&lt;/strong&gt; just because
everyone is talking about it right now.&lt;/p&gt;
&lt;p&gt;But even then, the security paranoia is not good for anyone. Software
is inherently buggy, people write software and makes mistakes, so a
possible vulnerability appears. In theory, these bugs are fixed when
discovered, so it's always recommended to update to the latest
version, because almost all known bugs will be fixed.&lt;/p&gt;
&lt;p&gt;But it's also known that new versions comes with new functionality and
code, and that means new "unknown" bugs or different behavior. That's
a headache, so that's why the stable and Long Term Support are popular
distributions, because &lt;strong&gt;"if it works, don't touch it"&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Stable packages just get the fixes, not new features, but fixes are
also code changes, so there's always a possibility to break something,
even with a patch update.&lt;/p&gt;
&lt;p&gt;The stable software has a lot of value, do not let the AI security
paranoia destroy that, and convert everything in a rolling release
with the latest and greatest (and possibly broken) software. Sometimes
it's better to keep using something old, with &lt;strong&gt;known&lt;/strong&gt;
vulnerabilities that you can mitigate, than use the latest with
&lt;strong&gt;unknown&lt;/strong&gt; new vulnerabilities that you can't do anything about.&lt;/p&gt;
&lt;h2&gt;I will fight AI with AI&lt;/h2&gt;
&lt;p&gt;Please, do not do that. What I was trying to argue during this long
post is not a technical problem. The current burnout problem in open
source is a social problem, you can't fix it with a new layer of
probabilistic tokens.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Community reaction against AI&lt;/strong&gt;. The current industry push for
   the usage of AI everywhere is affecting a lot of people, and as a
   reaction a lot of people are directly fighting back. Using gen AI
   just sends the message that you do not care enough to do it
   yourself, and destroy the trust on the project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It doesn't worth it&lt;/strong&gt;. Even if the AI works (that it doesn't) it
   doesn't worth it. Writing code is easier than reviewing, you learn
   and grow with every new line of code that you write, delegating
   the fun part and personal growth part to an AI will make you work
   more miserable and you will be a junior forever.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It doesn't create community&lt;/strong&gt;. Think about it, it's hard to get
   someone involved in a software project, but who will want to read
   or improve the code produced by a gen AI? The only future
   collaborator will be another AI.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Take it easy&lt;/h2&gt;
&lt;p&gt;Just remember, you can always say no, there's no hurry, and there's no
need to work on something that you don't want just because other
people consider that important.&lt;/p&gt;
&lt;p&gt;Free Source is something done by people, for people. The software is
important, but the community around it is sometimes more important. We
use Free source not because it's technically better (that it is), but
because we trust who, how and why are writing it.&lt;/p&gt;
&lt;p&gt;Remember why are you doing this, do not remove the Fun part, continue
with the &lt;a href="https://es.wikipedia.org/wiki/Just_for_fun"&gt;&lt;strong&gt;Just for Fun&lt;/strong&gt;&lt;/a&gt; mood.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 05 Jun 2026 12:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2026-06-05:/take-it-easy.html</guid><category>blog</category><category>suse</category><category>opensuse</category><category>gnome</category><category>open-source</category><category>AI</category></item><item><title>openSUSE: The new git workflow</title><link>https://danigm.net/git-workflow.html</link><description>&lt;p&gt;openSUSE is migrating the package source management from &lt;strong&gt;osc&lt;/strong&gt; to
&lt;strong&gt;git&lt;/strong&gt;. I will try to explain here what it is the "git workflow" in
openSUSE and give some practical information for contributors and
maintainers.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/opensuse-git.png" /&gt;
&lt;/p&gt;

&lt;p&gt;You can find some documentation in the &lt;a href="https://en.opensuse.org/openSUSE:Git_Packaging_Workflow"&gt;openSUSE wiki&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Why?&lt;/h2&gt;
&lt;p&gt;openSUSE uses &lt;a href="https://openbuildservice.org/"&gt;Open Build Service&lt;/a&gt; to
store package sources (.spec files and patches). The source control is
similar to &lt;a href="https://subversion.apache.org/"&gt;subversion&lt;/a&gt;, so you can
&lt;em&gt;osc checkout&lt;/em&gt;, &lt;em&gt;osc commit&lt;/em&gt;, &lt;em&gt;osc log&lt;/em&gt;, etc. to work with any package
source.&lt;/p&gt;
&lt;p&gt;I don't know all the reasons to do the change, and different people
will find different reasons, to support the change or to be against
it. I will just write here what I consider a good reason to migrate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Almost everyone has moved to git now, so today,
  &lt;a href="https://git-scm.com"&gt;git&lt;/a&gt; is the default source code management
  (scm) tool, almost all the people knows about
  &lt;a href="https://github.com"&gt;github&lt;/a&gt;, so it's good to be "&lt;em&gt;standard&lt;/em&gt;".&lt;/li&gt;
&lt;li&gt;With the concept of "&lt;em&gt;cheap&lt;/em&gt;" branches in git, it &lt;strong&gt;could&lt;/strong&gt; be
  easier to maintain different versions of the same package, same
  repository, different branches, instead of actual forks.&lt;/li&gt;
&lt;li&gt;Decouple the package source management from build. OBS does a lot of
  things, moving source code and review process to
  &lt;a href="https://gitea.com"&gt;gitea&lt;/a&gt; could reduce the complexity (but requires
  some integration).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;From OBS to gitea&lt;/h2&gt;
&lt;p&gt;All the development happens in &lt;a href="https://build.opensuse.org"&gt;OBS&lt;/a&gt;, so the
&lt;strong&gt;classic&lt;/strong&gt; workflow happens entirely there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;developer: branch -&amp;gt; checkout -&amp;gt; modify -&amp;gt; commit -&amp;gt; submit request&lt;/li&gt;
&lt;li&gt;maintainer: review -&amp;gt; accept/decline&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And everything is integrated in OBS that does the corresponding build
of the sources, checks with services, forward, etc.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;new&lt;/strong&gt; workflow changes almost all the interaction from
&lt;a href="https://build.opensuse.org"&gt;OBS&lt;/a&gt; to &lt;a href="https://src.opensuse.org"&gt;gitea&lt;/a&gt;. OBS is still
a really important piece of software in the process, but in the new
workflow it's a build backend, so the user interaction will be with
the git repo in &lt;a href="https://src.opensuse.org"&gt;gitea&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The new &lt;strong&gt;git workflow&lt;/strong&gt; happens in &lt;a href="https://src.opensuse.org"&gt;gitea&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;developer: fork -&amp;gt; clone -&amp;gt; modify -&amp;gt; commit -&amp;gt; push -&amp;gt; pull request&lt;/li&gt;
&lt;li&gt;maintainer: review -&amp;gt; approve/decline&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you may notice, the "&lt;em&gt;default&lt;/em&gt;" workflow is very similar, the
difference is in the tools, the &lt;strong&gt;classic&lt;/strong&gt; workflow occurs in
&lt;a href="https://build.opensuse.org"&gt;build.opensuse.org&lt;/a&gt; and the &lt;strong&gt;new&lt;/strong&gt; workflow in
&lt;a href="https://src.opensuse.org"&gt;src.opensuse.org&lt;/a&gt;. And the tools to work with the
sources are also different, &lt;strong&gt;osc&lt;/strong&gt; in the first one and &lt;strong&gt;git&lt;/strong&gt; in
the new workflow.&lt;/p&gt;
&lt;p&gt;And with this new workflow, there are some bots in gitea that sends
the changes to OBS, so for any pull request created you will have the
build results and approval from the bot if everything is building.&lt;/p&gt;
&lt;h2&gt;How to modify a package (leap 16.0)&lt;/h2&gt;
&lt;p&gt;Notice that you should have a &lt;a href="https://idp-portal.suse.com/univention/self-service/#page=createaccount"&gt;openSUSE account&lt;/a&gt; to work with the
gitea instance, and don't forget to &lt;a href="https://src.opensuse.org/user/settings/keys"&gt;configure your ssh key&lt;/a&gt; to be
able to push using the gitea@src.opensuse.org remote.&lt;/p&gt;
&lt;p&gt;So as a contributor, this is the basic workflow to follow to update a
package in openSUSE:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Look for the source package in the pool
   (&lt;a href="https://src.opensuse.org/pool"&gt;https://src.opensuse.org/pool&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Fork it in your user space, click the top right button. Skip this
   step if you have forked before&lt;/li&gt;
&lt;li&gt;Clone your fork and work on that repo, create a new branch, modify
   the spec file, add new soures, etc. And make sure to update the
   .changes file accordingly, you can still use &lt;code&gt;osc vc&lt;/code&gt; to do that.&lt;/li&gt;
&lt;li&gt;You can build locally your package with &lt;code&gt;osc build&lt;/code&gt;, as usual, but
   you will need to specify the build project:&lt;/li&gt;
&lt;/ol&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;git&lt;span class="w"&gt; &lt;/span&gt;obs&lt;span class="w"&gt; &lt;/span&gt;meta&lt;span class="w"&gt; &lt;/span&gt;pull
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;obs&lt;span class="w"&gt; &lt;/span&gt;meta&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--project&lt;span class="w"&gt; &lt;/span&gt;openSUSE:Backports:SLE-16.0
$&lt;span class="w"&gt; &lt;/span&gt;osc&lt;span class="w"&gt; &lt;/span&gt;build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Once you are happy with your changes, you can commit, push to your
   fork and then you can create a Pull Request. The pull request
   should target the &lt;strong&gt;pool&lt;/strong&gt; repo and desired product branch. Right
   now you can just target &lt;code&gt;leap-16.0&lt;/code&gt;, as factory is not migrated
   yet.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Devel projects&lt;/h2&gt;
&lt;p&gt;Some devel projects have been migrated now to git, so a similar
workflow is available to modify these packages in Tumbleweed. The
development of these packages is not happening in the &lt;em&gt;pool&lt;/em&gt;, so you
need to find first the devel project.&lt;/p&gt;
&lt;p&gt;There's no simple way to discover the actual package devel source, as
far as I know the easier way is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Look for the devel project of the package in the &lt;a href="https://src.opensuse.org/openSUSE/Factory/src/branch/main/pkgs/_meta/devel_packages"&gt;Factory list&lt;/a&gt;,
   (ex python-pytest)&lt;/li&gt;
&lt;li&gt;Go to the devel project in &lt;a href="1"&gt;OBS&lt;/a&gt; (ex &lt;a href="https://build.opensuse.org/project/show/devel:languages:python:pytest"&gt;devel:languages:python:pytest&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Click on the link &lt;a href="https://src.opensuse.org/python-pytest/_ObsPrj.git#main"&gt;This project is managed in SCM&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you have located the desired package to modify, the workflow is
similar to what I explained before, but instead of forking from
&lt;strong&gt;pool&lt;/strong&gt;, you should fork from the devel project. For example if you
want to modify &lt;strong&gt;python-pytest&lt;/strong&gt; you should fork from
&lt;a href="https://src.opensuse.org/python-pytest/python-pytest"&gt;https://src.opensuse.org/python-pytest/python-pytest&lt;/a&gt;, 
and create the pull request for that repo, to the main branch.&lt;/p&gt;
&lt;p&gt;Adding a new package follows a different process that's documented in
the &lt;a href="https://en.opensuse.org/openSUSE:OBS_to_Git#How_to_create_a_new_package?"&gt;wiki&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;What's migrated?&lt;/h2&gt;
&lt;p&gt;As I said, the migration is happening right now, so not everything is
migrated. The first project migrated was the Leap 16.0. And we are
slowly migrating some devel projects.&lt;/p&gt;
&lt;p&gt;Right now from the python-maintainers team, we've started the
migration of two subprojects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://src.opensuse.org/python-interpreters"&gt;python-interpreters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://src.opensuse.org/python-pytest"&gt;python-pytest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find more information about the migration current state in the
wiki: &lt;a href="https://en.opensuse.org/openSUSE:OBS_to_Git#Codestream_Project_Status_table"&gt;https://en.opensuse.org/opensuse:obs_to_git#codestream_project_status_table&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 14 Nov 2025 12:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2025-11-14:/git-workflow.html</guid><category>blog</category><category>suse</category><category>opensuse</category><category>git</category><category>packaging</category><category>python</category></item><item><title>GNOME Tour in openSUSE and welcome app</title><link>https://danigm.net/gnome-tour-opensuse.html</link><description>&lt;p&gt;As a follow up of the &lt;a href="https://danigm.net/hackweek24.html"&gt;Hackweek 24 project&lt;/a&gt;, I've continued working
on the gnome-tour fork for openSUSE with custom pages to replace the
welcome application for openSUSE distributions.&lt;/p&gt;
&lt;h2&gt;GNOME Tour modifications&lt;/h2&gt;
&lt;p&gt;All the modifications are on top of &lt;a href="https://gitlab.gnome.org/GNOME/gnome-tour/"&gt;upstream gnome-tour&lt;/a&gt; and
stored in the &lt;a href="https://github.com/openSUSE/gnome-tour"&gt;openSUSE/gnome-tour repo&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom &lt;strong&gt;initial page&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gnome-tour-opensuse.png" /&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A new donations page&lt;/strong&gt;. In openSUSE we remove the popup from GNOME
   shell for donations, so it's fair to add it in this place.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gnome-tour-donation.png" /&gt;
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Last page with custom openSUSE links&lt;/strong&gt;, this one is the used for
   opensuse-welcome app.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;opensuse-welcome package&lt;/h2&gt;
&lt;p&gt;The &lt;a href="github.com/openSUSE/openSUSE-welcome"&gt;original opensuse-welcome&lt;/a&gt; is a qt application, and this one
is used for all desktop environments, but it's more or less
unmaintained and looking for a replacement, we can use the gnome-tour
fork as the default welcome app for all desktop without a custom app.&lt;/p&gt;
&lt;p&gt;To do a minimal desktop agnostic opensuse-welcome application, I've
modified the gnome-tour to also generate a second binary but just with
the last page.&lt;/p&gt;
&lt;p&gt;The new opensuse-welcome rpm package is built as a subpackage of
&lt;a href="https://src.opensuse.org/pool/gnome-tour"&gt;gnome-tour&lt;/a&gt;. This new application is minimal and it doesn't have
lots of requirements, but as it's a gtk4 application, it requires gtk
and libadwaita, and also depends on gnome-tour-data to get the
resoures of the app.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/opensuse-welcome.png" /&gt;
&lt;/p&gt;

&lt;p&gt;To improve this welcome app we need to review the translations,
because I added three new pages to the gnome-tour and that specific
pages are not translated, so I should regenerate the .po files for all
languages and upload to &lt;a href="https://l10n.opensuse.org/"&gt;openSUSE Weblate&lt;/a&gt; for translations.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Tue, 21 Oct 2025 12:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2025-10-21:/gnome-tour-opensuse.html</guid><category>blog</category><category>gnome-tour</category><category>welcome</category><category>suse</category><category>gsoc</category><category>gnome</category></item><item><title>Log Detective: GSoC 2025 (part 2)</title><link>https://danigm.net/gsoc-2025-2.html</link><description>&lt;p&gt;This week is the last week of Google Summer of Code for this year
edition, and I'll do a summary of what we have been doing and future
plans for the Log Detective integration in openSUSE.&lt;/p&gt;
&lt;p&gt;I wrote a blog post about this project when it starts, so if you
didn't read, you can &lt;a href="https://danigm.net/gsoc-2025.html"&gt;take a look&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All the work and code was done in the
&lt;a href="https://github.com/openSUSE/logdetective-obs/"&gt;logdetective-obs github repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Aazam, aka the intern, also wrote
&lt;a href="https://alcadeus.hashnode.dev/tag/gsoc"&gt;some blog post about his work&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gsoc.png" /&gt;
&lt;/p&gt;

&lt;h2&gt;Initial Research&lt;/h2&gt;
&lt;p&gt;The idea of the project was to explore ways of integration of
&lt;a href="https://log-detective.com"&gt;LogDetective&lt;/a&gt; with the openSUSE dev
workflow. So we started collecting some build failures in the openSUSE
build service and testing with log detective to check if the output is
smart or even relevant.&lt;/p&gt;
&lt;p&gt;The intern creates a script to collect log from build failures and we
store the LLM answer.&lt;/p&gt;
&lt;p&gt;Doing this we detected that the log-detective.com explain is very slow
and the &lt;a href="https://pypi.org/project/logdetective/"&gt;local tool&lt;/a&gt; is less
accurate.&lt;/p&gt;
&lt;p&gt;The results that we got weren't too good, but at this point of the
project is something expected. The model is being trained and will
improve with every new log that users send.&lt;/p&gt;
&lt;h2&gt;Local vs Remote, model comparison&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;logdetective&lt;/code&gt; command line tool is nice, but LLM requires a lot
of resources to run locally. This tool also uses the models published
by fedora in &lt;a href="https://huggingface.co/fedora-copr"&gt;huggingface.co&lt;/a&gt;, so
it's not as accurate as the remote instance that has a better trained
model and is up to date.&lt;/p&gt;
&lt;p&gt;In any case, the local &lt;code&gt;logdetective&lt;/code&gt; tool is interesting and, at this
moment, it's faster than the deployed log-detective.com.&lt;/p&gt;
&lt;p&gt;Using this tool, Aazam did some research, comparing the output with
&lt;a href="https://github.com/openSUSE/logdetective-obs/tree/main/model-testing"&gt;different models&lt;/a&gt;.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;logdetective apache-arrow_standard_x86_64.log\
  --model unsloth/Qwen2.5-Coder-7B-Instruct-128K-GGUF\
  -F Qwen2.5-Coder-7B-Instruct-Q4_K_M.gguf\
  --prompt ~/prompt.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So using other specific models, the logdetective tool can return
better results.&lt;/p&gt;
&lt;h2&gt;The plugin&lt;/h2&gt;
&lt;p&gt;openSUSE packagers uses the &lt;a href="https://github.com/openSUSE/osc"&gt;osc&lt;/a&gt;
tool, to build packages in build.opensuse.org. This tool can be
extended with plugins and we created a
&lt;a href="https://pypi.org/project/osc_ld_plugin/"&gt;new plugin&lt;/a&gt; to use
log-detective.&lt;/p&gt;
&lt;p&gt;So a packager can get some AI explanation about a build failure with a
simple command:&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;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;osc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ld&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;devel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;languages&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;openSUSE_Tumbleweed&lt;/span&gt;
&lt;span class="err"&gt;🔍&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;logdetective&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="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;openSUSE_Tumbleweed&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="p"&gt;)...&lt;/span&gt;
&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="o"&gt;://&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;opensuse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;devel&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;languages&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;openSUSE_Tumbleweed&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x86_64&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pygame&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;_log&lt;/span&gt;
&lt;span class="err"&gt;🌐&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LogDetective&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;API&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RPM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;process&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="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`python-pygame`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;during&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;
&lt;span class="n n-Quoted"&gt;`%check`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;phase&lt;/span&gt;&lt;span class="p"&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;indicated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Bad exit status from /var/tmp/rpm-&lt;/span&gt;
&lt;span class="s2"&gt;tmp.hiddzT (%check)&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;snippet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;occurred&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;due&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seven&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&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="n"&gt;six&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;skipped&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&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;suite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;



&lt;span class="n"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;primary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;issue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;causing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;failure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seems&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traceback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`surface_test.py`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;which&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;following&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;snippets&lt;/span&gt;&lt;span class="o"&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;278s&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;278s&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/abuild/rpmbuild/BUILD/python-&lt;/span&gt;
&lt;span class="s2"&gt;pygame-2.6.1-build/BUILDROOT/usr/lib64/python3.11/site-&lt;/span&gt;
&lt;span class="s2"&gt;packages/pygame/tests/surface_test.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;284&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_copy_rle&lt;/span&gt;
&lt;span class="err"&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;278s&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;278s&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/abuild/rpmbuild/BUILD/python-&lt;/span&gt;
&lt;span class="s2"&gt;pygame-2.6.1-build/BUILDROOT/usr/lib64/python3.11/site-&lt;/span&gt;
&lt;span class="s2"&gt;packages/pygame/tests/surface_test.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;274&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;
&lt;span class="n"&gt;test_mustlock_surf_alpha_rle&lt;/span&gt;
&lt;span class="err"&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;278s&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;recent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;278s&lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/home/abuild/rpmbuild/BUILD/python-&lt;/span&gt;
&lt;span class="s2"&gt;pygame-2.6.1-build/BUILDROOT/usr/lib64/python3.11/site-&lt;/span&gt;
&lt;span class="s2"&gt;packages/pygame/tests/surface_test.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;342&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test_solarwolf_rle_usage&lt;/span&gt;
&lt;span class="err"&gt;]&lt;/span&gt;



&lt;span class="n"&gt;These&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traceback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;errors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;suggest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;there&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&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;functions&lt;/span&gt;
&lt;span class="n n-Quoted"&gt;`test_copy_rle`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`test_mustlock_surf_alpha_rle`&lt;/span&gt;&lt;span class="p"&gt;,&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="n n-Quoted"&gt;`test_solarwolf_rle_usage`&lt;/span&gt;
&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`surface_test.py`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;



&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Identify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cause&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;traceback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;errors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;each&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Fix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;found&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;either&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;modifying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&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;functions&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="n"&gt;correcting&lt;/span&gt;
&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;underlying&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;problem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;they&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="mf"&gt;3.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Re&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RPM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n n-Quoted"&gt;`surface_test.py`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;



&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s also recommended to review the other test failures and skipped steps, as&lt;/span&gt;
&lt;span class="s1"&gt;they might indicate other issues with the package or its dependencies that&lt;/span&gt;
&lt;span class="s1"&gt;should be addressed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or if we are building locally, it's possible to run using the
installed &lt;code&gt;logdetective&lt;/code&gt; command line. But this method is less
accurate, because the model used is not smart enough, yet:&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;osc&lt;span class="w"&gt; &lt;/span&gt;build
&lt;span class="o"&gt;[&lt;/span&gt;...&lt;span class="o"&gt;]&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;osc&lt;span class="w"&gt; &lt;/span&gt;ld&lt;span class="w"&gt; &lt;/span&gt;--local-log&lt;span class="w"&gt; &lt;/span&gt;--repo&lt;span class="w"&gt; &lt;/span&gt;openSUSE_Tumbleweed
Found&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;log:&lt;span class="w"&gt; &lt;/span&gt;/var/tmp/build-root/openSUSE_Tumbleweed-x86_64/.build.log
🚀&lt;span class="w"&gt; &lt;/span&gt;Analyzing&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;log:&lt;span class="w"&gt; &lt;/span&gt;/tmp/tmpuu1sg1q0
INFO:logdetective:Loading&lt;span class="w"&gt; &lt;/span&gt;model&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;fedora-copr/Mistral-7B-Instruct-v0.3-GGUF
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Future plans&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Adding &lt;code&gt;submit-log&lt;/code&gt; functionality to &lt;code&gt;osc-ld-plugin&lt;/code&gt;.
   &lt;a href="https://github.com/openSUSE/logdetective-obs/pull/17/"&gt;In-progress&lt;/a&gt;.
   This will make it easier to collaborate with log-detective.com,
   allowing openSUSE packagers to send new data for model training.&lt;/li&gt;
&lt;li&gt;Gitea bot. openSUSE development workflow is moving to
   &lt;a href="https://src.opensuse.org/products/PackageHub"&gt;git&lt;/a&gt;, so we can
   create a bot that comment on Pull Request with packages that fails
   to build. Something similar to what fedora people have for
   &lt;a href="https://gitlab.com/redhat/centos-stream/rpms/gimp/-/merge_requests/9#note_2514178124"&gt;centos gitlab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Add a new tab to &lt;a href="https://log-detective.com"&gt;log-detective.com&lt;/a&gt; website to submit logs directly
   &lt;a href="https://github.com/fedora-copr/logdetective-website/issues/292"&gt;from OBS&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This was an interesting Summer of Code project. I learned a bit about
LLM. I think that this project has a lot of potential, this can be
integrated in different workflows and an expert LLM can be a great
tool to help packagers, summarizing big logs, tagging similar
failures, etc.&lt;/p&gt;
&lt;p&gt;We have a lot of packages and a lot of data in
&lt;a href="https://build.opensuse.org"&gt;OBS&lt;/a&gt;, so we should start to feed the LLM with
this data, and in combination with the fedora project, the
log-detective could be a real expert in open source RPM packaging.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Wed, 27 Aug 2025 07:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2025-08-27:/gsoc-2025-2.html</guid><category>blog</category><category>ai</category><category>rpm</category><category>suse</category><category>gsoc</category><category>gnome</category></item><item><title>Log Detective: Google Summer of Code 2025</title><link>https://danigm.net/gsoc-2025.html</link><description>&lt;p&gt;I'm glad to say that I'll participate again in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;, as
mentor. This year we will try to improve the RPM packaging workflow
using AI, as part of the &lt;a href="https://www.opensuse.org/"&gt;openSUSE&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;So this summer I'll be mentoring an intern that will research how to
integrate &lt;a href="https://log-detective.com/"&gt;Log Detective&lt;/a&gt; with openSUSE tooling to improve the
packager workflow to maintain rpm packages.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gsoc.png" /&gt;
&lt;/p&gt;

&lt;h2&gt;Log Detective&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://log-detective.com/"&gt;Log Detective&lt;/a&gt; is an initiative created by the &lt;a href="https://fedoraproject.org/"&gt;Fedora project&lt;/a&gt;,
with the goal of&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"Train an AI model to understand RPM build logs and explain the
failure in simple words, with recommendations how to fix it. You
won't need to open the logs at all."&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/log-detective.png" /&gt;
&lt;/p&gt;

&lt;p&gt;As a project that was promoted by Fedora, it's highly integrated with
the build tools around this distribution and RPM packages. But RPM
packages are used in a lot of different distributions, so this
"expert" LLM will be helpful for everyone doing RPM, and everyone
doing RPM, &lt;em&gt;should&lt;/em&gt; contribute to it.&lt;/p&gt;
&lt;p&gt;This is open source, so if, at openSUSE, we want to have something
similar to improve the &lt;a href="https://build.opensuse.org/"&gt;OBS&lt;/a&gt;, we don't need to reimplement it, we
can collaborate. And that's &lt;a href="https://github.com/fedora-copr/logdetective-website/issues/213"&gt;the idea&lt;/a&gt; of this GSoC project.&lt;/p&gt;
&lt;p&gt;We want to use Log Detective, but also collaborate with failures from
openSUSE to improve the training and the AI, and this should benefit
openSUSE but also will benefit Fedora and all other RPM based
distributions.&lt;/p&gt;
&lt;h2&gt;The intern&lt;/h2&gt;
&lt;p&gt;The selected intern is &lt;a href="https://summerofcode.withgoogle.com/programs/2025/projects/SZ1Va8yZ"&gt;Aazam Thakur&lt;/a&gt;. He studies at University of
Mumbai, India. He has experience in using SUSE as he has previously
worked on SLES 15.6 during his previous &lt;a href="https://openmainframeproject.org/blog/summer-mentorship-2024-automating-feilong-packaging-a-technical-odyssey/"&gt;summer mentorship&lt;/a&gt; at
OpenMainFrame Project for RPM packaging.&lt;/p&gt;
&lt;p&gt;I'm sure that he will be able to achieve great things during these
three months. The project looks very promising and it's one of the
things where AI and LLM will shine, because digging into logs is
always something difficult and if we train a LLM with a lot of data it
can be really useful to categorize failures and give a short
description of what's happening.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Mon, 09 Jun 2025 12:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2025-06-09:/gsoc-2025.html</guid><category>blog</category><category>ai</category><category>rpm</category><category>suse</category><category>gsoc</category><category>gnome</category></item><item><title>Python 2</title><link>https://danigm.net/python2.html</link><description>&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/python2.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;In 2020, the
&lt;a href="https://www.python.org/doc/sunset-python-2/"&gt;Python foundation declared Python 2 as not maintained anymore&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Python 2 is really old, not maintained and should not be used by
anyone in any modern environment, but software is complex and python2
still exists in some modern Linux distributions like Tumbleweed.&lt;/p&gt;
&lt;p&gt;The past week the &lt;a href="https://build.opensuse.org/request/show/1240106"&gt;request to delete Python 2&lt;/a&gt; from Tumbleweed was
created and is going through the staging process.&lt;/p&gt;
&lt;p&gt;The main package keeping Python 2 around for Tumbleweed was Gimp 2,
that doesn't depends directly on Python 2, but some of the plugins
depends on it. Now that we've Gimp 3 in Tumbleweed, we are able to
finally remove it.&lt;/p&gt;
&lt;h2&gt;Python 2&lt;/h2&gt;
&lt;p&gt;The first version of Python 2 was released around 2000, so it's now 25
years old. That's not true, because software is a living creature, so
as you may know, Python 2 grew during the following years with patch
and minor releases until 2020 that was the final release 2.7.18.&lt;/p&gt;
&lt;p&gt;But even when it was maintained until 2020, it was deprecated for a
long time so everyone "should" have time to migrate to python 3.&lt;/p&gt;
&lt;h2&gt;Py3K&lt;/h2&gt;
&lt;p&gt;I started to write python code around the year 2006. I was bored
during a summer internship at my third year of computer science, and I
decided to learn something new. In the following months / years I
heard a lot about the futurist &lt;a href="https://peps.python.org/pep-3000/"&gt;Python 3000&lt;/a&gt;, but I didn't worry too
much until it was officially released and the &lt;a href="https://docs.python.org/3.10/library/2to3.html"&gt;migration&lt;/a&gt; started to be
a thing.&lt;/p&gt;
&lt;p&gt;If you have ever write python2 code you will know about some of the
main differences with python3:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;print vs print()&lt;/li&gt;
&lt;li&gt;raw_input() vs input()&lt;/li&gt;
&lt;li&gt;unicode() vs str&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some tools appeared to make it easier to migrate from python2 to
python3, and even it was possible to have code compatible with both
versions at the same time using the &lt;code&gt;__future__&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;You should have heard about the &lt;a href="https://pypi.org/project/six/"&gt;six&lt;/a&gt; package, 2 * 3 = 6. Maybe the
name should be five instead of six, because it was a Python "2 and 3"
compatibility library.&lt;/p&gt;
&lt;h2&gt;Python in Linux command line&lt;/h2&gt;
&lt;p&gt;When python3 started to be the main python, there were some discussion
about how to handle that in different Linux distributions. The
/usr/bin/python binary was present and everyone expect that to be
python2, so almost everyone decided to keep that relation forever and
distribute python3 as /usr/bin/python3, so you can have both installed
without conflicts and there's no confusion.&lt;/p&gt;
&lt;p&gt;But python is an interpreted language, and if you have python code,
you can't tell if it's python2 or python3. The shebang line in the
executable python scripts should point to the correct interpreter and
that should be enough like &lt;code&gt;#!/usr/bin/python3&lt;/code&gt; will use the python3
interpreter and &lt;code&gt;#!/usr/bin/python&lt;/code&gt; will use python2.&lt;/p&gt;
&lt;p&gt;But this is not always true, some distributions uses python3 in
&lt;code&gt;/usr/bin/python&lt;/code&gt; like Archlinux or if you create a virtualenv with
python3, the &lt;code&gt;python&lt;/code&gt; binary points to the python3 interpreter, so a
shebang like &lt;code&gt;#!/usr/bin/python&lt;/code&gt; could be something valid for a
python3 script.&lt;/p&gt;
&lt;p&gt;In any case, the recommended and safest way is to always use &lt;code&gt;python3&lt;/code&gt;
binary because that way it'll work correctly "everywhere".&lt;/p&gt;
&lt;h2&gt;Goodbye&lt;/h2&gt;
&lt;p&gt;It's time to say goodbye to &lt;code&gt;python2&lt;/code&gt;, at least we can remove it now
from Tumbleweed. It'll be around for some more time in Leap, but it's
the time to let it go.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Mon, 27 Jan 2025 12:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2025-01-27:/python2.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>opensuse</category></item><item><title>Hackweek 24</title><link>https://danigm.net/hackweek24.html</link><description>&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/hackweek24.png" width="50%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;It's the time for a new &lt;a href="https://hackweek.opensuse.org/"&gt;Hack Week&lt;/a&gt;. The Hack Week 24 was from
November 18th to November 22th, and I've decided to join the &lt;a href="https://hackweek.opensuse.org/projects/opensuse-welcome"&gt;New openSUSE-welcome&lt;/a&gt;
project this time.&lt;/p&gt;
&lt;p&gt;The idea of this project is to revisit the existing openSUSE welcome
app, and I've been trying to help here, specifically for the GNOME
desktop installation.&lt;/p&gt;
&lt;h2&gt;openSUSE-welcome&lt;/h2&gt;
&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/opensuse-welcome.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;Right now after installing any openSUSE distribution with a graphical
desktop, the user is welcomed on first login with a &lt;a href="https://github.com/openSUSE/openSUSE-welcome/"&gt;custom welcome app&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This custom application is a Qt/QML with some basic information and
useful links.&lt;/p&gt;
&lt;p&gt;The same generic application is used for all desktops, and for popular
desktops right now exists upstream applications for this purpose, so
we were talking on Monday morning about it and decided to use specific
apps for desktops.&lt;/p&gt;
&lt;p&gt;So for GNOME, we can use the &lt;a href="https://gitlab.gnome.org/GNOME/gnome-tour/"&gt;GNOME Tour&lt;/a&gt; application.&lt;/p&gt;
&lt;h2&gt;gnome-tour&lt;/h2&gt;
&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/gnome-tour.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;GNOME Tour is a simple rust/gtk4 application with some fancy images in
a slideshow.&lt;/p&gt;
&lt;p&gt;This application is generic and just shows information about GNOME
desktop, so I created a &lt;a href="https://github.com/openSUSE/gnome-tour"&gt;fork for openSUSE&lt;/a&gt; to do some openSUSE
specific customization and use this application as openSUSE welcome in
GNOME desktop for Tumbleweed and Leap.&lt;/p&gt;
&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/gnome-tour-opensuse.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;h2&gt;Desktop patterns, the welcome workflow&lt;/h2&gt;
&lt;p&gt;After some testing and investigation about the current workflow for
the welcome app:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://code.opensuse.org/package/patterns-base/blob/master/f/patterns-base.spec#_861"&gt;x11_enhanced&lt;/a&gt; pattern recommends opensuse-welcome app.&lt;/li&gt;
&lt;li&gt;We can add a &lt;code&gt;Recommends: gnome-tour&lt;/code&gt; to the &lt;a href="https://code.opensuse.org/package/patterns-gnome/blob/master/f/patterns-gnome.spec#_240"&gt;gnome pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The application run using &lt;a href="https://specifications.freedesktop.org/autostart-spec/latest/"&gt;xdg autostart&lt;/a&gt;, so gnome-tour package
   should put the file in &lt;code&gt;/etc/xdg/autostart&lt;/code&gt; and set to hidden on
   close.&lt;/li&gt;
&lt;li&gt;In the case of having a system with multiple desktops, we can
   choose the specific welcome app using the &lt;code&gt;OnlyShowIn/NotShowIn&lt;/code&gt;
   &lt;a href="https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html"&gt;config in desktop file&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So I've created a &lt;a href="https://github.com/openSUSE/openSUSE-welcome/pull/43"&gt;draft PR&lt;/a&gt; to do not show the openSUSE-welcome
app in GNOME, and I've also the &lt;a href="https://build.opensuse.org/package/show/home:dgarcia:branches:GNOME:Next/gnome-tour"&gt;gnome-tour fork&lt;/a&gt; in my home OBS
project.&lt;/p&gt;
&lt;p&gt;I've been testing this configuration in Tumbleweed with GNOME, KDE and
XFCE installed and it works as expected. The openSUSE-welcome is shown
in KDE and XFCE and the gnome-tour app is only shown in GNOME.&lt;/p&gt;
&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/gnome-tour-tumbleweed.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;h2&gt;Next steps&lt;/h2&gt;
&lt;p&gt;The next steps to have the GNOME Tour app as default welcome for
openSUSE GNOME installation are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Send forked &lt;code&gt;gnome-tour&lt;/code&gt; package to &lt;code&gt;GNOME:Next&lt;/code&gt; project in OBS.&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;Recommends: gnome-tour&lt;/code&gt; to &lt;code&gt;patterns-gnome&lt;/code&gt; to &lt;code&gt;GNOME:Next&lt;/code&gt; project in OBS.&lt;/li&gt;
&lt;li&gt;Make sure that any other welcome application is &lt;a href="https://github.com/openSUSE/openSUSE-welcome/pull/43"&gt;not shown in GNOME&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Review openQA tests that expect opensuse-welcome and adapt for the
   new application.&lt;/li&gt;
&lt;/ol&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 22 Nov 2024 12:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2024-11-22:/hackweek24.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>opensuse</category><category>hackweek</category></item><item><title>rpmlint: Google Summer of Code 2024</title><link>https://danigm.net/gsoc-2024.html</link><description>&lt;p&gt;I'm glad to say that I'll participate again in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;, as
mentor. This year we will continue the work done during the past year,
as part of the &lt;a href="https://www.opensuse.org/"&gt;openSUSE&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;So this summer I'll be mentoring an intern and we'll continue working
on improving the testing framework of the &lt;a href="https://github.com/openSUSE/mentoring/issues/204"&gt;rpmlint project&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gsoc.png" /&gt;
&lt;/p&gt;

&lt;p&gt;This year we've a better testing framework, thanks to the work done
during the past Summer of Code, by Afrid. So the goal for this year is
to try to modernize existing tests and remove as much files as
possible from &lt;code&gt;test/binary&lt;/code&gt; directory, replacing those with mock
packages defined with python code.&lt;/p&gt;
&lt;p&gt;The selected intern is &lt;a href="https://blog-gsoc-2024.blogspot.com/2024/05/gsoc-improve-test-coverage-in-rpmlint.html"&gt;Luz Marina Montilla Marín&lt;/a&gt;. She has done
some initial work in the rpmlint project, creating the mock packages
for some tests and we've just started with the work to do during the
GSoC program, evaluating the tests that we've right now and planning
were to start.&lt;/p&gt;
&lt;p&gt;She studies at Córdoba, Spain, my hometown. Every year I try to reach
young people at different local universities, here in Andalucía, and
sometimes I'm able to convince some students to participate, like the
&lt;a href="https://danigm.net/gsoc-2020.html"&gt;GSoC 2020&lt;/a&gt;, when Alejandro Dominguez, from Seville, were working
on Fractal. So I'm happy that I'm increasing the number of free
software developers in my local community :D&lt;/p&gt;
&lt;p&gt;I'm sure that she will be able to achieve great things during these
three months, so I'm looking forward to start to code and see how far
can we go.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Thu, 30 May 2024 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2024-05-30:/gsoc-2024.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><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>Hackweek 23</title><link>https://danigm.net/hackweek23.html</link><description>&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/hackweek23.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hackweek.opensuse.org/"&gt;Hack Week&lt;/a&gt; is the time SUSE employees experiment, innovate &amp;amp; learn
interruption-free for a whole week! Across teams or alone, but always without
limits.&lt;/p&gt;
&lt;p&gt;The Hack Week 23 was from November 6th to November 10th, and my project was to
gvie some &lt;a href="https://hackweek.opensuse.org/23/projects/gnome-love"&gt;love to the GNOME Project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before the start of the Hack week I asked in the GNOME devs Matrix channel,
what project needs some help and they gave me some ideas. At the end I decided
to work on the &lt;a href="https://gitlab.gnome.org/GNOME/gnome-calendar/"&gt;GNOME Calendar&lt;/a&gt;, more specifically, improving the test suite
and fixing &lt;a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/1093"&gt;issues related to timezones&lt;/a&gt;, DST, etc.&lt;/p&gt;
&lt;h2&gt;GNOME Calendar&lt;/h2&gt;
&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/gnome-calendar.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;GNOME Calendar is a &lt;a href="https://gtk.org/"&gt;Gtk4 application&lt;/a&gt;, written in C, that heavily uses the
&lt;a href="https://gitlab.gnome.org/GNOME/evolution-data-server"&gt;evolution-data-server&lt;/a&gt; library. It's a desktop calendar application with a
modern user interface that can connect handle local and remote calendars. It's
integrated in the GNOME desktop.&lt;/p&gt;
&lt;p&gt;The current gnome-calendar project has some unit tests, using the &lt;a href="https://docs.gtk.org/glib/testing.html"&gt;GLib testing
framework&lt;/a&gt;. But right now there are just a few tests, so the main goal right
now is to increase the number of tests as much as possible, to detect new
problems and regressions.&lt;/p&gt;
&lt;p&gt;Testing a desktop application is not something easy to do. The unit tests can
check basic operations, structures and methods, but the user interaction and
how it's represented is something hard to test. So the best approach is to try
replicate user interactions and check the outputs.&lt;/p&gt;
&lt;p&gt;A more sophisticated approach could be to start to use the accessibility stack
in tests, so it's possible to verify the UI widgets output without the need of
rendering the app.&lt;/p&gt;
&lt;p&gt;With gnome-calendar there's another point of complexity for tests because it
relies on the evolution-data-server to be running, the app communicates with it
using dbus, so to be able to do more complex tests we should mock the
evolution-data-server and we should create fake data for testing.&lt;/p&gt;
&lt;h2&gt;My contribution&lt;/h2&gt;
&lt;p&gt;By the end of the week I've created four &lt;a href="https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests?scope=all&amp;amp;state=all&amp;amp;author_username=danigm&amp;amp;label_name%5B%5D=Timezones"&gt;Merge requests&lt;/a&gt;, three of them
have been merged now, and I'll continue working on this project in the
following weeks/months.&lt;/p&gt;
&lt;p&gt;I'm happy with the work that I was able to do during this Hack Week. I've
learned a bit about testing with GLib in C, and a lot about the
evolution-data-server, timezones and calendar problems.&lt;/p&gt;
&lt;p&gt;It's just a desktop calendar application, how hard it could be? Have you ever
deal with dates, times and different regions and time zones? It's a nightmare.
There are a lot of edge cases working with dates that can cause problems,
operations with dates in different time zones, changes in dates for daylight
saving, if I've an event created for October 29th 2023 at 2:30 it will happens
two times?&lt;/p&gt;
&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/gnome-calendar-issues.png" width="100%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;A lot of problems could happen and there are a lot of bugs reported for
gnome-calendar related to this kind of issues, so working on this is not
something simple, it requires a lot of edge case testing and that's the plan,
to cover most of them with automated tests, because any small change could lead
to a bug related to time zones that won't be noticed until someone has an
appointment at a very specific time.&lt;/p&gt;
&lt;p&gt;And this week was very productive thanks to the people working on
gnome-calendar. Georges Stavracas reviews my MR very quickly and it was
possible to merge during the week, and Jeff Fortin does a great work with the
issues in gitlab and leading me to most relevant bugs.&lt;/p&gt;
&lt;p&gt;So after a week of going deep into the gnome-calendar source code it could be a
pity to just forget about it, so I'll try to keep the momentum and continue
working on this project, of course, I'll have just a few hours per week, but
any contribution is better than nothing. And maybe for the next summer I can
propose a Google Summer of Code project to get an intern working on this full
time.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Fri, 10 Nov 2023 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2023-11-10:/hackweek23.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>opensuse</category><category>hackweek</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><item><title>rpmlint updates (August 2023)</title><link>https://danigm.net/rpmlint-updates-2023-08-30.html</link><description>&lt;p&gt;We are at the end of the summer and this means that this year Google Summer of
code is ending.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/rpmlint-gitg-gsoc-2023.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The recent changes applied now in the main branch include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove usage of &lt;code&gt;pkg_resource&lt;/code&gt; because it's deprecated.&lt;/li&gt;
&lt;li&gt;Fix elf binary check with ELF files with a prefix.&lt;/li&gt;
&lt;li&gt;New check for python packages with multiple .pyc files for different python
   versions.&lt;/li&gt;
&lt;li&gt;Improve the testing framework (merged the work done during the GSoC 2023)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Summer of Code 2023 updates&lt;/h2&gt;
&lt;p&gt;The summer of code is ending and the work done by &lt;a href="https://github.com/rpm-software-management/rpmlint/pull/1101"&gt;Afrid was good enough to be merged&lt;/a&gt;,
so I merged it the past week.&lt;/p&gt;
&lt;p&gt;I'm really happy with the work done during the GSoC program, now we've a more
simple way to define tests for rpmlint checks mocking the rpm, so it's not
always needed to build a fake rpm binary for each new test. This will make a
lot easier to create simple tests, so I hope that we can increase the code
coverage using this &lt;a href="https://github.com/rpm-software-management/rpmlint/blob/main/test/README.md"&gt;new framework&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During this time Afrid has extended the &lt;code&gt;FakePkg&lt;/code&gt; class, so it's possible now
to define fake metadata and files with fake tags and attributes. It's not
complete and it's not a simple task to replace all the &lt;code&gt;rpm&lt;/code&gt; binaries used for
tests, because the &lt;code&gt;Pkg&lt;/code&gt; class and &lt;code&gt;RPM&lt;/code&gt; tags is a complex thing, but the
current state allow us to replace a lot of them. Afrid has replaced some of the
tests that uses binaries, but in the following months we can continue working
on this and &lt;a href="https://github.com/rpm-software-management/rpmlint/issues/1105"&gt;replace more&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After this work, we can now start to use more the &lt;code&gt;FakePkg&lt;/code&gt; class in tests,
so another task that we can do is to provide some &lt;a href="https://github.com/rpm-software-management/rpmlint/issues/1104"&gt;common fake pkgs&lt;/a&gt; to use
in different tests and new checks, so now it's possible to create fake packages
with dynamic random data, so we can extend tests with fuzz testing and maybe
this will help to improve the tool reliability.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/gsoc.png" /&gt;
&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I've participated as mentor several times now in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;summer of code&lt;/a&gt;, and
&lt;a href="https://www.outreachy.org/"&gt;outreachy&lt;/a&gt;, and almost always was a good experience. With the &lt;a href="https://www.gnome.org/"&gt;gnome foundation&lt;/a&gt;
in previous programs and this year with &lt;a href="https://www.opensuse.org/"&gt;opensuse&lt;/a&gt;. These two communities
are very open to collaboration and makes the whole process really simple, for
me as mentor, and also for the intern.&lt;/p&gt;
&lt;p&gt;I want to congratulate Afrid, because it was nice to work with him during this
summer, he has done a great work, not just technically, but communicating,
asking and finding his own solutions without requiring a continuous guidance.&lt;/p&gt;
&lt;p&gt;He is very passionate and looks like a nice person, so I hope that he will
continue around the open source, it could be opensuse, rpmlint or any other
community, but this kind of people is what you want to find in any community.&lt;/p&gt;
&lt;p&gt;After many years collaborating with different free software communities, it's
amazing that there are so many great people in every project, of course you can
find toxic communities and people, but in my experience, that's usually just
noise, there are a lot of nice people out there, doing a great work, and I'm
happy that young people like Afrid can be part of the free software movement,
because this is what makes the free software great, the people that is
working on it.&lt;/p&gt;
&lt;p&gt;So Thanks a lot to Google for another summer of code, thanks to SUSE for
letting me, and encourage me, to mentor, and thanks to all the free software
developers that are out there.&lt;/p&gt;
&lt;p&gt;I encourage everyone to participate in this kind of programs, for interns, it's
a good opportunity to learn and to make some money working on free software,
for mentors it's an opportunity to get some help in your project and help
newcomers to be part of the community.&lt;/p&gt;
&lt;p&gt;Have a lot of fun!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Wed, 30 Aug 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-08-30:/rpmlint-updates-2023-08-30.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><item><title>Python in openSUSE Tumbleweed</title><link>https://danigm.net/python-tw.html</link><description>&lt;p&gt;&lt;a href="https://www.opensuse.org/#Tumbleweed"&gt;openSUSE Tumbleweed&lt;/a&gt; is a rolling release distribution, so it's
ideal for developers and users that like to have the bleeding edge
software.&lt;/p&gt;
&lt;p&gt;It's also really "stable" to be a rolling release, from time
to time you can find a broken package because of one package is
updated and another one is not compatible yet, but it's something that
doesn't happen too often thanks to &lt;a href="https://openqa.opensuse.org/group_overview/1"&gt;openqa tests&lt;/a&gt;, so you don't
need to worry about a breaking system.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/python-tw.png" /&gt;
&lt;/p&gt;

&lt;p&gt;You can find the &lt;a href="https://www.python.org/"&gt;Python interpreter&lt;/a&gt; and a lot of &lt;a href="https://pypi.org/"&gt;python modules&lt;/a&gt;
in every Linux distribution, but Tumbleweed does an interesting thing
for Python.&lt;/p&gt;
&lt;h2&gt;Default Python version (python3 -&amp;gt; python-3.11)&lt;/h2&gt;
&lt;p&gt;If you don't worry about the python version, you can just rely on
&lt;code&gt;python3&lt;/code&gt;. In Tumbleweed &lt;code&gt;python3&lt;/code&gt; is not a real package, but the
default python version provides &lt;code&gt;python3&lt;/code&gt;, so depending on when you
install &lt;code&gt;python3&lt;/code&gt; you will get a different package, if you install
it today (August 2023) you'll get &lt;code&gt;python311&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In your system you'll have the &lt;code&gt;/usr/bin/python3&lt;/code&gt; binary that points
to the default python, so you don't need to worry about the current
version, you'll have there the default Python version for the
operating system.&lt;/p&gt;
&lt;p&gt;In addition to the Python interpreter, you can find in the
distribution a lot of python modules, but again you can use the
default version, so, for example, if you want to install &lt;code&gt;poetry&lt;/code&gt;, you
just use &lt;code&gt;zypper install python3-poetry&lt;/code&gt; and that will install
the real package &lt;code&gt;python311-poetry&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Multiple python versions (3.8, 3.9, 3.10, 3.11)&lt;/h2&gt;
&lt;p&gt;Besides the default Python, in Tumbleweed you can also find other
supported Python interpreters. Right now you can find all the Python
versions currently supported by the Python Foundation, from 3.8 to
3.11.&lt;/p&gt;
&lt;p&gt;For Python 3.8 you'll only find the interpreter, because the python
modules are not built anymore, but for all the other versions you can
find almost the same modules.&lt;/p&gt;
&lt;p&gt;All python modules that provide binaries uses the
&lt;code&gt;update-alternatives&lt;/code&gt;, so you can configure in your system the version
that you want to use as default. For example, if you want to use the
&lt;code&gt;3.9&lt;/code&gt; version of &lt;code&gt;poetry&lt;/code&gt;, having installed different versions you can
decide what &lt;code&gt;/usr/bin/poetry&lt;/code&gt; points to:&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;sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python311-poetry&lt;span class="w"&gt; &lt;/span&gt;python39-poetry
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;update-alternatives&lt;span class="w"&gt; &lt;/span&gt;--config&lt;span class="w"&gt; &lt;/span&gt;poetry
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;/usr/bin/python3&lt;/code&gt; is a link provided by the default python package,
so you can't modify with &lt;code&gt;update-alternatives&lt;/code&gt;, so if you want to use
a different python version, make sure to do the correct call with the
full name &lt;code&gt;python3.9&lt;/code&gt;, and use the correct shebang in your python
scripts, for example &lt;code&gt;#!/usr/bin/env python3.9&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;What happens when default changes?&lt;/h2&gt;
&lt;p&gt;This way of distributing Python interpreter and modules is useful,
because you don't need to update your software to work with the latest
Python version, if your software requires another version, you can just
install and continue using it, even on a bleeding-edge distribution
like Tumbleweed.&lt;/p&gt;
&lt;p&gt;But this method has some problems. When the default Python interpreter
is changed in the distribution, all packages that depends on &lt;code&gt;python3&lt;/code&gt;
will be updated, and that works correctly. But if you have installed
some python module using the &lt;code&gt;python3&lt;/code&gt; prefix, that package, and all
dependencies, is not updated automatically.&lt;/p&gt;
&lt;p&gt;For example, if you installed &lt;code&gt;python3-poetry&lt;/code&gt; when &lt;code&gt;python3.10&lt;/code&gt; was
the default system, and then the distribution updates the system
Python to &lt;code&gt;python3.11&lt;/code&gt;, you don't get the &lt;code&gt;python311-poetry&lt;/code&gt; package
by default, you'll need to install it again. This could break you
software, because if you use &lt;code&gt;python3&lt;/code&gt; and the dependencies are not
updated, you'll find that some dependencies are not installed after
updating.&lt;/p&gt;
&lt;p&gt;For that reason, when the default python is changed in Tumbleweed, if
you've software that rely on &lt;code&gt;python3&lt;/code&gt; you should make sure to install
dependencies again by hand. And also you can do a cleanup and remove
all old version packages that you don't need anymore.&lt;/p&gt;
&lt;p&gt;If you just want the latest version you can just do all at once with a
simple script like this:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c1"&gt;# up-py-tw.sh&lt;/span&gt;

&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;

&lt;span class="k"&gt;if&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="nv"&gt;$#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-lt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Usage:   up-py-tw.sh FROM TO&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;example: up-py-tw.sh 310 311&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Updating python packages from &lt;/span&gt;&lt;span class="nv"&gt;$FROM&lt;/span&gt;&lt;span class="s2"&gt; to &lt;/span&gt;&lt;span class="nv"&gt;$TO&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="nv"&gt;OLDP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;search&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="si"&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;tail&lt;span class="w"&gt; &lt;/span&gt;--lines&lt;span class="w"&gt; &lt;/span&gt;+4&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;--delimiter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--fields&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;NEWP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OLDP&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;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s/python&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;FROM&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/python&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TO&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/g&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;

sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$NEWP&lt;/span&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OLDP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should verify what will be installed and what will be removed to
make sure that just the python related packages are removed. It's
possible that other packages depend on a python version that's older
than the system one and that's okay.&lt;/p&gt;
&lt;h2&gt;Beta version (3.12.0b4)&lt;/h2&gt;
&lt;p&gt;In Tumbleweed, right now you can find all the supported Python
versions, but it's not just that. At this moment you can also find the
beta version of the next Python interpreter.&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;sudo&lt;span class="w"&gt; &lt;/span&gt;zypper&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;python312
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So if you are adventurous and want to test some new feature in the
next Python release, you can do it with the version provided there.
This version could also be used by openSUSE packagers to test the
packages before the Python version is released so it allow us to
prepare everything for the release and it could be in the distribution
earlier and more tested.&lt;/p&gt;
&lt;h2&gt;Development&lt;/h2&gt;
&lt;p&gt;All this multiple python versions is done at distribution level and
usually there's only one source package that produces the
&lt;code&gt;python39-foo&lt;/code&gt;, &lt;code&gt;python310-foo&lt;/code&gt; and &lt;code&gt;python311-foo&lt;/code&gt;. The source
package is usually called &lt;code&gt;python-foo&lt;/code&gt; and can be found in the
&lt;a href="https://build.opensuse.org/project/show/devel:languages:python"&gt;Python devel project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These packages spec uses the python-rpm-macros to generate all the
versions from one source. If you're a packager you can find more
information on the openSUSE wiki about &lt;a href="https://en.opensuse.org/openSUSE:Packaging_Python"&gt;Python Packaging&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sat, 05 Aug 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-08-05:/python-tw.html</guid><category>blog</category><category>software</category><category>suse</category><category>tumbleweed</category><category>gnome</category></item><item><title>rpmlint updates (July 2023)</title><link>https://danigm.net/rpmlint-updates.html</link><description>&lt;p&gt;I'm spending some time every week working in the &lt;a href="https://github.com/rpm-software-management/rpmlint"&gt;rpmlint&lt;/a&gt; project.
The tool is very stable and the functionality is well defined,
implemented and tested, so there's no crazy development or a lot of
new functionalities, but as in all the software, there are always bugs
to solve and things to improve.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/rpmlint-gitg-20230706.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The recent changes applied now in the main branch include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Update the usage of &lt;code&gt;rpm&lt;/code&gt; to not use old API.&lt;/li&gt;
&lt;li&gt;Fixes for &lt;code&gt;rpmdiff -v&lt;/code&gt;, check for NULL char, special macros in
   comments and spell checking of description in different languages.&lt;/li&gt;
&lt;li&gt;Move all the metadata from &lt;code&gt;setup.py&lt;/code&gt; to &lt;code&gt;pyproject.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Releasing rpmlint as pre-commit hook&lt;/li&gt;
&lt;li&gt;Improvements to the PythonCheck in the dependency checking.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Summer of Code 2023 updates&lt;/h2&gt;
&lt;p&gt;The first month of the Summer of Code has passed and &lt;a href="https://afridhussain.tech"&gt;Afrid&lt;/a&gt; is
doing a great job there. We've now a &lt;a href="https://github.com/rpm-software-management/rpmlint/pull/1079"&gt;draft Pull Request&lt;/a&gt; with some
initial changes that allow us to mock &lt;code&gt;rpm&lt;/code&gt; packages in tests so it's
easier to create new tests without the need of creating a binary
package.&lt;/p&gt;
&lt;p&gt;The first step done was to extend the existing &lt;code&gt;FakePkg&lt;/code&gt; class to
allow us to define package files and some package metadata.&lt;/p&gt;
&lt;p&gt;Now he's working in replacing all of the &lt;code&gt;test_python.py&lt;/code&gt; tests that
uses binaries &lt;code&gt;rpm&lt;/code&gt; to something that doesn't needed.&lt;/p&gt;
&lt;p&gt;The idea is to replace as much tests as possible to reduce the number
of rpm binaries and after that, provide helper functions, decorators
and classes to make it easy to write tests, writing less code.&lt;/p&gt;
&lt;h2&gt;Roadmap&lt;/h2&gt;
&lt;p&gt;In any software project there's always room for improvements, fixes
and enhancements. If the project is there for enough time, it's even
more critical to modernize the code to reduce the technical debt.&lt;/p&gt;
&lt;p&gt;My plan for 2023 is to improve the tests around rpmlint as much as
possible. First with the GSoC project, making it easier to write more
tests, improving the testing tools that we've. And after the summer,
improving the test coverage.&lt;/p&gt;
&lt;p&gt;There's also a tool that shares some of the ideas with rpmlint,
&lt;a href="https://github.com/rpm-software-management/spec-cleaner"&gt;spec-cleaner&lt;/a&gt;, it's also written in Python, so the next step,
after the tests improvements will be to take a deep look into the code
of these two tools and try to integrate in some way. Maybe it's
possible to refactor the common code into an external module, maybe we
can bring some ideas from spec-cleaner to rpmlint. Not sure yet, but
that'll be my next step.&lt;/p&gt;
&lt;p&gt;Don't forget that this is free software, so you can participate too!
If you find any issue in rpmlint or have an idea to improve it, don't
hesitate and &lt;a href="https://github.com/rpm-software-management/rpmlint/issues"&gt;create a new issue&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Thu, 06 Jul 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-07-06:/rpmlint-updates.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><item><title>rpmlint: Google Summer of Code 2023</title><link>https://danigm.net/gsoc-2023.html</link><description>&lt;p&gt;I'm glad to say that I'll participate again in the &lt;a href="https://summerofcode.withgoogle.com/"&gt;GSoC&lt;/a&gt;, as
mentor. This year will be a bit different from the previous ones,
because I'm not mentoring a GNOME project but a &lt;a href="https://www.opensuse.org/"&gt;openSUSE&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;I started to work at SUSE the past year and with this new job I get
involved in the openSUSE community and I started to contribute to
&lt;a href="https://github.com/rpm-software-management/rpmlint"&gt;rpmlint&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So this summer I'll be mentoring an intern and we'll work on improving
the testing framework of the &lt;a href="https://github.com/openSUSE/mentoring/issues/189"&gt;rpmlint project&lt;/a&gt;.&lt;/p&gt;
&lt;p class="img"&gt;
  &lt;img src="/pictures/rpmlint.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The rpmlint project is a command line tool to check rpm packages, the
correctness of these kind of packages and warn the packagers about
usual problems or good practices. It's widely used in all Linux
distributions based on rpm, mainly SUSE and RedHat.&lt;/p&gt;
&lt;p&gt;It is written in Python and uses pytest for testing the code. Right
now there are a lot of .rpm binary packages, to check different
functionality, but that way of testing makes a bit hard to write new
tests and to maintain with changes. The idea of this GSoC project is
to extend the testing framework of rpmlint to support an easy way
of writting tests that doesn't require a real rpm, something that can
mock what it's in the .rpm binary and try to replace some of the
current binary tests with this new mock.&lt;/p&gt;
&lt;p&gt;The selected intern is &lt;a href="https://afridhussain.tech/post/accepted-into-gsoc/"&gt;Afrid Hussain&lt;/a&gt;. He has done some initial
work in the rpmlint project, solving some minor issues and we're now
preparing the work to be done during the GSoC program. I'm sure that
he will be able to achieve great things during these three months, so
I'm looking forward to start to code and see how far can we go.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Tue, 16 May 2023 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2023-05-16:/gsoc-2023.html</guid><category>blog</category><category>gnome</category><category>software</category><category>rpmlint</category><category>suse</category><category>gsoc</category></item><item><title>Hackweek 2023</title><link>https://danigm.net/hackweek22.html</link><description>&lt;p&gt;&lt;center&gt;
    &lt;img src="/pictures/hackweek.png" width="50%"/&gt;
&lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hackweek.opensuse.org/"&gt;Hack Week&lt;/a&gt; is the time SUSE employees experiment, innovate &amp;amp; learn
interruption-free for a whole week! Across teams or alone, but always without
limits.&lt;/p&gt;
&lt;p&gt;This year the Hack Week was this week, the last week of January and for my
first SUSE hack week I decided to work in something funny, &lt;a href="https://hackweek.opensuse.org/22/projects/linux-immersive-learning-system-lils"&gt;LILS&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Linux Immersive Learning System (LILS)&lt;/h2&gt;
&lt;p&gt;I don't think that this is a good name, but don't focus on it. The main idea of
this project is to create some basic machinery to be able to write
"interactive" tutorials or games using the &lt;a href="https://www.inklestudios.com/ink/"&gt;INK language&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is not an original idea, indeed all I've done is something that's
currently working on &lt;a href="https://www.endlessos.org/"&gt;EndlessOS&lt;/a&gt;, and was the main idea behind the dead
project &lt;a href="https://www.hack-computer.com/"&gt;Hack Computer&lt;/a&gt;, you can even take a look to the
&lt;a href="https://flathub.org/apps/details/com.hack_computer.Clubhouse"&gt;Hack app in flathub&lt;/a&gt;. But I wanted to work around this, and create
something simpler, from scratch.&lt;/p&gt;
&lt;p&gt;I wanted to build something simple, with just Python, and make it simple enough
to be able to build other tools on top. The design is simple, an INK parser,
with a simple game runner. In the INK script you can define &lt;em&gt;commands&lt;/em&gt;, to do
something special, and wait for events with &lt;em&gt;listeners&lt;/em&gt;, to wait for an event
in the OS to continue.&lt;/p&gt;
&lt;p&gt;With this basic functionality it's possible to build different user interfaces
for different environments. And the original idea was to make the &lt;em&gt;commands&lt;/em&gt;
and &lt;em&gt;listeners&lt;/em&gt; something extensible with a simple API, but that's something
that I have not done yet, it's all Python functions without extension point.&lt;/p&gt;
&lt;p&gt;The code can be found in &lt;a href="https://github.com/danigm/lils"&gt;github&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;The INK parser&lt;/h2&gt;
&lt;p class="img"&gt;
    &lt;img src="/pictures/inky.png" /&gt;
&lt;/p&gt;

&lt;p&gt;The most complex part of this project is the INK language parser. The &lt;a href="https://github.com/inkle/ink"&gt;Ink&lt;/a&gt;
parser is free software and there's a Linux version that you can use to parse
and &lt;strong&gt;compile&lt;/strong&gt; to &lt;em&gt;json&lt;/em&gt;, but I wanted to create my own parser with Python.&lt;/p&gt;
&lt;p&gt;I've spent most of the Hack Week time fighting with the parser and indeed was
the most challenging and fun part, because I've not worked a lot with parsers
and it's not something easy as pie 😛️.&lt;/p&gt;
&lt;p&gt;I remember creating a java compiler long time ago, when I was in the Seville
University, for the Language Processors course. We did that with &lt;a href="https://www.antlr.org/"&gt;ANTLR&lt;/a&gt;, so
starting from that, and looking for a Python lib, I found the &lt;a href="https://github.com/lark-parser/lark"&gt;Lark&lt;/a&gt;
project. So if you like regular expressions, writing a grammar is a lot more
FUN.&lt;/p&gt;
&lt;p&gt;At the end I was able to support some basic INK language with support for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;li&gt;Tag support&lt;/li&gt;
&lt;li&gt;Options, with suppress text support&lt;/li&gt;
&lt;li&gt;Knots, Stitches and Diverts&lt;/li&gt;
&lt;li&gt;Include other .ink files&lt;/li&gt;
&lt;li&gt;Variable definition and basic operations&lt;/li&gt;
&lt;li&gt;Knots and Stitches automatic visiting count variables&lt;/li&gt;
&lt;li&gt;Conditional options using variables&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It still fails in some cases, the comments and &lt;em&gt;TODO&lt;/em&gt; placed in between text is
not detected correctly and there's a lot of complex stuff that's not supported
yet, but with what's supported right now it's possible to create complex
scripts with loops and complex game graphs, so it's good enough to build games
just with it.&lt;/p&gt;
&lt;h2&gt;GNOME shell extension&lt;/h2&gt;
&lt;p class="img"&gt;
    &lt;video src="/pictures/lils.mp4" width="100%" autoplay controls loop /&gt;
&lt;/p&gt;

&lt;p&gt;To integrate with the system I've done a simple &lt;a href="https://github.com/danigm/lils/tree/master/lils%40danigm.net"&gt;GNOME shell extension&lt;/a&gt;.
The extension just shows the text as bubbles and options as buttons, it's
really simple and I've no time to make it something ready to be used, but
I was able to make something usable.&lt;/p&gt;
&lt;p&gt;To be able to run the &lt;em&gt;LILS&lt;/em&gt; python library from &lt;em&gt;gjs&lt;/em&gt; I've created a simple
&lt;em&gt;dbus&lt;/em&gt; service that exposes the basic &lt;em&gt;InkScript&lt;/em&gt; class functionality as a dbus
API.&lt;/p&gt;
&lt;p&gt;I was thinking about being able to change the desktop background, depending of
the value of a &lt;em&gt;background&lt;/em&gt; variable in the script and do something similar to
play music and sounds, so it could be a cool &lt;em&gt;game engine&lt;/em&gt; with some additions.&lt;/p&gt;
&lt;h2&gt;SUSE Hack Week&lt;/h2&gt;
&lt;p&gt;So this Hack week was really fun and I learned a lot. It's really great that
SUSE does things like this, letting us work in different projects for a week,
to learn, to grow or to just explore different paths.&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/IxscORgeqOY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen&gt;&lt;/iframe&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Tue, 03 Jan 2023 00:00:00 +0100</pubDate><guid isPermaLink="false">tag:danigm.net,2023-01-03:/hackweek22.html</guid><category>blog</category><category>gnome</category><category>work</category><category>suse</category><category>ink</category><category>python</category></item><item><title>SUSE is my new distribution (new job)</title><link>https://danigm.net/suse.html</link><description>&lt;p class="img"&gt;
    &lt;a target="_blank" href="https://suse.com"&gt;
        &lt;img src="/pictures/Poster-Always-Changing.png" /&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This week I've started to work at &lt;a href="https://suse.com/"&gt;SUSE&lt;/a&gt;. I'll be working as Python
Specialist, in the packaging team, so I will go back to work on packaging and
distribution after more than ten years. My first job in 2008 was working on a
Ubuntu based local distribution, &lt;a href="https://en.wikipedia.org/wiki/Guadalinex"&gt;Guadalinex&lt;/a&gt;, so packaging and distribution
work is not something new for me.&lt;/p&gt;
&lt;h2&gt;Python&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.python.org/"&gt;Python&lt;/a&gt; was the first language that I fell in love. I learned to write code
with C and C++, but when I discovered Python, in 2006, I found a really nice
language to be able to create amazing things really fast and with a great
community behind.&lt;/p&gt;
&lt;p&gt;I'm very happy for this new opportunity to be able to collaborate to the Python
distribution in all the SUSE flavours, and also to be able to collaborate in
the creation of one of the most famous and used Linux distributions.&lt;/p&gt;
&lt;h2&gt;Tumbleweed&lt;/h2&gt;
&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;As part of this job change I've also installed &lt;a href="https://www.opensuse.org/#Tumbleweed"&gt;SUSE Tumbleweed&lt;/a&gt; for the
first time. Tumbleweed is a rolling release distribution with the latests
packages. In the past I was using other rolling releases distributions like
Arch, but this one looks more user friendly.&lt;/p&gt;
&lt;p&gt;I've not spent a lot of time here, but from the point of view of a GNOME
developer, I can say that it's a great distribution for development with
updated packages, and it looks "stable". You can choose the desktop to use on
installation and the GNOME desktop is there without any customization that I've
detected, so it looks like it's a good vanilla GNOME desktop distribution.&lt;/p&gt;
&lt;h2&gt;Endless, it's not the end&lt;/h2&gt;
&lt;p class="img"&gt;
    &lt;a target="_blank" href="https://endlessos.org"&gt;
        &lt;img src="/pictures/endless-farewell.jpg" /&gt;
    &lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;I'm not working for &lt;a href="https://endlessos.org"&gt;EndlessOS&lt;/a&gt; now, but it's not the end. I've been working
here for almost 4 years. At first I worked on the &lt;a href="https://hack-computer.com/"&gt;Hack Computer&lt;/a&gt; and after
that project didn't work, I was working on the &lt;a href="https://www.endlessos.org/key"&gt;Endless Key&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;During this time I've also collaborated a bit with the EndlessOS distribution,
and I can say that's a really nice distribution to use, the ostree usage for
the whole filesystem is a great idea, and the amount of content that comes with
the installation is really good.&lt;/p&gt;
&lt;p&gt;The EndlessOS Foundation Goal is to reduce the digital divide, providing
content and tools for offline people, centered on kids. This is a great mission
and in the future, if I find the opportunity to help my local community, I'll
try to use the EndlessOS tools and content to provide good learning content for
kids without online access.&lt;/p&gt;
&lt;p&gt;I was very happy these years at Endless, and I've learned a lot from different
great people. It's incredible the number of talented software engineers that
are related to Endless, and for me it was a real privilege to be able to share
this space and mission for a few years.&lt;/p&gt;
&lt;h2&gt;The future!&lt;/h2&gt;
&lt;p&gt;So there we go, I'm exited for this change, and also sad about leaving a great
project, but life is change and we should go ahead and think about the future!
And my future is green now.&lt;/p&gt;
&lt;p&gt;And if you don't know how to pronounce it, here you've a music video:&lt;/p&gt;
&lt;iframe width="560" height="315" src="https://www.youtube.com/embed/nLdexZlVkAY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">danigm</dc:creator><pubDate>Sun, 18 Sep 2022 00:00:00 +0200</pubDate><guid isPermaLink="false">tag:danigm.net,2022-09-18:/suse.html</guid><category>blog</category><category>gnome</category><category>work</category><category>endless</category><category>suse</category></item></channel></rss>