Feeds

Guido Günther: Free Software Activities November 2024

Planet Debian - 2 hours 29 min ago

Another short status update of what happened on my side last month. The larger blocks are the Phosh 0.43 release, the initial file chooser portal, phosh-osk-stub now handling digit, number, phone and PIN input purpose via special layouts as well as Phoc mostly catching up with wlroots 0.18 and the current development version targeting 0.19.

phosh
  • When taking a screenshot via keybinding or power button long press save screenshots to clipboard and disk (MR)
  • Robustify Screenshot CI job (MR)
  • Update CI pipeline (MR)
  • Fix notifications banners that aren't tall enough not being shown (MR). Another 4y old bug hopefully out of the way.
  • Add rfkill mock and docs (MR). Useful for HKS testing.
  • Release 0.43~rc1 and 0.43
  • Drop libsoup workaround (MR)
  • Ensure notification only takes its actual height (MR)
phoc
  • Move wlroots 0.18 update forward (MR). Needs a bit more work before we can make it default.
  • Catch up with wlroots development branch (MR) allowing us to test current wlroots again.
  • Some of the above already applies to main so schedule it for 0.44 (MR)
phosh-mobile-settings
  • Don't mark release notes as translatable to save some i18n effort (MR)
  • Release 0.43~rc1 and 0.43.0
libphosh-rs phosh-osk-stub
  • Add layouts for PIN, number and phone input purpose (MR)
  • Release 0.43~rc1
  • Ensure translation get picked up, various cleanups and release 0.43.0 (MR)
  • Make desktop file match app-id (MR)
phosh-tour
  • Fix typo and reduce number of strings to translate (MR)
  • Add translator comments (MR). This, the above and additional fixes in p-m-s were prompted by i18n feedback from Alexandre Franke, thanks a lot!
  • Release 0.43.0
pfs
  • Initial version of the adaptive file chooser dialog using gtk-rs. See demo.
  • Allow to activate via double click (for non-touch use) (MR)
xdg-desktop-portal-phosh
  • Use pfs to provide a file chooser portal (MR)
meta-phosh
  • Slightly improve point release handling (MR)
  • Improve string freeze announcements and add phosh-tour (MR)
Debian
  • Upload Phosh 0.43.0~rc1 and 0.43.0 (MR, MR, MR, MR, MR, MR, MR, MR, MR, MR, MR)
  • meta-phosh: Add Recommend: for xdg-desktop-portal-phosh (MR)
  • phosh-osk-data got accepted, create repo, brush up packaging and upload to unstable (MR
  • phosh-osk-stub: Recommend data packager (MR
  • Phosh: drop reverts (MR)
  • varnam-schemes: Fix autopkgtest (MR)
  • varnam-schemes: Improve packaging (MR)
  • Prepare govarnam 1.9.1 (MR)
Calls
  • ussd: Set input purpose and switch to AdwDialog (MR, Screenshot)
libcall-ui
  • Drop libhandy leftover (MR)
git-buildpackage
  • Improve docs and cleanup markdown (MR)
  • Mention gbp push in intro (MR)
  • Use application instead of productname entities to improve reading flow (MR)
wlroots
  • Drop mention of wlr_renderer_begin_with_buffer (MR)
python-dbusmock
  • Add mock for gsd-rfkill (MR)
xdg-spec
  • Sync notification categories with the portal spec (MR)
  • Add categories for SMS (MR)
  • Add a pubdate so it's clear the specs aren't stale (MR) (got fixed in a different and better way, thanks Matthias!)
ashpd
  • Allow to set filters in file chooser portal demo (MR)
govarnam
  • Robustify file generation (MR)
varnam-schemes
  • Unbreak tests on non intel/amd architectures (e.g. arm64) (MR)
Reviews

This is not code by me but reviews I did on other peoples code. The list is incomplete, but I hope to improve on this in the upcoming months. Thanks for the contributions!

  • flathub: livi runtime and gst update (MR)
  • phosh: Split linters into their own test suite (MR)
  • phosh; QuickSettings follow-up (MR)
  • phosh: Accent color fixes (MR)
  • phosh: Notification animation (MR)
  • phosh: end-session dialog timeout fix (MR)
  • phosh: search daemon (MR)
  • phosh-ev: Migrate to newer gtk-rs and async_channel (MR)
  • phosh-mobile-settings: Update gmobile (MR)
  • phosh-mobile-settings: Make panel-switcher scrollable (MR)
  • phosh-mobile-settings: i18n comments (MR)
  • gbp doc updates (MR)
  • gbp handle suite names with number prefix (MR)
  • Debian libvirt dependency changes (MR
  • Chatty: misc improvements (MR
  • iio-sensor-proxy: buffer driver without trigger (MR)
  • gbp doc improvements (MR)
  • gbp: More doc improvements (MR)
  • gbp: Clean on failure (MR)
  • gbp: DEP naming consistency (MR)
Help Development

If you want to support my work see donations. This includes a list of hardware we want to improve support for. Thanks a lot to all current and past donors.

Comments?

Join the Fediverse thread

Categories: FLOSS Project Planets

Colin Watson: Free software activity in November 2024

Planet Debian - 6 hours 23 min ago

Most of my Debian contributions this month were sponsored by Freexian.

You can also support my work directly via Liberapay.

Conferences

I attended MiniDebConf Toulouse 2024, and the MiniDebCamp before it. Most of my time was spent with the Freexian folks working on debusine; Stefano gave a talk about its current status with a live demo (frantically fixed up over the previous couple of days, as is traditional) and with me and others helping to answer questions at the end. I also caught up with some people I haven’t seen in ages, ate a variety of delicious cheeses, and generally had a good time. Many thanks to the organizers and sponsors!

After the conference, Freexian collaborators spent a day and a half doing some planning for next year, and then went for an afternoon visiting the Cité de l’espace.

Rust team

I upgraded these packages to new upstream versions, as part of upgrading pydantic and rpds-py:

  • rust-archery
  • rust-jiter (noticing an upstream test bug in the process)
  • rust-pyo3 (fixing CVE-2024-9979)
  • rust-pyo3-build-config
  • rust-pyo3-ffi
  • rust-pyo3-macros
  • rust-pyo3-macros-backend
  • rust-regex
  • rust-regex-automata
  • rust-regex
  • rust-serde
  • rust-serde-derive
  • rust-serde-json
  • rust-speedate
  • rust-triomphe
Python team

Last month, I mentioned that we still need to work out what to do about the multipart vs. python-multipart name conflict in Debian (#1085728). We eventually managed to come up with an agreed plan; Sandro has uploaded a renamed binary package to experimental, and I’ve begun work on converting reverse-dependencies (asgi-csrf, fastapi, python-curies, and starlette done so far). There’s a bit more still to do, but I expect we can finish it soon.

I fixed problems related to adding Python 3.13 support in:

I fixed some packaging problems that resulted in failures any time we add a new Python version to Debian:

I fixed other build/autopkgtest failures in:

I packaged python-quart-trio, needed for a new upstream version of python-urllib3, and contributed a small packaging tweak upstream.

I backported a twisted fix that caused problems in other packages, including breaking debusine‘s tests.

I disentangled some upstream version confusion in python-catalogue, and upgraded to the current upstream version.

I upgraded these packages to new upstream versions:

Other small fixes

I contributed Incus support to needrestart upstream.

In response to Helmut’s Cross building talk at MiniDebConf Toulouse, I fixed libfilter-perl to support cross-building (5b4c2e10, f9788c27).

I applied a patch to move aliased files from / to /usr in iprutils (#1087733).

I adjusted debconf to use the new /usr/lib/apt/apt-extracttemplates path (#1087523).

I upgraded putty to 0.82.

Categories: FLOSS Project Planets

gettext @ Savannah: GNU gettext 0.23 released

GNU Planet! - 7 hours 20 min ago

Download from https://ftp.gnu.org/pub/gnu/gettext/gettext-0.23.tar.gz

New in this release:

  • Internationalized data formats:
    • XML:
      • The escaping of characters such as & < > has been changed:
        • No escaping is done any more by xgettext, when creating a POT file.
        • Instead, extra escaping can be requested for the msgfmt pass, when merging into an XML file.
        • The default value of 'escape' in the <gt:escapeRule> was "yes"; now it is "no".
      • This means that existing translations of older POT files may no longer fully apply. As a maintainer of a package that has translatable XML files, you need to regenerate the POT file and pass it on to your translators.
      • XML schemas for .its and .loc files are now provided.
      • The value of the xml:lang attribute, inserted by msgfmt, now conforms to W3C standards.
      • 'msgfmt --xml' accept an option --replace-text, that causes the output to be a mono-lingual XML file instead of a multi-lingual XML file.
      • xgettext and 'msgfmt --xml' now support DocBook XML files.
    • Desktop: xgettext now produces POT files with correct line numbers.


  • Programming languages support:
    • Python:
      • xgettext now assumes source code for Python 3 rather than Python 2. This affects the interpretation of escape sequences in string literals.
      • xgettext now recognizes the f-string syntax.
    • Scheme:
      • xgettext now supports the option '-L Guile' as an alternative to '-L Scheme'.  They are nearly equivalent.  They differ in the interpretation of escape sequences in string literals: While 'xgettext -L Scheme' assumes the R6RS and R7RS syntax of string literals, 'xgettext -L Guile' assumes the syntax of string literals understood by Guile 2.x and 3.0 (without command-line option '--r6rs' or '--r7rs', and before a '#!r6rs' directive is seen).
      • xgettext now recognizes comments of the form '#; <expression>'.
    • Java: xgettext now has an improved recognition of format strings when the String.formatted method is used.
    • JavaScript:
      • xgettext now parses template literals inside JSX correctly.
    • xgettext has a new option --tag that customizes the behaviour of tagged template literals.
    • C#:
      • The build system and tools now also support 'dotnet' (.NET) as C# implementation.  In order to declare a preference for 'dotnet' over 'mono', you can use the configure option '--enable-csharp=dotnet'.
      • xgettext now recognizes strings with embedded expressions (a.k.a. interpolated strings).
    • awk: xgettext now recognizes string concatenation by juxtaposition.
    • Smalltalk: xgettext now recognizes the string concatenation operator ','.
    • Vala: xgettext now has an improved recognition of format strings when the string.printf method is used.
    • Glade: xgettext has improved support for GtkBuilder 4.
    • Tcl: With the recently released Tcl 9.0, characters outside the Unicode BMP in Tcl message catalogs (.msg files) will work regardless of the locale's encoding.
    • Perl:
      • xgettext now reports warnings instead of fatal errors.
      • xgettext now recognizes strings with embedded expressions (a.k.a. interpolated strings).
    • PHP:
      • xgettext now recognizes strings with embedded expressions.
      • xgettext now scans Heredoc and Nowdoc strings correctly.
      • xgettext now regards the format string directives %E, %F, %g, %G, %h, %H as valid.


  • Runtime behaviour:
    • In the C.UTF-8 locale, like in the C locale, the *gettext() functions now return the msgid untranslated. This is relevant for GNU systems, Linux with musl libc, FreeBSD, NetBSD, OpenBSD, Cygwin, and Android.


  • Documentation:
    • The section "Preparing Strings" now gives more advice how to deal with string concatenation and strings with embedded expressions.


  • xgettext:
    • Most of the diagnostics emitted by xgettext are now labelled as "warning" or "error".


  • msgmerge:
    • The option '--sorted-output' is now deprecated.


  • libgettextpo library:
    • This library is now multithread-safe.
    • The function 'po_message_set_format' now supports resetting a format string mark.
Categories: FLOSS Project Planets

Real Python: Python String Formatting: Available Tools and Their Features

Planet Python - 7 hours 24 min ago

String formatting is essential in Python for creating dynamic and well-structured text by inserting values into strings. This tutorial covers various methods, including f-strings, the .format() method, and the modulo operator (%). Each method has unique features and benefits for different use cases. The string formatting mini-language provides additional control over the output format, allowing for aligned text, numeric formatting, and more.

F-strings provide an intuitive and efficient way to embed expressions inside string literals. The .format() method offers flexibility for lazy interpolation and is compatible with Python’s formatting mini-language. The modulo operator is an older technique still found in legacy code. Understanding these methods will help you choose the best option for your specific string formatting needs.

By the end of this tutorial, you’ll understand that:

  • String formatting in Python involves inserting and formatting values within strings using interpolation.
  • Python supports different types of string formatting, including f-strings, the .format() method, and the modulo operator (%).
  • F-strings are generally the most readable and efficient option for eager interpolation in Python.
  • Python’s string formatting mini-language offers features like alignment, type conversion, and numeric formatting.
  • While f-strings are more readable and efficient compared to .format() and the % operator, the .format() method supports lazy evaluation.

To get the most out of this tutorial, you should be familiar with Python’s string data type and the available string interpolation tools. Having a basic knowledge of the string formatting mini-language is also a plus.

Get Your Code: Click here to download the free sample code you’ll use to learn about Python’s string formatting tools.

Take the Quiz: Test your knowledge with our interactive “Python String Formatting: Available Tools and Their Features” quiz. You’ll receive a score upon completion to help you track your learning progress:

Interactive Quiz

Python String Formatting: Available Tools and Their Features

You can take this quiz to test your understanding of the available tools for string formatting in Python, as well as their strengths and weaknesses. These tools include f-strings, the .format() method, and the modulo operator.

Interpolating and Formatting Strings in Python

String interpolation involves generating strings by inserting other strings or objects into specific places in a base string or template. For example, here’s how you can do some string interpolation using an f-string:

Python >>> name = "Bob" >>> f"Hello, {name}!" 'Hello, Bob!' Copied!

In this quick example, you first have a Python variable containing a string object, "Bob". Then, you create a new string using an f-string. In this string, you insert the content of your name variable using a replacement field. When you run this last line of code, Python builds a final string, 'Hello, Bob!'. The insertion of name into the f-string is an interpolation.

Note: To dive deeper into string interpolation, check out the String Interpolation in Python: Exploring Available Tools tutorial.

When you do string interpolation, you may need to format the interpolated values to produce a well-formatted final string. To do this, you can use different string interpolation tools that support string formatting. In Python, you have these three tools:

  1. F-strings
  2. The str.format() method
  3. The modulo operator (%)

The first two tools support the string formatting mini-language, a feature that allows you to fine-tune your strings. The third tool is a bit old and has fewer formatting options. However, you can use it to do some minimal formatting.

Note: The built-in format() function is yet another tool that supports the format specification mini-language. This function is typically used for date and number formatting, but you won’t cover it in this tutorial.

In the following sections, you’ll start by learning a bit about the string formatting mini-language. Then, you’ll dive into using this language, f-strings, and the .format() method to format your strings. Finally, you’ll learn about the formatting capabilities of the modulo operator.

Using F-Strings to Format Strings

Python 3.6 added a string interpolation and formatting tool called formatted string literals, or f-strings for short. As you’ve already learned, f-strings let you embed Python objects and expressions inside your strings. To create an f-string, you must prefix the string with an f or F and insert replacement fields in the string literal. Each replacement field must contain a variable, object, or expression:

Python >>> f"The number is {42}" 'The number is 42' >>> a = 5 >>> b = 10 >>> f"{a} plus {b} is {a + b}" '5 plus 10 is 15' Copied!

In the first example, you define an f-string that embeds the number 42 directly into the resulting string. In the second example, you insert two variables and an expression into the string.

Formatted string literals are a Python parser feature that converts f-strings into a series of string constants and expressions. These are then joined up to build the final string.

Using the Formatting Mini-Language With F-Strings

When you use f-strings to create strings through interpolation, you need to use replacement fields. In f-strings, you can define a replacement field using curly brackets ({}) as in the examples below:

Python >>> debit = 300.00 >>> credit = 450.00 >>> f"Debit: ${debit}, Credit: ${credit}, Balance: ${credit - debit}" 'Debit: $300, Credit: $450.0, Balance: $150.0' Copied! Read the full article at https://realpython.com/python-string-formatting/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Real Python: How to Check if a Python String Contains a Substring

Planet Python - 7 hours 24 min ago

To check if a string contains another string in Python, use the in membership operator. This is the recommended method for confirming the presence of a substring within a string. The in operator is intuitive and readable, making it a straightforward way to evaluate substring existence.

Additionally, you can use string methods like .count() and .index() to gather more detailed information about substrings, such as their frequency and position. For more complex substring searches, use regular expressions with the re module. When you’re dealing with tabular data, then pandas provides efficient tools for searching for substrings within DataFrame columns.

By the end of this tutorial, you’ll understand that:

  • The in membership operator is the recommended way to check if a Python string contains a substring.
  • Converting input text to lowercase generalizes substring checks by removing case sensitivity.
  • The .count() method counts occurrences of a substring, while .index() finds the first occurrence’s position.
  • Regular expressions in the re module allow for advanced substring searches based on complex conditions.
  • The .str.contains() method in pandas identifies which DataFrame entries contain a specific substring.

Understanding these methods and tools enables you to effectively check for substrings in Python strings, catering to various needs from simple checks to complex data analysis.

Get Your Code: Click here to download the free sample code that you’ll use to check if a string contains a substring.

How to Confirm That a Python String Contains Another String

If you need to check whether a string contains a substring, use Python’s membership operator in. In Python, this is the recommended way to confirm the existence of a substring in a string:

Python >>> raw_file_content = """Hi there and welcome. ... This is a special hidden file with a SECRET secret. ... I don't want to tell you The Secret, ... but I do want to secretly tell you that I have one.""" >>> "secret" in raw_file_content True Copied!

The in membership operator gives you a quick and readable way to check whether a substring is present in a string. You may notice that the line of code almost reads like English.

Note: If you want to check whether the substring is not in the string, then you can use not in:

Python >>> "secret" not in raw_file_content False Copied!

Because the substring "secret" is present in raw_file_content, the not in operator returns False.

When you use in, the expression returns a Boolean value:

  • True if Python found the substring
  • False if Python didn’t find the substring

You can use this intuitive syntax in conditional statements to make decisions in your code:

Python >>> if "secret" in raw_file_content: ... print("Found!") ... Found! Copied!

In this code snippet, you use the membership operator to check whether "secret" is a substring of raw_file_content. If it is, then you’ll print a message to the terminal. Any indented code will only execute if the Python string that you’re checking contains the substring that you provide.

Note: Python considers empty strings always as a substring of any other string, so checking for the empty string in a string returns True:

Python >>> "" in "secret" True Copied!

This may be surprising because Python considers emtpy strings as false, but it’s an edge case that is helpful to keep in mind.

The membership operator in is your best friend if you just need to check whether a Python string contains a substring.

However, what if you want to know more about the substring? If you read through the text stored in raw_file_content, then you’ll notice that the substring occurs more than once, and even in different variations!

Which of these occurrences did Python find? Does capitalization make a difference? How often does the substring show up in the text? And what’s the location of these substrings? If you need the answer to any of these questions, then keep on reading.

Generalize Your Check by Removing Case Sensitivity

Python strings are case sensitive. If the substring that you provide uses different capitalization than the same word in your text, then Python won’t find it. For example, if you check for the lowercase word "secret" on a title-case version of the original text, the membership operator check returns False:

Python >>> title_cased_file_content = """Hi There And Welcome. ... This Is A Special Hidden File With A Secret Secret. ... I Don't Want To Tell You The Secret, ... But I Do Want To Secretly Tell You That I Have One.""" >>> "secret" in title_cased_file_content False Copied!

Despite the fact that the word secret appears multiple times in the title-case text title_cased_file_content, it never shows up in all lowercase. That’s why the check that you perform with the membership operator returns False. Python can’t find the all-lowercase string "secret" in the provided text.

Humans have a different approach to language than computers do. This is why you’ll often want to disregard capitalization when you check whether a string contains a substring in Python.

Read the full article at https://realpython.com/python-string-contains-substring/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Real Python: Python Exceptions: An Introduction

Planet Python - 7 hours 24 min ago

Python exceptions provide a mechanism for handling errors that occur during the execution of a program. Unlike syntax errors, which are detected by the parser, Python raises exceptions when an error occurs in syntactically correct code. Knowing how to raise, catch, and handle exceptions effectively helps to ensure your program behaves as expected, even when encountering errors.

In Python, you handle exceptions using a try … except block. This structure allows you to execute code normally while responding to any exceptions that may arise. You can also use else to run code if no exceptions occur, and the finally clause to execute code regardless of whether an exception was raised.

By the end of this tutorial, you’ll understand that:

  • Exceptions in Python occur when syntactically correct code results in an error.
  • You can handle exceptions using the try, except, else, and finally keywords.
  • The try … except block lets you execute code and handle exceptions that arise.
  • Python 3 introduced more built-in exceptions compared to Python 2, making error handling more granular.
  • It’s bad practice to catch all exceptions at once using except Exception or the bare except clause.
  • Combining try, except, and pass allows your program to continue silently without handling the exception.
  • Using try … except is not inherently bad, but you should use it judiciously to handle only known issues appropriately.

In this tutorial, you’ll get to know Python exceptions and all relevant keywords for exception handling by walking through a practical example of handling a platform-related exception. Finally, you’ll also learn how to create your own custom Python exceptions.

Get Your Code: Click here to download the free sample code that shows you how exceptions work in Python.

Take the Quiz: Test your knowledge with our interactive “Python Exceptions: An Introduction” quiz. You’ll receive a score upon completion to help you track your learning progress:

Interactive Quiz

Python Exceptions: An Introduction

In this quiz, you'll test your understanding of Python exceptions. You'll cover the difference between syntax errors and exceptions and learn how to raise exceptions, make assertions, and use the try and except block.

Understanding Exceptions and Syntax Errors

Syntax errors occur when the parser detects an incorrect statement. Observe the following example:

Python Traceback >>> print(0 / 0)) File "<stdin>", line 1 print(0 / 0)) ^ SyntaxError: unmatched ')' Copied!

The arrow indicates where the parser ran into the syntax error. Additionally, the error message gives you a hint about what went wrong. In this example, there was one bracket too many. Remove it and run your code again:

Python >>> print(0 / 0) Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero Copied!

This time, you ran into an exception error. This type of error occurs whenever syntactically correct Python code results in an error. The last line of the message indicates what type of exception error you ran into.

Instead of just writing exception error, Python details what type of exception error it encountered. In this case, it was a ZeroDivisionError. Python comes with various built-in exceptions as well as the possibility to create user-defined exceptions.

Raising an Exception in Python

There are scenarios where you might want to stop your program by raising an exception if a condition occurs. You can do this with the raise keyword:

You can even complement the statement with a custom message. Assume that you’re writing a tiny toy program that expects only numbers up to 5. You can raise an error when an unwanted condition occurs:

Python low.py number = 10 if number > 5: raise Exception(f"The number should not exceed 5. ({number=})") print(number) Copied!

In this example, you raised an Exception object and passed it an informative custom message. You built the message using an f-string and a self-documenting expression.

When you run low.py, you’ll get the following output:

Python Traceback Traceback (most recent call last): File "./low.py", line 3, in <module> raise Exception(f"The number should not exceed 5. ({number=})") Exception: The number should not exceed 5. (number=10) Copied!

The program comes to a halt and displays the exception to your terminal or REPL, offering you helpful clues about what went wrong. Note that the final call to print() never executed, because Python raised the exception before it got to that line of code.

With the raise keyword, you can raise any exception object in Python and stop your program when an unwanted condition occurs.

Debugging During Development With assert Read the full article at https://realpython.com/python-exceptions/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

This Week in KDE Apps: OptiImage first release, Itinerary redesign and more

Planet KDE - 10 hours 3 min ago

Welcome to a new issue of "This Week in KDE Apps"! Every week we cover as much as possible of what's happening in the world of KDE apps.

This week, we are continuing to polish our applications for the KDE Gear 24.12.0 release, but already starting the work for the 25.04 release happening next year. We also made the first release of OptiImage, an image size optimizer.

Meanwhile, as part of the 2024 end-of-year fundraiser, you can "Adopt an App" in a symbolic effort to support your favorite KDE app. This week, we are particularly grateful to Yogesh Girikumar, Luca Weiss and 1peter10 for supporting Itinerary; Tobias Junghans and Curtis for Konsole; Daniel Bagge and Xavier Guillot for Filelight; F., Christian Terboven, Kevin Krammer and Sean M. for the Kontact suite; Tanguy Fardet, dabe, lengau and Joshua Strobl for NeoChat; Pablo Rauzy for KWrite; PJ. for LabPlot; Dominik Barth for Kasts; Kevin Krammer for Ruqola; Florent Tassy, elbekai and retrokestrel for Gwenview; MathiusD and Dadanaut for Elisa, Andreas Kilgus and @rph.space for Konqueror; trainden@lemmy.blahaj.zone for KRDC; Marco Rebhan and Travis McCoy for Ark; and domportera for Krfb.

Getting back to all that's new in the KDE App scene, let's dig in!

GCompris Educational game for children

GCompris 4.3 is out and contains bug fixes and graphics improvements on multiple activities.

Read full announcement

KDE Itinerary Digital travel assistant

We redesigned the timeline of your trips and the query result pages when searching for a public transport connection to work better with a small screen while still showing all the relevant information. (Carl Schwan, 25.04.0. Link 1 and link 2)

Checking for updates and downloading map data now are scoped to a trip and will only query data from the internet related to the trip. (Volker Krause, 25.04.0. Link 1 and link 2)

The export buttons used in Itinerary are not blurry anymore. (Carl Schwan, 24.12.0. Link)

Add an extractor for GoOut tickets (an event platform in Poland, Czechia and Slovakia) as well as luma and the pkpasses from Flixbus.de. (David Pilarcik, 24.12.0. Link, link 2 and link 3)

Optimize querying a location by sorting the list of countries only once instead of hundreds of times. (Carl Schwan, 24.12.0. Link)

OptiImage Image optimizer to reduce the size of images

OptiImage 1.0.0 is out! This is the initial release of this image size optimizer and you can read all the details on the announcement blog post.

Karp KDE arranger for PDFs

Karp is now directly using the QPDF library instead of invoking a separate process, which improves the speed while making PDF operation more reliable. (Tomasz Bojczuk. Link)

Kate Advanced Text Editor

Make it again possible to scroll, select text and click on links inside documentation tooltips in Kate. (Leia uwu, 24.12.0. Link) Leia also improved the tooltip positioning logic so that it doesn't obscure the hovered word. (Leia uwu, 25.04.0. Link)

KMail A feature-rich email application

The mail folder selection dialog now remembers which folders were collapsed and expanded between invocations.

Ruqola Rocket Chat Client

Ruqola 2.3.2 is out and includes many fixes for RocketChat 7.0!

Read full announcement

Spectacle Screenshot Capture Utility

On Wayland, the "Window Under Cursor" mode is renamed to "Select Window" as you need to select the window. (Noah Davis, 25.04.0. Link)

Tokodon Browse the Fediverse

Better icon for Android, which is also adaptable depending on your theme. (Alois Spitzbart, 24.12. Link)

Streaming timeline events and notifications now work for servers using GoToSocial. (snow flurry, 24.12. Link)

Slightly improved the performance of the timeline, with particular focus on the media. (Joshua Goins, 24.12. Link)

In the status composer, user info is now shown - useful if you post from multiple accounts. Also, the look of the text box has been updated. (Joshua Goins, 24.12. Link)

Added the ability to configure your notification policy. This allows you to reject or allow notifications e.g. for new accounts. (Joshua Goins, 25.03. Link)

Improved the appearance of the search page on desktop. (Joshua Goins, 24.12. Link)

Added preliminary support for Iceshrimp.NET instances. (Joshua Goins, 24.12. Link)

Added an error log in the UI to keep track of network errors. (Joshua Goins, 25.03. Link)

Kirigami Addons

Kirigami Addons 1.6.0. is out! You can read the full announcement on my (Carl's) blog. This week we also made the following changes:

Speedup loading Kirigami pages using FormComboboxDelegate, this is particularly noticable for the country combobox in Itinerary, but affects more applications. (Carl Schwan, Kirigami Addons 1.6.0. Link)

Add new RadioSelector and FormRadioSelectorDelegate components to Kirigami Addons. On the screenshot below you can see how they're used in Itinerary. (Mathis Brüchert, Kirigami Addons 1.6.0. Link)

…And Everything Else

This blog only covers the tip of the iceberg! If you’re hungry for more, check out Nate's blog about Plasma and be sure not to miss his This Week in Plasma series, where every Saturday he covers all the work being put into KDE's Plasma desktop environment.

For a complete overview of what's going on, visit KDE's Planet, where you can find all KDE news unfiltered directly from our contributors.

Get Involved

The KDE organization has become important in the world, and your time and contributions have helped us get there. As we grow, we're going to need your support for KDE to become sustainable.

You can help KDE by becoming an active community member and getting involved. Each contributor makes a huge difference in KDE — you are not a number or a cog in a machine! You don’t have to be a programmer either. There are many things you can do: you can help hunt and confirm bugs, even maybe solve them; contribute designs for wallpapers, web pages, icons and app interfaces; translate messages and menu items into your own language; promote KDE in your local community; and a ton more things.

You can also help us by donating. Any monetary contribution, however small, will help us cover operational costs, salaries, travel expenses for contributors and in general just keep KDE bringing Free Software to the world.

To get your application mentioned here, please ping us in invent or in Matrix.

Categories: FLOSS Project Planets

Tryton News: Newsletter December 2024

Planet Python - 14 hours 24 min ago

During the last month we focused on fixing bugs, improving the behaviour of things, speeding-up performance issues - building on the changes from our last Tryton Release 7.4. We also added some new features which we would like to introduce to you in this newsletter.

For an in depth overview of the Tryton issues please take a look at our issue tracker or see the issues and merge requests filtered by label.

Changes for the User Accounting, Invoicing and Payments

Now we compute the maturity date of grouped account move lines per debit/credit.

New Releases

We released bug fixes for the currently maintained long term support series
7.0 and 6.0, and for the penultimate series 7.4 and 7.2.

Changes for the Translators

Now we support plural translations for report and ir.message. The other translatable strings are labels that have no count. The plural rule is a Python expression which returns an integer following the gettext design. For the report, it is possible to use the Genshi i18n:choose, i18n:singular, i18n:plural and for OpenDocument the gettext and ngettext methods are added to the evaluation context.

Changes for the System Administrator

Now we can set the decimal precision of default context from the environment variable TRYTOND_DECIMAL_PREC.

Changes for Implementers and Developers

To provide better feedback to the user, now we also add equivalent domains of SQL constraints.

Now we extract the timesheet cost computation from the _get_cost method to allow customization e.g. to use a different composition of the costs.
Also we round the work total with currency digits in get_total method now, to allow extending the computation methods, without rounding too early.

A trytond.model.Model is defined by a python class:

from trytond.model import ModelSQL, fields class Party(ModelSQL): """Party""" __name__ = 'party.party'

It was needed to define three different identifiers:

  1. Python class name: Party
  2. class doc-string: Party
  3. trytond.model.Model.__name__: party.party

The translated text string of the model which is shown in the user interface was extracted from the __doc__ (doc-string) of the class definition.

Now we replaced the class doc-string extraction by parsing the trytond.model.Model.__name__ attribute and try to make it human readable. Changing an existing __name__ attribute usually implies a database migration.
To work-around existing not so useful __name__ values we introduced the new class attribute trytond.model.Model.__string__ which let you define the model string directly.

We also take the chance and clean-up the name-space by renaming

Finally we removed most of the former doc-strings from all the classes, only in some rare cases we add the __string__ attribute.

Authors: @dave @pokoli @udono

1 post - 1 participant

Read full topic

Categories: FLOSS Project Planets

Junichi Uekawa: Lots of travel and back to Tokyo.

Planet Debian - 14 hours 47 min ago
Lots of travel and back to Tokyo. Then I got sick. Trying to work on my bass piece, but it's really hard and I am having hard time getting to a reasonable shape. Discussions on Debconf 2026 bid. Hoping it will materialize soon.

Categories: FLOSS Project Planets

Russ Allbery: Review: Unexploded Remnants

Planet Debian - Sat, 2024-11-30 22:10

Review: Unexploded Remnants, by Elaine Gallagher

Publisher: Tordotcom Copyright: 2024 ISBN: 1-250-32522-6 Format: Kindle Pages: 111

Unexploded Remnants is a science fiction adventure novella. The protagonist and world background would support an episodic series, but as of this writing it stands alone. It is Elaine Gallagher's first professional publication.

Alice is the last survivor of Earth: an explorer, information trader, and occasional associate of the Archive. She scouts interesting places, looks for inconsistencies in the stories the galactic civilizations tell themselves, and pokes around ruins for treasure. As this story opens, she finds a supposedly broken computer core in the Alta Sidoie bazaar that is definitely not what the trader thinks it is. Very shortly thereafter, she's being hunted by a clan of dangerous Delosi while trying to decide what to do with a possibly malevolent AI with frightening intrusion abilities.

This is one of those stories where all the individual pieces sounded great, but the way they were assembled didn't click for me. Unusually, I'm not entirely sure why. Often it's the characters, but I liked Alice well enough. The Lewis Carroll allusions were there but not overdone, her computer agent Bugs is a little too much of a Warner Brothers cartoon but still interesting, and the world building has plenty of interesting hooks. I certainly can't complain about the pacing: the plot moves briskly along to a somewhat predictable but still adequate conclusion. The writing is smooth and competent, and the world is memorable enough that I'm still thinking about it.

And yet, I never connected with this story. I think it may be because both Alice and the tight third-person narrator tend towards breezy confidence and matter-of-fact descriptions. Alice does, at times, get scared or angry, but I never felt those emotions. They were just events that were described to me. There wasn't an emotional hook, a place where the character grabbed me, and so it felt like everything was happening at an odd remove. The advantage of this approach is that there are no overwrought emotional meltdowns or brooding angstful protagonists, just an adventure story about a competent and thoughtful character, but I think I wanted a bit more emotional involvement than I got.

The world background is the best part and feels like it could be part of a larger series. The Milky Way is connected by an old, vast, and only partly understood network of teleportation portals, which had cut off Earth for unknown reasons and then just as mysteriously reactivated when Alice, then Andrew, drunkenly poked at a standing stone while muttering an old prayer in Gaelic. The Archive spent a year sorting out her intellectual diseases (capitalism was particularly alarming) and giving her a fresh start with a new body. Humanity subsequently destroyed itself in a paroxysm of reactionary violence, leaving Alice a free agent, one of a kind in a galaxy of dizzying variety and forgotten history.

Gallagher makes great use of the weirdness of the portal network to create a Star Wars style of universe: the focus is more on the diversity of the planets and alien species than on a coherent unifying structure. The settings of this book are not prone to Planet of the Hats problems. They instead have the contrasts that one would get if one dropped portals near current or former Earth population centers and then took a random walk through them (or, in other words, what playing GeoGuessr on a world map feels like). I liked this effect, but I have to admit that it also added to that sense of sliding off the surface of the story. The place descriptions were great bits of atmosphere, but I never cared about them. There isn't enough emotional coherence to make them memorable.

One of the more notable quirks of this story is the description of ideologies and prejudices as viral memes that can be cataloged, cured, and deployed like weapons. This is a theme of the world-building as well: this society, or at least the Archive-affiliated parts of it, classifies some patterns of thought as potentially dangerous but treatable contagious diseases. I'm not going to object too much to this as a bit of background and characterization in a fairly short novella stuffed with a lot of other world-building and plot, but there's was something about treating ethical systems like diseases that bugged me in much the same way that medicalization of neurodiversity bugs me. I think some people will find that sense of moral clarity relaxing and others will find it vaguely irritating, and I seem to have ended up in the second group.

Overall, I would classify this as an interesting not-quite-success. It felt like a side story in a larger universe, like a story that would work better if I already knew Alice from other novels and had an established emotional connection with her. As is, I would not really recommend it, but there are enough good pieces here that I would be interested to see what Gallagher does next.

Rating: 6 out of 10

Categories: FLOSS Project Planets

Sandro Knauß: QML Dependency tracking in Debian

Planet Debian - Sat, 2024-11-30 19:00

Tracking library dependencies work in Debian to resolve from symbols usage to a library and add this to the list of dependencies. That is working for years now. The KDE community nowadays create more and more QML based applications. Unfortunately QML is a interpreted language, this means missing QML dependencies will only be an issue at runtime.

To fix this I created dh_qmldeps, that searches for QML dependencies at build time and will fail if it can't resolve the QML dependency.

Me didn't create an own QML interpreter, just using qmlimportscanner behind the scenes and process the output further to resolve the QML modules to Debian packages.

The workflow is like follows:

The package compiles normally and split to the binary packages. Than dh_qmldeps scans through the package content to find QML content ( .qml files, or qmldirfor QML modules). All founded files will be scanned by qmlimportscanner, the output is a list of depended QML modules. As QML modules have a standardized file path, we can ask the Debian system, which packages ship this file path. We end up with a list of Debian packages in the variable ${qml6:Depends}. This variable can be attached to the list of dependencies of the scanned package. A maintainer can also lower some dependencies to Recommends or Suggest, if needed.

You can find the source code on salsa and usage documentation you can find on https://qt-kde-team.pages.debian.net/dh_qmldeps.html.

The last weeks I now enabled dh_qmldeps for newly every package, that creates a QML6 module package. So the first bugs are solved and it should be usable for more packages.

By scanning with qmlimportscanner trough all code, I found several non-existing QML modules:

  • import QtQuick3DPrivate qt6-multimedia - no Private QML module QTBUG-131753.
  • import QtQuickPrivate qt6-graphs - no Private QML module QTBUG-131754.
  • import QtQuickTimeline qt6-quicktimeline - the correct QML name is QtQuick.Timeline QTBUG-131755.
  • import QtQuickControls2 qt6-webengine - looks like a porting bug as the QML6 modules name is QtQuick.Controls QTBUG-131756.
  • import QtGraphicalEffects kquickimageeditor - the correct name is for QML6 is qt5compat.graphicaleffects, properly as it is an example nobody checks it kquickimageeditor!7.

YEAH - the first milestone is reached. We are able to simply handle QML modules.

But QML applications there is still room for improvement. In apps the QML files are inside the executable. Additionally applications create internal QML modules, that are shipped directly in the same executable. I still search for a good way to analyse an executable to get a list of internal QML modules and a list of included QML files. Any ideas are welcomed :)

As workaround dh_qmldeps scans currently all QML files inside the application source code.

Categories: FLOSS Project Planets

Dima Kogan: Strava track filtering validation

Planet Debian - Sat, 2024-11-30 17:48

After years of seeing people's strava tracks, I became convinced that they insufficiently filter the data, resulting in over-estimating the effort. Today I did a bit of lazy analysis, and half-confirmed this: in the one case I looked at, strava reported reasonable elevation gain numbers, but greatly overestimated the distance traveled.

I looked at a single gps track of a long bike ride. This was uploaded to strava manually, as a .gpx file. I can imagine that different things happen if you use the strava app or some device that integrates with the service (the filtering might happen before the data hits the server, and the server could decide to not apply any more filtering).

I processed the data with a simple hysteretic filter, ignoring small changes in position and elevation, trying out different thresholds in the process. I completely ignore the timestamps, and only look at the differences between successive points. This handles the usual GPS noise; it does not handle GPS jumps, which I completely ignore in this analysis. Ignoring these would produce inflated elevation/gain numbers, but I'm working with a looong track, so hopefully this is a small effect.

Clearly this is not scientific, but it's something.

The code

Parsing .gpx is slow (this is a big file), so I cache that into a .vnl:

import sys import gpxpy filename_in = 'INPUT.gpx' filename_out = 'OUTPUT.gpx' with open(filename_in, 'r') as f: gpx = gpxpy.parse(f) f_out = open(filename_out, 'w') tracks = gpx.tracks if len(tracks) != 1: print("I want just one track", file=sys.stderr) sys.exit(1) track = tracks[0] segments = track.segments if len(segments) != 1: print("I want just one segment", file=sys.stderr) sys.exit(1) segment = segments[0] time0 = segment.points[0].time print("# time lat lon ele_m") for p in segment.points: print(f"{(p.time - time0).seconds} {p.latitude} {p.longitude} {p.elevation}", file = f_out)

And I process this data with the different filters (this is a silly Python loop, and is slow):

#!/usr/bin/python3 import sys import numpy as np import numpysane as nps import gnuplotlib as gp import vnlog import pyproj geod = None def dist_ft(lat0,lon0, lat1,lon1): global geod if geod is None: geod = pyproj.Geod(ellps='WGS84') return \ geod.inv(lon0,lat0, lon1,lat1)[2] * 100./2.54/12. f = 'OUTPUT.gpx' track,list_keys,dict_key_index = \ vnlog.slurp(f) t = track[:,dict_key_index['time' ]] lat = track[:,dict_key_index['lat' ]] lon = track[:,dict_key_index['lon' ]] ele_ft = track[:,dict_key_index['ele_m']] * 100./2.54/12. @nps.broadcast_define( ( (), ()), (2,)) def filter_track(ele_hysteresis_ft, dxy_hysteresis_ft): dist = 0.0 ele_gain_ft = 0.0 lon_accepted = None lat_accepted = None ele_accepted = None for i in range(len(lat)): if ele_accepted is not None: dxy_here = dist_ft(lat_accepted,lon_accepted, lat[i],lon[i]) dele_here = np.abs( ele_ft[i] - ele_accepted ) if dxy_here < dxy_hysteresis_ft and dele_here < ele_hysteresis_ft: continue if ele_ft[i] > ele_accepted: ele_gain_ft += dele_here; dist += np.sqrt(dele_here * dele_here + dxy_here * dxy_here) lon_accepted = lon[i] lat_accepted = lat[i] ele_accepted = ele_ft[i] # lose the last point. It simply doesn't matter dist_mi = dist / 5280. return np.array((ele_gain_ft, dist_mi)) Nele_hysteresis_ft = 20 ele_hysteresis0_ft = 5 ele_hysteresis1_ft = 100 ele_hysteresis_ft_all = np.linspace(ele_hysteresis0_ft, ele_hysteresis1_ft, Nele_hysteresis_ft) Ndxy_hysteresis_ft = 20 dxy_hysteresis0_ft = 5 dxy_hysteresis1_ft = 1000 dxy_hysteresis_ft = np.linspace(dxy_hysteresis0_ft, dxy_hysteresis1_ft, Ndxy_hysteresis_ft) # shape (Nele,Ndxy,2) gain,distance = \ nps.mv( filter_track( nps.dummy(ele_hysteresis_ft_all,-1), dxy_hysteresis_ft), -1,0 ) # Stolen from mrcal def options_heatmap_with_contours( plotoptions, # we update this on output *, contour_min = 0, contour_max, contour_increment = None, do_contours = True, contour_labels_styles = 'boxed', contour_labels_font = None): r'''Update plotoptions, return curveoptions for a contoured heat map''' gp.add_plot_option(plotoptions, 'set', ('view equal xy', 'view map')) if do_contours: if contour_increment is None: # Compute a "nice" contour increment. I pick a round number that gives # me a reasonable number of contours Nwant = 10 increment = (contour_max - contour_min)/Nwant # I find the nearest 1eX or 2eX or 5eX base10_floor = np.power(10., np.floor(np.log10(increment))) # Look through the options, and pick the best one m = np.array((1., 2., 5., 10.)) err = np.abs(m * base10_floor - increment) contour_increment = -m[ np.argmin(err) ] * base10_floor gp.add_plot_option(plotoptions, 'set', ('key box opaque', 'style textbox opaque', 'contour base', f'cntrparam levels incremental {contour_max},{contour_increment},{contour_min}')) if contour_labels_font is not None: gp.add_plot_option(plotoptions, 'set', f'cntrlabel format "%d" font "{contour_labels_font}"' ) else: gp.add_plot_option(plotoptions, 'set', f'cntrlabel format "%.0f"' ) plotoptions['cbrange'] = [contour_min, contour_max] # I plot 3 times: # - to make the heat map # - to make the contours # - to make the contour labels _with = np.array(('image', 'lines nosurface', f'labels {contour_labels_styles} nosurface')) else: gp.add_plot_option(plotoptions, 'unset', 'key') _with = 'image' using = \ f'({dxy_hysteresis0_ft}+$1*{float(dxy_hysteresis1_ft-dxy_hysteresis0_ft)/(Ndxy_hysteresis_ft-1)}):' + \ f'({ele_hysteresis0_ft}+$2*{float(ele_hysteresis1_ft-ele_hysteresis0_ft)/(Nele_hysteresis_ft-1)}):3' plotoptions['_3d'] = True plotoptions['_xrange'] = [dxy_hysteresis0_ft,dxy_hysteresis1_ft] plotoptions['_yrange'] = [ele_hysteresis0_ft,ele_hysteresis1_ft] plotoptions['ascii'] = True # needed for using to work gp.add_plot_option(plotoptions, 'unset', 'grid') return \ dict( tuplesize=3, legend = "", # needed to force contour labels using = using, _with=_with) contour_granularity = 1000 plotoptions = dict() curveoptions = \ options_heatmap_with_contours( plotoptions, # we update this on output # round down to the nearest contour_granularity contour_min = (np.min(gain) // contour_granularity)*contour_granularity, # round up to the nearest contour_granularity contour_max = ((np.max(gain) + (contour_granularity-1)) // contour_granularity) * contour_granularity, do_contours = True) gp.add_plot_option(plotoptions, 'unset', 'key') gp.add_plot_option(plotoptions, 'set', 'size square') gp.plot(gain, xlabel = "Distance hysteresis (ft)", ylabel = "Elevation hysteresis (ft)", cblabel = "Elevation gain (ft)", wait = True, **curveoptions, **plotoptions, title = 'Computed gain vs filtering parameters') contour_granularity = 10 plotoptions = dict() curveoptions = \ options_heatmap_with_contours( plotoptions, # we update this on output # round down to the nearest contour_granularity contour_min = (np.min(distance) // contour_granularity)*contour_granularity, # round up to the nearest contour_granularity contour_max = ((np.max(distance) + (contour_granularity-1)) // contour_granularity) * contour_granularity, do_contours = True) gp.add_plot_option(plotoptions, 'unset', 'key') gp.add_plot_option(plotoptions, 'set', 'size square') gp.plot(distance, xlabel = "Distance hysteresis (ft)", ylabel = "Elevation hysteresis (ft)", cblabel = "Distance (miles)", wait = True, **curveoptions, **plotoptions, title = 'Computed distance vs filtering parameters') Results: gain

Strava says the gain was 46307ft. The analysis says:

These show the filtered gain for different values of the distance and gain hysteresis thresholds. The same data is shown at diffent zoom levels. There's no sweet spot, but we get 46307ft with a reasonable amount of filtering. Maybe 46307ft is a bit low even.

Results: distance

Strava says the distance covered was 322 miles. The analysis says:

Once again, there's no sweet spot, but we get 322 miles only if we apply no filtering at all. That's clearly too high, and is not reasonable. From the map (and from other people's strava routes) the true distance is closer to 305 miles. Why those people's strava numbers are more believable is anybody's guess.

Categories: FLOSS Project Planets

Spinning Code: Architectures for Constituent Portals

Planet Drupal - Sat, 2024-11-30 17:17

One of the common needs, or at least desires, for CRM users is to link their CRM to some kind of constituent portal. There are several ways your can architect a good data pattern for your constituent portal. The trick is picking the right one for your organization.

This is the first in a series on what your choices are, and now to select the right one. The architecture you select will drive the implementation cost, maintenance costs, and scalability.

The Purpose of Your Constituent Portal

Before deciding on the architecture of your portal, you need to have a clear understanding of its intended purpose and expected scale. The purpose of the portal will also dictate the direction(s) data flows, and the scale will help you plan the long term costs.

If you can’t clearly state why you need a constituent portal, you don’t need one.

Different organizations have different reasons to create portals. Companies that sell products may want a warranty or support portal. Nonprofits often want a donor portal that provides tax recipes and allowed recurring donors to update their gift information. Member organizations want a place for members to see their benefits, update their information, and renew their memberships. And so on.

The purpose of your portal will determine the direction that data flows through it. There are essentially three directions that data can move.

Outbound Data

You can send data from your organization to your constituent. That could be things like receipts, memberships status, or product warranty information. Anything that is data you have, that your member might need to see, but not update.

Data Exchange

You can allow constituents to update information. That could be address changes, support requests, donation schedule updates, event registration details, and more.

Data Network

Your third option is to allow you constituents to exchange information with each other. This could be a any form of member community where they engage with each other.

When planning a network, remember you have to plan for content moderation and acceptable use policies.

Primary Portal Data Architectures

To support your portal, whatever the data flow is, there are three main data architectures you can choose from, each which a different strengths and weaknesses. The more complex your architecture the more options you will have for what it can support, but it will also increase costs and maintenance efforts. Bigger is not always better – sometimes it’s just more expensive.

1. All-in-One Constituent Portals

In an all-in-one solution your constituent portal is part of your CRM. For obvious reasons this is the type of portal that your CRM vendor wants to sell you. In Salesforce land this means Experience Cloud. There are also many nonprofit-focused CRMs which include one in their solution. When your portal is part of your CRM you get a bunch of advantages:

  • Data all lives in one place. There is no data sync to worry about setting up or maintaining.
  • You have one vendor. That means you can centralize your support arrangement and billing.
  • They are often fastest to implement. They are designed to be fast to market to help make them the obvious choice.
  • They generally do not require a developer. Again, your CRM vendor really wants you to select this path, so they clear as many hurdles as they can.
  • There is only one technology stack. By leveraging the technology of your CRM your investments in learning that technology carry over, at least in part, to your portal.

There are also downsides:

  • New template system to learn. The CRM’s portal likely has a different template system than the CMS on your main web site. That may be hard to make match your primary online branding.
  • The vendors make a lot of assumptions. To provide that ease listed above they make assumptions about how data flows, security, user experience, and how other elements should work – those assumptions may not match your ideal solution.
  • Costs often scale linearly. There are usually license costs that are scaled based on user count meaning your costs grow as the portal grows at more or less a 1:1 rate. While there are price breaks and other incentives this is the right expectation to have for estimating.
2. External Constituent Portal

In this pattern an external constituent portal moves the user experience from within your main CRM’s sphere of influence into a separate platform. In my career I’ve mostly built these with Salesforce as the CRM and Drupal as the portal platform – it’s a powerful pairing. The strengths and weaknesses here are more or less the mirror of the all-in-one portal.

  • You web team may already know the technology. If you use the same technology as your web developers use for your main web site(s) they already know who to handle design and branding.
  • You have greater control over the User Experience. The assumptions that go into the portal are yours not the ones imposed by the CRM.
  • You have greater control over security, along with data flow and formats. Since they aren’t built around assumptions you don’t control you have greater control and freedom.
  • Costs typically grow more slowly. It is less common to have per-user license costs in this context so the cost curve is likely closer to logarithmic.

The downsides:

  • You have to handle data synchronization. The two systems means data has to pass back and forth.
  • You have two difference vendors/platforms. When you had one system everything was centralized, now you have two different systems handling constituent data.
  • This design typically is harder to implement. All those short cuts your CRM provider had in mind for you are gone. Even if you use purpose built solution it’s going to take more time and effort.
  • This approach generally requires a developer and/or data architect. To implement this pattern you need someone who understands both platforms – ideally both for setup and support.
3. External Constituent Portals with Data Proxy

In some situations it makes sense to insert a data proxy, or API layer, between your main CRM and your constituent portal. This creates a layer of abstraction, security, and data augmentation that can benefit a lot of organizations. While this is the most complex of the three main architectures it is one I find is frequently overlooked – in part, I suspect, because no one partner benefits from selling it.

This setup certainly isn’t for everyone, but when it’s the right fit it makes a huge difference. It also creates a significant number of iterations – all of those arrows could be one directional or two directional.

An extra data layer makes the most sense when data from your CRM is going to multiple places and/or needs to be augmented by an external data source. For example think about an organization that provides trail maps for hiking or paddling. All that data about trails does not need to be in your CRM, but you probably want to know which members are interested in which trails. An organization like that may have a portal for members, a web site to find trails for non-members, apps for iPhone and Android, and perhaps a public API for other people to use to build their own web sites with. That’s a lot of API calls all with different data sets, all of which need to be very fast.

Your CRM is designed to be very stable and reliable – it is not designed to be very fast. What’s more, you often have limits on the number of API calls you get in your package with extra fees charged if you go over. By inserting another layer between your CRM and other needs you can bypass these limitations.

There is another added benefit to this design pattern, and that is increased security. By creating an additional layer in your system you are able to create a separation of concerns between the various systems. Each should have access to only the data is absolutely needs from any of the others.

How to Pick?

There are lots of considerations that go into selecting the right architecture for your project – which is why that’s getting it’s own post soon.

The post Architectures for Constituent Portals appeared first on Spinning Code.

Categories: FLOSS Project Planets

KDE Gear 24.11.90 Available on Fedora 41 (COPR)

Planet KDE - Sat, 2024-11-30 16:31

The Fedora KDE SIG is pleased to announce that KDE Gear 24.12 RC (24.11.90) is available on Fedora 41 via our @kdesig/kde-beta COPR repository

Enjoy!

Categories: FLOSS Project Planets

Enrico Zini: New laptop setup

Planet Debian - Sat, 2024-11-30 15:13

My new laptop Framework (Framework Laptop 13 DIY Edition (AMD Ryzen™ 7040 Series)) arrived, all the hardware works out of the box on Debian Stable, and I'm very happy indeed.

This post has the notes of all the provisioning steps, so that I can replicate them again if needed.

Installing Debian 12

Debian 12's installer just worked, with Secure Boot enabled no less, which was nice.

The only glitch is an argument with the guided partitioner, which was uncooperative: I have been hit before by a /boot partition too small, and I wanted 1G of EFI and 1G of boot, while the partitioner decided that 512Mb were good enough. Frustratingly, there was no way of changing that, nor I found how to get more than 1G of swap, as I wanted enough swap to fit RAM for hybernation.

I let it install the way it pleased, then I booted into grml for a round of gparted.

The tricky part of that was resizing the root btrfs filesystem, which is in an LV, which is in a VG, which is in a PV, which is in LUKS. Here's a cheatsheet.

Shrink partitions:

  • mount the root filesystem in /mnt
  • btrfs filesystem resize 6G /mnt
  • umount the root filesystem
  • lvresize -L 7G vgname/lvname
  • pvresize --setphysicalvolumesize /dev/mapper/pvname 8G
  • cryptsetup resize --device-size 9G name

note that I used an increasing size because I don't trust that each tool has a way of representing sizes that aligns to the byte. I'd be happy to find out that they do, but didn't want to find out the hard way that they didn't.

Resize with gparted:

Move and resize partitions at will. Shrinking first means it all takes a reasonable time, and you won't have to wait almost an hour for a terabyte-sized empty partition to be carefully moved around. Don't ask me why I know.

Regrow partitions:

  • cryptsetup resize name
  • pvresize /dev/mapper/pvname
  • lvresize -L 100% vgname/lvname
  • mount the root filesystem in /mnt
  • btrfs filesystem resize max /mnt
  • umount the root filesystem
Setup gnome

When I get a new laptop I have a tradition of trying to make it work with Gnome and Wayland, which normally ended up in frustration and a swift move to X11 and Xfce: I have a lot of long-time muscle memory involved in how I use a computer, and it needs to fit like prosthetics. I can learn to do a thing or two in a different way, but any papercut that makes me break flow and I cannot fix will soon become a dealbreaker.

This applies to Gnome as present in Debian Stable.

General Gnome settings tips

I can list all available settings with:

gsettings list-recursively

which is handy for grepping things like hotkeys.

I can manually set a value with:

gsettings set <schema> <key> <value>

and I can reset it to its default with:

gsettings reset <schema> <key>

Some applications like Gnome Terminal use "relocatable schemas", and in those cases you also need to specify a path, which can be discovered using dconf-editor:

gsettings set <schema>:<path> <key> <value> Install appindicators

First thing first: app install gnome-shell-extension-appindicator, log out and in again: the Gnome Extension manager won't see the extension as available until you restart the whole session.

I have no idea why that is so, and I have no idea why a notification area is not present in Gnome by default, but at least now I can get one.

Fix font sizes across monitors

My laptop screen and monitor have significantly different DPIs, so:

gsettings set org.gnome.mutter experimental-features "['scale-monitor-framebuffer']"

And in Settings/Displays, set a reasonable scaling factor for each display.

Disable Alt/Super as hotkey for the Overlay

Seeing all my screen reorganize and reshuffle every time I accidentally press Alt leaves me disoriented and seasick:

gsettings set org.gnome.mutter overlay-key '' Focus-follows-mouse and Raise-or-lower

My desktop is like my desktop: messy and cluttered. I have lots of overlapping window and I switch between them by moving the focus with the mouse, and when the visible part is not enough I have a handy hotkey mapped to raise-or-lower to bring forward what I need and send back what I don't need anymore.

Thankfully Gnome can be configured that way, with some work:

  • In gnome-shell settings, keyboard, shortcuts, windows, set "Raise window if covered, otherwise lower it" to "Super+Escape"
  • In gnome-tweak-tool, Windows, set "Focus on Hover"

This almost worked, but sometimes it didn't do what I wanted, like I expected to find a window to the front but another window disappeared instead. I eventually figured that by default Gnome delays focus changes by a perceivable amount, which is evidently too slow for the way I move around windows.

The amount cannot be shortened, but it can be removed with:

gsettings set org.gnome.shell.overrides focus-change-on-pointer-rest false Mouse and keyboard shortcuts

Gnome has lots of preconfigured sounds, shortcuts, animations and other distractions that I do not need. They also either interfere with key combinations I want to use in terminals, or cause accidental window moves or resizes that make me break flow, or otherwise provide sensory overstimulation that really does not work for me.

It was a lot of work, and these are the steps I used to get rid of most of them.

Disable Super+N combinations that accidentally launch a questionable choice of programs:

for i in `seq 1 9`; do gsettings set org.gnome.shell.keybindings switch-to-application-$i '[]'; done

Gnome-Shell settings:

  • Multitasking:
    • disable hot corner
    • disable active edges
    • set a fixed number of workspaces
    • workspaces on all displays
    • switching includes apps from current workspace only
  • Sound:
    • disable system sounds
  • Keyboard
    • Compose Key set to Caps Lock
    • View and Customize Shortcuts:
      • Launchers
        • launch help browser: remove
      • Navigation
        • move to workspace on the left: Super+Left
        • move to workspace on the right: Super+Right
        • move window one monitor …: remove
        • move window one workspace to the left: Shift+Super+Left
        • move window one workspace to the right: Shift+Super+Right
        • move window to …: remove
        • switch system …: remove
        • switch to …: remove
        • switch windows …: disabled
      • Screenshots
        • Record a screenshot interactively: Super+Print
        • Take a screenshot interactively: Print
        • Disable everything else
      • System
        • Focus the active notification: remove
        • Open the applcation menu: remove
        • Restore the keyboard shortctus: remove
        • Show all applications: remove
        • Show the notification list: remove
        • Show the overvire: remove
        • Show the run command prompt: remove (the default Gnome launcher is not for me) Super+F2 (or remove to leave it to the terminal)
      • Windows
        • Close window: remove
        • Hide window: remove
        • Maximize window: remove
        • Move window: remove
        • Raise window if covered, otherwise lower it: Super+Escape
        • Resize window: remove
        • Restore window: remove
        • Toggle maximization state: remove
    • Custom shortcuts
      • xfrun4, launching xfrun4, bound to Super+F2
  • Accessibility:
    • disable "Enable animations"

gnome-tweak-tool settings:

  • Keyboard & Mouse
    • Overview shortcut: Right Super. This cannot be disabled, but since my keyboard doesn't have a Right Super button, that's good enough for me. Oddly, I cannot find this in gsettings.
  • Window titlebars
    • Double-Click: Toggle-Maximize
    • Middle-Click: Lower
    • Secondary-Click: Menu
  • Windows
    • Resize with secondary click

Gnome Terminal settings:

Thankfully 10 years ago I took notes on how to customize Gnome Terminal, and they're still mostly valid:

  • Shortcuts

    • New tab: Super+T
    • New window: Super+N
    • Close tab: disabled
    • Close window: disabled
    • Copy: Super+C
    • Paste: Super+V
    • Search: all disabled
    • Previous tab: Super+Page Up
    • Next tab: Super+Page Down
    • Move tab…: Disabled
    • Switch to tab N: Super+Fn (only available after disabling overview)
    • Switch to tab N with Alt+Fn cannot be configured in the UI: Alt+Fn is detected as simply Fn. It can however be set with gsettings:

      sh for i in `seq 1 12`; do gsettings set org.gnome.Terminal.Legacy.Keybindings:/org/gnome/terminal/legacy/keybindings/ switch-to-tab-$i "<Alt>F$i"; done

  • Profile

    • Text
      • Sound: disable terminal bell

Other hotkeys that got in my way and had to disable the hard way:

for n in `seq 1 12`; do gsettings set org.gnome.mutter.wayland.keybindings switch-to-session-$n '[]'; done gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-down '[]' gsettings set org.gnome.desktop.wm.keybindings move-to-workspace-up '[]' gsettings set org.gnome.desktop.wm.keybindings panel-main-menu '[]' gsettings set org.gnome.desktop.interface menubar-accel '[]'

Note that even after removing F10 from being bound to menubar-accel, and after having to gsetting binding to F10 as is:

$ gsettings list-recursively|grep F10 org.gnome.Terminal.Legacy.Keybindings switch-to-tab-10 '<Alt>F10'

I still cannot quit Midnight Commander using F10 in a terminal, as that moves the focus in the window title bar. This looks like a Gnome bug, and a very frustrating one for me.

Appearance

Gnome-Shell settings:

  • Appearance:
    • dark mode

gnome-tweak-tool settings:

  • Fonts
    • Antialiasing: Subpixel
  • Top Bar
    • Clock/Weekday: enable (why is this not a default?)

Gnome Terminal settings:

  • General
    • Theme variant: Dark (somehow it wasn't picked by up from the system settings)
  • Profile
    • Colors
      • Background: #000
Other decluttering and tweaks

Gnome Shell Settings:

  • Search
    • disable application search
  • Removable media
    • set everything to "ask what to do"
  • Default applications
    • Web: Chromium
    • Mail: mutt
    • Calendar: khal is not sadly an option
    • Video: mpv
    • Photos: Geequie

Set a delay between screen blank and lock: when the screen goes blank, it is important for me to be able to say "nope, don't blank yet!", and maybe switch on caffeine mode during a presentation without needing to type my password in front of cameras. No UI for this, but at least gsettings has it:

gsettings set org.gnome.desktop.screensaver lock-delay 30 Extensions

I enabled the Applications Menu extension, since it's impossible to find less famous applications in the Overview without knowing in advance how they're named in the desktop. This stole a precious hotkey, which I had to disable in gsettings:

gsettings set org.gnome.shell.extensions.apps-menu apps-menu-toggle-menu '[]'

I also enabled:

  • Removable Drive Menu: why is this not on by default?
  • Workspace Indicator
  • Ubuntu Appindicators (apt install gnome-shell-extension-appindicator and restart Gnome)

I didn't go and look for Gnome Shell extentions outside what is packaged in Debian, as I'm very wary about running JavaScript code randomly downloaded from the internet with full access over my data and desktop interaction.

I also took care of checking that the Gnome Shell Extensions web page complains about the lacking "GNOME Shell integration" browser extension, because the web browser shouldn't be allowed to download random JavaScript from the internet and run it with full local access.

Yuck.

Run program dialog

The default run program dialog is almost, but not quite, totally useless to me, as it does not provide completion, not even just for executable names in path, and so it ends up being faster to open a new terminal window and type in there.

It's possible, in Gnome Shell settings, to bind a custom command to a key. The resulting keybinding will now show up in gsettings, though it can be located in a more circuitous way by grepping first, and then looking up the resulting path in dconf-editor:

gsettings list-recursively|grep custom-key org.gnome.settings-daemon.plugins.media-keys custom-keybindings ['/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/']

I tried out several run dialogs present in Debian, with sad results, possibly due to most of them not being tested on wayland:

  • fuzzel does not start
  • gmrun is gtk2, last updated in 2016, but works fine
  • kupfer segfaults as I type
  • rofi shows, but can't get keboard input
  • shellex shows a white bar at top of the screen and lots of errors on stderr
  • superkb wants to grab the screen for hotkeys
  • synapse searched news on the internet as I typed, which is a big no for me
  • trabucco crashes on startup
  • wofi works but looks like very much an acquired taste, though it has some completion that makes it more useful than Gnome's run dialog
  • xfrun4 (package xfce4-appfinder) struggles on wayland, being unable to center its window and with the pulldown appearing elsewhere in the screen, but it otherwise works

Both gmrun and xfrun4 seem like workable options, with xfrun4 being customizable with convenient shortcut prefixes, so xfrun4 it is.

TODO
  • Figure out what is still binding F10 to menu, and what I can do about it
  • Figure out how to reduce the size of window titlebars, which to my taste should be unobtrusive and not take 2.7% of vertical screen size each. There's a minwaita theme which isn't packaged in Debian. There's a User Theme extension, and then the whole theming can of worms to open. For another day.
  • Figure out if Gnome can be convinced to resize popup windows? Take the Gnome Terminal shortcut preferences for example: it takes ⅓ of the vertical screen and can only display ¼ of all available shortcuts, and I cannot find a valid reason why I shouldn't be allowed to enlarge it vertically.
  • Figure out if I can place shortcut launcher icons in the top panel, and how

I'll try to update these notes as I investigate.

Conclusion so far

I now have something that seems to work for me. A few papercuts to figure out still, but they seem manageable.

It all feels a lot harder than it should be: for something intended to be minimal, Gnome defaults feel horribly cluttered and noisy to me, continuosly getting in the way of getting things done until tamed into being out of the way unless called for. It felt like a device that boots into flashy demo mode, which needs to be switched off before actual use.

Thankfully it can be switched off, and now I have notes to do it again if needed.

gsettings oddly feels to me like a better UI than the interactive settings managers: it's more comprehensive, more discoverable, more scriptable, and more stable across releases. Most of the Q&A I found on the internet with guidance given on the UI was obsolete, while when given with gsettings command lines it kept being relevant. I also have the feeling that these notes would be easier to understand and follow if given as gsettings invocations instead of descriptions of UI navigation paths.

At some point I'll upgrade to Trixie and reevaluate things, and these notes will be a useful checklist for that.

Fingers crossed that this time I'll manage to stay on Wayland. If not, I know that Xfce is still there for me, and I can trust it to be both helpful and good at not getting in the way of my work.

Categories: FLOSS Project Planets

Kirigami Addons 1.6.0

Planet KDE - Sat, 2024-11-30 09:30

Kirigami Addons is a collection of additional components for Kirigami applications. This release brings mostly improvements to the FormCard module.

AboutPage

The about page provided by Kirigami Addons received many improvements. Joshua added icons to all the buttons.

I worked on the component section, which now contains more information about the default components as well as the underlying platform and now has a button to copy all this information to the clipboard. This is super helpful, when writing a bug report. There were also some small bug fixes with, for example, the license dialog being correctly sized.

RadioSelector

A new component is the RadioSelector, which is a simple component that allows one to choose an option between two or more choices in a horizontal layout. This is not a new component as it has already been used in Itinerary and Marknote for a long time.

There is also a FormCard version of this, called FormRadioSelectorDelegate.

FormPlaceholderMessageDelegate

Another new component is FormPlaceholderMessageDelegate, which is basically a Kirigami.PlaceholderMessage, but instead of putting it in a ListView, this one is to be put inside a FormCard.

FormPlaceholderMessageDelegate for the health certificate

Other

Volker fixed the Android integration of the date picker. He also added support for static builds (required for iOS and probably hopeful for other platforms).

Claudio fixed various issues with the DatePicker.

Joshua made the caption used in AlbumMaximizeComponent selectable with the mouse. He also fixed the separator for the IndicatorItemDelegate which only appeared after the first item.

I added icon support to FormSwitchDelegate, which is similar to what we already have in FormRadioDelegate and FormCheckDelegate.

Packager Section

Kirigami Addons 1.6.0 was tagged but the tarball are not yet available. I will update this post once it is available.

Categories: FLOSS Project Planets

OptiImage 1.0.0 is out!

Planet KDE - Sat, 2024-11-30 09:30

The first release of OptiImage is finally out! OptiImage is a useful image compressor that supports PNG, JPEG, WebP and SVG file types. It doesn’t do the compression itself but uses various tools like oxipng to do the compression.

OptiImage compressing screenshots

OptiImage’s settings page

Thanks to Mathis Brüchert for his work on the icon and to Soumyadeep Ghosh for a bunch of bug fixes and pushing me to do the release.

Packager Section

OptiImage 1.0.0 was tagged but the tarball are not yet available. I will update this post once it is available.

Categories: FLOSS Project Planets

Real Python: Python's F-String for String Interpolation and Formatting

Planet Python - Sat, 2024-11-30 09:00

Python f-strings offer a concise and efficient way to interpolate variables, objects, and expressions directly into strings. By prefixing a string with f or F, you can embed expressions within curly braces ({}), which are evaluated at runtime.

This makes f-strings faster and more readable compared to older approaches like the modulo (%) operator or the string .format() method. Additionally, f-strings support advanced string formatting using Python’s string format mini-language.

By the end of this tutorial, you’ll understand that:

  • An f-string in Python is a string literal prefixed with f or F, allowing for the embedding of expressions within curly braces {}.
  • To include dynamic content in an f-string, place your expression or variable inside the braces to interpolate its value into the string.
  • An f-string error in Python often occurs due to syntax issues, such as unmatched braces or invalid expressions within the string.
  • F-string calculation in Python involves writing expressions within the curly braces of an f-string, which Python evaluates at runtime.
  • Python 3.12 improved f-strings by allowing nested expressions and the use of backslashes.

This tutorial will guide you through the features and advantages of f-strings, including interpolation and formatting. By familiarizing yourself with these features, you’ll be able to effectively use f-strings in your Python projects.

Get Your Code: Click here to download the free sample code that shows you how to do string interpolation and formatting with Python’s f-strings.

Take the Quiz: Test your knowledge with our interactive “Python F-Strings” quiz. You’ll receive a score upon completion to help you track your learning progress:

Interactive Quiz

Python F-Strings

In this quiz, you'll test your knowledge of Python f-strings. With this knowledge, you'll be able to include all sorts of Python expressions inside your strings.

Interpolating and Formatting Strings Before Python 3.6

Before Python 3.6, you had two main tools for interpolating values, variables, and expressions inside string literals:

  1. The string interpolation operator (%), or modulo operator
  2. The str.format() method

You’ll get a refresher on these two string interpolation tools in the following sections. You’ll also learn about the string formatting capabilities that these tools offer in Python.

The Modulo Operator (%)

The modulo operator (%) was the first tool for string interpolation and formatting in Python and has been in the language since the beginning. Here’s what using this operator looks like in practice:

Python >>> name = "Jane" >>> "Hello, %s!" % name 'Hello, Jane!' Copied!

In this quick example, you use the % operator to interpolate the value of your name variable into a string literal. The interpolation operator takes two operands:

  • A string literal containing one or more conversion specifiers
  • The object or objects that you’re interpolating into the string literal

The conversion specifiers work as replacement fields. In the above example, you use the %s combination of characters as a conversion specifier. The % symbol marks the start of the specifier, while the s letter is the conversion type and tells the operator that you want to convert the input object into a string.

If you want to insert more than one object into your target string, then you can use a tuple. Note that the number of objects in the tuple must match the number of format specifiers in the string:

Python >>> name = "Jane" >>> age = 25 >>> "Hello, %s! You're %s years old." % (name, age) 'Hello, Jane! You're 25 years old.' Copied!

In this example, you use a tuple of values as the right-hand operand to %. Note that you’ve used a string and an integer. Because you use the %s specifier, Python converts both objects to strings.

You can also use dictionaries as the right-hand operand in your interpolation expressions. To do this, you need to create conversion specifiers that enclose key names in parentheses:

Python >>> "Hello, %(name)s! You're %(age)s years old." % {"name": "Jane", "age": 25} "Hello, Jane! You're 25 years old." Copied!

This syntax provides a readable approach to string interpolation with the % operator. You can use descriptive key names instead of relying on the positional order of values.

When you use the % operator for string interpolation, you can use conversion specifiers. They provide some string formatting capabilities that take advantage of conversion types, conversion flags, and some characters like the period (.) and the asterisk (*). Consider the following example:

Python >>> "Balance: $%.2f" % 5425.9292 'Balance: $5425.93' >>> print("Name: %s\nAge: %5s" % ("John", 35)) Name: John Age: 35 Copied! Read the full article at https://realpython.com/python-f-strings/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Real Python: What Does if __name__ == "__main__" Do in Python?

Planet Python - Sat, 2024-11-30 09:00

The if __name__ == "__main__" idiom is a Python construct that helps control code execution in scripts. It’s a conditional statement that allows you to define code that runs only when the file is executed as a script, not when it’s imported as a module.

When you run a Python script, the interpreter assigns the value "__main__" to the __name__ variable. If Python imports the code as a module, then it sets __name__ to the module’s name instead. By encapsulating code within if __name__ == "__main__", you can ensure that it only runs in the intended context.

By the end of this tutorial, you’ll understand that:

  • Python’s if __name__ == "__main__" idiom allows code to run only when the script is executed, not when it’s imported.
  • The idiom checks if the __name__ variable equals "__main__", confirming that the script is the top-level module.
  • Using this idiom helps prevent unintended code execution during module imports.
  • It’s useful for adding script-specific logic, such as user input or test cases, without affecting module imports.
  • Best practices suggest using this idiom minimally and placing it at the bottom of the script for clarity.

You’ve likely encountered Python’s if __name__ == "__main__" idiom when reading other people’s code. No wonder—it’s widespread! Understanding Python’s if __name__ == "__main__" idiom will help you to manage script execution and module imports effectively. In this tutorial you’ll explore its mechanics, appropriate usage, and best practices.

Take the Quiz: Test your knowledge with our interactive “Python Name-Main Idiom” quiz. You’ll receive a score upon completion to help you track your learning progress:

Interactive Quiz

Python Name-Main Idiom

Test your knowledge of Python's if __name__ == "__main__" idiom by answering a series of questions! You've probably encountered the name-main idiom and might have even used it in your own scripts. But did you use it correctly?

Get Your Code: Click here to download the free sample code that you’ll use to learn about the name-main idiom.

In Short: It Allows You to Execute Code When the File Runs as a Script, but Not When It’s Imported as a Module

For most practical purposes, you can think of the conditional block that you open with if __name__ == "__main__" as a way to store code that should only run when your file is executed as a script.

You’ll see what that means in a moment. For now, say you have the following file:

Python echo.py 1def echo(text: str, repetitions: int = 3) -> str: 2 """Imitate a real-world echo.""" 3 echoes = [text[-i:].lower() for i in range(repetitions, 0, -1)] 4 return "\n".join(echoes + ["."]) 5 6if __name__ == "__main__": 7 text = input("Yell something at a mountain: ") 8 print(echo(text)) Copied!

In this example, you define a function, echo(), that mimics a real-world echo by gradually printing fewer and fewer of the final letters of the input text.

Below that, in lines 6 to 8, you use the if __name__ == "__main__" idiom. This code starts with the conditional statement if __name__ == "__main__" in line 6. In the indented lines, 7 and 8, you then collect user input and call echo() with that input. These two lines will execute when you run echo.py as a script from your command line:

Shell $ python echo.py Yell something at a mountain: HELLOOOO ECHOOOOOOOOOO ooo oo o . Copied!

When you run the file as a script by passing the file object to your Python interpreter, the expression __name__ == "__main__" returns True. The code block under if then runs, so Python collects user input and calls echo().

Try it out yourself! You can download all the code files that you’ll use in this tutorial from the link below:

Get Your Code: Click here to download the free sample code that you’ll use to learn about the name-main idiom.

At the same time, if you import echo() in another module or a console session, then the nested code won’t run:

Python >>> from echo import echo >>> print(echo("Please help me I'm stuck on a mountain")) ain in n . Copied!

In this case, you want to use echo() in the context of another script or interpreter session, so you won’t need to collect user input. Running input() would mess with your code by producing a side effect when importing echo.

When you nest the code that’s specific to the script usage of your file under the if __name__ == "__main__" idiom, then you avoid running code that’s irrelevant for imported modules.

Nesting code under if __name__ == "__main__" allows you to cater to different use cases:

  • Script: When run as a script, your code prompts the user for input, calls echo(), and prints the result.
  • Module: When you import echo as a module, then echo() gets defined, but no code executes. You provide echo() to the main code session without any side effects.

By implementing the if __name__ == "__main__" idiom in your code, you set up an additional entry point that allows you to use echo() right from the command line.

There you go! You’ve now covered the most important information about this topic. Still, there’s more to find out, and there are some subtleties that can help you build a deeper understanding of this code specifically and Python more generally.

Read the full article at https://realpython.com/if-name-main-python/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Real Python: Logging in Python

Planet Python - Sat, 2024-11-30 09:00

Logging in Python lets you record important information about your program’s execution. You use the built-in logging module to capture logs, which provide insights into application flow, errors, and usage patterns. With Python logging, you can create and configure loggers, set log levels, and format log messages without installing additional packages. You can also generate log files to store records for later analysis.

Using a logging library instead of print() calls gives you better control over log management, formatting, and output destinations. The logging module also allows you to set severity levels, simplifying the management and filtering of log data.

By the end of this tutorial, you’ll understand that:

  • Logging in a computer involves recording program execution information for analysis.
  • You can use logging for debugging, performance analysis, and monitoring usage patterns.
  • No installation is needed for Python logging as the logging module is part of Python’s standard library.
  • Logging in Python works by configuring loggers and setting log levels.
  • Using a logging library provides structured logging and control over log output.
  • You should prefer logging over print() because it decreases the maintainance burden and allows you to manage log levels.
  • You can generate a log file in Python by setting filename and encoding through basicConfig().

You’ll do the coding for this tutorial in the Python standard REPL. If you prefer Python files, then you’ll find a full logging example as a script in the materials of this tutorial. You can download this script by clicking the link below:

Get Your Code: Click here to download the free sample code that you’ll use to learn about logging in Python.

Take the Quiz: Test your knowledge with our interactive “Logging in Python” quiz. You’ll receive a score upon completion to help you track your learning progress:

Interactive Quiz

Logging in Python

In this quiz, you'll test your understanding of Python's logging module. With this knowledge, you'll be able to add logging to your applications, which can help you debug errors and analyze performance.

If you commonly use Python’s print() function to get information about the flow of your programs, then logging is the natural next step for you. This tutorial will guide you through creating your first logs and show you how to make logging grow with your projects.

Starting With Python’s Logging Module

The logging module in Python’s standard library is a ready-to-use, powerful module that’s designed to meet the needs of beginners as well as enterprise teams.

Note: Since logs offer a variety of insights, the logging module is often used by other third-party Python libraries, too. Once you’re more advanced in the practice of logging, you can integrate your log messages with the ones from those libraries to produce a homogeneous log for your application.

To leverage this versatility, it’s a good idea to get a better understanding of how the logging module works under the hood. For example, you could take a stroll through the logging module’s source code

The main component of the logging module is something called the logger. You can think of the logger as a reporter in your code that decides what to record, at what level of detail, and where to store or send these records.

Exploring the Root Logger

To get a first impression of how the logging module and a logger work, open the Python standard REPL and enter the code below:

Python >>> import logging >>> logging.warning("Remain calm!") WARNING:root:Remain calm! Copied!

The output shows the severity level before each message along with root, which is the name the logging module gives to its default logger. This output shows the default format that can be configured to include things like a timestamp or other details.

In the example above, you’re sending a message on the root logger. The log level of the message is WARNING. Log levels are an important aspect of logging. By default, there are five standard levels indicating the severity of events. Each has a corresponding function that can be used to log events at that level of severity.

Note: There’s also a NOTSET log level, which you’ll encounter later in this tutorial when you learn about custom logging handlers.

Here are the five default log levels, in order of increasing severity:

Log Level Function Description DEBUG logging.debug() Provides detailed information that’s valuable to you as a developer. INFO logging.info() Provides general information about what’s going on with your program. WARNING logging.warning() Indicates that there’s something you should look into. ERROR logging.error() Alerts you to an unexpected problem that’s occured in your program. CRITICAL logging.critical() Tells you that a serious error has occurred and may have crashed your app.

The logging module provides you with a default logger that allows you to get started with logging without needing to do much configuration. However, the logging functions listed in the table above reveal a quirk that you may not expect:

Python >>> logging.debug("This is a debug message") >>> logging.info("This is an info message") >>> logging.warning("This is a warning message") WARNING:root:This is a warning message >>> logging.error("This is an error message") ERROR:root:This is an error message >>> logging.critical("This is a critical message") CRITICAL:root:This is a critical message Copied!

Notice that the debug() and info() messages didn’t get logged. This is because, by default, the logging module logs the messages with a severity level of WARNING or above. You can change that by configuring the logging module to log events of all levels.

Adjusting the Log Level

To set up your basic logging configuration and adjust the log level, the logging module comes with a basicConfig() function. As a Python developer, this camel-cased function name may look unusual to you as it doesn’t follow the PEP 8 naming conventions:

Read the full article at https://realpython.com/python-logging/ »

[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]

Categories: FLOSS Project Planets

Pages