Feeds
Talk Python to Me: #472: State of Flask and Pallets in 2024
KDE Human Interface Guidelines update
It’s been about a month and a half since I wrote about KDE’s new Human Interface Guidelines (HIG). It turns out there’s a surprising amount to report since then!
First of all, the news got picked up by Linux Magazine which did a story about it, including an interview with me! That felt nice.
Next, there have been a number of contributions and enhancements:
Joshua Goins- Fixed a lot of typos, awkward wordings, and small errors.
- Added information about using Qt to set Task Manager badges directly.
- Expanded the instructions on contributing to the HIG.
- Corrected several typos and spelling errors.
- Improved the grammatical correctness of one of the text recommendations.
- Polished up the text some more.
- Added additional suggested inclusiveness-related text replacements.
- Clarified when a hamburger menu is and isn’t appropriate.
- Updated the icon size recommendations.
- Added examples and suggested replacements for common acronyms.
- Wrote a recommendation for how to implement “go home” navigation.
- Mentioned when first-run wizards are and aren’t appropriate, migrating some content from our old “Frequently discussed topics” wiki page.
- Refined the recommendation for button length and combox text capitalization.
- Described when it’s appropriate to shorten button labels because nearby context indicates what they affect.
- Expanded the Icons page to offer more concrete guidelines about how to choose an icon and what style to use, and also added more pictures.
Overall I think it’s looking pretty good now, especially the Icons page which received a lot of attention recently.
In addition, there are more pending merge requests by Christoph Wolk, Emir Sari, and me. So it feels like an actual team project now! I think the goal of encouraging more contribution can be called a success.
Finally, Christoph Wolk and I have been going through System Settings pages and tweaking them to comply with the HIG. System Settings is good low-hanging fruit since it’s almost all QML at this point, so changes are easy. And there are a lot of pages, so it’s not hard to find small inconsistencies.
But were not finished yet! More eyeballs are needed. A few TODOs need resolving. More images could be helpful. So check out these two links to learn how to contribute changes:
- https://develop.kde.org/hig/#contributing
- https://invent.kde.org/documentation/develop-kde-org/-/blob/master/README.md
Even a beginner developer can help out by tweaking the user interface to conform to the HIG. And if you’re a hardcore developer, we still need some more components for writing powerful QML apps.
Still too scary? Then donate to KDE. Our budget is tiny, so your money genuinely does have an impact!
eiriksm.dev: Getting rid of cronner.module
Background: This blog post is part 2 of musings around legacy code on violinist.io. Violinist.io is an automated dependency updater for PHP/Composer. It's a SaaS built on Drupal 8, now running on Drupal 10, in its eigth year. In this second post I am looking at one way to approach legacy code, and how to use static analysis and test driven development to safely refactor and remove legacy code.
Some months ago I wrote about the combined feeling of shame and respect that surrounds legacy code. In an attempt to get rid of the legacy code in what is called cronner.module, I will start from the top of the .module file, and work my way towards removing it completely. From time to time, that can also result in a good blog post, I thought. Here's a blog post about that.
The first lines of the module file is this:
<?php /** * @file * Cronner module. * * Bad name, but what are you going to do, right? */The code here sounds a bit resigned when it asks about what are you going to do. But in this blog post, what are we going to do? We will start the process of getting rid of all of it, that's what we will do!
The first few lines of actual code are constant definitions. Here's the first one:
define('CRONNER_STATE_KEY_PREFIX', 'cronner_state.node.');So far we can speculate, but it seems to be a prefix. And it's used for storing some state about nodes. Defining constants like this might seem strange if you are a bit new to Drupal, but this way of defining constants was canonical in Drupal 7 and below, but also followed a lot of codebases into the Drupal 8 era. Drupal core as well actually. One such example is the constant FILE_EXISTS_RENAME which lived on until Drupal 9 (deprecated in 8.7.0). Anyway I digress.
What we want then, is to remove this one constant. Let's just try that and see what breaks? Here's the output from phpunit:
There were 19 errors: … Error: Undefined constant "CRONNER_STATE_KEY_PREFIX”The unit tests are failing. 19 of them. Good start, we have decent unit test coverage. Let's see if our integration tests fail?
xxx scenarios (xx passed, 112 failed) xxxx steps (xxxx passed, 49 failed, xxx skipped) xxmxx.xxs (90.59Mb)112 scenarios failed in our behat test suite. Great indication that we can remove things safely! Lastly let's do some static analysis with PHPStan:
Line web/modules/custom/cronner/cronner.module ------ --------------------------------------------------------------------- xxx Constant CRONNER_STATE_KEY_PREFIX not found.As expected, PHPStan also informs me about this change being a problem. Thanks PHPStan! It also indicates that among the scanned files, the constant is only used once. It's used like this:
/** * Gets the state key of a node. */ function _cronner_get_state_key(NodeInterface $node) { return CRONNER_STATE_KEY_PREFIX . $node->id(); }In addition to the comment being very little helpful, this tells me I have just encountered another part of the cronner module to remove. Let's remove this entire function as well since we already know the function must be covered by both unit tests and integration tests. Then let’s go ahead and use a combination of TDD and static analysis (with PHPStan) to make sure our refactoring is successful. I remove the function and re-run PHPStan:
Function _cronner_get_state_key not found. … [ERROR] Found 7 errorsPHPStan is helpfully pointing out all of the 7 places I should start with the refactoring. I look through some of them and see the usages are quite connected to some of the other constants in the beginning of the file:
define('CRONNER_PROJECT_NEW', 'new'); define('CRONNER_PROJECT_QUEUED', 'queued'); define('CRONNER_PROJECT_RUNNING', 'running'); define('CRONNER_PROJECT_PROCESSED', 'processed'); define('CRONNER_PROJECT_ERRORED', 'errored'); define('CRONNER_PROJECT_UNKNOWN', 'unknown');My mother always used to say. When you are tidying up your room it’s best to keep going while you are somewhat effective in deciding what to get rid of. If you find some of your old toys and start to play with them, it’s an indication that the tidying session is heading towards an unproductive state. And right now I feel effective and decide right away I am removing those constants as well. I guess that also makes the analogy to me tidying my room as a kid kind of weird, since the opposite would mean these constants were my toys, and I end up playing with them? I mean, I do end up playing with old code from time to time, but constants? No fun playing with.
But looking at these old toys, it also becomes obvious what we use these constants for. Node state could mean all kinds of things, right? This is used to store and update the job status of the projects. Like if they are currently queued, if they are currently running and so on.
So it turns out that while removing this, this actually seems like a good opportunity to clean up some of that code and make it a bit more modern. What I usually do when cleaning up custom code like this is to put as much as possible on drupal.org as open source code. This is the case now as well. So I open an issue to create a project run status service, and start to refactor the custom code and logic surrounding the removals of constants and functions in cronner.module. It can be found here: https://www.drupal.org/project/violinist_projects/issues/3453459.
Now I go ahead and start using this service. It quickly becomes obvious that some of the constants are also used in a map to display a human readable status to the user:
/** * Gets a human readable version of a status constant. * * @param string $status * A status constant. * * @return string * Something more sensible. */ function cronner_get_human_status($status) { $map = [ CRONNER_PROJECT_UNKNOWN => t('Unknown'), CRONNER_PROJECT_ERRORED => t('Errored'), CRONNER_PROJECT_PROCESSED => t('Processed'), CRONNER_PROJECT_RUNNING => t('Running'), CRONNER_PROJECT_NEW => t('New'), CRONNER_PROJECT_QUEUED => t('Queued'), ]; return !empty($map[$status]) ? $map[$status] : $status; }There’s also methods for getting a state from a node, and setting it. Which I am also removing, and finding usages of in static analysis:
xxx Function cronner_set_state not found. 💡 Learn more at https://phpstan.org/user-guide/discovering-symbols xxx Function _cronner_get_state_key not found. 💡 Learn more at https://phpstan.org/user-guide/discovering-symbols xxx Function cronner_get_human_status not found. 💡 Learn more at https://phpstan.org/user-guide/discovering-symbolsOr in unit tests like so:
ReplaceTokensTest::testClaimJobAndTokenReplaced Error: Call to undefined function cronner_set_state()Instead of these calls to getting the state, setting the state, and getting the human readable state, I am now using the newly created service. When I started writing this blog post I was very much looking forward to summarizing the numbers of deleted lines and how great that was, but in practice some of the changes are actually adding lines to the module:
- cronner_set_state($node, CRONNER_PROJECT_PROCESSED); + /** @var \Drupal\violinist_projects\ProjectRunStatus $run_status_service */ + $run_status_service = \Drupal::service('violinist_projects.run_status'); + $run_status_service->setRunStatusForProject($node, ProjectRunStatusValue::STATUS_PROCESSED);Jokes aside. After some successful deletions and refactorings into using a service I am looking at 99 deletions and 55 additions. A net positive result I would say. Unfortunately there is still quite a way to go before I can go ahead and delete the entire folder called “cronner”. But at least I managed to refactor the codebase and delete the first 7 lines of constants in the file.
To celebrate this tiny step towards getting rid of cronner.module I tried to search for cronner on giphy. No hits, at this point. Oh well, here is an animated gif that supposedly illustrates “cronn”
FSF Blogs: A world where software freedom has a fighting chance and hope exists
A world where software freedom has a fighting chance and hope exists
GSoC'24 Okular | Week 4-8 Recap
The past weeks involved a lot of work surrounding the implementation of Acrobat specific methods for processing form fields, added support for different types of form widgets and some UI improvements were made or are being worked upon. A detailed list of MRs merged and raised is described below.
MRs merged:- AFTime_Keystroke implementation : This method implementation specifies what input keystrokes are allowed in a form field accepting time information. !MR987
- AFSpecial_Keystroke implementation : This method implementation specifies what input keystrokes are allowed in form fields of special type i.e. those that accept as input phone numbers, ssn and zip codes. !MR1013
- AFPercent_Keystroke and AFNumber_Keystroke methods implemented : These methods specify input keystrokes for percents and numerical data. !MR988
- Implement AFDate_KeystrokeEx and AFDate_FormatEx methods. : For correctly accepting input dates and formatting them according to some pre-specified format. !MR1017
- Global object implementation : A very basic implementation of global object that allows users to read and write to the global object. Persistence and subscription not supported as of now. !MR1016
- Commit values and restore: Implemented the feature to restore values to the previous committed value upon entering a value that is rejected by a keystroke action.!MR985
- Fix numerical interpretation in form fields: Calculations were suffering from a major bug 474661 that caused incorrect results when using different locales. This was fixed in the !MR992. The MR focused on how numerical values should be interpreted in form fields.
- Implemented DocClose, DocWillPrint, DocDidPrint, DocWillSave and DocDidSave events: Now actions are triggered during these events with the changes introduced in the !MR1019.
- Radio Buttons and Check Boxes size fix: Now radio buttons and check boxes are painted with correct size and resized when zooming to provide a better user experience. !MR1015
- Implement value (getter), numItems, currentValueIndices properties and getItemAt for FormFieldChoices: These methods were introduced to improve the functionality of FormFieldChoices. !MR1031
- ResetForm functionality in Poppler: The Reset form functionality was added to the Qt frontend in Poppler. Introduced in this commit
Along with these, more MRs are under works for things like implementing UI experience when using form fields and extending functionality of different types of form fields and actions.
See you next time. Cheers!
libtool @ Savannah: libtool-2.5.1 released [beta]
Libtoolers!
The Libtool Team is pleased to announce the release of libtool 2.5.1, a beta release.
GNU Libtool hides the complexity of using shared libraries behind a
consistent, portable interface. GNU Libtool ships with GNU libltdl, which
hides the complexity of loading dynamic runtime libraries (modules)
behind a consistent, portable interface.
There have been 33 commits by 8 people in the 10 weeks since 2.5.0.
See the NEWS below for a brief summary.
Thanks to everyone who has contributed!
The following people contributed changes to this release:
Bruno Haible (3)
Ileana Dumitrescu (24)
Julien ÉLIE (1)
Khem Raj (1)
Peter Kokot (1)
Richard Purdie (1)
Vincent Lefevre (1)
trcrsired (1)
Ileana
[on behalf of the libtool maintainers]
==================================================================
Here is the GNU libtool home page:
https://gnu.org/s/libtool/
For a summary of changes and contributors, see:
https://git.sv.gnu.org/gitweb/?p=libtool.git;a=shortlog;h=v2.5.1
or run this command from a git-cloned libtool directory:
git shortlog v2.5.0..v2.5.1
Here are the compressed sources:
https://alpha.gnu.org/gnu/libtool/libtool-2.5.1.tar.gz (1.9MB)
https://alpha.gnu.org/gnu/libtool/libtool-2.5.1.tar.xz (1020KB)
Here are the GPG detached signatures:
https://alpha.gnu.org/gnu/libtool/libtool-2.5.1.tar.gz.sig
https://alpha.gnu.org/gnu/libtool/libtool-2.5.1.tar.xz.sig
Use a mirror for higher download bandwidth:
https://www.gnu.org/order/ftp.html
Here are the SHA1 and SHA256 checksums:
5e2f00be5b616b0a6120b2947e562b8448e139b2 libtool-2.5.1.tar.gz
aoPtr9QtTi69wJV5+ZzoKNX5MvFzjeAklcyMKITkMM4= libtool-2.5.1.tar.gz
9f72b896f593c4f81cdd6c20c9d99463663e48a9 libtool-2.5.1.tar.xz
0oDmTIzb8UXXb7kbOyGe2rAb20PLmUAuSsuX0BAGNv0= libtool-2.5.1.tar.xz
Verify the base64 SHA256 checksum with cksum -a sha256 --check
from coreutils-9.2 or OpenBSD's cksum since 2007.
Use a .sig file to verify that the corresponding file (without the
.sig suffix) is intact. First, be sure to download both the .sig file
and the corresponding tarball. Then, run a command like this:
gpg --verify libtool-2.5.1.tar.gz.sig
The signature should match the fingerprint of the following key:
pub rsa4096 2021-09-23 [SC]
FA26 CA78 4BE1 8892 7F22 B99F 6570 EA01 146F 7354
uid Ileana Dumitrescu <ileanadumi95@protonmail.com>
uid Ileana Dumitrescu <ileanadumitrescu95@gmail.com>
If that command fails because you don't have the required public key,
or that public key has expired, try the following commands to retrieve
or refresh it, and then rerun the 'gpg --verify' command.
gpg --locate-external-key ileanadumi95@protonmail.com
gpg --recv-keys 6570EA01146F7354
wget -q -O- 'https://savannah.gnu.org/project/release-gpgkeys.php?group=libtool&download=1' | gpg --import -
As a last resort to find the key, you can try the official GNU
keyring:
wget -q https://ftp.gnu.org/gnu/gnu-keyring.gpg
gpg --keyring gnu-keyring.gpg --verify libtool-2.5.1.tar.gz.sig
This release was bootstrapped with the following tools:
Autoconf 2.72e
Automake 1.17
Gnulib v1.0-563-gd3efdd55f3
NEWS
- Noteworthy changes in release 2.5.1 (2024-07-25) [beta]
** New features:
- Support C++17 compilers in the C++ tests.
- Add sysroot to library path for cross builds.
** Important incompatible changes:
- Autoconf 2.64 is required for libtool.m4 to use AS_VAR_APPEND.
** Bug fixes:
- Fix for uninitialized variable in libtoolize.
- Skip Fortran/C demo tests when using Clang with fsanitize to
avoid an incompatible ASan runtime.
- Updated documentation for testing.
- Fix failing test to account for program-prefix usage.
- Replaced a deprecated macro to remove warning messages in the
testsuite logs.
- Fix number of arguments for AC_CHECK_PROG call.
- Fix test failures with no-canonical-prefixes flag by checking
if the flag is supported first.
- Fix test failures with no-undefined flag by checking host OS
before appending the flag.
- Skip test when passing CXX flags through libtool to avoid test
failure on NetBSD.
- Remove texinfo warning for period in node name of pxref.
- Alter syntax in sed command to fix numerous test failures
on 64-bit windows/cygwin/mingw.
- Fix 'Wstrict-prototypes' warnings.
- Correct DLL Installation Path for mingw multilib builds.
- Fix '--preserve-dup-deps' stripping duplicates.
- Disable chained fixups for macOS, since it is not compatible with
'-undefined dynamic_lookup'.
** Changes in supported systems or compilers:
- Support additional flang-based compilers, 'flang-new' and 'ftn'.
Enjoy!
The Drop Times: A Look Back: Highlights from DrupalCamp Asheville 2024
mark.ie: My LocalGov Drupal contributions for week-ending July 26th, 2024
Here's what I've been working on for my LocalGov Drupal contributions this week. Thanks to Big Blue Door for sponsoring the time to work on these.
Tag1 Consulting: Migrating Your Data from D7 to D10: Migrating content types
This step-by-step series has covered a lot of ground on planning and preparing for a Drupal 7 to Drupal 10 migration. Today, we start putting that knowledge into practice by automatically migrating content types. First, we will execute a migration to pull all content types in Drupal 7. Then, we will customize the migration to remove unnecessary content types. Finally, we will learn how a separate node title label migration also affects content type configuration in Drupal 10.
Read more mauricio Thu, 07/25/2024 - 06:32Drupal Association blog: FAQs About Drupal 7's End of Life
As Drupal 7's end-of-life (EOL) approaches on 5 January 2025, many users have questions about what this means for their Drupal websites and what steps they need to take. Here, we address the most frequently asked questions to help you navigate this transition.
What does end-of-life mean for Drupal 7?End-of-life (EOL) means that Drupal 7 will no longer receive security updates, fixes, or official support from the Drupal community after 5 January 2025. This will impact the security, compliance, and functionality of any site that continues to run on Drupal 7.
Why is Drupal 7 being retired?Drupal 7 will be 14 years old when it reaches the end of life. That's a long time in the software world. Drupal 7 is being retired to allow the Drupal community to focus on newer versions built with a more modern architecture and more advanced capabilitie. This shift ensures that resources are directed towards maintaining and innovating the more modern versions of Drupal, including the Drupal Starshot intiative.
What are the key dates I need to know?- 23 February 2022: Announcement of Drupal 7 EOL extension.
- 1 August 2023: Commencement of reduced support for moderately critical issues, alongside other support changes.
- 5 January 2025: Official end-of-life date for Drupal 7.
Once Drupal 7 reaches its EOL, no further security advisories or updates will be provided. If you must remain on Drupal 7, we recommend opting for a commercial vendor who offers extended support. HeroDevs Drupal 7 Never-Ending Support (NES), is the first such offering available. This service is a seamless drop-in replacement for Drupal 7, providing your site with ongoing security updates, compliance support, and compatibility fixes past end-of-life.
What happens to unsupported modules and themes?Starting 1 August 2023, any unsupported Drupal 7 module or theme will no longer be eligible for new maintenance once it goes unsupported. If a module or theme you rely on becomes unsupported, it’s crucial to proactively adopt or migrate it to a newer version. HeroDevs Drupal 7 NES also provides module support if you choose that route.
What are the PHP version requirements?From 1 August 2023, Drupal 7 no longer supports PHP versions lower than 5.6. Further increases in the minimum PHP requirement may occur before Drupal 7's EOL.
Are there any specific operating system considerations?Drupal 7 security fixes for Windows-only issues ceased on 1 August 2023. If your site runs on Windows, migrating to another operating system is recommended.
Will drupal.org continue to package Drupal 7 distributions?No, as of 1 August 2023, Drupal.org stopped packaging Drupal 7 distributions. Users needing a distribution built must use Drush make locally.
What are my options moving forward?- Migrate to Modern Drupal: Upgrading to Drupal 10 or the upcoming Drupal 11 is strongly recommended to ensure continued security, support, and access to new features. Modern Drupal versions adopt the latest PHP standards and offer enhanced performance and security. In addition, Drupal Starshot is coming at the end of 2024, which bundles Drupal core with cutting-edge features and easier maintenance.
- Extended Security Support: The Drupal Association has partnered with HeroDevs to offer Drupal 7 Never-Ending Support (NES). This service provides ongoing security updates, compliance support, and compatibility fixes for Drupal 7 sites, allowing businesses more time to transition.
- Stay on Unsupported Drupal 7: Continuing to use Drupal 7 after its EOL is an option but comes with significant risks, including increased vulnerability to security exploits and compliance issues. Over time, support for PHP versions and other dependencies will also wane, making it harder to maintain your site. Other vendors may join the program before end of life.
The Drupal Association is certifying migration partners to help Drupal 7 site owners transition. Certified Migration Partners will be promoted on Drupal.org and can provide resources to assist in the migration process.
What should I do if I need help?For assistance, consider engaging with the Drupal community or Certified Migration Partners. Donating to the Drupal Security Team or sponsoring core maintainers and contributors can also help ensure the continuity and security of Drupal projects.
ConclusionOrganizations must make informed decisions as Drupal 7's EOL approaches to maintain security, compliance, and functionality. Upgrading to Drupal 10, Drupal 11, or leveraging extended support options will position your site for long-term success.
Real Python: Quiz: Getting Started With Testing in Python
In this quiz, you’ll test your understanding of testing your Python code.
Testing in Python is a huge topic and can come with a lot of complexity, but it doesn’t need to be hard. You can get started creating simple tests for your application in a few easy steps and then build on it from there.
With this quiz, you can check your understanding of the fundamentals of Python testing. Good luck!
[ 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 ]
Real Python: Quiz: Python Basics: Lists and Tuples
In Python Basics: Lists and Tuples, you’ve met two new and important data structures:
- Lists
- Tuples
Both of these data types are sequences, meaning they are objects that contain other objects in a certain order. They each have some important distinguishing properties and come with their own set of methods for interacting with objects of each type.
In this quiz, youll test your knowledge of:
- Creating lists and tuples
- Indexing and slicing lists and tuples
- Iterating over these containers
- Understanding their differences, specifically the impact of mutability
- Adding and removing items from a list
Then, you can move on to other Python Basics courses.
[ 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 ]
Qt Creator 14 released
We are happy to announce the release of Qt Creator 14!
Hailey Schoelkopf: Voices of the Open Source AI Definition
The Open Source Initiative (OSI) is running a blog series to introduce some of the people who have been actively involved in the Open Source AI Definition (OSAID) co-design process. The co-design methodology allows for the integration of diverging perspectives into one just, cohesive and feasible standard. Support and contribution from a significant and broad group of stakeholders is imperative to the Open Source process and is proven to bring diverse issues to light, deliver swift outputs and garner community buy-in.
This series features the voices of the volunteers who have helped shape and are shaping the Definition.
Meet Hailey Schoelkopf What’s your background related to Open Source and AI?One of the main reasons I was able to get more deeply involved in AI research was through open research communities such as the BigScience Workshop and EleutherAI, where discussions and collaboration were available to outsiders. These opportunities to share knowledge and learn from others more experienced than me were crucial to learning about the field and growing as a practitioner and researcher.
I co-lead the training of the Pythia language models (https://arxiv.org/abs/2304.01373), some of the first fully-documented and reproducible large-scale language models with as many related artifacts as possible released Open Source. We were happy and lucky to see these models fill a clear need, especially in the research community, where Pythia has since contributed to a large amount of studies attempting to build our understanding of LLMs, including interpreting their internals, understanding the process by which these models improve over training, and disentangling some of the effects of the dataset contents on these models’ downstream behavior.
What motivated you to join this co-design process to define Open Source AI?There has been a significant amount of confusion induced by the fact that not all ‘open-weights’ AI models released are released under OSI-compliant licenses-–or impose restrictions on their usage or adaptation-–so I was excited that OSI was working on reducing this confusion by producing a clear definition that could be used by the Open Source community. I more directly joined the process by helping discuss how the Open Source AI Definition could be mapped onto the Pythia language models and the accompanying artifacts we released.
Can you describe your experience participating in this process? What did you most enjoy about it and what were some of the challenges you faced?Deciding what counts as sufficient transparency and modifiability to be Open Source was an interesting problem. Although public model weights are very beneficial to the Open Source community, releasing model weights without sufficient detail to understand the model and its development process to make modifications or understand reasons behind its design and resulting characteristics can hinder understanding or prevent the full benefits of a completely Open Source model from being realized.
Why do you think AI should be Open Source?There are clear advantages to having models that are Open Source. Access to such fully-documented models can help a much, much broader group of people–trained researchers and also many others–who can use, study, and examine these models for their own purposes. While not every model should be made Open Source under all conditions, wider scrutiny and study of these models can help increase our understanding of AI systems’ behavior, raise societal preparedness and awareness of AI capabilities, and improve these models’ safety by allowing more people to understand them and explore their flaws.
With the Pythia language models, we’ve seen many researchers explore questions around the safety and biases of these models, including a breadth of questions we’d not have been able to study ourselves, or many that we could not even anticipate. These different perspectives are a crucial component in making AI systems safer and more broadly beneficial.
What do you think is the role of data in Open Source AI?Data is a crucial component of AI systems. Transparency around (and, potentially, open release of) training datasets can enable a wide range of extended benefits to researchers, practitioners, and society at large. I think that for a model to be truly Open Source, and to derive the greatest benefits from its openness, information on training data must be shared transparently. This information also importantly allows various members of the Open Source community to avoid replicating each other’s work independently. Transparent sharing about motivations and findings with respect to dataset creation choices can improve the community’s collective understanding of system and dataset design for the future and minimize overlapping, wasted effort.
Has your personal definition of Open Source AI changed along the way? What new perspectives or ideas did you encounter while participating in the co-design process?An interesting perspective that I’ve grown to appreciate is that the Open Source AI definition includes public and Open Source licensed training and inference code. Actually making one’s Open Source AI model effectively usable by the community and practitioners is a crucial step of promoting transparency, though not often enough discussed.
What do you think the primary benefit will be once there is a clear definition of Open Source AI?Having a clear definition of Open Source AI can make it clearer where existing currently “open” systems fall, and potentially encourage future open-weights models to be released with more transparency. Many current open-weights models are shared under bespoke licenses with terms not compliant with Open Source principles–this creates legal uncertainty and also makes it less likely that a new open-weights model release will benefit practitioners at large or contribute to better understanding of how to design better systems. I would hope that a clearer Open Source AI definition will make it easier to draw these lines and encourage those currently releasing open-weights models to do so in a way more closely fitting the Open Source AI standard.
What do you think are the next steps for the community involved in Open Source AI?An exciting future direction for the Open Source AI research community is to explore methods for greater control over AI model behavior; attempting to explore approaches to collective modification and collaborative development of AI systems that can adapt and be “patched” over time. A stronger understanding of how to properly evaluate these systems for capabilities, robustness, and safety will also be crucial. I hope to see the community direct greater attention to evaluation in the future as well.
How to get involvedThe OSAID co-design process is open to everyone interested in collaborating. There are many ways to get involved:
- Join the working groups: be part of a team to evaluate various models against the OSAID.
- Join the forum: support and comment on the drafts, record your approval or concerns to new and existing threads.
- Comment on the latest draft: provide feedback on the latest draft document directly.
- Follow the weekly recaps: subscribe to our newsletter and blog to be kept up-to-date.
- Join the town hall meetings: participate in the online public town hall meetings to learn more and ask questions.
- Join the workshops and scheduled conferences: meet the OSI and other participants at in-person events around the world.
Gary Benson: Python atomic counter
Do you need a thread-safe atomic counter in Python? Use itertools.count():
>>> from itertools import count >>> counter = count() >>> next(counter) 0 >>> next(counter) 1 >>> next(counter) 2I found this in the decorator package, labelled Atomic get-and-increment provided by the GIL. So simple! So cool!
The Drop Times: Drupal Cafe Lutsk #25 Recap: Key Insights and Community Support
Formatting Selected Text in QML
Let’s say we’re working on a QML project that involves a TextEdit.
There’s some text in it:
here is some text
We want to select part of this text and hit ctrl+B to make it bold:
here is some text
In Qt Widgets, this is trivial, but not so much in QML – we can get font.bold of the entire TextEdit, but not of just the text in the selection. We have to implement formattable selections manually.
To do this, there are two approaches we’ll look at:
- The first is to hack it together by getting the formatted text from the selection and editing this. Rather than setting properties of selected text, this solution actually inserts or removes formatting symbols from the underlying rich text source.
- The other way to do this is to create a QML object that is implemented in C++ and exposed to TextEdit as a property. This way we can make use of QTextDocument and QTextCursor to actually set text properties within the selection area. This more closely follows the patterns expected in Qt.
In Qt 6.7, the TextEdit QML element does have a cursorSelection property that works in this way, and by dissecting its implementation, we can write a pseudo-backport for other Qt versions.
Before we do this, let’s take a look at the hacky QML/JS solution.
Hacky ApproachWe start by focusing on just making ctrl+B bold shortcuts work:
TextEdit { id: txtEdit anchors.fill: parent selectByMouse: true textFormat: TextEdit.RichText } Shortcut { sequence: StandardKey.Bold onActivated: { if (txtEdit.selectedText.length > 0) { const start = txtEdit.selectionStart const end = txtEdit.selectionEnd let sel = txtEdit.getFormattedText(start, end) .split("<!--StartFragment-->")[1] .split("<!--EndFragment-->")[0] txtEdit.remove(start, end) if (sel.includes("font-weight:600;")) sel = sel.replace("font-weight:600;", "") else sel = "<b>" + sel + "</b>" txtEdit.insert(txtEdit.cursorPosition, sel) txtEdit.select(start, end) } } }Notice that we actually remove and replace the selected text, and reselect the insertion manually.
We can set up similar shortcuts for italics and underline trivially, but what if we want to set font properties of only the text in the selected area?
To keep things simple, let’s see what happens if we want to set just the font family and size:
FontDialog { id: fontDlg } Shortcut { id: fontShortcut property string sel: "" property int start: 0 property int end: 0 sequence: StandardKey.Find onActivated: { if (txtEdit.selectedText.length > 0) { start = txtEdit.selectionStart end = txtEdit.selectionEnd sel = txtEdit.getFormattedText(start, end) .split("<!--StartFragment-->")[1] .split("<!--EndFragment-->")[0] fontDlg.open() } } } Connections { target: fontDlg function onAccepted() { txtEdit.remove(fontShortcut.start, fontShortcut.end) if (fontShortcut.sel.includes("font-family:")) { let fontToReplace = fontShortcut.sel.split("font-family:'")[1].split("';")[0] fontShortcut.sel = fontShortcut.sel.replace(fontToReplace, fontDlg.font.family) } else { fontShortcut.sel = "<span style=\"font-family: '" + fontDlg.font.family + "'; font-size:" + (fontDlg.font.pixelSize ? fontDlg.font.pixelSize : fontDlg.font.pointSize) + "\">" + fontShortcut.sel + "</span>" } txtEdit.insert(txtEdit.cursorPosition, fontShortcut.sel) txtEdit.select(fontShortcut.start, fontShortcut.end) } }If we start messing with other font style properties like italic, bold, spacing, etc., we will end up with almost unreadably nasty string manipulation here.
This solution is overall hacky, as we replace HTML-formatted text from a snipped out section. It would be more Qt-idiomatic to retrieve QFont info from a selection and set the properties without editing raw rich text. Furthermore, it’s better to do as much logic as possible in C++ rather than with JavaScript in QML.
Implementation of cursorSelection in Qt 6.7 QMLLet’s take a look at the cursorSelection property of QtQuick TextEdit in Qt 6.7.
By looking at its property declaration in qquicktextedit_p.h, the type of cursorSelection is QQuickTextSelection.
This type is very basic. It has four read/write properties.
Here is the header qquicktextselection_p.h:
class Q_QUICK_EXPORT QQuickTextSelection : public QObject { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL) Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged FINAL) QML_ANONYMOUS QML_ADDED_IN_VERSION(6, 7) public: explicit QQuickTextSelection(QObject *parent = nullptr); QString text() const; void setText(const QString &text); QFont font() const; void setFont(const QFont &font); QColor color() const; void setColor(QColor color); Qt::Alignment alignment() const; void setAlignment(Qt::Alignment align); Q_SIGNALS: void textChanged(); void fontChanged(); void colorChanged(); void alignmentChanged(); private: QTextCursor cursor() const; void updateFromCharFormat(const QTextCharFormat &fmt); void updateFromBlockFormat(); private: QTextCursor m_cursor; QTextCharFormat m_charFormat; QTextBlockFormat m_blockFormat; QQuickTextDocument *m_doc = nullptr; QQuickTextControl *m_control = nullptr; };Notice we’ve got these private data members:
QTextCursor m_cursor; QTextCharFormat m_charFormat; QTextBlockFormat m_blockFormat; QQuickTextDocument *m_doc = nullptr; QQuickTextControl *m_control = nullptr;The m_doc and m_control are retrieved from the TextEdit which parents the selection object. The object is always constructed by a QQuickTextEdit, so in the constructor, the parent is cast to one using qmlobject_cast. Then we set these two fields.
QQuickTextSelection::QQuickTextSelection(QObject *parent) : QObject(parent) { // When QQuickTextEdit creates its cursorSelection, it passes itself as the parent if (auto *textEdit = qmlobject_cast<QQuickTextEdit *>(parent)) { m_doc = textEdit->textDocument(); m_control = QQuickTextEditPrivate::get(textEdit)->control; // ... // ...Now what are m_charFormat and m_blockFormat?
Text documents are composed of a list of text blocks, which can be paragraphs, lists, tables, images, etc. Thus, a block format represents an individual block’s alignment formatting. Char format contains formatting information at the character level, like font family, weight, style, size, color, and so forth.
To initialize these, we need to get the cursor from the text control.
QTextCursor QQuickTextSelection::cursor() const { if (m_control) return m_control->textCursor(); return m_cursor; }The cursor will give us a char format and a block format, which we use to get the font / color / alignment at the cursor’s location.
QFont QQuickTextSelection::font() const { return cursor().charFormat().font(); } // ... QColor QQuickTextSelection::color() const { return cursor().charFormat().foreground().color(); } // ... Qt::Alignment QQuickTextSelection::alignment() const { return cursor().blockFormat().alignment(); }currentCharFormatChanged is emitted by QQuickTextControl when the cursor moves or the document’s contents change. If this format is indeed different from the fields of the selection object, we must update them and emit the selection’s signals, just as we would in setters. Since we keep track of block alignment too, we have to do the same when the cursor moves and block format is different.
QQuickTextSelection::QQuickTextSelection(QObject *parent) : QObject(parent) { // When QQuickTextEdit creates its cursorSelection, it passes itself as the parent if (auto *textEdit = qmlobject_cast<QQuickTextEdit *>(parent)) { m_doc = textEdit->textDocument(); m_control = QQuickTextEditPrivate::get(textEdit)->control; connect(m_control, &QQuickTextControl::currentCharFormatChanged, this, &QQuickTextSelection::updateFromCharFormat); connect(m_control, &QQuickTextControl::cursorPositionChanged, this, &QQuickTextSelection::updateFromBlockFormat); } } // ... // ... // ... inline void QQuickTextSelection::updateFromCharFormat(const QTextCharFormat &fmt) { if (fmt.font() != m_charFormat.font()) emit fontChanged(); if (fmt.foreground().color() != m_charFormat.foreground().color()) emit colorChanged(); m_charFormat = fmt; } inline void QQuickTextSelection::updateFromBlockFormat() { QTextBlockFormat fmt = cursor().blockFormat(); if (fmt.alignment() != m_blockFormat.alignment()) emit alignmentChanged(); m_blockFormat = fmt; }Here are the setters for the properties, which use the cursor to access and mutate the character or block properties at its position.
void QQuickTextSelection::setText(const QString &text) { auto cur = cursor(); if (cur.selectedText() == text) return; cur.insertText(text); emit textChanged(); } // ... void QQuickTextSelection::setFont(const QFont &font) { auto cur = cursor(); if (cur.selection().isEmpty()) cur.select(QTextCursor::WordUnderCursor); if (font == cur.charFormat().font()) return; QTextCharFormat fmt; fmt.setFont(font); cur.mergeCharFormat(fmt); emit fontChanged(); } // ... void QQuickTextSelection::setColor(QColor color) { auto cur = cursor(); if (cur.selection().isEmpty()) cur.select(QTextCursor::WordUnderCursor); if (color == cur.charFormat().foreground().color()) return; QTextCharFormat fmt; fmt.setForeground(color); cur.mergeCharFormat(fmt); emit colorChanged(); } // ... void QQuickTextSelection::setAlignment(Qt::Alignment align) { if (align == alignment()) return; QTextBlockFormat format; format.setAlignment(align); cursor().mergeBlockFormat(format); emit alignmentChanged(); }Now, we want to do something like this in our code. The issue is that this implementation resides in the Qt source code itself, and cursorSelection is a property of QQuickTextEdit. If we want to do something like this without changing Qt source code, we have to use attached properties.
Implementing an Attached PropertyUsing CursorSelection as an attached property for a TextEdit in QML might look something like this:
Item { // ... // ... // ... Shortcut { // ctrl+B to toggle bold / not bold for selection sequence: StandardKey.Bold onActivated: { txtEdit.CursorSelection.font = Qt.font({ bold: txtEdit.CursorSelection.font.bold !== true }) } } TextEdit { id: txtEdit // ... CursorSelection.font { bold: false italic: false underline: false } } }To create our own attached property, we have to create two classes: CursorSelectionAttached and CursorSelection.
CursorSelectionAttached will contain the implementation of the selection, while CursorSelection serves as the attaching type, using the qmlAttachedProperties() method to expose the signals and properties of an instance of CursorSelectionAttached to the parent to which it is attached.
CursorSelection also needs the QML_ATTACHED() macro in its header declaration, and we must specify that it has an attached property with the macro QML_DECLARE_TYPEINFO() outside the class scope.
Thus, CursorSelection will just look like this:
// CursorSelection.h class CursorSelection : public QObject { Q_OBJECT QML_ATTACHED(CursorSelectionAttached) QML_ELEMENT public: static CursorSelectionAttached *qmlAttachedProperties(QObject *object); }; QML_DECLARE_TYPEINFO(CursorSelection, QML_HAS_ATTACHED_PROPERTIES)Where the entire implementation is just this function definition:
// CursorSelection.cpp CursorSelectionAttached *CursorSelection::qmlAttachedProperties(QObject *object) { if (auto *textEdit = qobject_cast<QQuickTextEdit *>(object)) return new CursorSelectionAttached(textEdit); return nullptr; }Notice that we perform the qobject_cast here and forward the result as the parent of the attached object. This way we only construct an attached object if we can cast the parent object to a TextEdit.
Now, let’s see how CursorSelectionAttached should be implemented. We begin with the constructor:
// we know that parent will be a QQuickTextEdit * CursorSelectionAttached::CursorSelectionAttached(QQuickTextEdit *parent) noexcept : QObject(parent) , mEdit(parent) // this is the TextEdit we are attached to { // make sure the QTextDocument exists const auto *const quickDoc = mEdit->textDocument(); // QQuickTextDocument * auto *doc = quickDoc->textDocument(); // QTextDocument * Q_ASSERT(doc != nullptr); // retrieve QTextCursor from the QTextDocument mCursor = QTextCursor(doc); // When deselecting, the cursor position and anchor are // set to the TextEdit's cursor position connect(mEdit, &QQuickTextEdit::selectedTextChanged, this, &CursorSelectionAttached::moveAnchorIfDeselected); connect(mEdit, &QQuickTextEdit::cursorPositionChanged, this, &CursorSelectionAttached::updatePosition); // if we set a format with no selection, we keep it in an optional // then when new text is added, it will have this formatting // for example, with no selection we press ctrl+B and then start // typing. we expect the text to be bold. connect(mEdit->textDocument()->textDocument(), &QTextDocument::contentsChange, this, &CursorSelectionAttached::applyFormatToNewTextIfNeeded); }Note that we connect to these three slots:
- moveAnchorIfDeselected
- updatePosition
- applyFormatToNewTextIfNeeded
Let’s investigate the purpose of these.
moveAnchorIfDeselected is invoked when the TextEdit’s selected text changes. A QTextCursor has an anchor, which controls selection area. If text is being selected, the anchor is fixed in place where the selection is started, and the cursor position moves independently of the anchor. The selection area is located between the two positions. When a cursor moves without selecting anything, the anchor is located at and moves along with the cursor position.
Thus, when a cursor’s position is moved, we need to know if the anchor should be moved with it.
Since we invoke moveAnchorIfDeselected when the selected text changes, we know that if the selection is now empty, this means there was a selection that has been deselected. Thus, the cursor and anchor should be equal to one another.
void CursorSelectionAttached::moveAnchorIfDeselected() { if (mEdit->selectedText().isEmpty()) mCursor.setPosition(mEdit->cursorPosition(), QTextCursor::MoveAnchor); }updatePosition is invoked when the TextEdit’s cursor position changes. Depending on the TextEdit’s selection start and end positions, there are a few ways the cursor could be updated.
If there is no selected area in the TextEdit, the cursor and anchor should move together. If a selection’s start and end position both change, we must move the cursor twice: once to the start position, with the anchor moving, and once to the end position, with the anchor fixed in place. If the selection area is being resized, for example by dragging or using Shift+ArrowKeys, the cursor should move with the anchor fixed in place.
void CursorSelectionAttached::updatePosition() { // if there's no selection, just move the cursor & anchor if (mEdit->selectionEnd() == mEdit->selectionStart()) { mCursor.setPosition(mEdit->cursorPosition(), QTextCursor::MoveAnchor); } // if both the start and end need to be updated: // move cursor and anchor to selection start, and // move cursor to selection end while keeping anchor at start // // we have to make sure the anchor is moved correctly so the // whole selection matches up -- otherwise cursor selection // start or end might be in the middle of the actual // selection, wherever the anchor is else if (mEdit->selectionStart() != mCursor.selectionStart() && mEdit->selectionEnd() != mCursor.selectionEnd()) { mCursor.setPosition(mEdit->selectionStart(), QTextCursor::MoveAnchor); mCursor.setPosition(mEdit->selectionEnd(), QTextCursor::KeepAnchor); } // these two cases are for selection dragging, only start or // end will move, so anchor stays in place else if (mEdit->selectionStart() != mCursor.selectionStart()) { mCursor.setPosition(mEdit->selectionStart(), QTextCursor::KeepAnchor); } else if (mEdit->selectionEnd() != mCursor.selectionEnd()) { mCursor.setPosition(mEdit->selectionEnd(), QTextCursor::KeepAnchor); } }applyFormatToNewTextIfNeeded is invoked when the contents of the text document change. This is because font properties might be set without an active selection. In this case, the expected behavior is for the characters added afterwards will have these properties.
For example, if the font family is changed with no selection, and we start typing, we expect our text to be in this new font. To do this, we need an optional in which we can save a format to apply to new text if needed, or otherwise contains nullopt. We will call it mOptFormat. It can be set in property setters, which you will see later. For now, we just make sure to use it when the text document content changes and there exists a value in the optional.
void CursorSelectionAttached::applyFormatToNewTextIfNeeded(int from, int charsRemoved, int charsAdded) { if (charsAdded && mOptFormat) { mCursor.setPosition(mCursor.position() - 1, QTextCursor::KeepAnchor); mCursor.mergeCharFormat(mOptFormat.value()); mOptFormat.reset(); } }Now, let’s take a look at the properties to expose to QML, and how they can be retrieved and set using the cursor. Like the QQuickTextSelection implementation, we will have properties text and font. We can implement the others as well, but for the sake of brevity, we will just focus on these two.
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL)We’ll need to declare and define these getters and setters, and declare the signals:
Getters:
[[nodiscard]] QString text() const; [[nodiscard]] QFont font() const;Setters:
void setText(const QString &text); void setFont(const QFont &font);Signals:
void textChanged(); void fontChanged();The getter and setter implementations will look very similar to the previous implementations shown for QQuickTextSelection, with some minor differences.
Getter implementations:
QString CursorSelectionAttached::text() const { return mCursor.selectedText(); } QFont CursorSelectionAttached::font() const { // simply get the font at the cursor position using charFormat auto ret = mCursor.charFormat().font(); // if the cursor is at the start of a selection, we need to take the font // at the position right in front of it. otherwise, the font will refer to the // character at the position right before the selection begins if (mCursor.hasSelection() && mCursor.position() == mCursor.selectionStart()) { auto cur = mCursor; cur.setPosition(cur.position() + 1); ret = cur.charFormat().font(); } return ret; }Setter implementations:
void CursorSelectionAttached::setText(const QString &text) { if (mCursor.selectedText() == text) return; mCursor.insertText(text); emit textChanged(); } void CursorSelectionAttached::setFont(const QFont &font) { if (font == mCursor.charFormat().font()) return; QTextCharFormat fmt = mCursor.charFormat(); fmt.setFont(font, QTextCharFormat::FontPropertiesSpecifiedOnly); // when no selection, formatting must be set on the next insertion if (mCursor.selection().isEmpty()) mOptFormat = fmt; else mCursor.mergeCharFormat(fmt); emit fontChanged(); }The only thing that needs to be done now is override the destructor, which can just be set to default:
~CursorSelectionAttached() override = default;Now we have all the implementation we need to use the attached property. If we put the two classes in one header file, it will look like this:
#pragma once #include <QObject> #include <QTextCursor> #include <QtQml> #include <optional> class QQuickTextEdit; class CursorSelectionAttached : public QObject { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL) QML_ANONYMOUS public: explicit CursorSelectionAttached(QQuickTextEdit *parent) noexcept; ~CursorSelectionAttached() override = default; [[nodiscard]] QString text() const; [[nodiscard]] QFont font() const; void setText(const QString &text); void setFont(const QFont &font); signals: void textChanged(); void fontChanged(); private slots: void moveAnchorIfDeselected(); void updatePosition(); void applyFormatToNewTextIfNeeded(int from, int charsRemoved, int charsAdded); private: QTextCursor mCursor; QQuickTextEdit *mEdit; std::optional<QTextCharFormat> mOptFormat; }; class CursorSelection : public QObject { Q_OBJECT QML_ATTACHED(CursorSelectionAttached) QML_ELEMENT public: static CursorSelectionAttached *qmlAttachedProperties(QObject *object); }; QML_DECLARE_TYPEINFO(CursorSelection, QML_HAS_ATTACHED_PROPERTIES)With this header, an implementation file containing the definitions, and a call to qmlRegisterUncreatableType<CursorSelection> in your main.cpp, the attached property can be used in QML.
Final RemarksThough this is not a perfect backport, this code allows us to set font properties for selected text in QML in a nearly identical way to its implementation in Qt 6.7. This is especially useful to implement any kind of richtext editing in a QML application, where this functionality is severely lacking in any Qt version prior to 6.7. Hopefully this is a helpful guide to backporting features, implementing attached properties, and doing more sane text editing in QML apps.
About KDAB
If you like this article and want to read similar material, consider subscribing via our RSS feed.
Subscribe to KDAB TV for similar informative short video content.
KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.
The post Formatting Selected Text in QML appeared first on KDAB.
EuroPython Society: EuroPython 2024 Code of Conduct Transparency Report
The 2024 version of the EuroPython conference took place both online and in person in July 2024. This was the second conference under our new Code of Conduct (CoC), and we had Code of Conduct working group members continuously available both online and in person.
ReportsWe had 4 Code of Conduct working group members continuously available both online and in person. Over the course of the conference the Code of Conduct team was made aware of the following issues:
- A disabled person had requested reserved seating for talks, but when he arrived the first day, there was none. He reported this to a CoC member, who filed a report with Ops. It turned out that while the request had been gathered on the web form, there was no mechanism to get that information to the people involved. Once they were informed, the issue was quickly resolved, and the reporter expressed satisfaction with the way it was handled.
- One person was uncomfortable with having their last name shown on Discord. They were informed that they could change that as soon as the registration bot ran, limiting the exposure to a minute or so, or that they could come to the registration desk for assistance. The report came via email and there was no response to the email suggesting those options.
- An attendee reported that one talk&aposs slides included a meme that seemed to reflect a racist trope. The CoC team reviewed that talk&aposs slides, and agreed that the meme might be interpreted that way. A member of the CoC team contacted the presenter who immediately agreed to remove that meme before uploading the slides, and the video team was alerted to edit that meme out of the talk video before final publication.
- There were multiple reports that the toilet signage was confusing and causing people to be uncomfortable with choosing a toilet. Once this was reported the signage was adjusted to make the gender designation visible and no further reports were received. It should be noted that none of the complaints objected to the text of the signs, just to the fact that covering of gender markers led to people entering a toilet they didn&apost want to.
- The CoC team also were presented with a potential lightning talk topic that had caused complaints at another conference due to references to current wars that some viewers found disturbing. Since lightning talks are too short for content warnings to be effective, and since they are not reviewed in any detail by the programme committee, the CoC team counselled the prospective presenter against using the references that had been problematic at a prior conference. Given that advice, the presenter elected not to submit that topic.
OSI at the United Nations OSPOs for Good
Earlier this month the Open Source Initiative participated in the “OSPOs for Good” event promoted by the United Nations in NYC. Stefano Maffulli, the Executive Director of the OSI, participated in a panel moderated by Mehdi Snene about Open Source AI alongside distinguished speakers Ashley Kramer, Craig Ramlal, Sasha Luccioni, and Sergio Gago. Please find below a transcript of Stefano’s presentation.
Mehdi Snene
What is Open Source in AI? What does it mean? What are the foundational pieces? How far along is the data? There is mention of weights, and data skills. How can we truly understand what Open Source in AI is? Today, joining us, we’ll have someone who can help us understand what Open Source in AI means and where we are heading. Stefano, can you offer your insights?
Stefano Maffulli
Thanks. We have some thoughts on this. We’ve been pondering these questions since they first emerged when GPT started to appear. We asked ourselves: How do we transfer the principles of permissionless innovation and the immense value created by the Open Source ecosystem into the AI space?
After a little over two years of research and global conversations with multiple stakeholders, we identified three key elements. Firstly, permissionless innovation needs to be ported to AI, but this is complex and must be broken down into smaller components.
We realized that, as developers, users, and deployers of AI systems, we need to understand how these systems are built. This involves studying all components carefully, being able to run them for any purpose without asking for permission (a basic tenet of Open Source), and modifying them to change outputs based on the same inputs. These basic principles include being able to share these modifications with others.
To achieve this, you need data, the code used for training and cleaning the data (e.g., removing duplicates), the parameters, the weights, and a way to run inference on those weights. It’s fairly straightforward. However, the challenge lies in the legal framework.
Now, the complicated piece is how Open Source software has had a very wonderful run, based on the fact that the legal framework that governs Open Source is fairly simple and globally accepted. It’s built on copyright, a system that has worked wonderfully in both ways. It gives exclusive rights to the content creators, but also the same mechanism can be used to grant rights to anyone who receives the creation.
With data, we don’t have that mechanism. That is a very simple and dramatic realization. When we talk about data, we should pay attention to what kind of data we’re discussing. There is data as content created, and there is data as facts; like fires, speed limits, or traces of a road. Those are facts, and they have different ways of being treated. There is also private data, personal information, and various other kinds of data, each with different rules and regulations around the world.
Governments’ major role in the future will be to facilitate permissionless innovation in data by harmonizing these rules. This will level the playing field, where currently larger corporations have significantly more power than Open Source developers or those wishing to create large language models. Governments should help create datasets, remove barriers, and facilitate access for academia, smaller developers, and the global south.
Mehdi Snene
We already have open data and Open Source. Now, we need to create open AI and open models. Are we bringing these two domains together and keeping them separate, or are we creating something new from scratch when we talk about open AI?
Stefano Maffulli
This is a very interesting and powerful question. I believe that open data as a movement has been around for quite a while. However, it’s only recently that data scientists have truly realized the value they hold in their hands. Data is fungible and can be used to build new things that are completely different from their original domains.
We need to talk more about this and establish platforms for better interaction. One striking example is a popular dataset of images used for training many image generation AI tools, which contained child sexual abuse images for many years. A research paper highlighted this huge problem, but no one filed a bug report, and there was no easy way for the maintainers of this dataset to notice and remove those images.
There are things that the software world understands very well, and things that data scientists understand very well. We are starting to see the need for more space for interactions and learning from each other.
The conversation is extremely complicated. Alex and I have had long discussions about this. I don’t want to focus entirely on this, but I do want to say that Open Source has never been about pleasing companies or specific stakeholders. We need to think of it as an ecosystem where the balances of power are maintained.
While Open Source software and Open Source AI are still evolving, the necessary ingredients—data, code, and other components—are there. However, the data piece still needs to be debated and finalized. Pushing for radical openness with data has clear drawbacks and issues. It’s going to be a balance of intentions, aiming for the best outcome for the general public and the whole ecosystem.
Mehdi Snene
Thank you so much. My next question is about the future. What are your thoughts on the next big technology?
Stefano Maffulli
From the perspective of open innovation, it’s about what’s going to give society control over technology. The focus of Open Source has always been to enable developers and end-users to have sovereignty over the technology they use. Whether it’s quantum computers, AI, or future technologies, maintaining that control is crucial.
Governments need to play a role in enabling innovation and ensuring that no single power becomes too dominant. The balance between the private sector, public sector, nonprofit sector, and the often-overlooked fourth sector—which includes developers and creators who work for the public good rather than for profit—must be maintained. This balance is essential for fostering an ecosystem where all stakeholders have equal interests and influence.
If you would like to listen to the panel discussion in its entirety, you can do so here (the Open Source AI panel starts at 1:00:00 approximately).