<?xml version="1.0"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">

<channel>
	<title>Planet Python</title>
	<link>http://planetpython.org/</link>
	<language>en</language>
	<description>Planet Python - http://planetpython.org/</description>

<item>
	<title>Python Morsels: Python 3.15's best new features</title>
	<guid>https://www.pythonmorsels.com/python315/</guid>
	<link>https://www.pythonmorsels.com/python315/</link>
	<description>&lt;p&gt;Python 3.15 includes a UTF-8 default encoding, explicit lazy imports, &lt;code&gt;*&lt;/code&gt; unpacking in comprehensions, a new sampling profiler, &lt;code&gt;sentinel&lt;/code&gt;, &lt;code&gt;frozendict&lt;/code&gt;, and more!&lt;/p&gt;


&lt;div&gt;
  
    &lt;a href=&quot;https://www.pythonmorsels.com/python315/&quot;&gt;&lt;img width=&quot;480&quot; height=&quot;270&quot; src=&quot;https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F2207113962-3a6d9dc0bde8de9e92896fa1859ba5a87ba481520df6aa2ad43dbf71486a5fa9-d_1920x1080%3F%26region%3Dus&amp;src1=http%3A%2F%2Ff.vimeocdn.com%2Fp%2Fimages%2Fcrawler_play.png&quot; /&gt;&lt;/a&gt;
  
  &lt;p&gt;
  &lt;strong&gt;Table of contents&lt;/strong&gt;
  &lt;ol&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#a-utf-8-default-encoding&quot; target=&quot;_blank&quot;&gt;A UTF-8 default encoding&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#sentinel-objects&quot; target=&quot;_blank&quot;&gt;Sentinel objects&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#unpacking-in-comprehensions&quot; target=&quot;_blank&quot;&gt;Unpacking in comprehensions&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#explicit-lazy-imports&quot; target=&quot;_blank&quot;&gt;Explicit lazy imports&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#the-new-profiling-package&quot; target=&quot;_blank&quot;&gt;The new &lt;code&gt;profiling&lt;/code&gt; package&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#improved-error-messages&quot; target=&quot;_blank&quot;&gt;Improved error messages&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#more-color&quot; target=&quot;_blank&quot;&gt;More color!&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#a-few-quick-ones&quot; target=&quot;_blank&quot;&gt;A few quick ones&lt;/a&gt;&lt;/li&gt;
  
  &lt;li&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/#try-out-python-315-yourself&quot; target=&quot;_blank&quot;&gt;Try out Python 3.15 yourself&lt;/a&gt;&lt;/li&gt;
  
  &lt;/ol&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
  
    &lt;h2&gt;A UTF-8 default encoding&lt;/h2&gt;
    
      
        &lt;p&gt;The best feature might be one of the most &lt;em&gt;boring&lt;/em&gt; ones.&lt;/p&gt;

      
        &lt;p&gt;As of Python 3.15, UTF-8 is the default file encoding on all operating systems, which means... Windows.&lt;/p&gt;

      
        &lt;p&gt;Linux and Mac already used UTF-8 as their default file encoding in Python.
But on Windows, Python used a legacy code page, which depended on your system's language settings.
With English language settings, it was usually CP-1252.&lt;/p&gt;

      
        &lt;p&gt;Say a coworker on a Mac writes a file with an accented character in it:&lt;/p&gt;

      
        &lt;div class=&quot;codehilite&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cafe.txt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;wt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;caf&amp;#233;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      
        &lt;p&gt;What happens if we &lt;em&gt;read&lt;/em&gt; that file from Python running on a Windows machine?
Using the Windows default encoding of CP-1252, this is what we'd see:&lt;/p&gt;

      
        &lt;div class=&quot;codehilite&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cafe.txt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cp1252&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;'caf&amp;#195;&amp;#169;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      
        &lt;p&gt;We don't get an error... but we &lt;em&gt;do&lt;/em&gt; get garbled text.
UTF-8 stores &lt;code&gt;&amp;#233;&lt;/code&gt; as two bytes, and CP-1252 happily reads those two bytes as two separate characters.&lt;/p&gt;

      
        &lt;p&gt;And if the file had an emoji in it, the old default encoding on Windows couldn't even &lt;em&gt;write&lt;/em&gt; the file to begin with:&lt;/p&gt;

      
        &lt;div class=&quot;codehilite&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;snake.txt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;wt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cp1252&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;... &lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;#128013;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;gt&quot;&gt;Traceback (most recent call last):&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&quot;&amp;lt;stdin&amp;gt;&quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;&amp;lt;module&amp;gt;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;#128013;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;pm&quot;&gt;~~~~~~~^^^^^^&lt;/span&gt;
  File &lt;span class=&quot;nb&quot;&gt;&quot;/home/trey/.local/share/uv/python/cpython-3.15.0rc2-linux-x86_64-gnu/lib/python3.15/encodings/cp1252.py&quot;&lt;/span&gt;, line &lt;span class=&quot;m&quot;&gt;19&lt;/span&gt;, in &lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;codecs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;charmap_encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding_table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;           &lt;/span&gt;&lt;span class=&quot;pm&quot;&gt;~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^&lt;/span&gt;
&lt;span class=&quot;gr&quot;&gt;UnicodeEncodeError&lt;/span&gt;: &lt;span class=&quot;n&quot;&gt;'charmap' codec can't encode character '\U0001f40d' in position 0: character maps to &amp;lt;undefined&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


      
        &lt;p&gt;In Python 3.15, the &lt;code&gt;open&lt;/code&gt; function uses UTF-8 as its default encoding on every operating system, so &lt;strong&gt;a file written on one machine reads the same on every other machine&lt;/strong&gt;.&lt;/p&gt;

      
        &lt;p&gt;If your code also needs to run on older versions of Python, it's still a good idea to &lt;a href=&quot;https://www.pythonmorsels.com/unicode-character-encodings-in-python/&quot; target=&quot;_blank&quot;&gt;explicitly pass &lt;code&gt;encoding=&quot;utf-8&quot;&lt;/code&gt;&lt;/a&gt; to the &lt;code&gt;open&lt;/code&gt; function.&lt;/p&gt;

      
    
  
    &lt;h2&gt;Sentinel objects&lt;/h2&gt;
    
      &lt;p&gt;There&amp;#x27;s also now an official …&lt;/p&gt;
    
  
&lt;/div&gt;
&lt;h3&gt;&lt;a href=&quot;https://www.pythonmorsels.com/python315/&quot; target=&quot;_blank&quot;&gt;Read the full article: https://www.pythonmorsels.com/python315/&lt;/a&gt;&lt;/h3&gt;</description>
	<pubDate>Fri, 09 Oct 2026 14:11:31 +0000</pubDate>
</item>
<item>
	<title>Rodrigo Girão Serrão: The 5 most exciting new features of Python 3.15</title>
	<guid>https://mathspp.com/blog/the-5-most-exciting-new-features-of-python-315</guid>
	<link>https://mathspp.com/blog/the-5-most-exciting-new-features-of-python-315</link>
	<description>&lt;img alt=&quot;&quot; src=&quot;https://mathspp.com/images/8/1/7/4/b/8174b8e656440d188f90971f4deec05758f89941-thumbnail.webp&quot; /&gt;
                                &lt;p&gt;This article explains the 5 best new features of Python 3.15 with clear examples and explanations.&lt;/p&gt;

&lt;p&gt;Python 3.15 has been published and &lt;a href=&quot;https://docs.python.org/3.15/whatsnew/3.15.html&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot; class=&quot;external-link no-image&quot;&gt;it packs plenty of new features and improvements&lt;/a&gt; over Python 3.14.
This article explores the five most exciting new features of Python 3.15:&lt;/p&gt;
&lt;ol&gt;&lt;li&gt;Lazy imports&lt;/li&gt;
&lt;li&gt;New built-in &lt;code&gt;frozendict&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;New built-in &lt;code&gt;sentinel&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Unpacking inside comprehensions&lt;/li&gt;
&lt;li&gt;Tachyon, a new sampling profiler&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;You'll get the elevator pitch of each feature and you'll see a couple of examples of their usage.&lt;/p&gt;
&lt;p&gt;By the end of this article you'll have a clear picture of some of the new cool features that Python 3.15 brings to the table and you'll be excited to try them out.&lt;/p&gt;
&lt;h2 id=&quot;15-days-of-python-3-15&quot;&gt;15 days of Python 3.15&lt;a href=&quot;https://mathspp.com/blog/tags/python.rss#15-days-of-python-3-15&quot; class=&quot;toc-anchor after&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To celebrate the release of Python 3.15, over the next 15 business days I'll be writing about a new 3.15 feature every day.
Explained clearly and with examples so you don't have to sift through the changelog.&lt;/p&gt;
&lt;p&gt;Subscribe to receive this free email series:&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;&lt;div id=&quot;enroll-wrapper&quot; class=&quot;form-wrapper&quot;&gt;



            










&lt;form name=&quot;enroll&quot; action=&quot;https://mathspp.com/courses/uv&quot; method=&quot;POST&quot; id=&quot;enroll&quot; class=&quot; &quot;&gt;
        
                                      
                          &lt;input type=&quot;text&quot; class=&quot;form-honeybear&quot; tabindex=&quot;-1&quot; name=&quot;data[honeypot]&quot; value=&quot;&quot; /&gt;&lt;div class=&quot;form-field form-group &quot;&gt;
          &lt;div class=&quot;form-data&quot;&gt;
                        &lt;div class=&quot;form-input-wrapper &quot;&gt;
                                    &lt;input name=&quot;data[email]&quot; value=&quot;&quot; type=&quot;email&quot; class=&quot;form-input &quot; /&gt;&lt;/div&gt;
                        &lt;/div&gt;
  &lt;/div&gt;
                                                      
                                  
                
    
            &lt;div class=&quot;form-field form-group &quot;&gt;
            &lt;div class=&quot;form-label-wrapper&quot;&gt;&lt;label class=&quot;form-label&quot;&gt;&lt;/label&gt;
      &lt;/div&gt;
        &lt;div class=&quot;form-data&quot;&gt;
                              
                
                                    
            &lt;div class=&quot;g-recaptcha-container&quot;&gt;
                                &lt;input type=&quot;hidden&quot; name=&quot;data[token]&quot; value=&quot;&quot; /&gt;&lt;input type=&quot;hidden&quot; name=&quot;data[action]&quot; value=&quot;361855331d16869a461c367f2049217b&quot; /&gt;&lt;/div&gt;

            
            &lt;/div&gt;
  &lt;/div&gt;
                                

        &lt;input type=&quot;hidden&quot; name=&quot;__form-name__&quot; value=&quot;enroll&quot; /&gt;&lt;input type=&quot;hidden&quot; name=&quot;__unique_form_id__&quot; value=&quot;cgcb9lefqm7xvin5qaxa&quot; /&gt;&lt;input type=&quot;hidden&quot; name=&quot;form-nonce&quot; value=&quot;546a82fdd0b04610f4049abc7a5f638e&quot; class=&quot;form-nonce-field&quot; /&gt;&lt;div class=&quot;button-wrapper&quot;&gt;
  

                    
      
      
  &lt;button type=&quot;submit&quot; class=&quot;btn &quot;&gt;Enroll for free &amp;#128013;&amp;#128640;&lt;/button&gt;

                    
        &lt;/div&gt;
  
  &lt;/form&gt;


&lt;/div&gt;
&lt;p&gt;If you want, you can also &lt;a href=&quot;https://mathspp.com/python-315&quot;&gt;check the schedule&lt;/a&gt; of the upcoming emails.&lt;/p&gt;
&lt;h2 id=&quot;lazy-imports&quot;&gt;Lazy imports&lt;a href=&quot;https://mathspp.com/blog/tags/python.rss#lazy-imports&quot; class=&quot;toc-anchor after&quot;&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Explicit lazy imports&lt;/strong&gt;, introduced in &lt;a href=&quot;https://peps.python.org/pep-0810/&quot; target=&quot;_blank&quot; rel=&quot;nofollow noopener noreferrer&quot; class=&quot;external-link no-image&quot;&gt;PEP 810&lt;/a&gt;, introduce the new keyword &lt;code&gt;lazy&lt;/code&gt; so that you can mark an import as lazy.
Lazy imports don't run the module you're importing &lt;em&gt;until&lt;/em&gt; the imported name is needed.&lt;/p&gt;
&lt;p&gt;This feature is very useful if you have applications that have a slow startup time because they import heavy modules.
For example, you can speed up the startup time of a CLI by lazy importing the dependencies of the CLI or the startup time of a development server that doesn't need to frontload every single dependency while you're debugging.&lt;/p&gt;
&lt;p&gt;A lazy import starts with the...&lt;/p&gt;</description>
	<pubDate>Fri, 09 Oct 2026 12:15:00 +0000</pubDate>
</item>
<item>
	<title>Glyph Lefkowitz: Programming Isn’t Special</title>
	<guid>https://blog.glyph.im/2026/10/programming-isnt-special.html</guid>
	<link>https://blog.glyph.im/2026/10/programming-isnt-special.html</link>
	<description>&lt;h2 id=&quot;creative-work&quot;&gt;Creative Work&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.wga.org/contracts/know-your-rights/artificial-intelligence&quot;&gt;Writers went on strike to get protections against “AI”&lt;/a&gt;. &lt;a href=&quot;https://www.theartnewspaper.com/2024/10/24/artists-statement-opposing-artificial-intelligence-content-scraping&quot;&gt;Thousands of artists have signed open letters in protest of “AI”&lt;/a&gt;. There are so many copyright lawsuits from creative industry groups against AI that &lt;a href=&quot;https://ailawsuittracker.com/ai-copyright-lawsuits/&quot;&gt;there’s a whole dedicated website for it&lt;/a&gt;.  Popular YouTubers &lt;a href=&quot;https://www.youtube.com/watch?v=UShsgCOzER4&quot;&gt;absolutely&lt;/a&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=VRjgNgJms3Q&quot;&gt;hate&lt;/a&gt; &lt;a href=&quot;https://www.youtube.com/watch?v=i0-ADeix0y8&quot;&gt;it&lt;/a&gt;.  If they’re also musicians, they &lt;a href=&quot;https://www.youtube.com/watch?v=xMYm2d9bmEA&quot;&gt;REALLY hate it&lt;/a&gt;.  Across all creative industries, there is a concerted push to reject this technology.&lt;/p&gt;
&lt;p&gt;Yet, almost unique among creative fields, many experienced programmers remain convinced that it’s fine to use “AI” for programming. We do seem to &lt;a href=&quot;https://www.businessinsider.com/developers-are-burned-out-as-ai-coding-reshapes-work-survey-2026-10&quot;&gt;hate it, and it’s making us all miserable&lt;/a&gt;, and what it’s doing to our industry, but we are &lt;a href=&quot;https://stackoverflow.blog/2026/10/06/the-results-of-the-2026-developer-survey-are-here/&quot;&gt;using it anyway&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A lot of the justification of this resignation seems to be to be because programming is not Art.  If the tool can get the job done, and the job is just functional, then why does it matter?&lt;/p&gt;
&lt;p&gt;It does matter, though.  It matters because we shouldn’t be using AI to produce Art, and &lt;em&gt;programming is Art&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;art-can-be-mundane&quot;&gt;Art can be Mundane&lt;/h2&gt;
&lt;p&gt;Some people will say that programs cannot be art because programs are &lt;em&gt;functional&lt;/em&gt;, rather than being &lt;em&gt;expressive&lt;/em&gt;.  Programs are mundane whereas art is transcendent.&lt;/p&gt;
&lt;p&gt;This is based on a distorted understanding of what Art actually &lt;em&gt;is&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In John Berger’s “Ways of Seeing”, he names this type of distortion “&lt;a href=&quot;https://www.ways-of-seeing.com/ch1&quot;&gt;mystification&lt;/a&gt;”.  His example of this process is both amusing and illustrative.  I encourage you to read it in its entirety.&lt;/p&gt;
&lt;p&gt;In summary, though: Berger critiques the florid prose of an art historian describing a commissioned group portrait, including phrases like “subtle modulations of the deep, glowing blacks” and “harmonious fusion”.  The portrait is described as sublime, in nearly ecstatic terms.&lt;/p&gt;
&lt;p&gt;Berger reveals that the &lt;em&gt;reality&lt;/em&gt; of this portrait is that a poor old painter needed some work, and some officials probably thought it might be nice to have an official portrait.  So they paid some money to the poor old man, and he painted it, and then they had a painting.  It’s a well-executed portrait of a group of people.  Beautiful, even.  But it was work commissioned for a fairly mundane purpose and it suited that purpose just fine.  It was not, and is not, a divine relic.&lt;/p&gt;
&lt;p&gt;Culturally, we are prone to mystifying painting, and sculpture, and film, and music. We imbue them with “subtle modulations”.  We ignore their functional aspects — we desire decoration, amusement, and distraction — and focus on their emotional impact.&lt;/p&gt;
&lt;p&gt;Don’t get me wrong: I love me some good aesthetic philosophy. I think it’s &lt;em&gt;great&lt;/em&gt; to really examine our reactions to artwork and to try and gain a deeper understanding of our culture and our selves through media analysis. If anything we really need to do more of it.&lt;/p&gt;
&lt;p&gt;This does &lt;em&gt;not&lt;/em&gt; mean that the creation of such works is &lt;em&gt;mystical&lt;/em&gt; or that it should be venerated beyond any other sort of labor.&lt;/p&gt;
&lt;p&gt;Not least of which other types of labor that are adjacent to, but not as culturally venerated, as fine art.  We tend to mystify the work of a novelist, but to denigrate the work of a journalist.  In reality, the functional prose of the journalist is no less important and deserves no less respect.&lt;/p&gt;
&lt;p&gt;Although they might be far below the ethereal realm that novelists inhabit in our collective imagination, even journalists receive more respect and thus more mystification than lowly copywriters.  Yet, there is no transcendental distinction between “novelist” and “copywriter”; the many of the skills are the same, and the distinction is merely an accident of commerce and opportunity.&lt;/p&gt;
&lt;p&gt;In fact, &lt;a href=&quot;https://www.theawl.com/2011/08/six-authors-who-were-copywriters-first/&quot;&gt;many famous writers have famously inhabited both roles&lt;/a&gt;.  This is not an accident!  Working with words professionally, even (perhaps especially) mundane words, is excellent &lt;em&gt;practice&lt;/em&gt; for working with words in a more purely artistic context, because even mundane creativity is still artistic.&lt;/p&gt;
&lt;h2 id=&quot;code-can-be-beautiful&quot;&gt;Code can be Beautiful&lt;/h2&gt;
&lt;p&gt;One thousand Internet years ago, when I was in my late teens, I would describe myself as a “code poet”.  I was relentlessly mocked for this as what the Youth would today call “being cringe”, and at the time was referred to as “pretentious”.&lt;/p&gt;
&lt;p&gt;I succumbed to the peer pressure, removed it from my email signature and my bio.  While I still believed strongly in the parallels, I accepted that — socially, at least — comparing code to poetry, or indeed to Art, was a silly thing to do.&lt;/p&gt;
&lt;p&gt;However, I never abandoned the idea, in my heart.&lt;/p&gt;
&lt;p&gt;The thing that I am &lt;a href=&quot;https://en.wikipedia.org/wiki/Glyph_Lefkowitz&quot;&gt;most well-known for&lt;/a&gt;, the invention of &lt;code&gt;Deferred&lt;/code&gt;, was specifically an &lt;em&gt;aesthetic&lt;/em&gt; reaction to the tedium of passing &lt;code&gt;callback&lt;/code&gt; and &lt;code&gt;errback&lt;/code&gt; parameters to every single remote procedure call in an RPC client/server application.  Those two callbacks got the job done just fine.  But they were ugly, and annoying to work with.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Deferred&lt;/code&gt; is an intentional poem about asynchronous task execution, with a deliberate eye to the aesthetics of the problem and the experience of using it. It was influential &lt;em&gt;because&lt;/em&gt; of its focus on aesthetics.&lt;/p&gt;
&lt;p&gt;I do not want to overstate the beauty or profundity of this minor contribution, or indeed its durability.  That a poem exists does not mean it is a &lt;em&gt;great&lt;/em&gt; poem, merely that it is a poem.&lt;/p&gt;
&lt;p&gt;Our aesthetic culture around programs is more like folk epic poetry than fine art, so the influence of this contribution is less about its specific enduring power than it is about its influence on what came next; from MochiKit.Async to JQuery Deferred to JavaScript Promises and eventually to &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;; a long chain of different artisans each adding something of their own until the original has all but dissolved. (And I wasn’t the “original” here, either, as I drew heavily from the &lt;a href=&quot;http://www.erights.org&quot;&gt;E&lt;/a&gt; language’s Promises, among other things.)&lt;/p&gt;
&lt;p&gt;In order to make code into a deliberate artistic expression, one must have spent quite a bit of time contemplating the problem domain.  Without having experienced the tedium of manually passing a thousand callback parameters, I would have had neither the skill, nor indeed the &lt;em&gt;motivation&lt;/em&gt;, to bother creating such a thing.&lt;/p&gt;
&lt;p&gt;Now, &lt;em&gt;most&lt;/em&gt; code does not have to be like this. Most code does not &lt;em&gt;get&lt;/em&gt; to be like this. Most code is functional, workday code. Most code &lt;a href=&quot;https://achewood.com/2002/11/08/title.html&quot;&gt;could not make a lady weep&lt;/a&gt;. It’s just copy-writing, if you will.&lt;/p&gt;
&lt;p&gt;As I explained previously, most writing couldn’t do that either. Most writing is just copy-writing, too. Most visual art is advertising. Most live music performance is background music in bars that will go largely ignored.&lt;/p&gt;
&lt;p&gt;However, code that &lt;em&gt;is&lt;/em&gt; intentionally aesthetically designed tends to be important, both socially and technologically.&lt;/p&gt;
&lt;p&gt;We do have &lt;em&gt;some&lt;/em&gt; tradition of self-mystification in software.  As &lt;a href=&quot;https://www.goodreads.com/quotes/9168-programs-must-be-written-for-people-to-read-and-only&quot;&gt;Abelson memorably put it&lt;/a&gt;, “Programs must be written for people to read, and only incidentally for machines to execute.”, so we have long had some conception of programs as highly expressive, even if we can’t always agree on what they’re expressing or to whom.  We will occasionally wax poetical about the &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_philosophy&quot;&gt;philosophical implications&lt;/a&gt; of a particular piece of software. This is not unique to a single piece of software, either; &lt;a href=&quot;https://peps.python.org/pep-0020/&quot;&gt;more than one community has indulged&lt;/a&gt; in &lt;a href=&quot;https://www.perl.com/pub/2003/06/25/perl6essentials.html/&quot;&gt;similar philosophizing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The expressive and aesthetic qualities of software are not limited to reading source code or interacting with other programmers via APIs, either.  For example, every year, &lt;a href=&quot;https://www.macstories.net/author/viticci/&quot;&gt;Federico Viticci&lt;/a&gt; does a review of Apple’s new operating system, which is (among other things) an aesthetic critique.  Such a project would not be possible if the software did not have an aesthetic impact on its users.&lt;/p&gt;
&lt;p&gt;Not to mention that every video game review is also a software review.&lt;/p&gt;
&lt;div class=&quot;aside&quot;&gt;
&lt;h3 id=&quot;a-brief-aside-about-software-literacy&quot;&gt;A Brief Aside about Software Literacy&lt;/h3&gt;
&lt;p&gt;It does make me a bit sad that we don’t have much of a critical reading tradition in the software community.  &lt;a href=&quot;https://en.wikipedia.org/wiki/Literate_programming&quot;&gt;Literate Programming&lt;/a&gt; is often praised, but rarely practiced.&lt;/p&gt;
&lt;p&gt;Moreover, it makes me sad that users have a pretty jumbled idea of what goes into making software, that programming literacy is pretty low, and that modern programming practices often &lt;em&gt;deliberately&lt;/em&gt; produce a bad mental model of what the software is doing so it’s even harder for the user to understand.  The aesthetic experience of software is often &lt;em&gt;wildly&lt;/em&gt; detached from its internal state.&lt;/p&gt;
&lt;p&gt;While all of these problems predate AI by years or indeed decades, that’s no reason to enthusiastically make them worse.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;defend-the-mundane&quot;&gt;Defend The Mundane&lt;/h2&gt;
&lt;p&gt;If we use AI to erase all the copy-writing, all the graphic design, all the boring mundane art, and yes, all the boring custom WordPress theme development, then we will be removing all the practical opportunities for the vast amounts of &lt;em&gt;practice&lt;/em&gt; and &lt;em&gt;contemplation&lt;/em&gt; required for people to elevate their craft to eventually achieve great things. Education is great, but the majority of true skill development happens &lt;a href=&quot;https://www.thatericalper.com/2026/08/13/what-the-beatles-can-teach-you-about-10000-hours-in-hamburg/&quot;&gt;on the job&lt;/a&gt; and always has.&lt;/p&gt;
&lt;p&gt;This doesn’t mean that we can’t use abstractions, or automation, to make our work easier. Programming is the art &lt;em&gt;of&lt;/em&gt; abstraction, of understanding how to compose smaller ideas into bigger ones, of how to understand the automation of a larger system by understanding the rules that automate smaller ones and understanding how to combine them.&lt;/p&gt;
&lt;p&gt;When we use “AI” to &lt;em&gt;eliminate&lt;/em&gt; that understanding rather than raise it up to a higher level, to entirely destroy that creative decision-making process, we do a disservice both to ourselves as programmers and to our users.  We would be doing a disservice to our users and our downstream fellow developers in the same way that a visual artist would be doing a disservice to their viewers or a musician would be doing a disservice to their listeners if they served them auto-generated filler instead of their own creative output.&lt;/p&gt;
&lt;p&gt;Slop is slop, no matter the medium.&lt;/p&gt;
&lt;p&gt;Each mundane project has some tiny chance — let’s say, something like 0.1% — of achieving greatness.  If we do a single project with AI, then sure, whatever, there’s almost no chance that &lt;em&gt;that&lt;/em&gt; project was going to be the one hit to create that career-defining moment for an engineer working on it.  If we make a habit of doing &lt;em&gt;all&lt;/em&gt; projects that way, though, we take the &lt;em&gt;total&lt;/em&gt; likelihood of those moments of greatness from “definitely sometimes” to “never”.&lt;/p&gt;
&lt;p&gt;The precisely appropriate ways in which to resist AI encroachment on all software development lie well beyond the margins of this one short post. How much you can resist and which specific uses you should resist are up to you. But it &lt;em&gt;is&lt;/em&gt; worth resisting in software just as much as it would be worth resisting in any creative medium.&lt;/p&gt;
&lt;p&gt;Programming isn’t special. It’s just Art, and Art is the most human — and thus, the most universal — thing that there is.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;
&lt;p class=&quot;update-note&quot;&gt;Thank you to &lt;a href=&quot;https://glyph.twistedmatrix.com/pages/patrons.html&quot;&gt;my patrons&lt;/a&gt; who are supporting my writing on
this blog.  If you like what you’ve read here and you’d like to read more of
it, or you’d like to support my &lt;a href=&quot;https://github.com/glyph/&quot;&gt;various open-source
endeavors&lt;/a&gt;, you can &lt;a href=&quot;https://glyph.twistedmatrix.com/pages/patrons.html&quot;&gt;support my work as a
sponsor&lt;/a&gt;!&lt;/p&gt;</description>
	<pubDate>Fri, 09 Oct 2026 07:00:00 +0000</pubDate>
</item>
<item>
	<title>Wingware: Wing Python IDE 12.1 Beta - October 9, 2026</title>
	<guid>https://wingware.com/news/2026-10-09</guid>
	<link>https://wingware.com/news/2026-10-09</link>
	<description>&lt;p&gt;Wing 12.1 is now available as a beta release. It introduces the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;
&lt;span class=&quot;pre&quot;&gt;Manager&lt;/span&gt;&lt;/tt&gt; for guided autonomous development. You write the specification,
answer questions, and review results. Agents design and write the code, unit
tests, and documentation. Wing keeps you in control, so you can decide what
to delegate, how to review the results, and when to ship.&lt;/p&gt;
&lt;img src=&quot;https://wingware.com/images/screenshots/wing12.1-screenshot.png&quot; alt=&quot;Wing 12.1 Screen Shot&quot; class=&quot;eye-candy-image unfloat-at-900&quot; width=&quot;650px&quot; /&gt;&lt;p&gt;The Tasks Manager accepts anything from a bug report to a high-level
specification for a new software product. It breaks down larger tasks, maps
out an implementation strategy, decides what tasks can safely run at the same
time, dispatches the work to AI worker agents, collects questions that need
your attention, tracks problems the agents find along the way, and lines up
the results for your review.&lt;/p&gt;
&lt;p&gt;You remain in control at whatever level you're comfortable with: inspect
every change in the code, read a high-level task summary and react to choices
made by the agents, or simply try the result and give instructions for further
development.&lt;/p&gt;
&lt;p&gt;Wing Pro 12.1 also introduces support for other AI coding agents, now
including Claude Code, Codex, Antigravity, Copilot, Cursor, goose,
and OpenCode, plus any other agent that speaks the &lt;a class=&quot;reference&quot; href=&quot;https://agentclientprotocol.com&quot;&gt;Agent
Client Protocol&lt;/a&gt; (ACP).&lt;/p&gt;
&lt;p&gt;The Tasks Manager and AI agent support are features of Wing Pro only. Other
improvements in Wing 12.1, such as the new Modern look and display themes,
are also in Wing Classic and Wing 101, as described below.&lt;/p&gt;
&lt;h3&gt;Downloads&lt;/h3&gt;&lt;div class=&quot;note&quot;&gt;
&lt;strong&gt;IMPORTANT&lt;/strong&gt; Be sure to &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Check&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Updates&lt;/span&gt;&lt;/tt&gt; from Wing's &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Help&lt;/span&gt;&lt;/tt&gt; menu
after installing so that you have the latest hot fixes.&lt;/div&gt;
&lt;p&gt;This is a beta release. Please try it and &lt;a class=&quot;reference&quot; href=&quot;mailto:support@wingware.com?subject=Wing%2012.1%20Early%20Access%20Feedback&quot;&gt;email us&lt;/a&gt;
if you find problems or have suggestions!&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;reference&quot; href=&quot;http://wingware.com/downloads/wing-pro/12.1.0&quot;&gt;Wing 12.1.0&lt;/a&gt; -- Full featured Python IDE
with two licensing tiers&lt;/p&gt;
&lt;p&gt;&lt;a class=&quot;reference&quot; href=&quot;http://wingware.com/downloads/wing-101/12.1.0&quot;&gt;Wing 101 12.1.0&lt;/a&gt; -- Free IDE for teaching
beginners to program&lt;/p&gt;
&lt;p&gt;Wing 12.1 will replace Wing 12.0 when it is installed. You can revert to Wing
12.0 by reinstalling it at any time.&lt;/p&gt;
&lt;p&gt;To get started quickly with autonomous development in Wing 12.1, see
&lt;a class=&quot;reference&quot; href=&quot;https://wingware.com/wingide/early-details&quot;&gt;Getting Started with Autonomous Development&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;New in Wing 12.1&lt;/h2&gt;&lt;h3&gt;Autonomous Development with the Tasks Manager&lt;/h3&gt;&lt;p&gt;The new &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Manager&lt;/span&gt;&lt;/tt&gt; is an agent that runs the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;&lt;/tt&gt; tool's queues
for you, so that development proceeds autonomously under your direction. You
write tasks, mark the ones you want started as &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Ready&lt;/span&gt;&lt;/tt&gt;, and review what
comes back.&lt;/p&gt;
&lt;p&gt;The Manager can break down high-level specifications into a design and
development plan. It decides task order, serializes those that are likely to edit the
same files, and runs closely related tasks in shared session context. It can
message a running agent to tell it about related work or new insights, or
redirect it if it goes astray.&lt;/p&gt;
&lt;p&gt;While the Manager is on, tasks run autonomously: Rather than stopping to ask
questions or present intermediate results, each works as far as it can and
ends with a report of the judgement calls it made along the way, and any
questions it has left. A new &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Questions&lt;/span&gt;&lt;/tt&gt; tab in the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;&lt;/tt&gt; tool collects
everything that is waiting for you, so you can provide answers in one place.
Follow-up work and problems that agents notice as they run are added to the
&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Plan&lt;/span&gt;&lt;/tt&gt; tab of the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;&lt;/tt&gt; tool as new tasks.  It may automatically start
found tasks that are closely related to ongoing work; others wait for your
review.&lt;/p&gt;
&lt;p&gt;You remain the one who decides which work runs, how much the Manager can do,
and how results are reviewed. Every change the Manager makes is listed
and can be reverted or revised, even after they are committed. You can also
talk to the Manager to ask why a task is being held, sort out a stuck queue,
or give it special instructions about your development workflow.&lt;/p&gt;
&lt;h3&gt;Your Choice of AI Agent&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Claude Code&lt;/strong&gt; and &lt;strong&gt;Codex&lt;/strong&gt; (run using its TUI) are best for autonomous
development, since they self-check the safety of commands that they run.
&lt;strong&gt;Antigravity&lt;/strong&gt;, &lt;strong&gt;Copilot&lt;/strong&gt;, and &lt;strong&gt;Cursor&lt;/strong&gt; also work but don't implement
the same level of safety checks. &lt;strong&gt;OpenCode&lt;/strong&gt; and &lt;strong&gt;goose&lt;/strong&gt; are not
recommended for autonomous development. &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Agent&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Safety&lt;/span&gt;&lt;/tt&gt; in the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt;
&lt;span class=&quot;pre&quot;&gt;Agent-Assisted&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Development&lt;/span&gt;&lt;/tt&gt; chapter of the manual in Wing 12.1's &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Help&lt;/span&gt;&lt;/tt&gt;
menu compares the agents in detail.&lt;/p&gt;
&lt;p&gt;Each agent can run in one of two ways. A &lt;em&gt;TUI&lt;/em&gt; session runs the agent's own
terminal user interface inside Wing's &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Agent&lt;/span&gt;&lt;/tt&gt; tool, and is the
recommended way to use every agent that has one. An &lt;em&gt;ACP&lt;/em&gt; session talks to
the agent over the Agent Client Protocol and renders in Wing's AI agent
conversation UI. Goose and some other agents work only through ACP.&lt;/p&gt;
&lt;p&gt;Every agent can use Wing's MCP servers for code analysis, debugging, testing,
and review, along with development guides that teach it how to work with
Wing. The &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;AI&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Agent&lt;/span&gt;&lt;/tt&gt; tool, the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;&lt;/tt&gt; tool, FIX and code actions,
&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Write&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Tests&lt;/span&gt;&lt;/tt&gt;, the review workflow, commit modes, the testing regimen, and
autonomous task queueing all work the same way with every agent.&lt;/p&gt;
&lt;p&gt;Each queue in the &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Tasks&lt;/span&gt;&lt;/tt&gt; tool can use a different agent. Agents may run on
the same host as the IDE or on a remote host.&lt;/p&gt;
&lt;p&gt;You bring your own subscription or API key for the agent you choose. Wing
does not install agents or provide access to models.&lt;/p&gt;
&lt;h3&gt;Other Improvements&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;User Interface:&lt;/strong&gt; An optional new &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Modern&lt;/span&gt;&lt;/tt&gt; look redesigns the toolbar,
&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Preferences&lt;/span&gt;&lt;/tt&gt; dialog, status bar, and tab overflow, and improves the
display font. A welcome window lets you choose what to open at startup.
Two new display themes, &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Night&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Flight&lt;/span&gt;&lt;/tt&gt; and &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Solo&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Flight&lt;/span&gt;&lt;/tt&gt;, have been
added. Themes can now be imported from VS Code, created from a small set
of colors, or exported from your current color configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tasks Tool (Wing Pro):&lt;/strong&gt; New &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Checklists&lt;/span&gt;&lt;/tt&gt; hold recurring reviews, fixes,
and release and deployment steps. A task's committed changes can now be
reverted, edited, or commented on. Every task has a short ID that links to
the task wherever it is cited, and mini-search works on every tab. Tracking
of changes made by concurrently running tasks is more reliable, and there are
many other fixes to task and session management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version Control (Wing Pro and Wing Classic):&lt;/strong&gt; The &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Git&lt;/span&gt;&lt;/tt&gt; and
&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Mercurial&lt;/span&gt;&lt;/tt&gt; logs now show a graphical history with expandable diffs,
&lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Log&lt;/span&gt;&lt;/tt&gt; replaces &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Changeset&lt;/span&gt;&lt;/tt&gt;, and the editor can show
annotations with commit message tooltips.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Editor and Analysis:&lt;/strong&gt; In all products, the editor's scroll bar shows marks
for diffs, search matches, and errors and warnings. Source analysis is faster
and its database is about 30% smaller.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Other Changes:&lt;/strong&gt; Wing now offers to remove large cache directories left
behind by older versions. &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Accept&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Debug&lt;/span&gt; &lt;span class=&quot;pre&quot;&gt;Connections&lt;/span&gt;&lt;/tt&gt; has moved to &lt;tt class=&quot;literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;Project&lt;/span&gt;
&lt;span class=&quot;pre&quot;&gt;Properties&lt;/span&gt;&lt;/tt&gt; so it is set per project. Wing 12.1 also includes many bug
fixes, particularly for remote development and Docker containers, debugging
free-threaded Python on Windows, git worktrees and submodules, non-ASCII text
on Windows, unit test discovery, and display themes.&lt;/p&gt;
&lt;p&gt;See the &lt;a class=&quot;reference&quot; href=&quot;https://wingware.com/pub/wingpro/12.1.0.0/CHANGELOG.txt&quot;&gt;change log&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;To get started quickly with autonomous development in Wing 12.1, see
&lt;a class=&quot;reference&quot; href=&quot;https://wingware.com/wingide/early-details&quot;&gt;Getting Started with Autonomous Development&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have questions, please don't hesitate to contact us at &lt;a class=&quot;reference&quot; href=&quot;mailto:support@wingware.com&quot;&gt;support&amp;#64;wingware.com&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Fri, 09 Oct 2026 01:00:00 +0000</pubDate>
</item>
<item>
	<title>Python Insider: Python 3.15.0 (final) is here!</title>
	<guid>https://blog.python.org/2026/10/python-3150-final-is-here/</guid>
	<link>https://blog.python.org/2026/10/python-3150-final-is-here/</link>
	<description>A brand new Python here for you to enjoy!</description>
	<pubDate>Fri, 09 Oct 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Anarcat: PSA: Europe changes time forward soon, North America next, for the last time?</title>
	<guid>https://anarc.at/blog/2026-10-08-dst-warning/</guid>
	<link>https://anarc.at/blog/2026-10-08-dst-warning/</link>
	<description>&lt;blockquote&gt;&lt;p&gt;This is a copy of an email I &lt;a href=&quot;https://lists.torproject.org/mailman3/hyperkitty/list/tor-project@lists.torproject.org/thread/P5YBMLD4VDI4QGAEC6HIPN34U3SVD42G/&quot;&gt;sent at work&lt;/a&gt;. I'm not sure I
should be making noise about this here, feedback welcome.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;This is your bi-yearly reminder that time is changing soon! October 25th
in Europe, November 1st in North America. Less people in Canada are
changing this year, with BC, Alberta, Manitoba and Northwest
Territories getting rid of DST.&lt;/p&gt;

&lt;h1 id=&quot;whats-happening&quot;&gt;What's happening?&lt;/h1&gt;

&lt;p&gt;Some places in the world implement what is called Daylight saving time
or DST:&lt;/p&gt;

&lt;p&gt;https://en.wikipedia.org/wiki/Daylight_saving_time&lt;/p&gt;

&lt;p&gt;Normally, you shouldn't have to do anything: computers automatically
change time following local rules, assuming they are correctly
configured, provided recent updates have been applied in the case of a
recent change in said rules (because yes, this happens, and happened
this year, and yes, you need to upgrade your software!).&lt;/p&gt;

&lt;p&gt;Of course, appliances like your microwave oven will likely &lt;em&gt;not&lt;/em&gt; change
time and will need to adjusted unless they are so-called &quot;smart&quot;, in
which case they are part of the skynet botnet and should be destroyed.&lt;/p&gt;

&lt;p&gt;If your clock is flashing &quot;0:00&quot; or &quot;12:00&quot;, you have no action to take
to adapt to this change, lucky you.&lt;/p&gt;

&lt;p&gt;If you haven't changed time in six months, congratulations, your clock
will be accurate again!&lt;/p&gt;

&lt;p&gt;In any case, you should still consider DST because it might affect some
of your meeting schedules, particularly if you set up a new meeting
schedule in the last 6 months and forgot to consider this change.&lt;/p&gt;

&lt;h1 id=&quot;if-your-location-does-not-have-dst&quot;&gt;If your location does not have DST&lt;/h1&gt;

&lt;p&gt;Properly scheduled meetings affecting multiple time zones are set in UTC
time, which does &lt;em&gt;not&lt;/em&gt; change. So if your location does not observer
time changes, your (local!) meeting time will &lt;em&gt;not&lt;/em&gt; change.&lt;/p&gt;

&lt;p&gt;But be aware that some other folks attending your meeting &lt;em&gt;might&lt;/em&gt; have
the DST bug and &lt;em&gt;their&lt;/em&gt; meeting times will change.&lt;/p&gt;

&lt;p&gt;Be kind to those poor souls which might be missing meetings by a full
&lt;em&gt;hour&lt;/em&gt; because time flies backwards for them.&lt;/p&gt;

&lt;h1 id=&quot;if-you-do-observe-dst&quot;&gt;If you do observe DST&lt;/h1&gt;

&lt;p&gt;If you are affected by daylight savings, your &lt;em&gt;local&lt;/em&gt; meeting times
&lt;em&gt;will&lt;/em&gt; change for UTC meetings. Normally, your meeting times are
scheduled to take this into account and the new hours should be
reasonable.&lt;/p&gt;

&lt;p&gt;But now is a good time to verify that. Take a look at your schedule for
the next couple of weeks and reschedule meetings &lt;em&gt;before&lt;/em&gt; the daylight
saving come up to avoid too much disruption. You have only a couple of
weeks to do so right now.&lt;/p&gt;

&lt;h1 id=&quot;when-do-times-change-how-and-and-where&quot;&gt;When do times change, how, and and where?&lt;/h1&gt;

&lt;p&gt;As regular readers will remember, the rule of thumb is:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Spring forward, fall backwards.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;That is, during the season of Spring, the clocks move forward, and
during the Fall (like right now), they move backwards. That is in the
northern hemisphere, but then the southern hemisphere is often saner and
doesn't switch anyways.&lt;/p&gt;

&lt;p&gt;So time will move &lt;em&gt;backwards&lt;/em&gt; which means an extra hour of sleep. Unless
you have children or bad sleep, in which case your body doesn't care
about what the clock says and will wake up one hour earlier than what it
should.&lt;/p&gt;

&lt;p&gt;And of course, this doesn't happen everywhere at once, so let's see when
it happens where.&lt;/p&gt;

&lt;h2 id=&quot;europe&quot;&gt;Europe&lt;/h2&gt;

&lt;p&gt;The dance starts in Europe.&lt;/p&gt;

&lt;p&gt;The change happens on the last Sunday in October at 01:00 UTC (not local
time!), that is October 25th. If you are in the central European
timezone, also known as Amsterdam, Berlin, or Paris time depending on
your national affiliation, that essentially means that at 2:59 local the
clocks will fall back to 2:00 instead of going to 3:00.&lt;/p&gt;

&lt;p&gt;Concretely, set your watch back one hour before going to bed, go to bed
at the normal time, and enjoy an extra hour of sleep or leisure.&lt;/p&gt;

&lt;p&gt;If you have kids, you might want to start getting them to bed slightly
earlier every day for a week before the change so they take time getting
used to the change. If you have trouble sleeping in the morning, find
your inner child and do that to yourself as well.&lt;/p&gt;

&lt;h2 id=&quot;usa-canada&quot;&gt;USA / Canada&lt;/h2&gt;

&lt;p&gt;Then it's the US[1] and Canada[2] joining the dance, on the First Sunday in
November at 02:00 local (not UTC!), that is, I believe, November 1st
2026.&lt;/p&gt;

&lt;p&gt;This means that, at 1:59, the clocks will flip to 1:00, instead of 2:00.&lt;/p&gt;

&lt;p&gt;Concretely, do like the Europeans and tweak your clock before going to
bed.&lt;/p&gt;

&lt;p&gt;That is a little less than four weeks from now.&lt;/p&gt;

&lt;p&gt;[1] except Arizona (except the Navajo nation), US territories, and
Hawaii&lt;/p&gt;

&lt;p&gt;[2] except Yukon, Saskatchewan, (newly) British Columbia, (newly)
Alberta, (newly) Northwest Territories, (newly) Manitoba, one island in
Nunavut (Southampton Island), one town in Ontario (Atikokan) and small
parts of Quebec (Le Golfe-du-Saint-Laurent)&lt;/p&gt;

&lt;h2 id=&quot;other-places-with-dst&quot;&gt;Other places with DST&lt;/h2&gt;

&lt;p&gt;This time again, I must apologize to the people of Cuba, Lebanon,
Israel, Palestine, Egypt, Chile, Australia, and New Zealand, as you fine
folks all have your own DST rules that are omitted here for brevity. I
rely on this page from Wikipedia to be updated by time nerds accurately
for this message, and it should provide you with a rough idea of what's
coming:&lt;/p&gt;

&lt;p&gt;https://en.wikipedia.org/wiki/Daylight_saving_time_by_country&lt;/p&gt;

&lt;p&gt;In general, changes also happen in October, but either on different
times or different days, except in the south hemisphere, where they
might happen in September (oops, sorry NZ folks, I'm late!).&lt;/p&gt;

&lt;h2 id=&quot;places-without-dst&quot;&gt;Places without DST&lt;/h2&gt;

&lt;p&gt;Everyone else, enjoy, you're on the right side of history, and we thank
you for the good example you give us.&lt;/p&gt;

&lt;h2 id=&quot;changes-since-last-time&quot;&gt;Changes since last time&lt;/h2&gt;

&lt;p&gt;There's been &lt;em&gt;lots&lt;/em&gt; of changes since last time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;British Columbia moved to permanent -07 on 2026-03-09, that is it
will &lt;em&gt;not&lt;/em&gt; change to normal time in November&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alberta moved to permanent -06 on 2026-06-18, similar to BC above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Canada’s Northwest Territories moved to permanent -06 on 2026-08-21,
matching Alberta.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manitoba moves to permanent -05 on 2026-10-31.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Morocco moves to permanent +00 on 2026-09-20.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Moldova has used EU transition times since 2022, but the tz database
only noticed in 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is my interpretation of the changes announced on the tzdata mailing
list here:&lt;/p&gt;

&lt;p&gt;https://lists.iana.org/hyperkitty/list/tz-announce@iana.org/latest&lt;/p&gt;

&lt;p&gt;If the eastward trend continues, Canada should adopt country-wide &quot;no
daylight savings&quot; rules by 2027, although there's actually no sign of
the other provinces (Ontario, Québec and so on) currently running bills
to change those rules just yet. Poor Canadians like me confused about
time in their countries can refer to this section of Wikipedia for
details:&lt;/p&gt;

&lt;p&gt;https://en.wikipedia.org/wiki/Daylight_saving_time_in_Canada#By_province_and_territory&lt;/p&gt;

&lt;p&gt;... and particularly the image featured there:&lt;/p&gt;

&lt;p&gt;https://commons.wikimedia.org/wiki/File:Canada_time_zone_map&lt;em&gt;-&lt;/em&gt;en.svg&lt;/p&gt;

&lt;p&gt;It also seems like the US government &lt;em&gt;might&lt;/em&gt; finally adopt a permanent
daylight saving change bill in 2026, as the &quot;Sunshine protection act&quot;
pass the house in July:&lt;/p&gt;

&lt;p&gt;https://en.wikipedia.org/wiki/Sunshine_Protection_Act&lt;/p&gt;

&lt;p&gt;True to form, this was associated with absolutely ridiculous pressure
from Donald Trump against republicans (his own party!) objecting to the
change:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;On July 14, 2026, the House passed a Sunshine Protection Act bill
backed by President Trump. Nevertheless, the bill was opposed in the
Senate by Republicans, including Senator Cotton. In response, on
October 3, 2026, Trump shared a post on Truth Social urging Cotton to
approve the bill, where he revealed Cotton's personal cellphone number
and called on people to call him.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;https://www.theguardian.com/us-news/2026/oct/03/trump-tom-cotton-daylight-saving-time&lt;/p&gt;

&lt;p&gt;Given that the last time the US did a major change to the daylight
savings policy (in 2005), Canada followed suit to stay in sync, it's
quite possible Trump's mad dash might actually finish getting rid of DST
in North America:&lt;/p&gt;

&lt;p&gt;https://en.wikipedia.org/wiki/Energy_Policy_Act_of_2005#Change_to_daylight_saving_time&lt;/p&gt;

&lt;!-- posted to the federation on 2026-10-08T15:30:10.875004 --&gt;</description>
	<pubDate>Thu, 08 Oct 2026 19:30:02 +0000</pubDate>
</item>
<item>
	<title>Django Weblog: Django security reporting update</title>
	<guid>https://www.djangoproject.com/weblog/2026/oct/08/django-security-reporting-update/</guid>
	<link>https://www.djangoproject.com/weblog/2026/oct/08/django-security-reporting-update/</link>
	<description>&lt;p&gt;We are no longer accepting new security reports for the Django project through HackerOne. Existing reports submitted through HackerOne will remain open and continue to be handled by the Django Security Team.&lt;/p&gt;
&lt;p&gt;If you discover a security issue in Django, please follow the reporting process described in the &lt;a href=&quot;https://www.djangoproject.com/security/&quot;&gt;Django security policies&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Security issues should be reported by emailing &lt;strong&gt;&lt;a href=&quot;mailto:security@djangoproject.com&quot;&gt;security@djangoproject.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
	<pubDate>Thu, 08 Oct 2026 11:00:00 +0000</pubDate>
</item>
<item>
	<title>Eli Bendersky: Monte-Carlo simulations</title>
	<guid>https://eli.thegreenplace.net/2026/monte-carlo-simulations/</guid>
	<link>https://eli.thegreenplace.net/2026/monte-carlo-simulations/</link>
	<description>&lt;p&gt;Monte Carlo simulations (or &lt;em&gt;methods&lt;/em&gt;) is the technique of applying
randomness and the &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Law_of_large_numbers&quot;&gt;Law of large numbers&lt;/a&gt;
to the solution of various scientific and engineering problems. One of its
first documented uses was by Stanislaw Ulam and John von Neumann for nuclear
weapon simulations after WWII &lt;a class=&quot;footnote-reference&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-1&quot; id=&quot;footnote-reference-1&quot;&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this post I want to provide examples of some simple uses of Monte Carlo
simulations. We'll start with the classical example of calculating the value
of \pi by throwing darts.&lt;/p&gt;
&lt;div class=&quot;section&quot; id=&quot;estimating-pi&quot;&gt;
&lt;h2&gt;Estimating pi&lt;/h2&gt;
&lt;p&gt;Suppose we take a square board and inscribe a quarter of a circle into it. We
then proceed to throw darts at the board and record whether each dart hits
inside or outside the quarter circle. Having thrown many such darts, we
calculate the ratio of the darts inside the circle to the total number thrown.&lt;/p&gt;
&lt;p&gt;Assuming our darts are distributed uniformly over the
square, by the Law of large numbers this ratio should approach the ratio of
areas of the quarter circle A_{circ} to the full square A_{square}.&lt;/p&gt;
&lt;p&gt;With a square side length of 1, we have:&lt;/p&gt;
\[\frac{A_{circ}}{A_{square}}=\frac{\pi/4}{1}=\frac{\pi}{4}\]
&lt;p&gt;Therefore:&lt;/p&gt;
\[\pi\approx 4\frac{\text{hits inside}}{\text{total throws}}\]
&lt;p&gt;Here's a visualization:&lt;/p&gt;


&lt;div class=&quot;pi-monte-carlo-wrap&quot;&gt;
  
    A quarter circle of radius 1 inside a unit square.
  

  &lt;div class=&quot;pi-monte-carlo-controls&quot;&gt;
    &lt;div class=&quot;pi-monte-carlo-row&quot;&gt;
      &lt;div class=&quot;pi-monte-carlo-slider&quot;&gt;
        &lt;label class=&quot;pi-monte-carlo-label&quot; for=&quot;pi-monte-carlo-samples&quot;&gt;
          Samples 200
        &lt;/label&gt;
        &lt;input id=&quot;pi-monte-carlo-samples&quot; class=&quot;pi-monte-carlo-range&quot; type=&quot;range&quot; value=&quot;200&quot; /&gt;
        &lt;div class=&quot;pi-monte-carlo-range-labels&quot;&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;button id=&quot;pi-monte-carlo-go&quot; class=&quot;pi-monte-carlo-button&quot; type=&quot;button&quot;&gt;Run&lt;/button&gt;
    &lt;/div&gt;

    &lt;p class=&quot;pi-monte-carlo-result&quot;&gt;
      &lt;span class=&quot;pi-monte-carlo-symbol&quot;&gt;π&lt;/span&gt; ≈ &lt;span id=&quot;pi-monte-carlo-estimate&quot;&gt;—&lt;/span&gt;
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Change the number of samples (dart throws) and click &amp;quot;Run&amp;quot; to regenerate. The
code is very simple - here's a slightly sanitized version:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;samples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inside&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inCircle&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inCircle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inside&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;estimateValue&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inside&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You'll notice that the estimate is relatively poor - even with 1000 samples - if
you click &amp;quot;Run&amp;quot; several times, some numbers will be way off mark. While this
method does estimate \pi, it's not a particularly &lt;em&gt;good&lt;/em&gt; estimate. I
find that running ~10 billion samples is necessary to estimate it to 4 digits
after the decimal with reasonable reliability.&lt;/p&gt;
&lt;p&gt;In general, for independent trials like these, the typical sampling error
decreases in proportion to 1/\sqrt{N}, where N is the number of trials.
This means that halving the error requires four times as many samples.&lt;/p&gt;
&lt;p&gt;While the \pi estimation may seem whimsical, it's an example of an
important class of problems to which Monte Carlo simulation is applied:
numerical integration. Our simulation estimates the area
under the quarter-circle curve, which is a definite integral.&lt;/p&gt;
&lt;p&gt;Many integrals are very difficult to solve analytically, and much research has
been done in the area of numerical analysis to develop methods to calculate
integrals. Monte Carlo methods are
particularly useful for high-dimensional integrals, where other numerical
methods can become prohibitively expensive.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;section&quot; id=&quot;combinatorial-simulation-the-game-of-set&quot;&gt;
&lt;h2&gt;Combinatorial simulation - the game of SET&lt;/h2&gt;
&lt;p&gt;A common use of Monte Carlo methods is estimating complex combinatorial
calculations. These often don't have analytical solutions, and enumerating all
options is intractable due to the scale of the numbers involved. As an example,
let's consider &lt;a class=&quot;reference external&quot; href=&quot;https://en.wikipedia.org/wiki/Set_(card_game)&quot;&gt;the game of SET&lt;/a&gt;. Each SET card has four
attributes:&lt;/p&gt;
&lt;ol class=&quot;arabic simple&quot;&gt;
&lt;li&gt;Number of shapes (1, 2 or 3)&lt;/li&gt;
&lt;li&gt;Color (Red, Green or Purple)&lt;/li&gt;
&lt;li&gt;Shape type (Oval, Diamond or Squiggle)&lt;/li&gt;
&lt;li&gt;Shading (Empty, Striped or Solid)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And the goal is to find a &amp;quot;set&amp;quot; - three cards that are either all different or
all the same &lt;em&gt;for each attribute separately&lt;/em&gt;. As an example, here's
a hand with a single set; see if you can find it &lt;a class=&quot;footnote-reference&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-2&quot; id=&quot;footnote-reference-2&quot;&gt;[2]&lt;/a&gt;:&lt;/p&gt;
SET hand with a single set
&lt;p&gt;And the next hand doesn't have any sets:&lt;/p&gt;
SET hand with no hands
&lt;p&gt;Here's a question: given a freshly shuffled SET deck, what are the odds that
the first 12 cards drawn will have no sets among them? This question is
difficult to answer without using a computer.&lt;/p&gt;
&lt;p&gt;It's easy to calculate the number of ways to deal a 12-card hand from
a deck of 81:&lt;/p&gt;
\[\binom{81}{12}=70,724,320,184,700\]
&lt;p&gt;But how many of these hands have no sets? Enumerating 70 trillion SET hands
and checking each one can take quite a while, and there is no straightforward
counting formula to answer this question. Some clever methods can be employed to
leverage symmetries and other mathematical properties of SET to cut down this
search space considerably. Donald Knuth himself worked on this problem and came
up with a neat program (&lt;tt class=&quot;docutils literal&quot;&gt;&lt;span class=&quot;pre&quot;&gt;setset-all&lt;/span&gt;&lt;/tt&gt; on &lt;a class=&quot;reference external&quot; href=&quot;https://cs.stanford.edu/~knuth/programs.html&quot;&gt;his programs page&lt;/a&gt;) that found 2,284,535,476,080
such hands. Therefore, the answer to our question is:&lt;/p&gt;
\[\frac{2,284,535,476,080}{70,724,320,184,700}\approx 0.0323\]
&lt;p&gt;There's a 3.23% chance that a randomly drawn hand of 12 cards from a full deck
of SET will have no set in it.&lt;/p&gt;
&lt;p&gt;Let's see how we can use a Monte Carlo simulation to answer this question
with relatively small effort, without deep knowledge of the mathematical
properties of SET that enable cutting down the search space Knuth-style.
We can use the following pseudo-code:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;C = 0
run N times:
  draw a random 12-card hand from a fresh deck
  count sets in the hand
  if no sets:
    C += 1

Estimated probability = C / N
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After running 10 million simulated draws, I got an answer of 0.0323, which
matches the real answer very closely.&lt;/p&gt;
&lt;p&gt;The Monte Carlo approach lets us solve rather complicated problems in a very
simple way. Suppose we want to answer the same question for a hand of 15 cards;
this would blow up the search space considerably - there are about 100x more
ways to select 15-card hands than there are to select 12-card hands. But for
a Monte Carlo simulation, we adjust one small parameter and get a very reliable
&lt;a class=&quot;footnote-reference&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-3&quot; id=&quot;footnote-reference-3&quot;&gt;[3]&lt;/a&gt; answer (about 0.00037, in case you were wondering).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;section&quot; id=&quot;retirement-projection&quot;&gt;
&lt;h2&gt;Retirement projection&lt;/h2&gt;
&lt;p&gt;One domain where Monte Carlo simulations are ubiquitous is projections for
retirement portfolios. Suppose someone prepares to retire with a total sum
of 1 million dollars in their portfolio; they'd like to be able to draw
$30,000 a year from the portfolio for their living expenses. Would that work?&lt;/p&gt;
&lt;p&gt;There's a large number of factors to take into account when analyzing this
question, but for simplicity let's focus on just two: portfolio return and
inflation. We can run a naive estimate, assuming average values: suppose an
average yearly portfolio return of 4%, and average yearly inflation of 2% &lt;a class=&quot;footnote-reference&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-4&quot; id=&quot;footnote-reference-4&quot;&gt;[4]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Let's denote our portfolio return as r=0.04, and inflation as
q=0.02. Then the real return each year is:&lt;/p&gt;
\[r^{\mathrm{real}}=\frac{1+r}{1+q}-1\approx0.0196\]
&lt;p&gt;Starting with $1,000,000, at the end of the year we'll have $1,019,600
and then draw $30,000 for living expenses &lt;a class=&quot;footnote-reference&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-5&quot; id=&quot;footnote-reference-5&quot;&gt;[5]&lt;/a&gt;, ending with $989,600. If we
continue this way, the money runs out after ~55 years, which means that a
person retiring at the age of 65 should be reasonably safe, right?&lt;/p&gt;
&lt;p&gt;But this is &lt;em&gt;very simplistic&lt;/em&gt;; assuming just average returns is risky, because
they do a poor job of representing reality, and many factors have uncertainty.
For example, the sequence of returns matters a lot; a bad year (-10%) followed
by a great year (+18%) would still count as &amp;quot;4% on average&amp;quot; but produces
significantly less money than two consecutive +4% years.
Inflation is also unpredictable, and sometimes
correlated with portfolio returns; there could be bad years of high inflation and
low / volatile returns that can wreak havoc on a portfolio.&lt;/p&gt;
&lt;p&gt;As we add factors (variance in yearly draws, mixed portfolios of stocks, bonds,
real estate, life expectancy, unexpected events, changing tax laws etc.),
relying on a single average estimate becomes increasingly more fraught. This
is why Monte Carlo simulations are very popular in this domain: by drawing
from reasonable distributions based on historical data, a Monte Carlo simulation
can easily run a million different scenarios and provide estimates: for example,
what are the odds of money running out before death.&lt;/p&gt;
&lt;p&gt;Here's a useful chart from a simulation I ran:&lt;/p&gt;
&lt;img alt=&quot;Monte Carlo simulation of retirement, showing percentiles and odds of funds running out&quot; class=&quot;align-center&quot; src=&quot;https://eli.thegreenplace.net/images/2026/retirement-monte-carlo.png&quot; /&gt;
&lt;p&gt;In the top chart:&lt;/p&gt;
&lt;ul class=&quot;simple&quot;&gt;
&lt;li&gt;The dashed line shows the constant assumptions mentioned before: what happens
when yearly return is always 4% and inflation is always 2%.&lt;/li&gt;
&lt;li&gt;The shaded blue areas demonstrate the outcomes of 1,000,000 simulations where
inflation and return numbers are drawn from reasonable normal distributions
based on historical data. We see that in 25% of the cases, all money ran out
by roughly 22 years.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the bottom chart:&lt;/p&gt;
&lt;ul class=&quot;simple&quot;&gt;
&lt;li&gt;It's even easier to see how long the funds last; if we're interested in
knowing, say, what are the odds that this plan will have enough money for
30 years - the chart shows it's about 60% (since in 40% of the simulations
the funds were depleted at this point).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Looking a this simulation, under the current assumptions the plan sounds much
riskier than the average assumption makes it appear. Assuming that a 65-y.o.
person would plan for
25 years of retirement until death, the ~30% odds of not having sufficient funds
for this duration of time are sobering. Perhaps a change in plans is needed
(such as a more frugal lifestyle or securing additional funds in some way).&lt;/p&gt;
&lt;p&gt;Retirement projection is only one of may ways in which Monte Carlo simulations
are used for financial and economical applications; given the high uncertainty
of these domains, it's very difficult to plan using analytical calculations.
Company sales projections, growth projections, stock offering prices and much
more uses Monte Carlo simulations to arrive at estimates with reasonable error
bars.&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;section&quot; id=&quot;code&quot;&gt;
&lt;h2&gt;Code&lt;/h2&gt;
&lt;p&gt;All the code for the explorations in this post is &lt;a class=&quot;reference external&quot; href=&quot;https://github.com/eliben/code-for-blog/tree/main/2026/monte-carlo&quot;&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;hr class=&quot;docutils&quot; /&gt;
&lt;table class=&quot;docutils footnote&quot; frame=&quot;void&quot; id=&quot;footnote-1&quot; rules=&quot;none&quot;&gt;
&lt;colgroup&gt;&lt;col class=&quot;label&quot; /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign=&quot;top&quot;&gt;
&lt;tr&gt;&lt;td class=&quot;label&quot;&gt;&lt;a class=&quot;fn-backref&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-reference-1&quot;&gt;[1]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;While these techniques were conceptually understood much earlier, it's
not surprising that their first real applications coincided with the
development of the first digital computers. As we'll see later in the
post, Monte Carlo simulations benefit from running large numbers of
trials to get reasonable accuracy.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class=&quot;docutils footnote&quot; frame=&quot;void&quot; id=&quot;footnote-2&quot; rules=&quot;none&quot;&gt;
&lt;colgroup&gt;&lt;col class=&quot;label&quot; /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign=&quot;top&quot;&gt;
&lt;tr&gt;&lt;td class=&quot;label&quot;&gt;&lt;a class=&quot;fn-backref&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-reference-2&quot;&gt;[2]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;The answer is: three empty red diamonds, three solid purple ovals, three
striped green squiggles. Note that for each of the 4 SET attributes,
these three cards are either all the same or all different.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class=&quot;docutils footnote&quot; frame=&quot;void&quot; id=&quot;footnote-3&quot; rules=&quot;none&quot;&gt;
&lt;colgroup&gt;&lt;col class=&quot;label&quot; /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign=&quot;top&quot;&gt;
&lt;tr&gt;&lt;td class=&quot;label&quot;&gt;&lt;a class=&quot;fn-backref&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-reference-3&quot;&gt;[3]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;For the same number of trials, this estimate has greater relative
uncertainty than the 12-card estimate, because we encounter far fewer
hands without a set.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class=&quot;docutils footnote&quot; frame=&quot;void&quot; id=&quot;footnote-4&quot; rules=&quot;none&quot;&gt;
&lt;colgroup&gt;&lt;col class=&quot;label&quot; /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign=&quot;top&quot;&gt;
&lt;tr&gt;&lt;td class=&quot;label&quot;&gt;&lt;a class=&quot;fn-backref&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-reference-4&quot;&gt;[4]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;For the examples in this post, we'll be using &lt;em&gt;real dollars&lt;/em&gt;, or today's
value of the money. We'll assume that the $30,000 yearly draw doesn't
change and will instead apply inflation to the portfolio itself.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table class=&quot;docutils footnote&quot; frame=&quot;void&quot; id=&quot;footnote-5&quot; rules=&quot;none&quot;&gt;
&lt;colgroup&gt;&lt;col class=&quot;label&quot; /&gt;&lt;col /&gt;&lt;/colgroup&gt;
&lt;tbody valign=&quot;top&quot;&gt;
&lt;tr&gt;&lt;td class=&quot;label&quot;&gt;&lt;a class=&quot;fn-backref&quot; href=&quot;https://eli.thegreenplace.net/feeds/python.atom.xml#footnote-reference-5&quot;&gt;[5]&lt;/a&gt;&lt;/td&gt;&lt;td&gt;More sophisticated simulations would let us control these parameters;
for example, are the expense funds drawn at the beginning or end of each
year, or distributed on a monthly basis?&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 08 Oct 2026 09:35:03 +0000</pubDate>
</item>
<item>
	<title>LernerPython blog, from Reuven Lerner: Pandas groupby with two columns: Reshape results with unstack</title>
	<guid>https://lernerpython.com/2026/10/07/pandas-groupby-with-two-columns-reshape-results-with-unstack/</guid>
	<link>https://lernerpython.com/2026/10/07/pandas-groupby-with-two-columns-reshape-results-with-unstack/</link>
	<description>&lt;img src=&quot;https://lernerpython.com/wp-content/uploads/2026/10/2026-10-07.png&quot; alt=&quot;Pandas groupby with two columns: Reshape results with unstack&quot; class=&quot;wp-image-17978&quot; width=&quot;1876&quot; height=&quot;1306&quot; /&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Invoke &amp;#8220;groupby&amp;#8221; with two categorical columns in Python Pandas, and get a two-part multi-index:&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;g = df.groupby(['passenger_count', 'VendorID'])['trip_distance'].mean()&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Turn into a data frame with unstack:&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;g.unstack()  # index 0-6 (passenger_count), columns 1-2 (VendorID)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The post &lt;a href=&quot;https://lernerpython.com/2026/10/07/pandas-groupby-with-two-columns-reshape-results-with-unstack/&quot;&gt;Pandas groupby with two columns: Reshape results with unstack&lt;/a&gt; appeared first on &lt;a href=&quot;https://lernerpython.com&quot;&gt;LernerPython&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Wed, 07 Oct 2026 06:00:00 +0000</pubDate>
</item>
<item>
	<title>Python GUIs: Change the color of the ProgressBar indicator text when it exceeds 50%</title>
	<guid>https://www.pythonguis.com/faq/change-the-color-of-the-progressbar-indicator-text-when-it-exceeds-50/</guid>
	<link>https://www.pythonguis.com/faq/change-the-color-of-the-progressbar-indicator-text-when-it-exceeds-50/</link>
	<description>&lt;blockquote&gt;
&lt;p&gt;How can I change the text color from black to white of the percentage indicator inside the &lt;code&gt;QProgressBar&lt;/code&gt; when it exceeds the value of 50?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When a &lt;code&gt;QProgressBar&lt;/code&gt; fills past the halfway mark, the dark-colored chunk behind the text can make the default black percentage label hard to read. A common solution is to switch the text color to white once the value crosses 50%. Let's walk through how to do this in PyQt5 using stylesheets and a signal connection.&lt;/p&gt;
&lt;h2 id=&quot;why-the-text-becomes-hard-to-read&quot;&gt;Why the text becomes hard to read&lt;/h2&gt;
&lt;p&gt;By default, &lt;code&gt;QProgressBar&lt;/code&gt; draws its percentage text on top of the bar. When the colored &quot;chunk&quot; is small, the text sits against a light background and black text is fine. As the chunk grows and fills most of the bar, the text ends up on top of a dark background &amp;mdash; and black-on-dark is difficult to see.&lt;/p&gt;
&lt;p&gt;The fix is straightforward: watch for value changes and update the stylesheet to swap the text color at the right moment.&lt;/p&gt;
&lt;h2 id=&quot;styling-the-qprogressbar-text&quot;&gt;Styling the &lt;code&gt;QProgressBar&lt;/code&gt; text&lt;/h2&gt;
&lt;p&gt;The text color on a &lt;code&gt;QProgressBar&lt;/code&gt; is controlled by the &lt;code&gt;color&lt;/code&gt; property on the &lt;code&gt;QProgressBar&lt;/code&gt; selector itself &amp;mdash; not on &lt;code&gt;QProgressBar::chunk&lt;/code&gt;. The &lt;code&gt;::chunk&lt;/code&gt; sub-control only styles the filled portion of the bar (its background color, border, etc.), while &lt;code&gt;color&lt;/code&gt; on &lt;code&gt;QProgressBar&lt;/code&gt; sets the text color.&lt;/p&gt;
&lt;p&gt;Here's a quick example of setting the text to white:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;self.progress_bar.setStyleSheet(&quot;QProgressBar { color: white; }&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And setting it back to black:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;self.progress_bar.setStyleSheet(&quot;QProgressBar { color: black; }&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&quot;responding-to-value-changes&quot;&gt;Responding to value changes&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;QProgressBar&lt;/code&gt; emits a &lt;code&gt;valueChanged&lt;/code&gt; signal every time its value updates. You can connect a slot to this signal that checks the current value and applies the appropriate stylesheet.&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;self.progress_bar.valueChanged.connect(self.update_progress_text_color)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then define the slot:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;def update_progress_text_color(self, value):
    if value &amp;gt; 50:
        self.progress_bar.setStyleSheet(&quot;&quot;&quot;
            QProgressBar {
                color: white;
            }
        &quot;&quot;&quot;)
    else:
        self.progress_bar.setStyleSheet(&quot;&quot;&quot;
            QProgressBar {
                color: black;
            }
        &quot;&quot;&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Each time the value changes, this method checks whether it's above 50 and sets the text color accordingly.&lt;/p&gt;
&lt;h2 id=&quot;preserving-other-styles&quot;&gt;Preserving other styles&lt;/h2&gt;
&lt;p&gt;If you already have a stylesheet on your progress bar (for example, customizing the chunk color or the bar's border), you'll want to include those properties in both branches so they aren't lost when the stylesheet is replaced. Every call to &lt;code&gt;setStyleSheet()&lt;/code&gt; replaces the previous stylesheet entirely.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;BASE_STYLE = &quot;&quot;&quot;
    QProgressBar {
        border: 1px solid grey;
        border-radius: 5px;
        text-align: center;
    }
    QProgressBar::chunk {
        background-color: #4CAF50;
        border-radius: 5px;
    }
&quot;&quot;&quot;

def update_progress_text_color(self, value):
    if value &amp;gt; 50:
        color_style = &quot;QProgressBar { color: white; }&quot;
    else:
        color_style = &quot;QProgressBar { color: black; }&quot;

    self.progress_bar.setStyleSheet(BASE_STYLE + color_style)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Because the &lt;code&gt;color_style&lt;/code&gt; rule comes after &lt;code&gt;BASE_STYLE&lt;/code&gt;, it overrides the text color while keeping everything else intact.&lt;/p&gt;
&lt;h2 id=&quot;complete-working-example&quot;&gt;Complete working example&lt;/h2&gt;
&lt;p&gt;Here's a full PyQt5 application you can copy and run. It uses a &lt;code&gt;QTimer&lt;/code&gt; to increment the progress bar automatically so you can see the text color flip from black to white as the bar crosses 50%.&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QProgressBar, QPushButton,
)
from PyQt5.QtCore import QTimer


BASE_STYLE = &quot;&quot;&quot;
    QProgressBar {
        border: 1px solid grey;
        border-radius: 5px;
        text-align: center;
        font-size: 14px;
    }
    QProgressBar::chunk {
        background-color: #3874f2;
        border-radius: 5px;
    }
&quot;&quot;&quot;


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;QProgressBar Text Color Demo&quot;)
        self.resize(400, 120)

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.progress_bar = QProgressBar()
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(100)
        self.progress_bar.setValue(0)
        self.progress_bar.setStyleSheet(BASE_STYLE + &quot;QProgressBar { color: black; }&quot;)
        layout.addWidget(self.progress_bar)

        self.start_button = QPushButton(&quot;Start&quot;)
        self.start_button.clicked.connect(self.start_progress)
        layout.addWidget(self.start_button)

        self.progress_bar.valueChanged.connect(self.update_progress_text_color)

        self.timer = QTimer()
        self.timer.timeout.connect(self.advance_progress)

    def start_progress(self):
        self.progress_bar.setValue(0)
        self.timer.start(50)

    def advance_progress(self):
        current = self.progress_bar.value()
        if current &amp;gt;= 100:
            self.timer.stop()
            return
        self.progress_bar.setValue(current + 1)

    def update_progress_text_color(self, value):
        if value &amp;gt; 50:
            color_style = &quot;QProgressBar { color: white; }&quot;
        else:
            color_style = &quot;QProgressBar { color: black; }&quot;

        self.progress_bar.setStyleSheet(BASE_STYLE + color_style)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When you run this, click &lt;strong&gt;Start&lt;/strong&gt; and watch the percentage label. While the bar is at 50% or below, the text is black. The moment it passes 50%, the text switches to white, keeping it readable against the blue chunk.&lt;/p&gt;
&lt;p&gt;You can adjust the threshold, the colors, or even add a gradual transition by checking at multiple thresholds &amp;mdash; the same pattern applies. Connect to &lt;code&gt;valueChanged&lt;/code&gt;, check the value, and set the stylesheet accordingly.&lt;/p&gt;
            &lt;p&gt;For an in-depth guide to building Python GUIs with PyQt5 see my book, &lt;a href=&quot;https://www.pythonguis.com/pyqt5-book/&quot;&gt;Create GUI Applications with Python &amp;amp; Qt5.&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 07 Oct 2026 06:00:00 +0000</pubDate>
</item>
<item>
	<title>Python GUIs: Using Complex Data Sources with PyQt6 Model/View Architecture — How to use JSON, nested data, and other complex structures in your Qt table and list views</title>
	<guid>https://www.pythonguis.com/faq/complex-data-in-pyqt-models/</guid>
	<link>https://www.pythonguis.com/faq/complex-data-in-pyqt-models/</link>
	<description>&lt;blockquote&gt;
&lt;p&gt;I have a complex data set in a JSON file. Is it possible to use this as my model's data in PyQt6 views, or do I need to simplify it to a basic table?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great news: you can use &lt;em&gt;any&lt;/em&gt; data structure you like in a PyQt6 model. JSON files, nested dictionaries, lists of objects, database results &amp;mdash; it all works. The model acts as an interface between how &lt;em&gt;you&lt;/em&gt; store your data and how &lt;em&gt;Qt&lt;/em&gt; expects to see it. As long as your model returns data in the format Qt expects, the view will display it without complaint.&lt;/p&gt;
&lt;p&gt;In this tutorial, we'll walk through how to load a JSON file and display its data in a &lt;code&gt;QTableView&lt;/code&gt; using a custom &lt;code&gt;QAbstractTableModel&lt;/code&gt;. Along the way, you'll see how the model translates between your real-world data and Qt's row-and-column view of the world.&lt;/p&gt;
&lt;h2 id=&quot;how-modelview-works-with-complex-data&quot;&gt;How Model/View Works with Complex Data&lt;/h2&gt;
&lt;p&gt;Qt's &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyqt6-modelview-architecture/&quot;&gt;Model/View architecture&lt;/a&gt; separates &lt;em&gt;data&lt;/em&gt; from &lt;em&gt;presentation&lt;/em&gt;. The view (e.g. &lt;code&gt;QTableView&lt;/code&gt;, &lt;code&gt;QListView&lt;/code&gt;) asks the model questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&quot;How many rows are there?&quot;&lt;/li&gt;
&lt;li&gt;&quot;How many columns are there?&quot;&lt;/li&gt;
&lt;li&gt;&quot;What's the data at row 2, column 3?&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your model answers these questions by looking at whatever underlying data structure you're using. The view doesn't care whether your data lives in a flat list, a JSON file, a pandas DataFrame, or a SQL database. It only cares about the answers.&lt;/p&gt;
&lt;p&gt;This means you can wrap &lt;em&gt;any&lt;/em&gt; data source in a model. You just need to translate between your data's shape and the row/column format that Qt uses.&lt;/p&gt;
&lt;h2 id=&quot;a-simple-json-example&quot;&gt;A Simple JSON Example&lt;/h2&gt;
&lt;p&gt;Let's start with a straightforward example. Suppose you have a JSON file containing a list of people, where each person has several fields:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-json&quot;&gt;json&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;json&quot;&gt;[
    {
        &quot;name&quot;: &quot;Alice&quot;,
        &quot;age&quot;: 34,
        &quot;city&quot;: &quot;Berlin&quot;,
        &quot;role&quot;: &quot;Engineer&quot;
    },
    {
        &quot;name&quot;: &quot;Bob&quot;,
        &quot;age&quot;: 28,
        &quot;city&quot;: &quot;London&quot;,
        &quot;role&quot;: &quot;Designer&quot;
    },
    {
        &quot;name&quot;: &quot;Charlie&quot;,
        &quot;age&quot;: 41,
        &quot;city&quot;: &quot;New York&quot;,
        &quot;role&quot;: &quot;Manager&quot;
    },
    {
        &quot;name&quot;: &quot;Diana&quot;,
        &quot;age&quot;: 25,
        &quot;city&quot;: &quot;Tokyo&quot;,
        &quot;role&quot;: &quot;Developer&quot;
    }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Save this as &lt;code&gt;people.json&lt;/code&gt; in the same directory as your Python script.&lt;/p&gt;
&lt;p&gt;Each object in the list becomes a row in the table, and each field becomes a column. The model's job is to map between these two representations.&lt;/p&gt;
&lt;h2 id=&quot;building-the-model&quot;&gt;Building the Model&lt;/h2&gt;
&lt;p&gt;To display this data in a &lt;code&gt;QTableView&lt;/code&gt;, we subclass &lt;code&gt;QAbstractTableModel&lt;/code&gt; and implement three required methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rowCount()&lt;/code&gt; &amp;mdash; returns the number of rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;columnCount()&lt;/code&gt; &amp;mdash; returns the number of columns&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data()&lt;/code&gt; &amp;mdash; returns the data for a given row and column&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's how that looks:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import json
from PyQt6.QtCore import Qt, QAbstractTableModel


class JsonTableModel(QAbstractTableModel):
    def __init__(self, data, headers=None):
        super().__init__()
        self._data = data
        # Use provided headers, or extract keys from the first item.
        if headers:
            self._headers = headers
        elif data:
            self._headers = list(data[0].keys())
        else:
            self._headers = []

    def rowCount(self, parent=None):
        return len(self._data)

    def columnCount(self, parent=None):
        return len(self._headers)

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            row = self._data[index.row()]
            key = self._headers[index.column()]
            return str(row.get(key, &quot;&quot;))
        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                return self._headers[section].capitalize()
        return None
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Let's walk through what's happening here.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;__init__&lt;/code&gt; method stores the list of dictionaries and figures out the column headers. If you don't provide headers explicitly, it grabs the keys from the first dictionary in the list.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;rowCount()&lt;/code&gt; method returns the length of the data list &amp;mdash; one row per dictionary.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;columnCount()&lt;/code&gt; method returns the number of headers &amp;mdash; one column per key.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;data()&lt;/code&gt; method is where the translation happens. Qt calls this method with an &lt;code&gt;index&lt;/code&gt; (which contains a row and column number) and a &lt;code&gt;role&lt;/code&gt; (which describes &lt;em&gt;what kind&lt;/em&gt; of data Qt wants). For display purposes, we use &lt;code&gt;Qt.ItemDataRole.DisplayRole&lt;/code&gt;. We look up the right dictionary from the list using the row number, then look up the right value using the column header as a key.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;headerData()&lt;/code&gt; method provides labels for the column headers at the top of the table.&lt;/p&gt;
&lt;h2 id=&quot;displaying-the-data&quot;&gt;Displaying the Data&lt;/h2&gt;
&lt;p&gt;Now let's wire everything together in a small application:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
import json

from PyQt6.QtWidgets import QApplication, QMainWindow, QTableView
from PyQt6.QtCore import Qt, QAbstractTableModel


class JsonTableModel(QAbstractTableModel):
    def __init__(self, data, headers=None):
        super().__init__()
        self._data = data
        if headers:
            self._headers = headers
        elif data:
            self._headers = list(data[0].keys())
        else:
            self._headers = []

    def rowCount(self, parent=None):
        return len(self._data)

    def columnCount(self, parent=None):
        return len(self._headers)

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            row = self._data[index.row()]
            key = self._headers[index.column()]
            return str(row.get(key, &quot;&quot;))
        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                return self._headers[section].capitalize()
        return None


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;JSON Table Model&quot;)

        # Load data from the JSON file.
        with open(&quot;people.json&quot;, &quot;r&quot;) as f:
            data = json.load(f)

        # Create the model and view.
        self.model = JsonTableModel(data)
        self.table = QTableView()
        self.table.setModel(self.model)

        self.setCentralWidget(self.table)
        self.resize(500, 300)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Run this and you'll see a table view displaying the data from your JSON file, complete with column headers.&lt;/p&gt;
&lt;h2 id=&quot;working-with-nested-json&quot;&gt;Working with Nested JSON&lt;/h2&gt;
&lt;p&gt;Real-world JSON is often more complex than a flat list of objects. You might have nested structures like this:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-json&quot;&gt;json&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;json&quot;&gt;[
    {
        &quot;name&quot;: &quot;Alice&quot;,
        &quot;age&quot;: 34,
        &quot;address&quot;: {
            &quot;city&quot;: &quot;Berlin&quot;,
            &quot;country&quot;: &quot;Germany&quot;
        },
        &quot;skills&quot;: [&quot;Python&quot;, &quot;C++&quot;]
    },
    {
        &quot;name&quot;: &quot;Bob&quot;,
        &quot;age&quot;: 28,
        &quot;address&quot;: {
            &quot;city&quot;: &quot;London&quot;,
            &quot;country&quot;: &quot;UK&quot;
        },
        &quot;skills&quot;: [&quot;JavaScript&quot;, &quot;CSS&quot;]
    }
]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Save this as &lt;code&gt;people_nested.json&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;QTableView&lt;/code&gt; is inherently a flat, two-dimensional grid. You can't directly display nested structures in it, but you &lt;em&gt;can&lt;/em&gt; flatten the data in your model. The model is the perfect place to do this &amp;mdash; your original data stays complex, but the model presents a simplified view to Qt.&lt;/p&gt;
&lt;p&gt;Here's a model that handles nested dictionaries by using dot-notation column definitions:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;class NestedJsonTableModel(QAbstractTableModel):
    def __init__(self, data, columns):
        super().__init__()
        self._data = data
        # columns is a list of tuples: (header_label, key_path)
        # key_path is a dot-separated string like &quot;address.city&quot;
        self._columns = columns

    def rowCount(self, parent=None):
        return len(self._data)

    def columnCount(self, parent=None):
        return len(self._columns)

    def _resolve(self, obj, key_path):
        &quot;&quot;&quot;Walk into a nested dict using a dot-separated path.&quot;&quot;&quot;
        keys = key_path.split(&quot;.&quot;)
        for key in keys:
            if isinstance(obj, dict):
                obj = obj.get(key, &quot;&quot;)
            else:
                return &quot;&quot;
        return obj

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            row = self._data[index.row()]
            _, key_path = self._columns[index.column()]
            value = self._resolve(row, key_path)
            # Handle lists by joining them into a string.
            if isinstance(value, list):
                return &quot;, &quot;.join(str(v) for v in value)
            return str(value)
        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                label, _ = self._columns[section]
                return label
        return None
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;_resolve&lt;/code&gt; method walks through the nested dictionary using a dot-separated path. So &lt;code&gt;&quot;address.city&quot;&lt;/code&gt; first looks up &lt;code&gt;&quot;address&quot;&lt;/code&gt; (getting a nested dict), then looks up &lt;code&gt;&quot;city&quot;&lt;/code&gt; inside that. This keeps the logic clean and reusable.&lt;/p&gt;
&lt;p&gt;You define the columns you want to display when creating the model:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;columns = [
    (&quot;Name&quot;, &quot;name&quot;),
    (&quot;Age&quot;, &quot;age&quot;),
    (&quot;City&quot;, &quot;address.city&quot;),
    (&quot;Country&quot;, &quot;address.country&quot;),
    (&quot;Skills&quot;, &quot;skills&quot;),
]

with open(&quot;people_nested.json&quot;, &quot;r&quot;) as f:
    data = json.load(f)

model = NestedJsonTableModel(data, columns)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This approach gives you full control over which parts of your data appear in the table and in what order. Your JSON stays as-is &amp;mdash; the model handles the mapping.&lt;/p&gt;
&lt;h2 id=&quot;complete-working-example-with-nested-data&quot;&gt;Complete Working Example with Nested Data&lt;/h2&gt;
&lt;p&gt;Here's the full application with the nested JSON model:&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
import json

from PyQt6.QtWidgets import QApplication, QMainWindow, QTableView
from PyQt6.QtCore import Qt, QAbstractTableModel


class NestedJsonTableModel(QAbstractTableModel):
    &quot;&quot;&quot;A table model that can display data from nested JSON structures.&quot;&quot;&quot;

    def __init__(self, data, columns):
        super().__init__()
        self._data = data
        # columns: list of (header_label, dot_separated_key_path)
        self._columns = columns

    def rowCount(self, parent=None):
        return len(self._data)

    def columnCount(self, parent=None):
        return len(self._columns)

    def _resolve(self, obj, key_path):
        &quot;&quot;&quot;Walk into a nested dict using a dot-separated path.&quot;&quot;&quot;
        keys = key_path.split(&quot;.&quot;)
        for key in keys:
            if isinstance(obj, dict):
                obj = obj.get(key, &quot;&quot;)
            else:
                return &quot;&quot;
        return obj

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            row = self._data[index.row()]
            _, key_path = self._columns[index.column()]
            value = self._resolve(row, key_path)
            if isinstance(value, list):
                return &quot;, &quot;.join(str(v) for v in value)
            return str(value)
        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                label, _ = self._columns[section]
                return label
        return None


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;Nested JSON Table Model&quot;)

        # Define which fields to show and how to reach them.
        columns = [
            (&quot;Name&quot;, &quot;name&quot;),
            (&quot;Age&quot;, &quot;age&quot;),
            (&quot;City&quot;, &quot;address.city&quot;),
            (&quot;Country&quot;, &quot;address.country&quot;),
            (&quot;Skills&quot;, &quot;skills&quot;),
        ]

        # Load the nested JSON data.
        with open(&quot;people_nested.json&quot;, &quot;r&quot;) as f:
            data = json.load(f)

        self.model = NestedJsonTableModel(data, columns)
        self.table = QTableView()
        self.table.setModel(self.model)

        # Resize columns to fit their contents.
        self.table.resizeColumnsToContents()

        self.setCentralWidget(self.table)
        self.resize(600, 300)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&quot;adding-sorting-with-qsortfilterproxymodel&quot;&gt;Adding Sorting with QSortFilterProxyModel&lt;/h2&gt;
&lt;p&gt;Once you have your model working, adding sorting is straightforward using &lt;code&gt;QSortFilterProxyModel&lt;/code&gt;. This sits between your model and the view, providing sort and filter capabilities without modifying your original data. For more details on sorting and filtering tables, see our &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyqt6-modelview-sort-filter-tables/&quot;&gt;guide to sorting and filtering in Qt Model/View&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;code-block&quot;&gt;
&lt;span class=&quot;code-block-language code-block-python&quot;&gt;python&lt;/span&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;import sys
import json

from PyQt6.QtWidgets import QApplication, QMainWindow, QTableView
from PyQt6.QtCore import Qt, QAbstractTableModel, QSortFilterProxyModel


class NestedJsonTableModel(QAbstractTableModel):
    def __init__(self, data, columns):
        super().__init__()
        self._data = data
        self._columns = columns

    def rowCount(self, parent=None):
        return len(self._data)

    def columnCount(self, parent=None):
        return len(self._columns)

    def _resolve(self, obj, key_path):
        keys = key_path.split(&quot;.&quot;)
        for key in keys:
            if isinstance(obj, dict):
                obj = obj.get(key, &quot;&quot;)
            else:
                return &quot;&quot;
        return obj

    def data(self, index, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            row = self._data[index.row()]
            _, key_path = self._columns[index.column()]
            value = self._resolve(row, key_path)
            if isinstance(value, list):
                return &quot;, &quot;.join(str(v) for v in value)
            return str(value)
        return None

    def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
        if role == Qt.ItemDataRole.DisplayRole:
            if orientation == Qt.Orientation.Horizontal:
                label, _ = self._columns[section]
                return label
        return None


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle(&quot;Sortable JSON Table&quot;)

        columns = [
            (&quot;Name&quot;, &quot;name&quot;),
            (&quot;Age&quot;, &quot;age&quot;),
            (&quot;City&quot;, &quot;address.city&quot;),
            (&quot;Country&quot;, &quot;address.country&quot;),
            (&quot;Skills&quot;, &quot;skills&quot;),
        ]

        with open(&quot;people_nested.json&quot;, &quot;r&quot;) as f:
            data = json.load(f)

        # Create the source model.
        self.source_model = NestedJsonTableModel(data, columns)

        # Wrap it in a proxy model for sorting.
        self.proxy_model = QSortFilterProxyModel()
        self.proxy_model.setSourceModel(self.source_model)

        self.table = QTableView()
        self.table.setModel(self.proxy_model)
        self.table.setSortingEnabled(True)
        self.table.resizeColumnsToContents()

        self.setCentralWidget(self.table)
        self.resize(600, 300)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Click any column header to sort by that column. Click again to reverse the sort order. The &lt;code&gt;QSortFilterProxyModel&lt;/code&gt; handles all of this automatically &amp;mdash; you don't need to write any sorting logic yourself.&lt;/p&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;The Model/View architecture in PyQt6 is designed to work with whatever data you have. The model is a translation layer: it takes your data &amp;mdash; whether it's a flat list, nested JSON, a database query, or anything else &amp;mdash; and presents it in the row-and-column format that Qt's views expect.&lt;/p&gt;
&lt;p&gt;When working with complex data structures, keep these principles in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Your data stays as-is.&lt;/strong&gt; You don't need to restructure your JSON or flatten your database. The model handles the translation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Define your columns explicitly.&lt;/strong&gt; For nested data, decide upfront which fields you want to display and how to reach them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use helper methods.&lt;/strong&gt; A small utility like &lt;code&gt;_resolve()&lt;/code&gt; keeps your &lt;code&gt;data()&lt;/code&gt; method clean and makes it easy to access deeply nested values.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layer on functionality.&lt;/strong&gt; Use &lt;code&gt;QSortFilterProxyModel&lt;/code&gt; to add sorting and filtering without touching your model code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you're working with tabular data from pandas or numpy instead of JSON, take a look at our tutorial on &lt;a href=&quot;https://www.pythonguis.com/tutorials/pyqt6-qtableview-modelviews-numpy-pandas/&quot;&gt;displaying pandas DataFrames in QTableView&lt;/a&gt;. For making your table cells editable, see our guide on &lt;a href=&quot;https://www.pythonguis.com/faq/editing-pyqt6-tableview/&quot;&gt;editing data in a PyQt6 QTableView&lt;/a&gt;.&lt;/p&gt;
            &lt;p&gt;For an in-depth guide to building Python GUIs with PyQt6 see my book, &lt;a href=&quot;https://www.pythonguis.com/pyqt6-book/&quot;&gt;Create GUI Applications with Python &amp;amp; Qt6.&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 07 Oct 2026 06:00:00 +0000</pubDate>
</item>
<item>
	<title>Python Bytes: #499 So many questions??</title>
	<guid>https://pythonbytes.fm/episodes/show/499/so-many-questions</guid>
	<link>https://pythonbytes.fm/episodes/show/499/so-many-questions</link>
	<description>&amp;lt;strong&amp;gt;Topics covered in this episode:&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;

&amp;lt;ul&amp;gt;
	&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://peps.python.org/pep-0824?featured_on=pythonbytes&quot;&amp;gt;PEP 824 brings ?? and ??= to Python for None handling&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://blog.python.org/2026/10/python-3150-rc3/?featured_on=pythonbytes&quot;&amp;gt;Python 3.15&amp;lt;/a&amp;gt; gets a surprise RC3, and &amp;lt;a href=&quot;https://blog.python.org/2026/10/python-31022-31117/?featured_on=pythonbytes&quot;&amp;gt;Python 3.10&amp;lt;/a&amp;gt; reaches end of life&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://docs.python.org/3/library/asyncio-task.html#shielding-from-cancellation&quot;&amp;gt;asyncio.shield&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;a href=&quot;https://github.com/kitao/pyxel?featured_on=pythonbytes&quot;&amp;gt;Pyxel: the retro game engine for Python&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Extras&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Joke&amp;lt;/strong&amp;gt;&amp;lt;/li&amp;gt;

&amp;lt;/ul&amp;gt;&amp;lt;a href='https://www.youtube.com/watch?v=uXakV6i1-wc' style='font-weight: bold;' data-umami-event=&quot;Livestream-Past&quot; data-umami-event-episode=&quot;499&quot;&amp;gt;Watch on YouTube&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;About the show&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Sponsored by us! Support our work through:&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Our &amp;lt;a href=&quot;https://training.talkpython.fm/?featured_on=pythonbytes&quot;&amp;gt;&amp;lt;strong&amp;gt;courses at Talk Python&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Consulting from &amp;lt;a href=&quot;https://sixfeetup.com/?featured_on=pythonbytes&quot;&amp;gt;&amp;lt;strong&amp;gt;Six Feet Up&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Connect with the hosts&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Michael: &amp;lt;a href=&quot;https://fosstodon.org/@mkennedy&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/mkennedy.codes?featured_on=pythonbytes&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/mkennedy?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://www.linkedin.com/in/mkennedy/?featured_on=pythonbytes&quot;&amp;gt;LinkedIn&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Calvin: &amp;lt;a href=&quot;https://sixfeetup.social/@calvin?featured_on=pythonbytes&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/calvinhp.com?featured_on=pythonbytes&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/calvinhp?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://www.linkedin.com/in/calvinhp/?featured_on=pythonbytes&quot;&amp;gt;LinkedIn&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Show: &amp;lt;a href=&quot;https://fosstodon.org/@pythonbytes&quot;&amp;gt;Mastodon&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://bsky.app/profile/pythonbytes.fm&quot;&amp;gt;BlueSky&amp;lt;/a&amp;gt; / &amp;lt;a href=&quot;https://x.com/PythonBytes?featured_on=pythonbytes&quot;&amp;gt;X&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;Join us on YouTube at &amp;lt;a href=&quot;https://pythonbytes.fm/stream/live&quot;&amp;gt;&amp;lt;strong&amp;gt;pythonbytes.fm/live&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt; to be part of the audience. Usually &amp;lt;strong&amp;gt;Tuesday at 7am PT&amp;lt;/strong&amp;gt;. Older video versions available there too.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Finally, if you want an artisanal, hand-crafted digest of every week of the show notes in email form? Add your name and email to &amp;lt;a href=&quot;https://pythonbytes.fm/friends-of-the-show&quot;&amp;gt;our friends of the show list&amp;lt;/a&amp;gt;, we'll never share it.&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Michael #1: &amp;lt;a href=&quot;https://peps.python.org/pep-0824?featured_on=pythonbytes&quot;&amp;gt;PEP 824 brings ?? and ??= to Python for None handling&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;PEP 824, a new draft from Marc Mueller sponsored by Guido van Rossum, proposes None-coalescing operators for Python 3.16. The ?? operator returns its left-hand side unless that value is None, and ??= assigns a fallback only when the target is None. It revives the long-deferred &amp;lt;a href=&quot;https://peps.python.org/pep-0505/?featured_on=pythonbytes&quot;&amp;gt;PEP 505&amp;lt;/a&amp;gt; from over a decade ago, trimmed to just these two operators, with None-aware access split off into PEP 823. The goal is replacing verbose is None checks with something closer to or, but keyed on None instead of truthiness.&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Every Python codebase has piles of if x is None fallback code, and this is the first serious move in ten years to give it real syntax.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;user.age ?? &quot;unknown&quot; is like or but only falls back on None, so 0, &quot;&quot;, and [] pass through instead of getting clobbered&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&quot;http://user.name?featured_on=pythonbytes&quot;&amp;gt;user.name&amp;lt;/a&amp;gt; ??= &quot;unknown&quot; replaces the two-line check-then-assign pattern, with left-side subexpressions evaluated and cached exactly once&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Precedence sits between or and conditional expressions, matching JavaScript and C#, and ?? lands as a BoolOp in the AST next to and and or&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Unlike +=, ??= is a conditional assignment that skips the right side entirely, which is why it gets its own AST node rather than AugAssign&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Still draft status targeting 3.16, with a working reference implementation and an online demo to try, and it notably rejects a soft keyword like otherwise in favor of the familiar ??&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Discussion-worthy: the PEP answers the old objection that making None easier will proliferate its use, pointing out None is already everywhere and the status quo just produces uglier code&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;div class=&quot;codehilite&quot;&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;code&amp;gt;&amp;lt;span class=&quot;c1&quot;&amp;gt;# OG way&amp;lt;/span&amp;gt;
&amp;lt;span class=&quot;n&quot;&amp;gt;user&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;o&quot;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;n&quot;&amp;gt;db&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;get_user&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;p&quot;&amp;gt;()&amp;lt;/span&amp;gt;
&amp;lt;span class=&quot;n&quot;&amp;gt;city&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;o&quot;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;kc&quot;&amp;gt;None&amp;lt;/span&amp;gt;
&amp;lt;span class=&quot;k&quot;&amp;gt;if&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;n&quot;&amp;gt;user&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;ow&quot;&amp;gt;is&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;ow&quot;&amp;gt;not&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;kc&quot;&amp;gt;None&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;p&quot;&amp;gt;:&amp;lt;/span&amp;gt;
    &amp;lt;span class=&quot;k&quot;&amp;gt;if&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;n&quot;&amp;gt;user&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;address&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;ow&quot;&amp;gt;is&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;ow&quot;&amp;gt;not&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;kc&quot;&amp;gt;None&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;p&quot;&amp;gt;:&amp;lt;/span&amp;gt;
        &amp;lt;span class=&quot;k&quot;&amp;gt;if&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;n&quot;&amp;gt;user&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;address&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;city&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;ow&quot;&amp;gt;is&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;ow&quot;&amp;gt;not&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;kc&quot;&amp;gt;None&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;p&quot;&amp;gt;:&amp;lt;/span&amp;gt;
            &amp;lt;span class=&quot;n&quot;&amp;gt;city&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;o&quot;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;n&quot;&amp;gt;user&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;address&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;city&amp;lt;/span&amp;gt;

&amp;lt;span class=&quot;c1&quot;&amp;gt;# Michael's preferred way&amp;lt;/span&amp;gt;
&amp;lt;span class=&quot;n&quot;&amp;gt;user&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;o&quot;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;n&quot;&amp;gt;db&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;get_user&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;p&quot;&amp;gt;()&amp;lt;/span&amp;gt;
&amp;lt;span class=&quot;n&quot;&amp;gt;city&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;o&quot;&amp;gt;=&amp;lt;/span&amp;gt; &amp;lt;span class=&quot;n&quot;&amp;gt;user&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;err&quot;&amp;gt;?&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;address&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;err&quot;&amp;gt;?&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;o&quot;&amp;gt;.&amp;lt;/span&amp;gt;&amp;lt;span class=&quot;n&quot;&amp;gt;city&amp;lt;/span&amp;gt;
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Calvin #2: &amp;lt;a href=&quot;https://blog.python.org/2026/10/python-3150-rc3/?featured_on=pythonbytes&quot;&amp;gt;Python 3.15&amp;lt;/a&amp;gt; gets a surprise RC3, and &amp;lt;a href=&quot;https://blog.python.org/2026/10/python-31022-31117/?featured_on=pythonbytes&quot;&amp;gt;Python 3.10&amp;lt;/a&amp;gt; reaches end of life&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;The release team added a surprise third release candidate for Python 3.15 to fix last-minute lazy-import release blockers. They wanted time to test the fixes properly.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;That pushes the 3.15.0 final release from October 2 to October 9, 2026.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;RC3 has about 156 fixes from 82 contributors. The headline features are explicit lazy imports (PEP 810), the new frozendict (PEP 814) and sentinel (PEP 661) built-ins, and UTF-8 as the default encoding (PEP 686).&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;No more ABI changes are coming, so library authors should be building 3.15 wheels now. uv 0.12.23 already added CPython 3.15.0rc3.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;On October 1, Python 3.10.22, 3.11.17, 3.12.15, 3.13.16 and 3.14.8 shipped together with nine common security fixes. They cover SSL validation, tarfile and zipfile handling, and urllib credentials.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Python 3.10.22 is the final 3.10 release. After five years it gets no more security updates, so anyone still on 3.10 should upgrade.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Python 3.13.16 is the last full maintenance release of 3.13, which now moves to security-only fixes. Only 3.13.16 and 3.14.8 have Windows and macOS installers, and the older releases are source-only.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Python 3.11 gets security fixes through October 2027, and 3.12 through October 2028.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;A natural way to tie the two together: one version is nearly out the door and one is officially gone, and the same week is the time to test your code on 3.15 and move off 3.10.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Michael #3: &amp;lt;a href=&quot;https://docs.python.org/3/library/asyncio-task.html#shielding-from-cancellation&quot;&amp;gt;asyncio.shield&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;h1&amp;gt;Where async code can be cancelled&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;In async Python, every await is a point where your coroutine can be stopped. If someone cancels the task, asyncio raises CancelledError at whichever await the coroutine is paused on, and nothing after that line runs.
Quart does this on purpose. When the client disconnects, it cancels the request's task. From quart/asgi.py:&amp;lt;/p&amp;gt;

&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;elif message[&quot;type&quot;] == &quot;http.disconnect&quot;:
    self._disconnected = True
    request.body.disconnect()
    request_task.cancel()
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;

&amp;lt;p&amp;gt;That's reasonable for a slow page nobody is waiting on anymore. It's a problem for a handler that writes to the database in two steps:&amp;lt;/p&amp;gt;

&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;await downloads.insert_one(event)            # 1. log the download
await totals.update_one(..., {'$inc': ...})  # 2. bump the episode's total
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;

&amp;lt;p&amp;gt;A podcast app requests the MP3, gets what it needs, and hangs up. If it hangs up while step 2 is in flight, step 1 has already landed and step 2 never runs. Nothing is logged and nothing reaches Sentry, because a cancelled request isn't an error. The two collections just drift apart.
Under WSGI this couldn't happen. A disconnect didn't stop your view; the view finished both writes and the server only failed later, when it tried to send the response.&amp;lt;/p&amp;gt;

&amp;lt;h1&amp;gt;The demo&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;I ran this on Python 3.14. The &quot;client&quot; hangs up 15 ms into a pair of 10 ms writes:&amp;lt;/p&amp;gt;

&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;async def record_download():
    await db_write('events')
    await db_write('total')
_pending: set[asyncio.Task] = set()
async def record_download_shielded():
    task = asyncio.create_task(record_download())
    _pending.add(task)
    task.add_done_callback(_pending.discard)
    await asyncio.shield(task)
record_download            events=1 total=0
record_download_shielded   events=1 total=1
&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;

&amp;lt;p&amp;gt;The unshielded version loses the increment. The shielded version finishes it, even though the request was cancelled. The full script is in the scratchpad as shield_demo.py if you want it for the show.&amp;lt;/p&amp;gt;

&amp;lt;h1&amp;gt;What asyncio.shield does, and its traps&amp;lt;/h1&amp;gt;

&amp;lt;p&amp;gt;shield(task) protects the inner task from a cancellation aimed at the outer one. The handler still gets CancelledError immediately, so nothing after that line runs, but the inner task keeps going until both writes finish. The traps:&amp;lt;/p&amp;gt;

&amp;lt;ol&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Keep a reference to the task.&amp;lt;/strong&amp;gt; The event loop only holds weak references to tasks, so a task with no other reference can be garbage-collected mid-run. The asyncio docs warn about this. That's what _pending is for.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;Its errors go nowhere by default.&amp;lt;/strong&amp;gt; If a shielded write fails after the handler has already been cancelled, nobody awaits the result. You only get a &quot;Task exception was never retrieved&quot; warning. Log errors from inside the task, or in the done callback.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;It doesn't survive a process shutdown.&amp;lt;/strong&amp;gt; If the event loop is closing, as during a Granian worker recycle or a deploy, pending tasks are still cancelled. The window is tiny, but it isn't zero.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;It hides hangs.&amp;lt;/strong&amp;gt; A shielded write to a stuck database lives forever. Put a timeout inside the shielded task (asyncio.timeout(...)), not outside it.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;strong&amp;gt;It makes the pair finish, not atomic.&amp;lt;/strong&amp;gt; A crash between the two writes still splits them. The real fix is one operation that can't half-happen. That's what the SQLite move gets: an insert and an upsert in one synchronous transaction, with no await in the middle. Shield is the right patch for the Mongo code until then.
The general lesson: in async code, related writes made one after another are only as reliable as the client's patience. Before shipping something like that, check whether your framework cancels on disconnect. Quart does, and I believe Django 5's async views do too. I don't think Starlette cancels a plain endpoint, but I haven't checked any of these other frameworks' source, so verify them before you say it on air.&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Calvin #4: &amp;lt;a href=&quot;https://github.com/kitao/pyxel?featured_on=pythonbytes&quot;&amp;gt;Pyxel: the retro game engine for Python&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Pyxel is a free, MIT-licensed retro game engine for Python, built and maintained by a single developer. It has been in development since 2018 and has passed 18,000 GitHub stars.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;It's modeled on classic game consoles and deliberately limits you to 16 colors and 4 sound channels, which keeps scope small and games finishable.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Built-in editors cover pixel art, tilemaps, sound and music, so you can make the graphics, audio and game logic in one place.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;The engine is implemented in Rust and compiled to WebAssembly, but you write your games in plain Python.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Pyxel Code Maker is a browser playground with a code editor, resource tools and a run button. It loads projects from local files, GitHub Gists or URLs, and saves back to a Gist for sharing.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Games can also run on the web, so sharing one can be as simple as sending a link.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;It's a fun, low-barrier way into game development, good for beginners and for teaching kids.&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Extras&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;Calvin:&amp;lt;/p&amp;gt;

&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;Python Lang Summit 2026 &amp;lt;a href=&quot;https://blog.python.org/2026/09/language-summit-2026-namespaces/?featured_on=pythonbytes&quot;&amp;gt;discusses&amp;lt;/a&amp;gt; a &amp;lt;code&amp;gt;sys&amp;lt;/code&amp;gt; namespace&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&quot;https://arstechnica.com/gadgets/2026/09/owners-mourn-spoiled-food-after-firmware-update-bricks-samsung-smart-fridges/?featured_on=pythonbytes&quot;&amp;gt;Be Careful Updating Your Refrigerator&amp;lt;/a&amp;gt;
Michael:&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;New Siri is No Bueno&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Who out there is doing interesting work with &amp;lt;a href=&quot;https://www.youtube.com/watch?v=QOBXFCYYMvk&quot;&amp;gt;sqlite and litestream&amp;lt;/a&amp;gt;? Trying to put an episode together on it.&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;Tinymongo shoutout https://tinymongo.org&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;

&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Joke: &amp;lt;a href=&quot;https://www.linkedin.com/posts/william-s-vincent_talking-today-with-a-colleague-about-how-share-7496135068114006016-EOou/?featured_on=pythonbytes&quot;&amp;gt;I was there&amp;lt;/a&amp;gt;.&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;</description>
	<pubDate>Tue, 06 Oct 2026 23:16:32 +0000</pubDate>
</item>
<item>
	<title>PyCoder’s Weekly: Issue #755: 3.15 Gets an RC3, New Feature Rundown, Sampling Profiler, and More (2026-10-06)</title>
	<guid>https://pycoders.com/issues/755</guid>
	<link>https://pycoders.com/issues/755</link>
	<description>&lt;p&gt; &lt;span&gt;#755 – OCTOBER 6, 2026&lt;/span&gt;&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/issues/755/feed&quot;&gt;View in Browser »&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;p&gt;&lt;a href=&quot;https://pycoders.com&quot;&gt;&lt;img alt=&quot;The PyCoder&amp;rsquo;s Weekly Logo&quot; src=&quot;https://cdn.pycoders.com/37bdf31dc645f968ffb90196e5d38ff5&quot; /&gt;&lt;/a&gt;&lt;/p&gt; &lt;hr /&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17183/feed&quot; target=&quot;_blank&quot;&gt;Python Adds a Release: 3.15.0rc3&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Due to issues found in the new lazy loading features, an emergency Release Candidate has been adding, delaying Python 3.15 by a week.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17183/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17181/feed&quot; target=&quot;_blank&quot;&gt;Python 3.15: Cool New Features for You to Try&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Learn what&amp;rsquo;s new in Python 3.15, from lazy imports, frozendict, and sentinels to a sampling profiler and friendlier error messages. Also available as a &lt;a href=&quot;https://pycoders.com/link/17202/feed&quot; target=&quot;_blank&quot;&gt;video course&lt;/a&gt;.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17181/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17179/feed&quot; target=&quot;_blank&quot;&gt;Quiz: Python 3.15: Cool New Features for You to Try&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17179/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17208/feed&quot; target=&quot;_blank&quot;&gt;Connect Python AI Agents to Real-Time ClickHouse&lt;/a&gt;&lt;/h3&gt; &lt;a href=&quot;https://pycoders.com/link/17208/feed&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://cdn.pycoders.com/54f401fd73bcc6539dbdd720a34b568d&quot; alt=&quot;alt&quot; /&gt;&lt;/a&gt; &lt;p&gt; Give your Python AI agents and memory systems low-latency access to analytical data. Tinybird turns high-volume event streams into sub-100ms REST APIs with native Python SDKs, CLI tooling, &amp;amp; MCP support. Skip building data pipelines and feed real-time context directly into your Python agent workflow &lt;a href=&quot;https://pycoders.com/link/17208/feed&quot; target=&quot;_blank&quot;&gt;Start Building Free with Python SDK&lt;/a&gt;&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17208/feed&quot; target=&quot;_blank&quot;&gt;TINYBIRD&lt;/a&gt;&lt;/span&gt; &lt;span&gt;sponsor&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17185/feed&quot; target=&quot;_blank&quot;&gt;Tachyon, Python 3.15&amp;rsquo;s Built-in Sampling Profiler&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Talk Python interviews László Kiss Kollár and Pablo Galindo Salgado, key contributors to the new sampling profiler code named &amp;ldquo;Tachyon&amp;rdquo; which has been added to Python 3.15.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17185/feed&quot; target=&quot;_blank&quot;&gt;TALK PYTHON&lt;/a&gt;&lt;/span&gt; &lt;span&gt;podcast&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17196/feed&quot; target=&quot;_blank&quot;&gt;Python 3.15 Preview: Sentinel Values&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Learn how to create a Python sentinel value with the new built-in in Python 3.15 and get readable signatures, type hints, and safe copying and pickling.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17196/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17180/feed&quot; target=&quot;_blank&quot;&gt;Quiz: Python 3.15 Preview: Sentinel Values&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Test your grasp of Python 3.15&amp;rsquo;s new sentinel built-in, from readable signatures and type hints to safe copying, pickling, and when to use one.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17180/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17203/feed&quot; target=&quot;_blank&quot;&gt;PEP 824: None-Coalescing Operators (Draft)&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17203/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17177/feed&quot; target=&quot;_blank&quot;&gt;PEP 823: None-Aware Access Operators (Draft)&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17177/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17176/feed&quot; target=&quot;_blank&quot;&gt;Python 3.10.22, 3.11.17, 3.12.15, 3.13.16 and 3.14.8 Released&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17176/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17192/feed&quot; target=&quot;_blank&quot;&gt;The Python Documentation Is Now Available in Persian&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17192/feed&quot; target=&quot;_blank&quot;&gt;PYTHON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;h2&gt;Articles &amp;amp; Tutorials&lt;/h2&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17205/feed&quot; target=&quot;_blank&quot;&gt;Protocol or ABC? Designing a Pluggable Provider Interface&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Designing a CLI tool that talks to two different image-generation backends. Same inputs from the user, two different SDKs underneath. How best to define the shared contract: an abstract base class, or a typing.Protocol? This article looks at both options.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17205/feed&quot; target=&quot;_blank&quot;&gt;BELDERBOS.DEV&lt;/a&gt; • Shared by &lt;a href=&quot;https://pycoders.com/link/17198/feed&quot; target=&quot;_blank&quot;&gt;Bob Belderbos&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17182/feed&quot; target=&quot;_blank&quot;&gt;PyScript Is in Maintenance Mode&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; PyScript entered maintenance mode last month — the API is frozen, and only Pyodide updates continue. This piece walks through the honest landscape of Python-in-the-browser tools now that the default answer has stopped moving.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17182/feed&quot; target=&quot;_blank&quot;&gt;DEV.TO&lt;/a&gt; • Shared by Aswanth R&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17209/feed&quot; target=&quot;_blank&quot;&gt;Stop Falling Behind on AI. Catch Up in Five Minutes&lt;/a&gt;&lt;/h3&gt; &lt;a href=&quot;https://pycoders.com/link/17209/feed&quot; target=&quot;_blank&quot;&gt;&lt;img src=&quot;https://cdn.pycoders.com/55d8e8e20e17c3f2bf901934322c05af&quot; alt=&quot;alt&quot; /&gt;&lt;/a&gt; &lt;p&gt; New models, new prices, new agent tools, all the time. Real Python&amp;rsquo;s new AI newsletter gives you the handful of stories you actually need as a developer. Tell us how often you want it (daily, weekly, or monthly) and save your spot. &lt;a href=&quot;https://pycoders.com/link/17209/feed&quot; target=&quot;_blank&quot;&gt;Get the Free Roundup →&lt;/a&gt;&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17209/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;span&gt;sponsor&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17191/feed&quot; target=&quot;_blank&quot;&gt;Working With AI Agents: Focused Live Courses for Python Developers&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Five focused live courses for Python developers who use AI agents: predict what they&amp;rsquo;ll do, check what they wrote, direct them on a real project, run them as a team, and trust them unattended.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17191/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17193/feed&quot; target=&quot;_blank&quot;&gt;Python Language Summit 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; The 2026 Python Language Summit was hosted in Kraków, Poland as part of EuroPython 2026. There were 15 talks covering free-threading, Rust, garbage collection, type annotations, and more.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17193/feed&quot; target=&quot;_blank&quot;&gt;SETH LARSON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17190/feed&quot; target=&quot;_blank&quot;&gt;Tracing &lt;code&gt;np.add&lt;/code&gt;, All the Way Down&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; NumPy&amp;rsquo;s &lt;code&gt;add&lt;/code&gt; method does what you&amp;rsquo;d expect: it adds two objects together. Under the covers there is a lot going on. This deep dive shows you just what is happening behind the scenes.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17190/feed&quot; target=&quot;_blank&quot;&gt;VEIT HELLER&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17174/feed&quot; target=&quot;_blank&quot;&gt;The Export Keyword (PEPs 842 and 843)&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; There have been multiple PEPs recently proposing different ways of managing what is and isn&amp;rsquo;t visible outside of a module. This post runs down the various proposals.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17174/feed&quot; target=&quot;_blank&quot;&gt;ANDRE ROBERGE&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17206/feed&quot; target=&quot;_blank&quot;&gt;Undocumented Django: Generating a SECRET_KEY&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Exploring the &amp;ldquo;hidden features&amp;rdquo; lurking in Django&amp;rsquo;s codebase that allow you to generate a secret key along with some advice on how to keep it secret.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17206/feed&quot; target=&quot;_blank&quot;&gt;LEARN DJANGO&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17188/feed&quot; target=&quot;_blank&quot;&gt;Pipenv: A Guide to the Python Packaging Tool&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Pipenv replaces pip, virtualenv, and requirements.txt with a single tool. See what it solves and how to manage dependencies with it.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17188/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17178/feed&quot; target=&quot;_blank&quot;&gt;Object-Oriented Programming (OOP) in Python&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; Learn object-oriented programming in Python: the OOP paradigm, classes and inheritance, and how to instantiate objects from a class.&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17178/feed&quot; target=&quot;_blank&quot;&gt;REAL PYTHON&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;h2&gt;Projects &amp;amp; Code&lt;/h2&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17195/feed&quot; target=&quot;_blank&quot;&gt;Ciaren: Visual ETL That Exports pandas and Polars&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17195/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/CIAREN-LABS&lt;/a&gt; • Shared by Ciaren Labs (submitted by an assistant)&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17175/feed&quot; target=&quot;_blank&quot;&gt;proxy-benchmark: Benchmarks for Proxies &amp;amp; Browsers&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17175/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/NODEMAVEN&lt;/a&gt; • Shared by Alexandr&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17186/feed&quot; target=&quot;_blank&quot;&gt;RightWayUp: Find Up in an Image From Python or CLI&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17186/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/ORTUSAITECH&lt;/a&gt; • Shared by &lt;a href=&quot;https://pycoders.com/link/17194/feed&quot; target=&quot;_blank&quot;&gt;Vladimir Ilyash&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17173/feed&quot; target=&quot;_blank&quot;&gt;Flowfile: Turn Polars Style Code Into an ETL Pipeline&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17173/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/EDWARDVANEECHOUD&lt;/a&gt; • Shared by Edward van Eechoud&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17197/feed&quot; target=&quot;_blank&quot;&gt;FlexViz: Interactive Exploration of 1 Billion Data Points&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17197/feed&quot; target=&quot;_blank&quot;&gt;GITHUB.COM/FLEX-ANALYTICS&lt;/a&gt; • Shared by Jeroen Van Der Donckt&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;h2&gt;Events&lt;/h2&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17204/feed&quot; target=&quot;_blank&quot;&gt;PyCon Africa 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 7 to October 12, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17204/feed&quot; target=&quot;_blank&quot;&gt;PYCON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17200/feed&quot; target=&quot;_blank&quot;&gt;Weekly Real Python Office Hours Q&amp;amp;A (Virtual)&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 7, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17200/feed&quot; target=&quot;_blank&quot;&gt;REALPYTHON.COM&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17207/feed&quot; target=&quot;_blank&quot;&gt;PyEducation: IPAF&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 8 to October 9, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17207/feed&quot; target=&quot;_blank&quot;&gt;PYCON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17201/feed&quot; target=&quot;_blank&quot;&gt;Python Atlanta&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 8 to October 9, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17201/feed&quot; target=&quot;_blank&quot;&gt;MEETUP.COM&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17189/feed&quot; target=&quot;_blank&quot;&gt;DFW Pythoneers 2nd Saturday Teaching Meeting&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 10, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17189/feed&quot; target=&quot;_blank&quot;&gt;MEETUP.COM&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17187/feed&quot; target=&quot;_blank&quot;&gt;PyCon Greece 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 12 to October 14, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17187/feed&quot; target=&quot;_blank&quot;&gt;PYCON.GR&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17199/feed&quot; target=&quot;_blank&quot;&gt;PyCon NL 2026&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 15 to October 16, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17199/feed&quot; target=&quot;_blank&quot;&gt;PYCON-NL.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;div&gt; &lt;h3&gt;&lt;a href=&quot;https://pycoders.com/link/17184/feed&quot; target=&quot;_blank&quot;&gt;PyCon Taiwan&lt;/a&gt;&lt;/h3&gt; &lt;p&gt; October 17 to October 19, 2026&lt;br /&gt; &lt;span&gt;&lt;a href=&quot;https://pycoders.com/link/17184/feed&quot; target=&quot;_blank&quot;&gt;PYCON.ORG&lt;/a&gt;&lt;/span&gt; &lt;/p&gt; &lt;/div&gt; &lt;hr /&gt; &lt;p&gt;Happy Pythoning!&lt;br /&gt;This was PyCoder&amp;rsquo;s Weekly Issue #755.&lt;br /&gt;&lt;a href=&quot;https://pycoders.com/issues/755/feed&quot;&gt;View in Browser »&lt;/a&gt;&lt;/p&gt; &lt;img src=&quot;https://pycoders.com/issues/755/open/feed&quot; width=&quot;1&quot; height=&quot;1&quot; alt=&quot;alt&quot; /&gt; 
        &lt;hr /&gt;
        &lt;p&gt;&lt;em&gt;[ Subscribe to 🐍 PyCoder&amp;rsquo;s Weekly 💌 – Get the best Python news, articles, and tutorials delivered to your inbox once a week &lt;a href=&quot;https://pycoders.com/?utm_source=pycoders&amp;utm_medium=feed&amp;utm_campaign=footer&quot;&gt;&amp;gt;&amp;gt; Click here to learn more&lt;/a&gt; ]&lt;/em&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 06 Oct 2026 19:30:00 +0000</pubDate>
</item>
<item>
	<title>Tryton News: Tryton Release 8.2</title>
	<guid>https://discuss.tryton.org/t/tryton-release-8-2/9421</guid>
	<link>https://discuss.tryton.org/t/tryton-release-8-2/9421</link>
	<description>&lt;div&gt; &lt;/div&gt;
&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;lightbox-wrapper&quot;&gt;&lt;a class=&quot;lightbox&quot; href=&quot;https://discuss-cdn.tryton.org/uploads/default/original/2X/5/540fb2923602ec7b3bd69ee701714d0c6bc2d424.jpeg&quot; title=&quot;Credit: Pexels by fauxels&quot;&gt;&lt;img src=&quot;https://discuss-cdn.tryton.org/uploads/default/optimized/2X/5/540fb2923602ec7b3bd69ee701714d0c6bc2d424_2_690x459.jpeg&quot; alt=&quot;Coworkers analyzing data charts on laptops during a team meeting&quot; title=&quot;Credit: Pexels by fauxels&quot; width=&quot;690&quot; height=&quot;459&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;We are proud to announce the 8.2 release of &lt;a href=&quot;https://www.tryton.org/&quot;&gt;Tryton&lt;/a&gt;.&lt;br /&gt;
This release provides many bug fixes, performance improvements and some fine tuning.&lt;br /&gt;
You can give it a &lt;a href=&quot;https://www.tryton.org/demo&quot;&gt;try on the demo server&lt;/a&gt;, &lt;a href=&quot;https://hub.docker.com/r/tryton/tryton/&quot;&gt;use the docker image&lt;/a&gt; or &lt;a href=&quot;https://www.tryton.org/download&quot;&gt;download it here&lt;/a&gt;.&lt;br /&gt;
As usual &lt;a href=&quot;https://docs.tryton.org/8.2/server/topics/setup_database.html#update-a-database&quot;&gt;upgrading from previous series&lt;/a&gt; is fully supported.&lt;/p&gt;
&lt;p&gt;Here is a list of the most noticeable changes:&lt;/p&gt;
&lt;h2 id=&quot;heading--user&quot;&gt;Changes for the User&lt;/h2&gt;
&lt;h3 id=&quot;heading--user-client&quot;&gt;Client&lt;/h3&gt;
&lt;p&gt;When deleting or removing multiple rows from a list widget, a popup is displayed to confirm the selection that will be deleted or removed.&lt;br /&gt;
And when clicking on delete or remove from a list widget with no row selected, a search popup is raised to search and select the rows to delete or remove.&lt;/p&gt;
&lt;p&gt;When selecting multiple rows for editing from a &lt;code&gt;One2Many&lt;/code&gt; widget, the edition popup loops over each record. This is a faster and more reliable way to perform a mass edition.&lt;/p&gt;
&lt;p&gt;The login services can now display an icon to represent the service provider. This makes it easier for users to select the right services.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Binary&lt;/code&gt; widget supports filtering the file selection per file extension and mime type.&lt;br /&gt;
And when the field has no file name defined, the widget will use the record name as a fallback file name when the content is downloaded.&lt;/p&gt;
&lt;p&gt;It is now possible to mark as read a set of notifications.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-accounting&quot;&gt;Accounting&lt;/h3&gt;
&lt;p&gt;The “Open Journal” menu entry has been replaced by the “Lines” menu entry which uses a journal and period header as default values.&lt;br /&gt;
This new menu entry also provides a new way to search for accounting lines.&lt;/p&gt;
&lt;p&gt;We now use the maturity date before the effective date to calculate the reconciliation date.&lt;/p&gt;
&lt;p&gt;The wizard to create dunning allows limiting the creation to a selection of companies.&lt;/p&gt;
&lt;p&gt;The wizard to create direct debits allows limiting the creation to a selection of companies.&lt;/p&gt;
&lt;p&gt;When posting an invoice, the system will check the validity of the European tax identifiers used.&lt;/p&gt;
&lt;p&gt;A relate is now available from the period and the fiscal year to open the related invoices.&lt;br /&gt;
This is useful when you need to collect all the invoices done in a period, for example to send to an external accountant.&lt;/p&gt;
&lt;p&gt;The SEPA payment module now includes the flavors &lt;code&gt;pain.001.001.09&lt;/code&gt; and &lt;code&gt;pain.008.001.08&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A generic CSV format has been added to import statements. You can configure the format to map columns to the Tryton fields.&lt;br /&gt;
It is common that banks provide only a custom CSV format for the statements.&lt;/p&gt;
&lt;p&gt;It is now possible to create tax rules based on organizations.&lt;br /&gt;
This is useful for example to create a single rule that applies to all European countries.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-edocument&quot;&gt;E-document&lt;/h3&gt;
&lt;h4 id=&quot;heading--user-edocument-peppol&quot;&gt;PEPPOL&lt;/h4&gt;
&lt;p&gt;We added a configurable processing delay on each PEPPOL service.&lt;br /&gt;
This prevents sending the newly posted invoice directly and allows some time for the user to correct any mistakes.&lt;/p&gt;
&lt;h4 id=&quot;heading--user-edocument-uncefact&quot;&gt;UN/CEFACT&lt;/h4&gt;
&lt;p&gt;Tryton can now parse the UN/CEFACT invoice to create a supplier invoice.&lt;br /&gt;
This will be useful to implement &lt;a href=&quot;https://discuss.tryton.org/t/sponsoring-super-pdp-integration/9229&quot;&gt;French e-invoicing&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-party&quot;&gt;Party&lt;/h3&gt;
&lt;p&gt;The wizard to check VAT numbers with the VIES service has been replaced by an automatic background task.&lt;br /&gt;
Once a number has been validated, it is considered valid for a configurable period before being re-validated.&lt;/p&gt;
&lt;p&gt;When entering a contact mechanism, the system will try to guess the type.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-product&quot;&gt;Product&lt;/h3&gt;
&lt;p&gt;The products can now be added or removed directly from the category form.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-production&quot;&gt;Production&lt;/h3&gt;
&lt;p&gt;A tolerance can now be configured on each &lt;a href=&quot;https://en.wikipedia.org/wiki/Bill_of_materials&quot;&gt;BoM&lt;/a&gt;. It raises warnings when the input or output quantities deviate from the calculated quantities from the BoM. It also detects additional or missing products.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-purchase&quot;&gt;Purchase&lt;/h3&gt;
&lt;p&gt;Tryton now calculates the actual average lead time of each product supplier over the last year.&lt;br /&gt;
This is useful to update the configured lead time or to find poor suppliers.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-sales&quot;&gt;Sales&lt;/h3&gt;
&lt;p&gt;It is now possible to configure sales to create customer shipments only in draft (instead of waiting).&lt;br /&gt;
This is useful when the workflow requires a manual validation of the shipment before being processed.&lt;/p&gt;
&lt;p&gt;The wizard to create invoices and consumptions of subscriptions allows limiting the creation to a selection of companies.&lt;/p&gt;
&lt;p&gt;A stock lot can now be set on the sale line from a POS.&lt;br /&gt;
This is useful for businesses that require tracking the lot sold to customers.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-stock&quot;&gt;Stock&lt;/h3&gt;
&lt;p&gt;Tryton now warns when an inventory modifies the quantities or costs too much.&lt;br /&gt;
The variations are now displayed with a visual hint when they are close to the tolerance.&lt;/p&gt;
&lt;p&gt;A scheduled task has been added to create stock periods automatically using a configured interval. And another task closes them after a configured delay.&lt;br /&gt;
This removes the need to manually close stock periods, which is important for performance.&lt;/p&gt;
&lt;h3 id=&quot;heading--user-web-shop&quot;&gt;Web Shop&lt;/h3&gt;
&lt;p&gt;A scheduled task has been added to cancel abandoned sales after a configured delay per web shop.&lt;br /&gt;
This prevents the list of draft sales from increasing too much.&lt;/p&gt;
&lt;h2 id=&quot;heading--new-modules&quot;&gt;New Modules&lt;/h2&gt;
&lt;h3 id=&quot;heading--module-account-invoice-factur-x&quot;&gt;Account Invoice Factur-X&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.tryton.org/8.2/modules-account-invoice-factur-x&quot;&gt;&lt;em&gt;Account Invoice Factur-X Module&lt;/em&gt;&lt;/a&gt; allows to generate invoices in &lt;a href=&quot;https://fnfe-mpe.org/factur-x/factur-x_en/&quot;&gt;Factur-X&lt;/a&gt; format.&lt;/p&gt;
&lt;h3 id=&quot;heading--module-document-incoming-ocr-eagle-doc&quot;&gt;Document Incoming OCR Eagle Doc&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.tryton.org/8.2/modules-document-incoming-ocr-eagle-doc&quot;&gt;&lt;em&gt;Document Incoming OCR Eagle Doc Module&lt;/em&gt;&lt;/a&gt; provides integration with &lt;a href=&quot;https://www.eagle-doc.com/&quot;&gt;Eagle Doc&lt;/a&gt; services.&lt;/p&gt;
&lt;h3 id=&quot;heading--module-project-disbursement&quot;&gt;Project Disbursement&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.tryton.org/8.2/modules-project-disbursement&quot;&gt;&lt;em&gt;Project Disbursement Module&lt;/em&gt;&lt;/a&gt; provides support for paying and invoicing disbursements per project.&lt;/p&gt;
&lt;h3 id=&quot;heading--module-stock-conversion&quot;&gt;Stock Conversion&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.tryton.org/8.2/modules-stock-conversion&quot;&gt;&lt;em&gt;Stock Conversion Module&lt;/em&gt;&lt;/a&gt; transforms one product into another with ease.&lt;/p&gt;
&lt;h2 id=&quot;heading--sysadmin&quot;&gt;Changes for the System Administrator&lt;/h2&gt;
&lt;h3 id=&quot;heading--sysadmin-server&quot;&gt;Server&lt;/h3&gt;
&lt;p&gt;The “Administration” group has been replaced by an “Administrator” flag on the user.&lt;br /&gt;
This ensures that an administrator always has access to everything even if a resource access is restricted to a group (which was not the “Administration” group).&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;trytond-admin&lt;/code&gt; command can now manage any user. This means that it can create a new user, activate or deactivate, promote as administrator or demote from administrator, set the email or password and send a reset password email.&lt;/p&gt;
&lt;p&gt;The unfinished queued tasks are now retried automatically by a scheduled task.&lt;/p&gt;
&lt;p&gt;A timer is now attached to every RPC request with a &lt;code&gt;timeout&lt;/code&gt; defined. It ensures that the request does not last longer by raising a &lt;code&gt;TimeOutException&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://discuss-cdn.tryton.org/images/emoji/twitter/warning.png?v=15&quot; title=&quot;:warning:&quot; class=&quot;emoji&quot; alt=&quot;:warning:&quot; width=&quot;20&quot; height=&quot;20&quot; /&gt; The webhooks must be updated to include the &lt;code&gt;/r/&lt;/code&gt; prefix inherited from the new &lt;code&gt;Router&lt;/code&gt;.&lt;br /&gt;
We have kept the former routes for backward compatibility.&lt;/p&gt;
&lt;h3 id=&quot;heading--sysadmin-accounting&quot;&gt;Accounting&lt;/h3&gt;
&lt;p&gt;The Stripe API has been updated to the version &lt;code&gt;2026-09-30.endive&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;heading--sysadmin-stock&quot;&gt;Stock&lt;/h3&gt;
&lt;p&gt;The DPD Shipment Service API has been updated to version &lt;code&gt;4.5&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;heading--developer&quot;&gt;Changes for the Developer&lt;/h2&gt;
&lt;h3 id=&quot;heading--developer-server&quot;&gt;Server&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;readonly&lt;/code&gt; attribute and &lt;code&gt;states&lt;/code&gt; are now enforced on the server-side when checking the access rights of the user.&lt;/p&gt;
&lt;p&gt;The fields have a new &lt;code&gt;editable&lt;/code&gt; &lt;code&gt;states&lt;/code&gt; which completes the existing &lt;code&gt;readonly&lt;/code&gt; but it is not enforced, only used for UI purposes.&lt;/p&gt;
&lt;p&gt;We added &lt;code&gt;BulkBuffer&lt;/code&gt; for creation, deletion, save or any function on &lt;code&gt;ModelStorage&lt;/code&gt;.&lt;br /&gt;
The &lt;code&gt;BulkBuffer&lt;/code&gt;s are &lt;a href=&quot;http://docs.python.org/reference/datamodel.html#context-managers&quot;&gt;context managers&lt;/a&gt; that are flushed when reaching a defined size by calling a function with the current content.&lt;br /&gt;
This is useful when looping on a large set of records to limit the memory consumption.&lt;br /&gt;
Ex:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;lang-python&quot;&gt;# records are saved every 2000 records
with Model.bulk_save() as save:
    for record in records:
         record.amount += 10
         save.push(record)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A new &lt;code&gt;router&lt;/code&gt; type of object is now supported in the &lt;code&gt;Pool&lt;/code&gt;.&lt;br /&gt;
A &lt;code&gt;Router&lt;/code&gt; exposes entrypoints but as it is registered in the &lt;code&gt;Pool&lt;/code&gt; it can be extended by other modules.&lt;br /&gt;
The entrypoint of a &lt;code&gt;Router&lt;/code&gt; is only registered for the database for which the origin module is activated.&lt;/p&gt;
&lt;p&gt;A route has been added for the &lt;code&gt;custom.js&lt;/code&gt; and &lt;code&gt;custom.css&lt;/code&gt; files of sao. It chains a list of files that can be extended by any module.&lt;/p&gt;
&lt;p&gt;The ORM is now using a &lt;code&gt;BrowseList&lt;/code&gt; instead of a simple list of instances. The &lt;code&gt;BrowseList&lt;/code&gt; allows keeping the cache and prefetching aligned with its content when it is mutated, for example by &lt;code&gt;.sort()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is now possible to define the filename extension of &lt;code&gt;Binary&lt;/code&gt; fields.&lt;br /&gt;
And it is also possible to set filters on the &lt;code&gt;binary&lt;/code&gt; and &lt;code&gt;image&lt;/code&gt; widgets.&lt;/p&gt;
&lt;p&gt;The database connection &lt;code&gt;cursor&lt;/code&gt; now supports row factories like &lt;code&gt;dict_row&lt;/code&gt;, &lt;code&gt;namedtuple_row&lt;/code&gt; and &lt;code&gt;scalar_row&lt;/code&gt;. They change the default &lt;code&gt;tuple&lt;/code&gt; type of fetched records.&lt;br /&gt;
Thanks to the row factory, the &lt;code&gt;cursor_dict&lt;/code&gt; has been removed.&lt;/p&gt;
&lt;p&gt;It is now possible to configure &lt;a href=&quot;https://en.wikipedia.org/wiki/Mixin&quot;&gt;Mixins&lt;/a&gt; to apply to the &lt;code&gt;Database&lt;/code&gt; and &lt;code&gt;TableHandler&lt;/code&gt; of the backend.&lt;br /&gt;
This feature is now used for the &lt;a href=&quot;https://en.wikipedia.org/wiki/Geographic_information_system&quot;&gt;GIS&lt;/a&gt; backend.&lt;/p&gt;
&lt;p&gt;We added support for &lt;code&gt;AGE&lt;/code&gt; to the SQLite backend.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;DBTestCase&lt;/code&gt; is now public and can be reused by modules. It is useful to create test cases based on a module but without the generic tests from &lt;code&gt;ModuleTestCase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/XML&quot;&gt;XML&lt;/a&gt; record tag now supports a &lt;code&gt;search&lt;/code&gt; attribute. The value is a domain used to search for existing records and reuse them when the &lt;code&gt;id&lt;/code&gt; is not yet known.&lt;br /&gt;
This is useful for example to create a country record which may have been already created.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;convert&lt;/code&gt; module gains an &lt;code&gt;import_xml&lt;/code&gt; function which can be used to import &lt;a href=&quot;https://en.wikipedia.org/wiki/XML&quot;&gt;XML&lt;/a&gt; files into the database (like the file declared in the module).&lt;br /&gt;
It can be useful for tests that need to have such records created.&lt;/p&gt;
&lt;p&gt;The email validation tools now have a check deliverability option.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;URLAccessor&lt;/code&gt; can now accept a &lt;code&gt;request&lt;/code&gt; parameter to use instead of the &lt;code&gt;Transaction.context&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ResourceAccessMixin&lt;/code&gt; gains two new fields &lt;code&gt;last_user&lt;/code&gt; and &lt;code&gt;last_modification&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;heading--developer-proteus&quot;&gt;Proteus &lt;small&gt;the scripting client&lt;/small&gt;&lt;/h3&gt;
&lt;p&gt;When configured with &lt;code&gt;trytond&lt;/code&gt; (on the server host), it allows controlling access checks with the &lt;code&gt;_check_access&lt;/code&gt; contextual keyword.&lt;/p&gt;
&lt;h3 id=&quot;heading--developer-company&quot;&gt;Company&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;companies&lt;/code&gt; and &lt;code&gt;employees&lt;/code&gt; are now in the user context.&lt;br /&gt;
This is useful to write domains that restrict a selection to only allowed companies or employees.&lt;/p&gt;
            &lt;p&gt;&lt;small&gt;1 post - 1 participant&lt;/small&gt;&lt;/p&gt;
            &lt;p&gt;&lt;a href=&quot;https://discuss.tryton.org/t/tryton-release-8-2/9421&quot;&gt;Read full topic&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Tue, 06 Oct 2026 16:00:22 +0000</pubDate>
</item>
<item>
	<title>Django Weblog: Django security releases issued: 6.1.2, 6.0.9, and 5.2.18</title>
	<guid>https://www.djangoproject.com/weblog/2026/oct/06/security-releases/</guid>
	<link>https://www.djangoproject.com/weblog/2026/oct/06/security-releases/</link>
	<description>&lt;p&gt;In accordance with &lt;a href=&quot;https://docs.djangoproject.com/en/dev/internals/security/&quot;&gt;our security release policy&lt;/a&gt;,
the Django team is issuing releases for
&lt;a href=&quot;https://docs.djangoproject.com/en/dev/releases/6.1.2/&quot;&gt;Django 6.1.2&lt;/a&gt;, &lt;a href=&quot;https://docs.djangoproject.com/en/dev/releases/6.0.9/&quot;&gt;Django
6.0.9&lt;/a&gt;, and &lt;a href=&quot;https://docs.djangoproject.com/en/dev/releases/5.2.18/&quot;&gt;Django
5.2.18&lt;/a&gt;.
These releases address the security issues detailed below. We encourage all
users of Django to upgrade as soon as possible.&lt;/p&gt;
&lt;h2 id=&quot;s-cve-2026-77050-potential-denial-of-service-vulnerability-in-get_supported_language_variant&quot;&gt;CVE-2026-77050: Potential denial-of-service vulnerability in &lt;code&gt;get_supported_language_variant()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;django.utils.translation.get_supported_language_variant()&lt;/code&gt; was subject to
a potential denial-of-service attack when processing many distinct, very long
language codes. Language codes were used as keys in an in-memory cache before
their length was limited, potentially consuming excessive process memory.&lt;/p&gt;
&lt;p&gt;To mitigate this vulnerability, language codes longer than 500 characters are
now rejected or truncated before the cached lookup.&lt;/p&gt;
&lt;p&gt;This issue has severity &quot;low&quot; according to the &lt;a href=&quot;https://docs.djangoproject.com/en/dev/internals/security/#security-issue-severity-levels&quot;&gt;Django security policy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to Gleb Lizunov for the report.&lt;/p&gt;
&lt;h2 id=&quot;s-cve-2026-84429-potential-denial-of-service-vulnerability-in-http-header-parsing&quot;&gt;CVE-2026-84429: Potential denial-of-service vulnerability in HTTP header parsing&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;django.utils.http.parse_header_parameters()&lt;/code&gt; was subject to a potential denial-of-service attack due to quadratic time complexity when parsing a value with many separators inside a quoted parameter. An unauthenticated request could reach this parsing through headers such as &lt;code&gt;Accept&lt;/code&gt; or &lt;code&gt;Content-Type&lt;/code&gt;, for instance via the content negotiation performed by &lt;code&gt;HttpRequest.accepts()&lt;/code&gt;. The per-call length limit does not bound the combined size of repeated headers.&lt;/p&gt;
&lt;p&gt;The undocumented &lt;code&gt;django.utils.http.parse_header_parameters()&lt;/code&gt; function now uses Python's &lt;code&gt;email.message.Message&lt;/code&gt; for parsing. As a result, parsing of some malformed or unusual header values may differ, for example, RFC 2231 values with a missing encoding are now decoded.&lt;/p&gt;
&lt;p&gt;This issue has severity &quot;moderate&quot; according to the &lt;a href=&quot;https://docs.djangoproject.com/en/stable/internals/security/#severity-levels&quot;&gt;Django security policy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to Jisung Chae for the report.&lt;/p&gt;
&lt;h2 id=&quot;s-cve-2026-87890-potential-request-forgery-via-spatial-lookup-byte-values&quot;&gt;CVE-2026-87890: Potential request forgery via spatial lookup byte values&lt;/h2&gt;
&lt;p&gt;Spatial lookups accepted raster values provided as &lt;code&gt;bytes&lt;/code&gt; without requiring
them to be explicitly wrapped in &lt;code&gt;django.contrib.gis.gdal.GDALRaster&lt;/code&gt;.
Although these values were opened through GDAL's in-memory virtual filesystem,
they could contain a VRT document referencing an external raster source. This
could cause GDAL to issue network requests as the Django process user while
preparing the lookup.&lt;/p&gt;
&lt;p&gt;This issue could be exploited by applications that passed attacker-controlled
bytes directly to a spatial lookup. It was overlooked in the fix for
CVE-2026-15307.&lt;/p&gt;
&lt;p&gt;To mitigate this issue, raster values provided as &lt;code&gt;bytes&lt;/code&gt; must now be wrapped
in &lt;code&gt;GDALRaster&lt;/code&gt; before being used in spatial lookups. Byte values representing
valid hexadecimal geometries remain accepted.&lt;/p&gt;
&lt;p&gt;This is a backward incompatible change. As a reminder, all untrusted user input
should be validated before use.&lt;/p&gt;
&lt;p&gt;This issue has severity &quot;moderate&quot; according to the &lt;a href=&quot;https://docs.djangoproject.com/en/dev/internals/security/#security-issue-severity-levels&quot;&gt;Django security policy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to sicksec for the report.&lt;/p&gt;
&lt;h2 id=&quot;s-cve-2026-87975-privilege-abuse-in-model-formsets-with-editable-primary-keys&quot;&gt;CVE-2026-87975: Privilege abuse in model formsets with editable primary keys&lt;/h2&gt;
&lt;p&gt;Model formsets incorrectly allowed forged &lt;code&gt;POST&lt;/code&gt; data to either delete
instances outside the limiting queryset or create instances via &lt;code&gt;edit-only&lt;/code&gt;
formsets when the model's primary key could be set through the form, 
such as with: a &lt;code&gt;OneToOneField&lt;/code&gt; (or parent link used as the primary key
of an inline formset's model), or a natural or UUID primary key included
in the form's fields. Models using the default &lt;code&gt;BigAutoField&lt;/code&gt; primary key
were not affected.&lt;/p&gt;
&lt;p&gt;This issue has severity &quot;moderate&quot; according to the &lt;a href=&quot;https://docs.djangoproject.com/en/stable/internals/security/#severity-levels&quot;&gt;Django security policy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to Seonggwon Yoon for the report.&lt;/p&gt;
&lt;h2 id=&quot;s-affected-supported-versions&quot;&gt;Affected supported versions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Django main&lt;/li&gt;
&lt;li&gt;Django 6.1&lt;/li&gt;
&lt;li&gt;Django 6.0&lt;/li&gt;
&lt;li&gt;Django 5.2&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;s-resolution&quot;&gt;Resolution&lt;/h2&gt;
&lt;p&gt;Patches to resolve the issue have been applied to Django's
main, 6.1, 6.0, and 5.2 branches.
The patches may be obtained from the following changesets.&lt;/p&gt;
&lt;h3 id=&quot;s-cve-2026-77050-potential-denial-of-service-vulnerability-in-get_supported_language_variant_1&quot;&gt;CVE-2026-77050: Potential denial-of-service vulnerability in &lt;code&gt;get_supported_language_variant()&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/c88b304cc2d90fc37d3bd1f5f3829706fa6c13bc&quot;&gt;main branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/7e878b0f8bd42260903e6a0d38996a93b0474a0b&quot;&gt;6.1 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/3d32ee80ae52745d686bf94d3555000ddf073267&quot;&gt;6.0 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/02a69e3791e3df23d45ea4ea7e7fc489f0eef2be&quot;&gt;5.2 branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;s-cve-2026-84429-potential-denial-of-service-vulnerability-in-http-header-parsing_1&quot;&gt;CVE-2026-84429: Potential denial-of-service vulnerability in HTTP header parsing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/7ff7fcc0508864a4bc39693128ace38b1e95a890&quot;&gt;main branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/de56deeabd4c48dfb5193f0001469d80102fb367&quot;&gt;6.1 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/3d8f121695c21234aff3071de0d38b6bd38c3f52&quot;&gt;6.0 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/6ecd66e09a383be004a78a3a738ea9727ff07b0e&quot;&gt;5.2 branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;s-cve-2026-87890-potential-request-forgery-via-spatial-lookup-byte-values_1&quot;&gt;CVE-2026-87890: Potential request forgery via spatial lookup byte values&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/ebcb13b327301f28cbc6cd5e4988a719f00575aa&quot;&gt;main branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/4e77ef1e69c94780006b82795aa7db101996c3af&quot;&gt;6.1 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/a2347fe8234a1831d56c875acc0ea51e0742957c&quot;&gt;6.0 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/dd0558d1617619e0d66163675ef02135d0f54e5f&quot;&gt;5.2 branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;s-cve-2026-87975-privilege-abuse-in-model-formsets-with-editable-primary-keys_1&quot;&gt;CVE-2026-87975: Privilege abuse in model formsets with editable primary keys&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/83cbd21be57483e6b3eb6e4688a561c841aff75e&quot;&gt;main branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/cce6c57ed30ea83725f9d6abb2fe5ee932bab107&quot;&gt;6.1 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/b83ab92bc5474558b083a840ea4628b3261b2cfe&quot;&gt;6.0 branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the &lt;a href=&quot;https://github.com/django/django/commit/ff27883ca055aa9ab23015b50674a5b10dfe5a41&quot;&gt;5.2 branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;s-the-following-releases-have-been-issued&quot;&gt;The following releases have been issued&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Django 6.1.2 (&lt;a href=&quot;https://www.djangoproject.com/download/6.1.2/tarball/&quot;&gt;tarball&lt;/a&gt; | &lt;a href=&quot;https://www.djangoproject.com/download/6.1.2/checksum/&quot;&gt;checksums&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Django 6.0.9 (&lt;a href=&quot;https://www.djangoproject.com/download/6.0.9/tarball/&quot;&gt;tarball&lt;/a&gt; | &lt;a href=&quot;https://www.djangoproject.com/download/6.0.9/checksum/&quot;&gt;checksums&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Django 5.2.18 (&lt;a href=&quot;https://www.djangoproject.com/download/5.2.18/tarball/&quot;&gt;tarball&lt;/a&gt; | &lt;a href=&quot;https://www.djangoproject.com/download/5.2.18/checksum/&quot;&gt;checksums&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The PGP key ID used for this release is Sarah Boyce: &lt;a href=&quot;https://github.com/sarahboyce.gpg&quot;&gt;3955B19851EA96EF&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;s-general-notes-regarding-security-reporting&quot;&gt;General notes regarding security reporting&lt;/h2&gt;
&lt;p&gt;As always, we ask that potential security issues be reported via private email
to &lt;code&gt;security@djangoproject.com&lt;/code&gt;, and not via Django's Trac instance, nor via
the Django Forum. Please see
&lt;a href=&quot;https://www.djangoproject.com/security/&quot;&gt;our security policies&lt;/a&gt; for further
information.&lt;/p&gt;</description>
	<pubDate>Tue, 06 Oct 2026 13:00:00 +0000</pubDate>
</item>
<item>
	<title>LernerPython blog, from Reuven Lerner: Pandas groupby with sort=False: Keep groups in order of appearance</title>
	<guid>https://lernerpython.com/2026/10/06/pandas-groupby-with-sort-false-keep-groups-in-order-of-appearance/</guid>
	<link>https://lernerpython.com/2026/10/06/pandas-groupby-with-sort-false-keep-groups-in-order-of-appearance/</link>
	<description>&lt;img src=&quot;https://lernerpython.com/wp-content/uploads/2026/10/2026-10-06.png&quot; alt=&quot;Pandas groupby with sort=False: Keep groups in order of appearance&quot; class=&quot;wp-image-17972&quot; width=&quot;2535&quot; height=&quot;1194&quot; /&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;A &amp;#8220;groupby&amp;#8221; call in Python Pandas is normally sorted by index.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;But if you&amp;#8217;re grouping by month name, April will come before January.&lt;/p&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Pass &amp;#8220;sort=False&amp;#8221;, and the index will reflect the order of appearance:&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;df.groupby('passenger_count', sort=False)['trip_distance'].mean()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The post &lt;a href=&quot;https://lernerpython.com/2026/10/06/pandas-groupby-with-sort-false-keep-groups-in-order-of-appearance/&quot;&gt;Pandas groupby with sort=False: Keep groups in order of appearance&lt;/a&gt; appeared first on &lt;a href=&quot;https://lernerpython.com&quot;&gt;LernerPython&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Tue, 06 Oct 2026 06:00:00 +0000</pubDate>
</item>
<item>
	<title>Armin Ronacher: What is Codemode</title>
	<guid>https://lucumr.pocoo.org/2026/10/6/codemode/</guid>
	<link>https://lucumr.pocoo.org/2026/10/6/codemode/</link>
	<description>&lt;p&gt;More than a year ago I wrote a few posts here that recommended people not to
load custom tools into their context (or
&lt;a href=&quot;https://en.wikipedia.org/wiki/Model_Context_Protocol&quot;&gt;MCP&lt;/a&gt; servers) but to just
use more scripts.  Most importantly I wrote that &lt;a href=&quot;https://lucumr.pocoo.org/2025/7/3/tools/&quot;&gt;Code Is All You
Need&lt;/a&gt; and I wrote about that &lt;a href=&quot;https://lucumr.pocoo.org/2025/8/18/code-mcps/&quot;&gt;MCP needs
code&lt;/a&gt;.  With Pi 1.0 we now added MCP support via Codemode
which in some ways is a long time coming, but then also maybe somewhat
surprising to some.  So I want to share some updated thoughts on this blog on
what this all means.&lt;/p&gt;
&lt;h2&gt;What Are Tools&lt;/h2&gt;
&lt;p&gt;When a harness like Pi provides tools for an LLM to call, it does so by
supplying some tool definitions which then translate into some token structure
on the server side.  Whether a model is encouraged to call a tool is the result
of the reinforcement learning process.  Something &lt;a href=&quot;https://lucumr.pocoo.org/2026/7/4/better-models-worse-tools/&quot;&gt;I wrote about
before&lt;/a&gt; if you want to learn more.&lt;/p&gt;
&lt;p&gt;One of the reasons we strongly lean towards CLI and bash is because it allows
easy composition of calls, and because the model also learns how the file system
works when it&amp;#8217;s trained.  So when it invokes a tool like &lt;code&gt;echo foo &amp;gt; /tmp/test.txt&lt;/code&gt; the model also learns that after that tool call, there is now a
file called &lt;code&gt;test.txt&lt;/code&gt; in &lt;code&gt;/tmp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However bash has one fundamental limitation which is that it can only compose
programs that run.  And there are some things, which are not programs, but
native tools to the LLM and they sort of have to be.&lt;/p&gt;
&lt;p&gt;The most obvious example here is &lt;code&gt;read&lt;/code&gt; or &lt;code&gt;view_image&lt;/code&gt;. If a multimodal model
needs to read an image, it cannot use &lt;code&gt;cat&lt;/code&gt; for that because the harness needs
to inject the actual image payload into the protocol of the LLM.&lt;/p&gt;
&lt;p&gt;Another quite vivid example are sub agents.  In order to spawn and orchestrate
sub agents, it&amp;#8217;s tricky to avoid tools that are provided by the harness.  While
in theory the agent could provide a CLI tool that talks to the outer harness
via environment variables and Unix sockets, it&amp;#8217;s a rather crude process.  It
however has another issue, and that is where the code runs.&lt;/p&gt;
&lt;h2&gt;Brains vs Hands&lt;/h2&gt;
&lt;p&gt;To better understand that, it&amp;#8217;s important to think a bit more about where all the
bits and pieces run.  There really usually are two different systems involved.
The first is the brain, the harness: it runs on one machine. It&amp;#8217;s trusted.  The
second is &lt;em&gt;often&lt;/em&gt; the same machine, but it&amp;#8217;s really where the tools are
executing: the hands.  In Pi we now call this the execution environment, but you
can think of it as the target of all the operations.&lt;/p&gt;
&lt;p&gt;Crucially what is important for us, is that there is a dividing line between the
harness brain and the target environment that runs bash and executes the tools.&lt;/p&gt;
&lt;p&gt;And splitting this in half has some really important consequences.  For a start
it means that they are running on different file systems and they have different
levels of trust.  If you for instance use a sandboxing solution &lt;a href=&quot;https://earendil-works.github.io/gondolin/&quot;&gt;like
Gondolin&lt;/a&gt; your bash stuff will be
sandboxed just fine, but the harness itself will not be.&lt;/p&gt;
&lt;h2&gt;Orchestrating The Harness&lt;/h2&gt;
&lt;p&gt;Which brings us to what Codemode really does: it&amp;#8217;s a way for the LLM to express
and orchestrate complex operations on the harness side, but not the execution
environment side. Codemode runs in the harness, in its own sandbox.  In case of
Pi it&amp;#8217;s running in QuickJS within a WASM runtime with intentional limitations:
no network, no file system, no timers, limited RAM.  The only way is to call
more tools.  You could also imagine that Codemode could run Scheme or some other
language as well.&lt;/p&gt;
&lt;p&gt;If you are not familiar with Codemode, it&amp;#8217;s basically just a way to issue
tool calls from within some language, in our case JavaScript.  That allows you
to compose those calls without necessarily going through the LLM&amp;#8217;s context.
Credit for naming goes to our friends at Cloudflare &lt;a href=&quot;https://blog.cloudflare.com/code-mode/&quot;&gt;who coined
it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For instance if you issue a bash call as a regular tool call in the LLM, then
we only throw the trailing 2000 lines into the context and if the agent wants
more, it needs to look at the overflow file itself.  If however the agent issues
that invocation via Codemode, then the Codemode side gets larger outputs
sent structurally.&lt;/p&gt;
&lt;p&gt;Most importantly, because Codemode is JavaScript the agent can express
concurrent operations and basic workflows.  A common way in which you see agents
now use this, is to first probe at 5-10 items from some tool response to see
what it looks like, and to then write a Codemode script that processes the next
n items.&lt;/p&gt;
&lt;p&gt;Codemode also allows you to throw state into the transcript!  That means that
one Codemode invocation can stash away data, that the next call in the session
can load again.  And remember: this is on the harness host, not the sandbox.&lt;/p&gt;
&lt;p&gt;In case of Pi, Codemode also allows you to issue calls that naturally do not
make any sense in Pi&amp;#8217;s traditional interface.  For instance if you want to
generate images with an image model or you want to classify some text with a
one shot classifier model, those Pi APIs are exposed via Codemode, but not via
regular tools where they would just waste context.&lt;/p&gt;
&lt;h2&gt;What It Looks Like&lt;/h2&gt;
&lt;p&gt;So now that we talked a bunch about it, it&amp;#8217;s probably worth being a bit more
explicit about it.  Let&amp;#8217;s walk ourselves through some invocations of Codemode
of recent Pi sessions of mine.  Note that none of this code is human written.
It&amp;#8217;s from real sessions of Pi, just re-indented for your viewing pleasure.  The
agent starts using Codemode automatically either because it&amp;#8217;s a task where the
model already naturally picks up that tool, or because a user asked it to.&lt;/p&gt;
&lt;p&gt;Note that Codemode is by default only enabled in Pi when MCP is enabled, but you
can turn it on with &lt;code&gt;&amp;quot;defaultTools&amp;quot;: [&amp;quot;+codemode&amp;quot;]&lt;/code&gt; in the settings.  Just ask
Pi to enable it for you.&lt;/p&gt;
&lt;h3&gt;Generating Images&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s start simple with image generation.  Image generation is a feature that Pi
supports in the AI SDK core, but it&amp;#8217;s not a tool that the agent can use.  In the
past the only way to use image models has been to write a bespoke extension or
to have the agent run node itself and use the internal image APIs.  However
because we expose quite a few of the internal model APIs within Codemode, it
means that the agent can use it:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;painter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAvailableOfType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;generateImages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;painter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;A cute little puppy sitting on a grassy &amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;lawn, soft natural light, photorealistic&amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stopReason&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;stop&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errorMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the call to &lt;code&gt;image()&lt;/code&gt; sends the image back as image content to the
LLM.  On the harness side it feeds it directly into both the agent, as well as
onto disk as a temporary artifact in case the agent wants to be able to pass
that image back to bash.&lt;/p&gt;
&lt;h3&gt;Classifying Things&lt;/h3&gt;
&lt;p&gt;Similar things apply to classifier models such as &lt;a href=&quot;https://typesafe.ai/&quot;&gt;Jev&lt;/a&gt;.
They also do not fit well into the workflows of an agent through the typical
tools.  But rather than making a bespoke tool available, Codemode just allows
the agent to reach into the AI SDK and invoke those directly.  Here you can see
how Jev is used to mass process GitHub issues for a quick sentiment analysis:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jev&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getModelOfType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;classifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;typesafe&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;jev-latest&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;gh issue list --state open --limit 100 &amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;--json number,title,body,comments&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issues&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;comments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;questions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sentiment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;choice&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instructions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;What is the overall sentiment of the author towards pi?&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;criteria&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;positive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Appreciative, happy, constructive praise&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;neutral&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Matter-of-fact report or request without emotion&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;negative&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Frustrated, annoyed, upset, or angry&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;frustration&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;score&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instructions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;How frustrated is the reporter?&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;criteria&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;not at all&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;mildly&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;clearly frustrated&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;very angry&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;choice&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instructions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;What kind of issue is this?&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;criteria&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Bug report or regression&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Feature request or enhancement&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;question&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Question or support request&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Docs, discussion, meta, spam&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stopReason&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;stop&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errorMessage&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;issue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;answers&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;sentiment_results&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;frustration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;frustration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`#&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;frustration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note how in that above example we also call &lt;code&gt;store()&lt;/code&gt; which dumps the result of
that execution into the session transcript.  A future invocation of Codemode can
thus read back that result if it wants to.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Promise.all&lt;/code&gt; here is fine, because Pi limits the total number of concurrent
tool executions itself to four and maintains a queue for the rest.&lt;/p&gt;
&lt;p&gt;A more adventurous example is to use Jev to drive a game engine for debugging
purposes:&lt;/p&gt;
Codemode with Jev for Game Debugging
&lt;p&gt;Here it knows about my &lt;code&gt;tankctl&lt;/code&gt; command and it built itself quickly a minimal
harness around it to drive a game loop to assist a user with debugging a
problem. Note how it built a 30 step loop in which each step goes back to both
the game engine to get a text dump of what&amp;#8217;s going on, and then to Jev to
determine what to do next:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jev&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getModelOfType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;classifier&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;typesafe&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;jev-latest&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tank&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`tools/tankctl &amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;&amp;quot;`&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;start --map assets/maps/night_arena.map&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;questions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;choice&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instructions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;You control the tank '@' in a top-down tank game. &amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Choose the best next action.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;criteria&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;an enemy has line of sight to you and you can fire at it&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;approach&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;no enemy has line of sight; drive toward the nearest enemy&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dodge&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;an enemy shot is heading at you and will hit soon&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;powerup&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;a powerup is close and no enemy threatens you&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;commandFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enemies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;los&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;los&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;attack&amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`fire_at tank &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;; frames 30 until clear,damage,kill`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;dodge&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// move perpendicular to the closest incoming shot&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;projectiles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;yours&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;vel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;+down&amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;+up&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;+right&amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;+left&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`input &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;; frames 20 until damage; input stop`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;powerup&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;powerups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;===&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;powerup&amp;quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;powerup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`goto &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;powerup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;powerup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; 180`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`goto &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;enemy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; 90`&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;state&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;playing&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threats&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;projectiles&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;yours&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;miss_dist&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eta&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`incoming shot dist &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; eta &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eta&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;s`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;no incoming shots&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;classify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;jev&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;view 8&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;threats&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hp&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;questions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stopReason&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;stop&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`#&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; classifier error: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errorMessage&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;answers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;commandFor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`#&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;step&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; hp=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;st&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;player&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hp&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;choice&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt; -&amp;gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Calling MCP Servers&lt;/h3&gt;
&lt;p&gt;Lastly, Codemode obviously is great for calling MCP servers.  And because we
do not actually expose any of the MCP tools to the LLM, the agent first uses
provided APIs to issue a tool search within Codemode to discover what it might
be able to do with the connected servers. This form of progressive discovery
makes the whole MCP business work well enough for a lot of use cases today.&lt;/p&gt;
&lt;p&gt;Here for instance you can see the agent reach for the Sentry MCP straight away,
even without discovering the tools, presumably because it has learned during the
RL process already about what the Sentry MCP looks like.  But it learns from
what we inject into the system prompt, that the Sentry server is available to
begin with.  It&amp;#8217;s not completely guessing here.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;orgs&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mcp__sentry__find_organizations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({});&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;organizations&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;orgs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;structuredContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;allSettled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;organizations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mcp__sentry__find_projects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;organizationSlug&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;regionUrl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;regionUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;organizations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;fulfilled&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;projects&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;structuredContent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;projects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Modern MCP Is A Fight&lt;/h2&gt;
&lt;p&gt;I really don&amp;#8217;t want to talk too much about MCP here, but MCP is in fact a
protocol that greatly benefits from Codemode.  The problem in parts is that MCP
in practice often targets harnesses that do not (yet?) use Codemode.  But the
tide is shifting.  In the meantime, a temporary crutch has been to do what
Cloudflare did, and do Codemode within the MCP server.  But now we have Codemode
in Codemode which is pretty bad.  It means double JSON escaping, easy for
smaller models to get confused by and the inner code cannot call the outer
tools.  So if you for instance use the Cloudflare MCP servers in Pi, the agent
needs to write JavaScript and funnel it through more JavaScript. This is really
not optimal, but it&amp;#8217;s also understandable that this is happening:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;accRes&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mcp__cloudflare__execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`async () =&amp;gt; {&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;    const r = await cloudflare.request({ method: &amp;quot;GET&amp;quot;, path: &amp;quot;/accounts&amp;quot; });&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;    return r.result.map(a =&amp;gt; ({ id: a.id, name: a.name }));&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;  }`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;accRes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;accounts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tools&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mcp__cloudflare__execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;account_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`async () =&amp;gt; {&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;      const r = await cloudflare.request({&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;        method: &amp;quot;GET&amp;quot;,&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;        path: \`/accounts/\${accountId}/workers/scripts\`,&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;      });&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;      return r.result.map(s =&amp;gt; ({ id: s.id, modified: s.modified_on }));&lt;/span&gt;
&lt;span class=&quot;sb&quot;&gt;    }`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;w&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;account&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;workers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;MCP Desires&lt;/h2&gt;
&lt;p&gt;So to end things off: how well does Codemode work with MCP today?  Well … not
amazingly well.  That&amp;#8217;s because MCP servers are not really targeting harnesses
that use Codemode yet (though at this point I think most harnesses support it).&lt;/p&gt;
&lt;p&gt;For this to work well some recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Structured content:&lt;/strong&gt; Codemode wants calls to return some nicely
formatted JSON.  So that needs to come back from the server, and many don&amp;#8217;t
do that yet.  The &lt;code&gt;outputSchema&lt;/code&gt; system in MCP is great for that.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Consistent results:&lt;/strong&gt; an interesting failure case is when an MCP server
does not return consistent data.  For instance because it tries to token
optimize things depending on how many items are in the result set.  This can
cause an initial probe with 5 items to succeed, but then fail when the server
returns the maximum batch size.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Large binary data:&lt;/strong&gt; today MCP does not yet support large binary data
so quite a few use cases that are really interesting do not work well at all
yet.  You end up with all kinds of weird workarounds such as pre-signed URLs
to allow file uploads then to happen through non MCP channels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composable tool search:&lt;/strong&gt; the MCP server might know better than the MCP
client which tool is appropriate for a task.  But there is no good mechanism
today that allows a harness to fan out tool searches across multiple MCP
servers.  It&amp;#8217;s all emergent behavior and it does not scale well to multiple
active servers.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Future of Codemode&lt;/h2&gt;
&lt;p&gt;So where does this leave us?  Is this a reversal of what I wrote a year ago
where I encouraged CLIs?  I don&amp;#8217;t think so.  In fact, the MCP ecosystem from my
perspective picked up on exactly what we pointed out a year ago works: code.
But Codemode goes beyond MCP in that it can act as a capable mechanism within
the harness to express more freedom for the agent.&lt;/p&gt;
&lt;p&gt;There are however also some things that we still need to figure out.  For one,
durability with Codemode is trickier.  We might have to adopt some ideas from
durable workflow engines here to snapshot invocations.  Or maybe, something like
Starlark is a better composition language than JavaScript given its
deterministic nature.&lt;/p&gt;
&lt;p&gt;Images, binary data and just the inability of this pattern to work with smaller
models is also something that needs to be fleshed out.  So it&amp;#8217;s for sure not a
perfect solution yet, but it&amp;#8217;s quite a useful pattern that I expect us to
leverage more.&lt;/p&gt;</description>
	<pubDate>Tue, 06 Oct 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Tryton News: Security Release for issue 15032</title>
	<guid>https://discuss.tryton.org/t/security-release-for-issue-15032/9411</guid>
	<link>https://discuss.tryton.org/t/security-release-for-issue-15032/9411</link>
	<description>&lt;p&gt;&lt;a href=&quot;https://foss.heptapod.net/jaisurya-me&quot;&gt;Jaisurya&lt;/a&gt; has discovered that &lt;a href=&quot;https://bugs.tryton.org/15032&quot;&gt;the content of the HTML editor was not escaped&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;p-40519-impact-1&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40519-impact-1&quot;&gt;&lt;/a&gt;Impact&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.first.org/cvss/calculator/3-0#CVSS:3.0/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N&quot;&gt;CVSS v3.0 Base Score: 5.4&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attack Vector: Network&lt;/li&gt;
&lt;li&gt;Attack Complexity: Low&lt;/li&gt;
&lt;li&gt;Privileges Required: Low&lt;/li&gt;
&lt;li&gt;User Interaction: Required&lt;/li&gt;
&lt;li&gt;Scope: Changed&lt;/li&gt;
&lt;li&gt;Confidentiality: Low&lt;/li&gt;
&lt;li&gt;Integrity: Low&lt;/li&gt;
&lt;li&gt;Availability: None&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name=&quot;p-40519-workaround-2&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40519-workaround-2&quot;&gt;&lt;/a&gt;Workaround&lt;/h2&gt;
&lt;p&gt;Setup restrictive CSP without unsafe inline script may prevent the attack.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;p-40519-resolution-3&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40519-resolution-3&quot;&gt;&lt;/a&gt;Resolution&lt;/h2&gt;
&lt;p&gt;All affected users should upgrade &lt;code&gt;trytond&lt;/code&gt; to the latest version.&lt;/p&gt;
&lt;p&gt;Affected versions per series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;trytond&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;8.0: &amp;lt;= 8.0.10&lt;/li&gt;
&lt;li&gt;7.8: &amp;lt;= 7.8.16&lt;/li&gt;
&lt;li&gt;7.0: &amp;lt;= 7.0.57&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not affected versions per series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;trytond&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;8.0: &amp;gt;= 8.0.11&lt;/li&gt;
&lt;li&gt;7.8: &amp;gt;= 7.8.17&lt;/li&gt;
&lt;li&gt;7.0: &amp;gt;= 7.0.58&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name=&quot;p-40519-reference-4&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40519-reference-4&quot;&gt;&lt;/a&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bugs.tryton.org/15032&quot;&gt;https://bugs.tryton.org/15032&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name=&quot;p-40519-concerns-5&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40519-concerns-5&quot;&gt;&lt;/a&gt;Concerns?&lt;/h2&gt;
&lt;p&gt;Any security concerns should be reported on the bug-tracker at &lt;a href=&quot;https://bugs.tryton.org/&quot;&gt;https://bugs.tryton.org/&lt;/a&gt; with the confidential checkbox checked.&lt;/p&gt;
            &lt;p&gt;&lt;small&gt;1 post - 1 participant&lt;/small&gt;&lt;/p&gt;
            &lt;p&gt;&lt;a href=&quot;https://discuss.tryton.org/t/security-release-for-issue-15032/9411&quot;&gt;Read full topic&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 05 Oct 2026 06:00:21 +0000</pubDate>
</item>
<item>
	<title>Tryton News: Security Release for issue 15035</title>
	<guid>https://discuss.tryton.org/t/security-release-for-issue-15035/9412</guid>
	<link>https://discuss.tryton.org/t/security-release-for-issue-15035/9412</link>
	<description>&lt;p&gt;&lt;a href=&quot;https://foss.heptapod.net/paradox0909&quot;&gt;lizparadox_&lt;/a&gt; has discovered that &lt;a href=&quot;https://bugs.tryton.org/15035&quot;&gt;the report name can be used to execute commands on the server&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;p-40520-impact-1&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40520-impact-1&quot;&gt;&lt;/a&gt;Impact&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.first.org/cvss/calculator/3-0#CVSS:3.0/AV:N/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:H&quot;&gt;CVSS v3.0 Base Score: 6.8&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attack Vector: Network&lt;/li&gt;
&lt;li&gt;Attack Complexity: Low&lt;/li&gt;
&lt;li&gt;Privileges Required: High&lt;/li&gt;
&lt;li&gt;User Interaction: Required&lt;/li&gt;
&lt;li&gt;Scope: Unchanged&lt;/li&gt;
&lt;li&gt;Confidentiality: High&lt;/li&gt;
&lt;li&gt;Integrity: High&lt;/li&gt;
&lt;li&gt;Availability: High&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name=&quot;p-40520-workaround-2&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40520-workaround-2&quot;&gt;&lt;/a&gt;Workaround&lt;/h2&gt;
&lt;p&gt;There is no workaround.&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;p-40520-resolution-3&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40520-resolution-3&quot;&gt;&lt;/a&gt;Resolution&lt;/h2&gt;
&lt;p&gt;All affected users should upgrade &lt;code&gt;trytond&lt;/code&gt; to the latest version.&lt;/p&gt;
&lt;p&gt;Affected versions per series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;trytond&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;8.0: &amp;lt;= 8.0.10&lt;/li&gt;
&lt;li&gt;7.8: &amp;lt;= 7.8.16&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not affected versions per series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;trytond&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;8.0: &amp;gt;= 8.0.11&lt;/li&gt;
&lt;li&gt;7.8: &amp;gt;= 7.8.17&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name=&quot;p-40520-reference-4&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40520-reference-4&quot;&gt;&lt;/a&gt;Reference&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bugs.tryton.org/15035&quot;&gt;https://bugs.tryton.org/15035&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;a name=&quot;p-40520-concerns-5&quot; class=&quot;anchor&quot; href=&quot;https://discuss.tryton.org#p-40520-concerns-5&quot;&gt;&lt;/a&gt;Concerns?&lt;/h2&gt;
&lt;p&gt;Any security concerns should be reported on the bug-tracker at &lt;a href=&quot;https://bugs.tryton.org/&quot;&gt;https://bugs.tryton.org/&lt;/a&gt; with the confidential checkbox checked.&lt;/p&gt;
            &lt;p&gt;&lt;small&gt;1 post - 1 participant&lt;/small&gt;&lt;/p&gt;
            &lt;p&gt;&lt;a href=&quot;https://discuss.tryton.org/t/security-release-for-issue-15035/9412&quot;&gt;Read full topic&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Mon, 05 Oct 2026 06:00:21 +0000</pubDate>
</item>
<item>
	<title>LernerPython blog, from Reuven Lerner: Pandas groupby basics: Aggregating a numeric column by category</title>
	<guid>https://lernerpython.com/2026/10/05/pandas-groupby-basics-aggregating-a-numeric-column-by-category/</guid>
	<link>https://lernerpython.com/2026/10/05/pandas-groupby-basics-aggregating-a-numeric-column-by-category/</link>
	<description>&lt;img src=&quot;https://lernerpython.com/wp-content/uploads/2026/10/2026-10-05.png&quot; alt=&quot;Pandas groupby basics: Aggregating a numeric column by category&quot; class=&quot;wp-image-17964&quot; width=&quot;1223&quot; height=&quot;637&quot; /&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;The simplest grouping in Python Pandas is groupby:&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;df.groupby(CATEGORICAL)[NUMERIC].AGG_METHOD()&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;For example:&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;df.groupby('passenger_count')['trip_distance'].mean()&lt;/code&gt;&lt;/pre&gt;



&lt;p class=&quot;wp-block-paragraph&quot;&gt;Returns a series whose index is the unique values from passenger_count.&lt;/p&gt;
&lt;p&gt;The post &lt;a href=&quot;https://lernerpython.com/2026/10/05/pandas-groupby-basics-aggregating-a-numeric-column-by-category/&quot;&gt;Pandas groupby basics: Aggregating a numeric column by category&lt;/a&gt; appeared first on &lt;a href=&quot;https://lernerpython.com&quot;&gt;LernerPython&lt;/a&gt;.&lt;/p&gt;</description>
	<pubDate>Mon, 05 Oct 2026 06:00:00 +0000</pubDate>
</item>
<item>
	<title>Mark Dufour: Shed Skin v0.9.14, v1.0 coming soon!</title>
	<guid>http://shed-skin.blogspot.com/2026/10/shed-skin-v0914-v10-coming-soon.html</guid>
	<link>http://shed-skin.blogspot.com/2026/10/shed-skin-v0914-v10-coming-soon.html</link>
	<description>&lt;p&gt;I have just released &lt;a href=&quot;https://github.com/shedskin/shedskin/releases/tag/v0.9.14-1&quot;&gt;version 0.9.14&lt;/a&gt; of &lt;a href=&quot;https://github.com/shedskin/shedskin&quot;&gt;Shed Skin&lt;/a&gt;, a restricted-python to C++ transpiler. Shed Skin allows one to effectively convert (or transpile) pure Python code to highly optimized machine code. This comes at the cost though of having to conform to a seriously restricted subset of Python features/libraries. Although, it is possible to generate extension modules, that can be used in larger, unrestricted, programs.
  
&lt;p&gt;While the previous release was just a month ago, I felt like there were so many important improvements already that I didn't want them to wait for the 1.0 release which looks like it may finally happen within a few months! From a completely rewritten and faster, more scalable, type inference engine, to full Unicode support, to almost complete feature parity with Python 3.15 (for the supported modules), to support for heterogeneous 3-len tuples - it has been a hectic month :)
  
&lt;p&gt;With all this in place, I'm starting to plan the final pieces I would like to see in place for a 1.0 release. There is still quite a bit of work left, but much of it is mechanical and just working through a long list of minor decisions and details.. It should be possible to have all that done around the end of the year.
  
&lt;p&gt;I'm also happy to mention a relatively new but similar project here, &lt;a href=&quot;https://tpy-lang.org/&quot;&gt;TurboPython&lt;/a&gt;, which may be of interest to those reading this. The most interesting difference with Shed Skin is that it uses a RUST-like memory model:

&quot;TurboPython is a general-purpose, statically typed language that compiles Python through C++ to a native binary. It combines Python's syntax with an ownership model that gives memory safety and predictable performance—no garbage collector, no automatic reference counting, no GIL.&quot;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;&lt;/p&gt;</description>
	<pubDate>Sun, 04 Oct 2026 11:29:40 +0000</pubDate>
</item>
<item>
	<title>Brian Okken: PyBay 2026 Talk info and slides</title>
	<guid>https://pythontest.com/tdd-pybay-2026/</guid>
	<link>https://pythontest.com/tdd-pybay-2026/</link>
	<description>&lt;p&gt;&lt;strong&gt;Talk Title:&lt;/strong&gt; Is TDD even relevant anymore? Yes, but don&amp;rsquo;t be dumb about it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Event:&lt;/strong&gt; &lt;a href=&quot;https://pybay.org/&quot;&gt;PyBay 2026&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Slides:&lt;/strong&gt; &lt;a href=&quot;https://pythontest.com/tdd-pybay-2026.pdf&quot;&gt;tdd-pybay-2026.pdf&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Sat, 03 Oct 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Python Software Foundation: Announcing the 2026 PSF Board Election Results!</title>
	<guid>https://pyfound.blogspot.com/2026/09/announcing-2026-psf-board-election.html</guid>
	<link>https://pyfound.blogspot.com/2026/09/announcing-2026-psf-board-election.html</link>
	<description>&lt;p&gt;The 2026 election for the PSF Board created an opportunity for conversations about the PSF's work to serve the global Python community. We appreciate community members' perspectives, passion, and engagement in the election process this year.&amp;nbsp;&lt;/p&gt;&lt;p&gt;We want to send a big thanks to everyone who ran and was willing to serve on the PSF Board. Even if you were not elected, we appreciate all the time and effort you put into thinking about how to improve the PSF and represent the parts of the community you participate in. We hope that you will continue to think about these issues, share your ideas, and join a PSF Work Group or PSF initiative if you feel called to do so.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Board Members Elect&amp;nbsp;&lt;/h3&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwa029mAK-VzIrvSzCbyYd6Ns0C2gefTG30Zjizu9A4UywuwEimTNiZuURqrcN6QiLAqUq4H7AjytpgKT0dXXgAhF9Bcr1_CaIIPCYIr6N9MasdJ1q1HXJwBWwfj2Y61KtjmjoGAOGt77rGSL_fr2d3cNLWotjwn7bZWb1g_69KhLb_XfIbg/s1200/election%20announcement(1).png&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwa029mAK-VzIrvSzCbyYd6Ns0C2gefTG30Zjizu9A4UywuwEimTNiZuURqrcN6QiLAqUq4H7AjytpgKT0dXXgAhF9Bcr1_CaIIPCYIr6N9MasdJ1q1HXJwBWwfj2Y61KtjmjoGAOGt77rGSL_fr2d3cNLWotjwn7bZWb1g_69KhLb_XfIbg/w400-h400/election%20announcement(1).png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;Congratulations to our three new and one returning Board members who have been elected!&amp;nbsp;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Elaine Wong&lt;/li&gt;&lt;li&gt;Ee Durbin&lt;/li&gt;&lt;li&gt;Laís Carvalho&amp;nbsp;&lt;/li&gt;&lt;li&gt;Georgi Ker&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We’ll be in touch with all the elected candidates shortly to schedule onboarding. Newly elected PSF Board members are provided orientation for their service and will be joining the upcoming board meeting in October.&amp;nbsp;&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Thank you!&lt;/h3&gt;&lt;p&gt;We’d like to take this opportunity to thank our outgoing board members. Cheuk Ting Ho has been a super engaged PSF Board member, participating in many committees, and helping out on many PSF Programs and projects during her time on the PSF Board. Chris Neugebauer has been a longtime board member and in particular has been the watch guard of our bylaws conversations and has always been ready to share institutional knowledge. Denny Perez has been instrumental on the PSF Board, serving on the Executive Committee, as Treasurer, and on various committees during her tenure. All three of you helped shape the PSF’s Strategic Plan for the next 5 years, which was a massive undertaking. Thank you, Cheuk, Chris, and Denny for your leadership and dedication to the PSF and the Python community. You will be missed and are deeply appreciated!&lt;/p&gt;&lt;p&gt;Our heartfelt thanks go out to each of you who took the time to review the candidates and submit your votes. Your participation helps the PSF represent our community. We received 670 total ballots, easily reaching quorum–1/3 of affirmed voting members (1123). We’re especially grateful for your patience with continuing to navigate the additions to the elections processes with the inaugural Python Packaging Council election.&lt;br /&gt;&lt;br /&gt;We also want to thank everyone who helped promote this year’s board election, especially Board Member KwonHan Bae, who took the initiative to cover this year’s election and worked with PSF Staff to conduct written interviews with candidates. This promotional effort was inspired by the work of &lt;a href=&quot;https://pythoncommunitynews.com/&quot; target=&quot;_blank&quot;&gt;Python Community News&lt;/a&gt; in 2023. We also want to highlight the PSF staff members and PSF Board members who put in tons of effort each year as we work to continually improve the PSF elections.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;What’s next?&lt;/h3&gt;&lt;p&gt;If you’re interested in the complete tally, make sure to check the &lt;a href=&quot;https://opavote.com/results/6289918744854528&quot; target=&quot;_blank&quot;&gt;Python Software Foundation Board of Directors Election 2026 Results page&lt;/a&gt;. &lt;i&gt;These results will be available until November 10, 2026.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;The PSF Election team will conduct a retrospective of this year’s election process to ensure we are improving year over year. We received valuable feedback about the process and tooling. We hope to be able to implement more changes for next year to ensure a smooth and accessible election process for everyone in our community. If you have feedback or comments about this year’s PSF Board election, we welcome you to &lt;a href=&quot;https://discuss.python.org/t/2026-psf-board-election/107797&quot; target=&quot;_blank&quot;&gt;join the discussion on discuss.python.org&lt;/a&gt; or email psf-elections@pyfound.org.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Finally, it might feel a little early to mention this, but we will have at least 3 seats open again next year. If you're interested in running or learning more, we encourage you to contact a current PSF Board member or two this year and ask them about their experience serving on the board.&lt;/p&gt;</description>
	<pubDate>Fri, 02 Oct 2026 09:27:53 +0000</pubDate>
</item>
<item>
	<title>Talk Python to Me: #565: Tachyon, Python 3.15's Built-in Sampling Profiler</title>
	<guid>https://talkpython.fm/episodes/show/565/tachyon-python-3.15s-built-in-sampling-profiler</guid>
	<link>https://talkpython.fm/episodes/show/565/tachyon-python-3.15s-built-in-sampling-profiler</link>
	<description>Do you know what's actually slow in your Python app? Or are you guessing? Until now, profiling Python meant a tracing profiler that made your code 2 to 3 times slower. Or a third-party tool that broke with every new release. Python 3.15 fixes that. It ships Tachyon, a sampling profiler built into the standard library. It attaches to live production apps with almost zero overhead. My guests are Pablo Galindo Salgado, CPython core developer and Steering Council member, and László Kiss Kollár from Bloomberg's Python infrastructure team. Their first prototype ran at two samples a second. Now it does over a million hz. And it lands in Python 3.15 this October.&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Episode sponsors&amp;lt;/strong&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;a href='https://talkpython.fm/sentry'&amp;gt;Sentry Error Monitoring, Code talkpython26&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;a href='https://talkpython.fm/devopsbook'&amp;gt;Python in Production&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;a href='https://talkpython.fm/training'&amp;gt;Talk Python Courses&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;h2 class=&quot;links-heading mb-4&quot;&amp;gt;Links from the show&amp;lt;/h2&amp;gt;
&amp;lt;div&amp;gt;&amp;lt;strong&amp;gt;Guests&amp;lt;/strong&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;László Kiss Kollár&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://www.linkedin.com/in/lkollar/?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;linkedin.com&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Pablo Galindo Salgado&amp;lt;/strong&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;3.11&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://talkpython.fm/episodes/show/388/python-3.11-is-here-and-its-fast&quot; target=&quot;_blank&quot; &amp;gt;talkpython.fm&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Memray&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://talkpython.fm/episodes/show/425/memray-the-endgame-python-memory-profiler&quot; target=&quot;_blank&quot; &amp;gt;talkpython.fm&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;PyStack&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://talkpython.fm/episodes/show/419/debugging-python-in-production-with-pystack&quot; target=&quot;_blank&quot; &amp;gt;talkpython.fm&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;profile and cProfile&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://docs.python.org/3/library/profile.html?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;docs.python.org&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;py-spy&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://github.com/benfred/py-spy?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;github.com&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Austin&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://github.com/P403n1x87/austin?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;github.com&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;PEP 799&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://peps.python.org/pep-0799/?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;peps.python.org&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;PEP 768&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://peps.python.org/pep-0768/?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;peps.python.org&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;PyCon US 2026 talk&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://us.pycon.org/2026/schedule/presentation/31?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;us.pycon.org&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;The docs&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://docs.python.org/3.15/library/profiling.sampling.html?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;docs.python.org&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Backport to 3.14&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://github.com/pythonbackport/python-profiling?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;github.com&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Watch this episode on YouTube&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://www.youtube.com/watch?v=yZdfOf8kQo4&quot; target=&quot;_blank&quot; &amp;gt;youtube.com&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Episode #565 deep-dive&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://talkpython.fm/episodes/show/565/tachyon-python-3.15s-built-in-sampling-profiler#takeaways-anchor&quot; target=&quot;_blank&quot; &amp;gt;talkpython.fm/565&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Episode transcripts&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://talkpython.fm/episodes/transcript/565/tachyon-python-3.15s-built-in-sampling-profiler&quot; target=&quot;_blank&quot; &amp;gt;talkpython.fm&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Theme Song: Developer Rap&amp;lt;/strong&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;🥁 Served in a Flask 🎸&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://talkpython.fm/flasksong&quot; target=&quot;_blank&quot; &amp;gt;talkpython.fm/flasksong&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;---==  Don't be a stranger  ==---&amp;lt;/strong&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;YouTube&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://talkpython.fm/youtube&quot; target=&quot;_blank&quot; &amp;gt;&amp;lt;i class=&quot;fa-brands fa-youtube&quot;&amp;gt;&amp;lt;/i&amp;gt; youtube.com/@talkpython&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Bluesky&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://bsky.app/profile/talkpython.fm&quot; target=&quot;_blank&quot; &amp;gt;@talkpython.fm&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Mastodon&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://fosstodon.org/web/@talkpython&quot; target=&quot;_blank&quot; &amp;gt;&amp;lt;i class=&quot;fa-brands fa-mastodon&quot;&amp;gt;&amp;lt;/i&amp;gt; @talkpython@fosstodon.org&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;X.com&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://x.com/talkpython&quot; target=&quot;_blank&quot; &amp;gt;&amp;lt;i class=&quot;fa-brands fa-twitter&quot;&amp;gt;&amp;lt;/i&amp;gt; @talkpython&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Michael on Bluesky&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://bsky.app/profile/mkennedy.codes?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;@mkennedy.codes&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Michael on Mastodon&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://fosstodon.org/web/@mkennedy&quot; target=&quot;_blank&quot; &amp;gt;&amp;lt;i class=&quot;fa-brands fa-mastodon&quot;&amp;gt;&amp;lt;/i&amp;gt; @mkennedy@fosstodon.org&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;strong&amp;gt;Michael on X.com&amp;lt;/strong&amp;gt;: &amp;lt;a href=&quot;https://x.com/mkennedy?featured_on=talkpython&quot; target=&quot;_blank&quot; &amp;gt;&amp;lt;i class=&quot;fa-brands fa-twitter&quot;&amp;gt;&amp;lt;/i&amp;gt; @mkennedy&amp;lt;/a&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/div&amp;gt;</description>
	<pubDate>Fri, 02 Oct 2026 00:09:20 +0000</pubDate>
</item>
<item>
	<title>Python Insider: Python 3.15.0 candidate 3 is here!</title>
	<guid>https://blog.python.org/2026/10/python-3150-rc3/</guid>
	<link>https://blog.python.org/2026/10/python-3150-rc3/</link>
	<description>Following tradition, a surprise rc3!</description>
	<pubDate>Fri, 02 Oct 2026 00:00:00 +0000</pubDate>
</item>

</channel>
</rss>
