CINXE.COM
Python Software Foundation News: 05/01/2022 - 06/01/2022
<!DOCTYPE html> <html class='v2' dir='ltr' lang='en' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <!-- Google tag (gtag.js) --> <script async='async' src='https://www.googletagmanager.com/gtag/js?id=G-H6ZX4B41B7'></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-H6ZX4B41B7'); </script> <meta content='Python Software Foundation Blog' property='og:site_name'/> <meta content='https://pyfound.blogspot.com' property='og:url'/> <meta content='' property='og:description'/> <meta content='' property='og:type'/> <meta content='https://s3.dualstack.us-east-2.amazonaws.com/pythondotorg-assets/media/psf/grants/report-2006-10/psf-logo.png' property='og:image'/> <meta content='width=1100' name='viewport'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='https://pyfound.blogspot.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='https://pyfound.blogspot.com/2022/05/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Python Software Foundation News - Atom" href="https://pyfound.blogspot.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Python Software Foundation News - RSS" href="https://pyfound.blogspot.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Python Software Foundation News - Atom" href="https://www.blogger.com/feeds/8520/posts/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='https://pyfound.blogspot.com/2022/05/' property='og:url'/> <meta content='Python Software Foundation News' property='og:title'/> <meta content='聽聽News from the Python Software Foundation' property='og:description'/> <title>Python Software Foundation News: 05/01/2022 - 06/01/2022</title> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Simple Designer: Blogger URL: www.blogger.com ----------------------------------------------- */ /* Variable definitions ==================== <Variable name="keycolor" description="Main Color" type="color" default="#66bbdd"/> <Group description="Page Text" selector="body"> <Variable name="body.font" description="Font" type="font" default="normal normal 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="body.text.color" description="Text Color" type="color" default="#222222"/> </Group> <Group description="Backgrounds" selector=".body-fauxcolumns-outer"> <Variable name="body.background.color" description="Outer Background" type="color" default="#66bbdd"/> <Variable name="content.background.color" description="Main Background" type="color" default="#ffffff"/> <Variable name="header.background.color" description="Header Background" type="color" default="transparent"/> </Group> <Group description="Links" selector=".main-outer"> <Variable name="link.color" description="Link Color" type="color" default="#2288bb"/> <Variable name="link.visited.color" description="Visited Color" type="color" default="#888888"/> <Variable name="link.hover.color" description="Hover Color" type="color" default="#33aaff"/> </Group> <Group description="Blog Title" selector=".header h1"> <Variable name="header.font" description="Font" type="font" default="normal normal 60px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="header.text.color" description="Title Color" type="color" default="#3399bb" /> </Group> <Group description="Blog Description" selector=".header .description"> <Variable name="description.text.color" description="Description Color" type="color" default="#777777" /> </Group> <Group description="Tabs Text" selector=".tabs-inner .widget li a"> <Variable name="tabs.font" description="Font" type="font" default="normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="tabs.text.color" description="Text Color" type="color" default="#999999"/> <Variable name="tabs.selected.text.color" description="Selected Color" type="color" default="#000000"/> </Group> <Group description="Tabs Background" selector=".tabs-outer .PageList"> <Variable name="tabs.background.color" description="Background Color" type="color" default="#f5f5f5"/> <Variable name="tabs.selected.background.color" description="Selected Color" type="color" default="#eeeeee"/> </Group> <Group description="Post Title" selector="h3.post-title, .comments h4"> <Variable name="post.title.font" description="Font" type="font" default="normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> </Group> <Group description="Date Header" selector=".date-header"> <Variable name="date.header.color" description="Text Color" type="color" default="#666666"/> <Variable name="date.header.background.color" description="Background Color" type="color" default="transparent"/> <Variable name="date.header.font" description="Text Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="date.header.padding" description="Date Header Padding" type="string" default="inherit"/> <Variable name="date.header.letterspacing" description="Date Header Letter Spacing" type="string" default="inherit"/> <Variable name="date.header.margin" description="Date Header Margin" type="string" default="inherit"/> </Group> <Group description="Post Footer" selector=".post-footer"> <Variable name="post.footer.text.color" description="Text Color" type="color" default="#666666"/> <Variable name="post.footer.background.color" description="Background Color" type="color" default="#f9f9f9"/> <Variable name="post.footer.border.color" description="Shadow Color" type="color" default="#eeeeee"/> </Group> <Group description="Gadgets" selector="h2"> <Variable name="widget.title.font" description="Title Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="widget.title.text.color" description="Title Color" type="color" default="#000000"/> <Variable name="widget.alternate.text.color" description="Alternate Color" type="color" default="#999999"/> </Group> <Group description="Images" selector=".main-inner"> <Variable name="image.background.color" description="Background Color" type="color" default="#ffffff"/> <Variable name="image.border.color" description="Border Color" type="color" default="#eeeeee"/> <Variable name="image.text.color" description="Caption Text Color" type="color" default="#666666"/> </Group> <Group description="Accents" selector=".content-inner"> <Variable name="body.rule.color" description="Separator Line Color" type="color" default="#eeeeee"/> <Variable name="tabs.border.color" description="Tabs Border Color" type="color" default="#ffd343"/> </Group> <Variable name="body.background" description="Body Background" type="background" color="#eeeeee" default="$(color) none repeat scroll top left"/> <Variable name="body.background.override" description="Body Background Override" type="string" default=""/> <Variable name="body.background.gradient.cap" description="Body Gradient Cap" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="body.background.gradient.tile" description="Body Gradient Tile" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/body_gradient_tile_light.png)"/> <Variable name="content.background.color.selector" description="Content Background Color Selector" type="string" default=".content-inner"/> <Variable name="content.padding" description="Content Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.padding.horizontal" description="Content Horizontal Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.shadow.spread" description="Content Shadow Spread" type="length" default="40px" min="0" max="100px"/> <Variable name="content.shadow.spread.webkit" description="Content Shadow Spread (WebKit)" type="length" default="5px" min="0" max="100px"/> <Variable name="content.shadow.spread.ie" description="Content Shadow Spread (IE)" type="length" default="10px" min="0" max="100px"/> <Variable name="main.border.width" description="Main Border Width" type="length" default="0" min="0" max="10px"/> <Variable name="header.background.gradient" description="Header Gradient" type="url" default="none"/> <Variable name="header.shadow.offset.left" description="Header Shadow Offset Left" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.offset.top" description="Header Shadow Offset Top" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.spread" description="Header Shadow Spread" type="length" default="1px" min="0" max="100px"/> <Variable name="header.padding" description="Header Padding" type="length" default="30px" min="0" max="100px"/> <Variable name="header.border.size" description="Header Border Size" type="length" default="1px" min="0" max="10px"/> <Variable name="header.bottom.border.size" description="Header Bottom Border Size" type="length" default="1px" min="0" max="10px"/> <Variable name="header.border.horizontalsize" description="Header Horizontal Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="description.text.size" description="Description Text Size" type="string" default="140%"/> <Variable name="tabs.margin.top" description="Tabs Margin Top" type="length" default="0" min="0" max="100px"/> <Variable name="tabs.margin.side" description="Tabs Side Margin" type="length" default="30px" min="0" max="100px"/> <Variable name="tabs.background.gradient" description="Tabs Background Gradient" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="tabs.border.width" description="Tabs Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="tabs.bevel.border.width" description="Tabs Bevel Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="post.margin.bottom" description="Post Bottom Margin" type="length" default="25px" min="0" max="100px"/> <Variable name="image.border.small.size" description="Image Border Small Size" type="length" default="2px" min="0" max="10px"/> <Variable name="image.border.large.size" description="Image Border Large Size" type="length" default="5px" min="0" max="10px"/> <Variable name="page.width.selector" description="Page Width Selector" type="string" default=".region-inner"/> <Variable name="page.width" description="Page Width" type="string" default="auto"/> <Variable name="main.section.margin" description="Main Section Margin" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding" description="Main Padding" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding.top" description="Main Padding Top" type="length" default="30px" min="0" max="100px"/> <Variable name="main.padding.bottom" description="Main Padding Bottom" type="length" default="30px" min="0" max="100px"/> <Variable name="paging.background" color="#ffffff" description="Background of blog paging area" type="background" default="transparent none no-repeat scroll top center"/> <Variable name="footer.bevel" description="Bevel border length of footer" type="length" default="0" min="0" max="10px"/> <Variable name="mobile.background.overlay" description="Mobile Background Overlay" type="string" default="transparent none repeat scroll top left"/> <Variable name="mobile.background.size" description="Mobile Background Size" type="string" default="auto"/> <Variable name="mobile.button.color" description="Mobile Button Color" type="color" default="#ffffff" /> <Variable name="startSide" description="Side where text starts in blog language" type="automatic" default="left"/> <Variable name="endSide" description="Side where text ends in blog language" type="automatic" default="right"/> */ /* Content ----------------------------------------------- */ body { font: normal normal 12px 'Trebuchet MS', Trebuchet, Verdana, sans-serif; color: #666666; background: #eeeeee none repeat scroll top left; padding: 0 0 0 0; } html body .region-inner { min-width: 0; max-width: 100%; width: auto; } h2 { font-size: 22px; } a:link { text-decoration:none; color: #2b5b84; } a:visited { text-decoration:none; color: #2b5b84; } a:hover { text-decoration:underline; color: #3776ab; } .body-fauxcolumn-outer .fauxcolumn-inner { background: transparent none repeat scroll top left; _background-image: none; } .body-fauxcolumn-outer .cap-top { position: absolute; z-index: 1; height: 400px; width: 100%; } .body-fauxcolumn-outer .cap-top .cap-left { width: 100%; background: transparent none repeat-x scroll top left; _background-image: none; } .content-outer { -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .15); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .15); -goog-ms-box-shadow: 0 0 0 #333333; box-shadow: 0 0 0 rgba(0, 0, 0, .15); margin-bottom: 1px; } .content-inner { padding: 10px 40px; } .content-inner { background-color: #ffffff; } /* Header ----------------------------------------------- */ .header-outer { background: #2b5b84 none repeat-x scroll 0 -400px; _background-image: none; } .Header h1 { font: normal normal 40px 'Trebuchet MS',Trebuchet,Verdana,sans-serif; color: #000000; text-shadow: 0 0 0 rgba(0, 0, 0, .2); } .Header h1 a { color: #000000; } .Header .description { font-size: 18px; color: #ffd343; } .header-inner .Header .titlewrapper { padding: 22px 0; } .header-inner .Header .descriptionwrapper { padding: 0 0; } /* Tabs ----------------------------------------------- */ .tabs-inner .section:first-child { border-top: 0 solid #dddddd; } .tabs-inner .section:first-child ul { margin-top: -1px; border-top: 1px solid #dddddd; border-left: 1px solid #dddddd; border-right: 1px solid #dddddd; } .tabs-inner .widget ul { background: transparent none repeat-x scroll 0 -800px; _background-image: none; border-bottom: 1px solid #dddddd; margin-top: 0; margin-left: -30px; margin-right: -30px; } .tabs-inner .widget li a { display: inline-block; padding: .6em 1em; font: normal normal 12px 'Trebuchet MS', Trebuchet, Verdana, sans-serif; color: #000000; border-left: 1px solid #ffffff; border-right: 1px solid #dddddd; } .tabs-inner .widget li:first-child a { border-left: none; } .tabs-inner .widget li.selected a, .tabs-inner .widget li a:hover { color: #000000; background-color: #eeeeee; text-decoration: none; } /* Columns ----------------------------------------------- */ .main-outer { border-top: 0 solid #ffd343; } .fauxcolumn-left-outer .fauxcolumn-inner { border-right: 1px solid #ffd343; } .fauxcolumn-right-outer .fauxcolumn-inner { border-left: 1px solid #ffd343; } /* Headings ----------------------------------------------- */ div.widget > h2, div.widget h2.title { margin: 0 0 1em 0; font: normal bold 11px 'Trebuchet MS',Trebuchet,Verdana,sans-serif; color: #000000; } /* Widgets ----------------------------------------------- */ .widget .zippy { color: #999999; text-shadow: 2px 2px 1px rgba(0, 0, 0, .1); } .widget .popular-posts ul { list-style: none; } /* Posts ----------------------------------------------- */ h2.date-header { font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; } .date-header span { background-color: #bbbbbb; color: #ffffff; padding: 0.4em; letter-spacing: 3px; margin: inherit; } .main-inner { padding-top: 35px; padding-bottom: 65px; } .main-inner .column-center-inner { padding: 0 0; } .main-inner .column-center-inner .section { margin: 0 1em; } .post { margin: 0 0 45px 0; } h3.post-title, .comments h4 { font: normal normal 22px 'Trebuchet MS',Trebuchet,Verdana,sans-serif; margin: .75em 0 0; } .post-body { font-size: 110%; line-height: 1.4; position: relative; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 2px; background: #ffffff; border: 1px solid #eeeeee; -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body .tr-caption-container { color: #666666; } .post-body .tr-caption-container img { padding: 0; background: transparent; border: none; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .1); box-shadow: 0 0 0 rgba(0, 0, 0, .1); } .post-header { margin: 0 0 1.5em; line-height: 1.6; font-size: 90%; } .post-footer { margin: 20px -2px 0; padding: 5px 10px; color: #666666; background-color: #eeeeee; border-bottom: 1px solid #eeeeee; line-height: 1.6; font-size: 90%; } #comments .comment-author { padding-top: 1.5em; border-top: 1px solid #ffd343; background-position: 0 1.5em; } #comments .comment-author:first-child { padding-top: 0; border-top: none; } .avatar-image-container { margin: .2em 0 0; } #comments .avatar-image-container img { border: 1px solid #eeeeee; } /* Comments ----------------------------------------------- */ .comments .comments-content .icon.blog-author { background-repeat: no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==); } .comments .comments-content .loadmore a { border-top: 1px solid #999999; border-bottom: 1px solid #999999; } .comments .comment-thread.inline-thread { background-color: #eeeeee; } .comments .continue { border-top: 2px solid #999999; } /* Accents ---------------------------------------------- */ .section-columns td.columns-cell { border-left: 1px solid #ffd343; } .blog-pager { background: transparent url(//www.blogblog.com/1kt/simple/paging_dot.png) repeat-x scroll top center; } .blog-pager-older-link, .home-link, .blog-pager-newer-link { background-color: #ffffff; padding: 5px; } .footer-outer { border-top: 1px dashed #bbbbbb; } /* Mobile ----------------------------------------------- */ body.mobile { background-size: auto; } .mobile .body-fauxcolumn-outer { background: transparent none repeat scroll top left; } .mobile .body-fauxcolumn-outer .cap-top { background-size: 100% auto; } .mobile .content-outer { -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .15); box-shadow: 0 0 3px rgba(0, 0, 0, .15); } .mobile .tabs-inner .widget ul { margin-left: 0; margin-right: 0; } .mobile .post { margin: 0; } .mobile .main-inner .column-center-inner .section { margin: 0; } .mobile .date-header span { padding: 0.1em 10px; margin: 0 -10px; } .mobile h3.post-title { margin: 0; } .mobile .blog-pager { background: transparent none no-repeat scroll top center; } .mobile .footer-outer { border-top: none; } .mobile .main-inner, .mobile .footer-inner { background-color: #ffffff; } .mobile-index-contents { color: #666666; } .mobile-link-button { background-color: #2b5b84; } .mobile-link-button a:link, .mobile-link-button a:visited { color: #ffffff; } .mobile .tabs-inner .section:first-child { border-top: none; } .mobile .tabs-inner .PageList .widget-content { background-color: #eeeeee; color: #000000; border-top: 1px solid #dddddd; border-bottom: 1px solid #dddddd; } .mobile .tabs-inner .PageList .widget-content .pagelist-arrow { border-left: 1px solid #dddddd; } --></style> <style id='template-skin-1' type='text/css'><!-- body { min-width: 960px; } .content-outer, .content-fauxcolumn-outer, .region-inner { min-width: 960px; max-width: 960px; _width: 960px; } .main-inner .columns { padding-left: 0; padding-right: 310px; } .main-inner .fauxcolumn-center-outer { left: 0; right: 310px; /* IE6 does not respect left and right together */ _width: expression(this.parentNode.offsetWidth - parseInt("0") - parseInt("310px") + 'px'); } .main-inner .fauxcolumn-left-outer { width: 0; } .main-inner .fauxcolumn-right-outer { width: 310px; } .main-inner .column-left-outer { width: 0; right: 100%; margin-left: -0; } .main-inner .column-right-outer { width: 310px; margin-right: -310px; } #layout { min-width: 0; } #layout .content-outer { min-width: 0; width: 800px; } #layout .region-inner { min-width: 0; width: auto; } body#layout div.add_widget { padding: 8px; } body#layout div.add_widget a { margin-left: 32px; } --></style> <script type='text/javascript'> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-55961911-3', 'auto', 'blogger'); ga('blogger.send', 'pageview'); </script> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=8520&zx=8701fd18-1ad6-4934-b568-398844ff6721' media='none' onload='if(media!='all')media='all'' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=8520&zx=8701fd18-1ad6-4934-b568-398844ff6721' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?display=swap&family=Montserrat"></head> <body class='loading'> <div class='navbar section' id='navbar' name='Navbar'><div class='widget Navbar' data-version='1' id='Navbar1'><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar/8520?origin\x3dhttps://pyfound.blogspot.com', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe" }); } }); </script><script type="text/javascript"> (function() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = '//pagead2.googlesyndication.com/pagead/js/google_top_exp.js'; var head = document.getElementsByTagName('head')[0]; if (head) { head.appendChild(script); }})(); </script> </div></div> <div class='body-fauxcolumns'> <div class='fauxcolumn-outer body-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content'> <div class='content-fauxcolumns'> <div class='fauxcolumn-outer content-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content-outer'> <div class='content-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left content-fauxborder-left'> <div class='fauxborder-right content-fauxborder-right'></div> <div class='content-inner'> <header> <div class='header-outer'> <div class='header-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left header-fauxborder-left'> <div class='fauxborder-right header-fauxborder-right'></div> <div class='region-inner header-inner'> <div class='header section' id='header' name='Header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner'> <a href='https://pyfound.blogspot.com/' style='display: block'> <img alt='Python Software Foundation News' height='82px; ' id='Header1_headerimg' src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD_WIGHsseqGaGnsXVjcNYZ5g6EIb1XoDEmltAoM6Bi6_R9uDS1BPJP9oPJKj1k4I5R8ALUVZZfy4_DLjEDs6i2GxsCDnf3xO5eo54utZQ5E2pyUhtbQGOiiwBrmLU5asONQ/s1600-r/psf-logo.png' style='display: block' width='334px; '/> </a> <div class='descriptionwrapper'> <p class='description'><span>  News from the Python Software Foundation</span></p> </div> </div> </div></div> </div> </div> <div class='header-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </header> <div class='tabs-outer'> <div class='tabs-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left tabs-fauxborder-left'> <div class='fauxborder-right tabs-fauxborder-right'></div> <div class='region-inner tabs-inner'> <div class='tabs no-items section' id='crosscol' name='Cross-Column'></div> <div class='tabs no-items section' id='crosscol-overflow' name='Cross-Column 2'></div> </div> </div> <div class='tabs-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='main-outer'> <div class='main-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left main-fauxborder-left'> <div class='fauxborder-right main-fauxborder-right'></div> <div class='region-inner main-inner'> <div class='columns fauxcolumns'> <div class='fauxcolumn-outer fauxcolumn-center-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-left-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-right-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <!-- corrects IE6 width calculation --> <div class='columns-inner'> <div class='column-center-outer'> <div class='column-center-inner'> <div class='main section' id='main' name='Main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class="date-outer"> <h2 class='date-header'><span>Thursday, May 26, 2022</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHxWC4w8f5Q3EDLpRvRrsnMRNRRJxhhSF-9lKzKWSDfDDjSqfYpS3KEAvrAxps-tFqV8SP1y2xCyjjwzilmNiQj7Wpje9w0Yzhh-qxB8-qCrKYjThgxp-eFtSSL3BIzMgV7DFntVEP0IJ1hmGT9FJTxdWUuuFlFPLcB5RYBqF-JtrkjQko/w400-h199/pycon-jp-assosiation.jpeg' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='1920875822739740199' itemprop='postId'/> <a name='1920875822739740199'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/pycon-jp-association-awarded-psf.html'>PyCon JP Association Awarded the PSF Community Service Award for Q4 2021</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-1920875822739740199' itemprop='description articleBody'> <table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHxWC4w8f5Q3EDLpRvRrsnMRNRRJxhhSF-9lKzKWSDfDDjSqfYpS3KEAvrAxps-tFqV8SP1y2xCyjjwzilmNiQj7Wpje9w0Yzhh-qxB8-qCrKYjThgxp-eFtSSL3BIzMgV7DFntVEP0IJ1hmGT9FJTxdWUuuFlFPLcB5RYBqF-JtrkjQko/s5358/pycon-jp-assosiation.jpeg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2665" data-original-width="5358" height="199" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHxWC4w8f5Q3EDLpRvRrsnMRNRRJxhhSF-9lKzKWSDfDDjSqfYpS3KEAvrAxps-tFqV8SP1y2xCyjjwzilmNiQj7Wpje9w0Yzhh-qxB8-qCrKYjThgxp-eFtSSL3BIzMgV7DFntVEP0IJ1hmGT9FJTxdWUuuFlFPLcB5RYBqF-JtrkjQko/w400-h199/pycon-jp-assosiation.jpeg" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The PyCon JP Association team from left to right. Takayuki, Shunsuke, Jonas, Manabu, Takanori</td></tr></tbody></table><p><br /></p><p>The <a href="https://www.pycon.jp/committee/english.html">PyCon JP Association</a> team was awarded the 2021 Q4 Community Service Award.</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><p style="text-align: justify;"></p><blockquote>RESOLVED, that the Python Software Foundation award the 2021 Q4 Community Service Award to the following members of the PyCon JP Association for their work in organizing local and regional PyCons, the work of monitoring our trademarks, and in particular organizing the "PyCon JP Charity Talks" raising more than $25,000 USD in funds for the PSF: <a href="https://twitter.com/terapyon" target="_blank">Manabu Terada</a>, <a href="https://twitter.com/takanory" target="_blank">Takanori Suzuki</a>, <a href="https://twitter.com/shimizukawa" target="_blank">Takayuki Shimizukawa</a>, <a href="https://twitter.com/koedoyoshida" target="_blank">Shunsuke Yoshida</a>, <a href="https://twitter.com/ojiidotch" target="_blank">Jonas Obrist</a>.</blockquote><p></p></blockquote><p>We interviewed Jonas Obrist on behalf of the PyCon JP Association to learn more about their inspiration, their work with the Python community, and supporting the Python Software Foundation - PSF. <a href="https://twitter.com/pydebb" target="_blank">D茅bora Azevedo</a> also contributed to this article, by sharing more light on the PyCon JP Association's efforts and commitment to the Python community.</p><h3 style="text-align: left;">Jonas Obrist Speaks on the motivation behind the PyCon JP Association</h3><div><b>What inspired the PyCon JP Association team into raising funds to support the PSF?</b></div><div><b><br /></b></div><div>We were inspired to raise funds after reading an announcement by the PSF about <a href="https://pyfound.blogspot.com/2020/09/the-python-software-foundation-re-opens.html" target="_blank">the impact of the pandemic on the foundation and PyCon US</a>. We could of course empathize with the struggle given that we have a similar situation, even if on a much smaller scale.</div><div><br /></div><div>We tried to think of a good way to help and either <a href="https://twitter.com/terapyon" target="_blank">Manabu</a> or <a href="https://twitter.com/takanory" target="_blank">Takanori</a> came up with the idea to host online events with presentations by members of the community with all proceeds going to the PSF. We held two such events so far with over a hundred attendees and even managed to gather some companies and individuals as sponsors. </div><div><br /></div><div>Thanks to the online nature, costs were kept very low and we were able to make a sizeable donation to the PSF, hopefully softening the financial blow of the pandemic a bit.</div><div><br /></div><div><b>How do you think other Python communities can support the PSF?</b></div><div><br /></div><div>I think other communities have various ways to support the PSF depending on each community's situation.</div><div><br /></div><div>We have the fortune to be well established with great support from the wider community and especially local companies, so we were able to make a <a href="https://www.python.org/psf/donations/" target="_blank">direct financial contribution</a>. </div><div><br /></div><div>Not all communities are this fortunate, but I think there are still other ways to contribute.</div><div><br /></div><div>One such way is simply to boost awareness of the Python programming language in the local developer community. ideally, this would eventually lead to companies adopting Python more widely, which in turn could lead to <a href="https://psfmember.org/civicrm/contribute/transact?reset=1&id=37" target="_blank">direct support to the PSF</a>, either via direct donations or support of <a href="https://us.pycon.org/2022/about/what-is-pycon/" target="_blank">PyCon US</a> by these companies.</div><div><br /></div><div>Boosting local communities also leads to more Python developers in general, leading to a broader pool of people who could support the PSF in various ways.</div><div><br /></div><div>The most important thing is for each community to think about what they can do, even if it is just a small thing, given that we owe so much to the PSF.</div><div><br /></div><div><h3>D茅bora Azevedo speaks about the impact and significance of the PyCon JP Association</h3></div><div>One of the things I am most excited about is seeing the PyCon JP Association team receiving this CSA and realizing that the work being done outside the US-Europe countries is acknowledged.</div><div><br /></div><div>PyCon JP association has risen to the financial challenge that the PSF went through due to the pandemic and has organized <a href="https://pyconjp.connpass.com/event/218154/" target="_blank">PyCon JP Charity Talks</a>. Aiming to increase awareness within the industry about the importance of the PSF is so meaningful. The charity talks were initiatives by the PyCon JP association, and it was a significant effort on their part. Their work is such an outstanding work that shouldn't be overlooked.</div><div><br /></div><div>As part of the wider Python community, it warms my heart to see that there are many amazing people worldwide working so we can have a more sustainable Python community.</div><div><br /></div><div>Seeing local communities contributing to the global community, especially regarding this financial aspect, shows that the community feels the need to have different types of work done and understands the importance and impact of each one of them.</div><div><br /></div><div>And, as part of the Diversity and Inclusion workgroup and understanding the impact of seeing people from non-US-based communities being acknowledged for doing the work, it feels like we are being heard.</div><div><br /></div><div>The PyCon JP association's community work is outstanding and I am so grateful to them and for being in a community that values each contribution to its development and growth.</div><div><br /></div><div>The Python Software Foundation congratulates and celebrates the PyCon JP association team - <a href="https://twitter.com/terapyon" target="_blank">Manabu Terada</a>, <a href="https://twitter.com/takanory" target="_blank">Takanori Suzuki</a>, <a href="https://twitter.com/shimizukawa" target="_blank">Takayuki Shimizukawa</a>, <a href="https://twitter.com/koedoyoshida" target="_blank">Shunsuke Yoshida</a>, <a href="https://twitter.com/ojiidotch" target="_blank">Jonas Obrist</a>.</div><div><br /></div><div>You can learn more about making a <a href="https://www.python.org/psf/donations/" target="_blank">donation to the PSF here</a>.</div><div><br /></div><p></p> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/03943153715517080869' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/03943153715517080869' rel='author' title='author profile'> <span itemprop='name'>Charles Freeborn</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/pycon-jp-association-awarded-psf.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/pycon-jp-association-awarded-psf.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-26T15:32:00-04:00'>5/26/2022 03:32:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-988902719'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=1920875822739740199&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> </div></div> <div class="date-outer"> <h2 class='date-header'><span>Wednesday, May 11, 2022</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='8520' itemprop='blogId'/> <meta content='4387924340252607838' itemprop='postId'/> <a name='4387924340252607838'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit.html'>The 2022 Python Language Summit: Lightning talks</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-4387924340252607838' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><p><span>These were a series of short talks, each lasting around five minutes.</span></p><p><span><br /></span></p><p><span><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html">Read the rest of the 2022 Python Language Summit coverage here.</a></span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Lazy imports, with Carl Meyer</span></h2><p><span>Carl Meyer, an engineer at Instagram, presented on a proposal that has since blossomed into </span><a href="https://peps.python.org/pep-0690/" rel="noopener" target="_blank"><span>PEP 690</span></a><span>: lazy imports, a feature that has already been implemented in <a href="https://github.com/facebookincubator/cinder">Cinder</a>, Instagram’s performance-optimised fork of CPython 3.8.</span></p><p><span>What’s a </span><em><span>lazy import</span></em><span>? Meyer explained that the core difference with lazy imports is that the import does not happen until the imported object is referenced.</span></p><h3 class="raw"><span>Examples</span></h3><p><span>In the following Python module, </span><code>spam.py</code><span>, with lazy imports activated, the module </span><code>eggs</code><span> would never in fact be imported since </span><code>eggs</code><span> is never referenced after the import:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="gutter linenumber"><br /></div><div class="code"><span class="hljs-comment"># spam.py</span> <span class="hljs-keyword">import</span> sys <span class="hljs-keyword">import</span> eggs <span class="hljs-keyword">def</span> <span class="hljs-title function_">main</span>(): <span class="hljs-built_in">print</span>(<span class="hljs-string">"Doing some spammy things."</span>) sys.exit(<span class="hljs-number">0</span>) <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>: main() </div><div class="code"><br /></div><div class="code"><br /></div></div></code></pre><p><span>And in </span><em><span>this</span></em><span> Python module, </span><code>ham.py</code><span>, with lazy imports activated, the function </span><code>bacon_function</code><span> </span><em><span>is</span></em><span> imported – but only right at the end of the script, after we’ve completed a for-loop that’s taken a very long time to finish:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><br /><span></span></div><div class="code"><span class="hljs-keyword"># ham.py</span></div><div class="code"><span class="hljs-keyword">import sys</span></div><div class="code"><span class="hljs-keyword">import time</span></div><div class="code"><span class="hljs-keyword">from</span> bacon <span class="hljs-keyword">import</span> bacon_function <span class="hljs-keyword">def</span> <span class="hljs-title function_">main</span>(): <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1_000_000_000</span>): <span class="hljs-built_in">print</span>(<span class="hljs-string">'Doing hammy things'</span>) time.sleep(<span class="hljs-number">1</span>) bacon_function()</div><div class="code"> sys.exit(0) <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>: main() </div><div class="code"><br /></div><div class="code"><br /></div></div></code></pre><p><span>Meyer revealed that the Instagram team’s work on lazy imports had resulted in startup time improvements of up to 70%, memory usage improvements of up to 40%, and the elimination of almost all import cycles within their code base. (This last point will be music to the ears of anybody who has worked on a Python project larger than a few modules.)</span></p><h3 class="raw"><span>Downsides</span></h3><p><span>Meyer also laid out a number of costs to having lazy imports. Lazy imports create the risk that </span><code>ImportError</code><span> (or any other error resulting from an unsuccessful import) could potentially be raised… anywhere. Import side effects could also become “even less predictable than they already weren’t”.</span></p><p><span>Lastly, Meyer noted, “If you’re not careful, your code might implicitly start to require it”. In other words, you might unexpectedly reach a stage where – because your code has been using lazy imports – it now no longer runs without the feature enabled, because your code base has become a huge, tangled mess of cyclic imports.</span></p><h3 class="raw"><span>Where next for lazy imports?</span></h3><p><span>Python users who have opinions either for or against the proposal are encouraged to join </span><a href="https://discuss.python.org/t/pep-690-lazy-imports/" rel="noopener" target="_blank"><span>the discussion on discuss.python.org</span></a><span>.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Python-Dev versus Discourse, with Thomas Wouters</span></h2><p><span>This was less of a talk, and more of an announcement.</span></p><p><span>Historically, if somebody wanted to make a significant change to CPython, they were required to post on <a href="https://mail.python.org/mailman3/lists/python-dev.python.org/">the python-dev mailing list</a>. The Steering Council now views the alternative venue for discussion, </span><a href="http://discuss.python.org" rel="noopener" target="_blank"><span>discuss.python.org</span></a><span>, to be a superior forum in many respects.</span></p><p><span>Thomas Wouters, Core Developer and Steering Council member, said that the Steering Council was planning on loosening the requirements, stated in several places, that emails had to be sent to python-dev in order to make certain changes. Instead, they were hoping that </span><a href="http://discuss.python.org" rel="noopener" target="_blank"><span>discuss.python.org</span></a><span> would become the authoritative discussion forum in the years to come.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Asks from Pyston, with Kevin Modzelewski</span></h2><p><span>Kevin Modzelewski, core developer of the <a href="https://www.pyston.org">Pyston</a> project, gave a short presentation on ways forward for CPython optimisations. Pyston is a performance-oriented fork of CPython 3.8.12.</span></p><p><span>Modzelewski argued that CPython needed better benchmarks; the existing benchmarks on </span><a href="https://github.com/python/pyperformance" rel="noopener" target="_blank"><span>pyperformance</span></a><span> were “not great”. Modzelewski also warned that his “unsubstantiated hunch” was that the <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_2.html?m=1">Faster CPython</a> team had already accomplished “greater than one-half” of the optimisations that could be achieved within the current constraints. Modzelewski encouraged the attendees to consider future optimisations that might cause backwards-incompatible behaviour changes.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Core Development and the PSF, with Thomas Wouters</span></h2><p><span>This was another short announcement from Thomas Wouters on behalf of the Steering Council. After sponsorship from Google providing funding for <a href="https://pyfound.blogspot.com/2021/04/the-psf-is-hiring-developer-in.html">the first ever CPython Developer-In-Residence</a> (<span face="arial, sans-serif" style="color: #202124;">艁</span>ukasz Langa), Meta has provided sponsorship for a second year. The Steering Council also now has sufficient funds to hire a second Developer-In-Residence – and attendees were notified that they were open to the idea of hiring somebody who was not currently a core developer.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>“Forward classes”, with Larry Hastings</span></h2><p><span>Larry Hastings, CPython core developer, gave a brief presentation on a proposal he had </span><a href="https://groups.google.com/g/dev-python/c/AuvirC3UNFU?pli=1" rel="noopener" target="_blank"><span>sent round to the python-dev mailing list</span></a><span> in recent days: a “forward class” declaration that would avoid all issues with two competing </span><code>typing</code><span> PEPs: </span><a href="https://peps.python.org/pep-0563/" rel="noopener" target="_blank"><span>PEP 563</span></a><span> and </span><a href="https://peps.python.org/pep-0649/" rel="noopener" target="_blank"><span>PEP 649</span></a><span>. In brief, the proposed syntax would look something like this:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code"><br /></div><div class="code"><br /></div><div class="code">forward <span class="hljs-keyword">class</span> <span class="hljs-title class_">X</span>() <span class="hljs-keyword">continue</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">X</span>: <span class="hljs-comment"># class body goes here</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, key</span>): self.key = key </div><div class="code"><br /></div><div class="code"><br /></div></div></code></pre><p><span>In theory, according to Hastings, this syntax could avoid </span><a href="https://github.com/samuelcolvin/pydantic/issues/2678" rel="noopener" target="_blank"><span>issues around runtime evaluation of annotations that have plagued PEP 563</span></a><span>, while also circumventing many of </span><a href="https://discuss.python.org/t/finding-edge-cases-for-peps-484-563-and-649-type-annotations/14314" rel="noopener" target="_blank"><span>the edge cases that unexpectedly fail</span></a><span> in a world where PEP 649 is implemented.</span></p><p><span>The idea was in its early stages, and reaction to the proposal was mixed. The next day, at the Typing Summit, there was more enthusiasm voiced for a plan laid out by Carl Meyer for a tweaked version of Hastings’s earlier attempt at solving this problem: </span><a href="https://peps.python.org/pep-0649/" rel="noopener" target="_blank"><span>PEP 649</span></a><span>.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Better fields access, with Samuel Colvin</span></h2><p><span>Samuel Colvin, maintainer of the <a href="https://pydantic-docs.helpmanual.io">Pydantic</a> library, gave a short presentation on a proposal (</span><a href="https://discuss.python.org/t/better-fields-access-and-allowing-a-new-character-at-the-start-of-identifiers/14529" rel="noopener" target="_blank"><span>recently discussed on discuss.python.org</span></a><span>) to reduce name clashes between field names in a subclass, and method names in a base class.</span></p><p><span>The problem is simple. Suppose you’re a maintainer of a library, </span><code>whatever_library</code><span>. You release Version 1 of your library, and one user start to use your library to make classes like the following:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span> <span></span></div><div class="code"><span class="hljs-keyword">from</span> whatever_library <span class="hljs-keyword">import</span> BaseModel <span class="hljs-keyword">class</span> <span class="hljs-title class_">Farmer</span>(<span class="hljs-title class_ inherited__">BaseModel</span>): name: <span class="hljs-built_in">str</span> fields: <span class="hljs-built_in">list</span>[<span class="hljs-built_in">str</span>] </div><div class="code"><br /></div><div class="code"><br /></div></div></code></pre><p><span>Both the user and the maintainer are happy, until the maintainer releases Version 2 of the library. Version 2 adds a method, </span><code>.fields()</code><span> to BaseModel, which will print out all the field names of a subclass. But this creates a name clash with your user’s existing code, wich has </span><code>fields</code><span> as the name of an instance attribute rather than a method.</span></p><p><span>Colvin briefly sketched out an idea for a new way of looking up names that would make it unambiguous whether the name being accessed was a method or attribute.</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="gutter linenumber"><br /></div><div class="gutter linenumber"><br /></div><div class="code"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Farmer</span>(<span class="hljs-title class_ inherited__">BaseModel</span>): $name: <span class="hljs-built_in">str</span> $fields: <span class="hljs-built_in">list</span>[<span class="hljs-built_in">str</span>] farmer = Farmer(name=<span class="hljs-string">'Jones'</span>, fields=[<span class="hljs-string">'meadow'</span>, <span class="hljs-string">'highlands'</span>]) <span class="hljs-built_in">print</span>(farmer.$fields) <span class="hljs-comment"># -> ['meadow', 'highlands']</span> <span class="hljs-built_in">print</span>(farmer.fields()) <span class="hljs-comment"># -> ['name', 'fields']</span> </div></div></code></pre></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T13:40:00-04:00'>5/11/2022 01:40:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=4387924340252607838&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUczmNuNdBhbIdRAeODp2yjmHK-_mcpMWNRI8WTjIXx_1tkgvMgZNGdgEHNr3KGVJTACb0vFLSlZ-U5I8YLXytAFz3tymHxwMYIBDeLzIOY_7F0MjND1qXalKF8xMy5t7-34LOJq1wBxKb9ojSgsa3qXYCeFbB48gtLkv_fOC8xnrv4NY/w400-h226/Achieving%20immortality.png' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='5393695162742528824' itemprop='postId'/> <a name='5393695162742528824'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_11.html'>The 2022 Python Language Summit: Achieving immortality</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5393695162742528824' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><p><span>What does it mean to achieve immortality? At<a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html"> the 2022 Python Language Summit</a>, Eddie Elizondo, an engineer at Instagram, and Eric Snow, CPython core developer, set out to explain just that.</span></p><p><span>Only for Python objects, though. Not for humans. That will have to be another PEP.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Objects in Python, as they currently stand</span></h2><p><span>In Python, as is well known, </span><a href="https://linux.die.net/diveintopython/html/getting_to_know_python/everything_is_an_object.html#d0e4665" rel="noopener" target="_blank"><span>everything is an object</span></a><span>. This means that if you want to calculate even a simple sum, such as </span><code>194 + 3.14</code><span>, the Python interpreter must create two objects: one object of type </span><code>int</code><span> representing the number </span><code>194</code><span>, and another object of type </span><code>float</code><span> representing the number </span><code>3.14</code><span>.</span></p><p><span>All objects in Python maintain a </span><a href="https://docs.python.org/3.6/c-api/intro.html#objects-types-and-reference-counts" rel="noopener" target="_blank"><em><span>reference count</span></em></a><span>: a running total of the number of active references to that object that currently exist in the program. If the reference count of an object drops to 0, the object is eventually destroyed (through a process known as </span><a href="https://devguide.python.org/garbage_collector/" rel="noopener" target="_blank"><em><span>garbage collection</span></em></a><span>). This process ensures that programmers writing Python don’t normally need to concern themselves with manually deleting an object when they’re done with it. Instead, memory is automatically freed up.</span></p><p><span>The need to keep reference counts for all objects (along with a few other mutable fields on all objects) means that there is currently no way of having a “truly immutable” object in Python.</span></p><p><span>This is a distinction that only really applies at the C level. For example, the </span><code>None</code><span> singleton cannot be mutated at runtime at the Python level:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span> <span></span></div><div class="gutter linenumber"><br /></div><div class="code"><span class="hljs-meta">>>> </span><span class="hljs-literal">None</span>.__bool__ = <span class="hljs-keyword">lambda</span> self: <span class="hljs-literal">True</span> Traceback (most recent call last): File <span class="hljs-string">"<stdin>"</span>, line <span class="hljs-number">1</span>, <span class="hljs-keyword">in</span> <module> AttributeError: <span class="hljs-string">'NoneType'</span> <span class="hljs-built_in">object</span> attribute <span class="hljs-string">'__bool__'</span> <span class="hljs-keyword">is</span> read-only </div><div class="code"><br /></div><div class="code"><br /></div></div></code></pre><p><span>However, at the C level, the object representing </span><code>None</code><span> is mutating constantly, as the reference count to the singleton changes constantly.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Immortal objects</span></h2><p><span>An “immortal object”, according to </span><a href="https://peps.python.org/pep-0683/" rel="noopener" target="_blank"><span>PEP 683</span></a><span> (written by Elizondo/Snow), is an object marked by the runtime as being effectively immutable, even at the C level. The reference count for an immortal object will never reach 0; thus, an immortal object will never be garbage-collected, and will never die.</span></p><p><span><br /></span></p><blockquote> <p><span>“The fundamental improvement here is that now an object can be truly immutable.”</span></p> <p><span>– </span><span>Eddie Elizondo and Eric Snow, </span><em>PEP 683</em></p></blockquote><p> </p><p><span>The lack of truly immutable objects in Python, PEP 683 explains, “can have a large negative impact on CPU and memory performance, especially for approaches to increasing Python’s scalability”.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>The benefits of immortality</span></h2><p><span>At their talk at the Python Language Summit, Elizondo and Snow laid out a number of benefits that their proposed changes could bring.</span></p><p><span>Guaranteeing “true memory immutability”, Elizondo explained, “we can simplify and enable larger initiatives,” including Eric Snow’s proposal for a <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html">per-interpreter GIL</a>, but also Sam Gross’s proposal for a version of Python that operates <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html">without the GIL entirely</a>. The proposal could also unlock new optimisation techniques in the future by helping create new ways of thinking about problems in the CPython code base.</span></p><p><span><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUczmNuNdBhbIdRAeODp2yjmHK-_mcpMWNRI8WTjIXx_1tkgvMgZNGdgEHNr3KGVJTACb0vFLSlZ-U5I8YLXytAFz3tymHxwMYIBDeLzIOY_7F0MjND1qXalKF8xMy5t7-34LOJq1wBxKb9ojSgsa3qXYCeFbB48gtLkv_fOC8xnrv4NY/s607/Achieving%20immortality.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="344" data-original-width="607" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUczmNuNdBhbIdRAeODp2yjmHK-_mcpMWNRI8WTjIXx_1tkgvMgZNGdgEHNr3KGVJTACb0vFLSlZ-U5I8YLXytAFz3tymHxwMYIBDeLzIOY_7F0MjND1qXalKF8xMy5t7-34LOJq1wBxKb9ojSgsa3qXYCeFbB48gtLkv_fOC8xnrv4NY/w400-h226/Achieving%20immortality.png" width="400" /></a></div><br /><span><br /></span><p></p><p><br /></p><hr /><h2 class="raw"><span>The costs</span></h2><p><span>A naive implementation of immortal objects is costly, resulting in performance regeressions of around 6%. This is mainly due to adding a new branch of code to the logic keeping track of an object’s reference count.</span></p><p><span>With mitigations, however, Elizondo and Snow explained that the performance regression could be reduced to around 2%. The question they posed to the assembled developers in the audience was whether this was an “acceptable” performance regression – and, if not, what would be?</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Reception</span></h2><p><span>The proposal was greeted with a mix of curious interest and healthy scepticism. There was agreement that certain aspects of the proposal would reach wide support among the community, and consensus that a performance regression of 1-2% would be acceptable if clear benefits could be shown. However, there was also concern that parts of the proposal would change semantics in a backwards-incompatible way.</span></p><p><span>Pablo Galindo Salgado, Release Manager for Python 3.10/3.11 and CPython Core Developer, worried that all the benefits laid out by the speakers were only </span><em><span>potential</span></em><span> benefits, and asked for more specifics. He pointed out that changing the semantics of reference-counting would be likely to break an awful lot of projects, given that popular third-party libraries such as </span><a href="https://numpy.org" rel="noopener" target="_blank"><code>numpy</code></a><span>, for example, use C extensions which continuously check reference counts.</span></p><p><span>Thomas Wouters, CPython Core Developer and Steering Council Member, concurred, saying that it probably “wasn’t possible” to make these changes without changing the </span><a href="https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface" rel="noopener" target="_blank"><span>stable ABI</span></a><span>. Kevin Modzelewski, a maintainer of </span><a href="https://www.pyston.org/" rel="noopener" target="_blank"><span>Pyston</span></a><span>, a performance-oriented fork of Python 3.8, noted that Pyston had had immortal objects for a while – but Pyston had never made any promise to support the stable ABI, freeing the project of that constraint.</span></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_11.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_11.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T13:14:00-04:00'>5/11/2022 01:14:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=5393695162742528824&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2EUCU6ikZiV8w1wuTSN8OBKzR9qCGteSCtRuzvVVvzaVQe8eVL960HTn5j7unO8Bjl2_yRxh8tQmrqw1kVWBb-SH6cdkxpdYZKHBY3Zs-G5wAKbcZ346avXq8UdPztF7dJ7xukMCf1lTzMK6yzi5lRKZMZ4N6IBV7Dc66ZP7IavC9qi4/w400-h226/pyinterpreterstruct%20commit.png' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='3991171560132788018' itemprop='postId'/> <a name='3991171560132788018'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html'>The 2022 Python Language Summit: A per-interpreter GIL</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-3991171560132788018' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><p><span>“Hopefully,” the speaker began, “This is the </span><em><span>last time</span></em><span> I give a talk on this subject.”</span></p><p><span>“My name is Eric Snow, I’ve been a core developer since 2012, and I’ve been working towards a per-interpreter GIL since 2014.”</span></p><p><span><br /></span></p><hr /><p><span>In 1997, the </span><code>PyInterpreterState</code><span> struct </span><a href="https://github.com/python/cpython/commit/a027efa5bfa7911b5c4b522b6a0698749a6f2e4a" rel="noopener" target="_blank"><span>was added to CPython</span></a><span>, allowing multiple Python interpreters to be run simultaneously within a single process. “For the longest time,” Snow noted, speaking at <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html">the 2022 Python Language Summit</a>, this functionality was little used and little understood. In recent years, however, awareness and adoption of the idea has been spreading.</span></p><p><span><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2EUCU6ikZiV8w1wuTSN8OBKzR9qCGteSCtRuzvVVvzaVQe8eVL960HTn5j7unO8Bjl2_yRxh8tQmrqw1kVWBb-SH6cdkxpdYZKHBY3Zs-G5wAKbcZ346avXq8UdPztF7dJ7xukMCf1lTzMK6yzi5lRKZMZ4N6IBV7Dc66ZP7IavC9qi4/s608/pyinterpreterstruct%20commit.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="344" data-original-width="608" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2EUCU6ikZiV8w1wuTSN8OBKzR9qCGteSCtRuzvVVvzaVQe8eVL960HTn5j7unO8Bjl2_yRxh8tQmrqw1kVWBb-SH6cdkxpdYZKHBY3Zs-G5wAKbcZ346avXq8UdPztF7dJ7xukMCf1lTzMK6yzi5lRKZMZ4N6IBV7Dc66ZP7IavC9qi4/w400-h226/pyinterpreterstruct%20commit.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p><span>Multiple interpreters, however, cannot yet be run in true isolation from each other when run inside the same process. Part of this is due to the </span><a href="https://realpython.com/python-gil/" rel="noopener" target="_blank"><span>GIL (“Global Interpreter Lock”)</span></a><span>, a core feature of CPython that is the building block for much of the language. The obvious solution to this problem is to have a </span><em><span>per-interpreter GIL</span></em><span>: a separate lock for each interpreter spawned within the process.</span></p><p><span>With a per-interpreter GIL, Snow explained, CPython will be able to achieve true multicore parallelism for code running in different interpreters.</span></p><p><span>A per-interpreter GIL, however, is no small task. “In general, any mutable state shared between multiple interpreters must be guarded by a lock,” Snow explained. Ultimately, what this means is that the amount of state shared between multiple interpreters must be brought down to an absolute minimum if the GIL is to become per-interpreter. As of 2017, there were still several thousand global variables; now, after a huge amount of work (and </span><a href="https://peps.python.org/pep-0554/" rel="noopener" target="_blank"><span>several</span></a><span> </span><a href="https://peps.python.org/pep-0684/" rel="noopener" target="_blank"><span>PEPs</span></a><span>), this has been reduced to around 1200 remaining globals.</span></p><p style="text-align: center;"><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy15SMZfkahQzCpBxyIV5UGpsu5xiTus0IsavfNsOmndM7vNpQ3zTgq_Wh8PE1mtrADQjlUwrOwIMCJhZgOaXQEsO5F16KpDyy32WoOFwInYA7_PPhtTbBr_f2XqC1Q7G9YXUOrXmQqyeDtvt2ezBpePgvXVVW0brzYSsuGJgIknrKAEg/s608/consolidating%20global%20state.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="344" data-original-width="608" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy15SMZfkahQzCpBxyIV5UGpsu5xiTus0IsavfNsOmndM7vNpQ3zTgq_Wh8PE1mtrADQjlUwrOwIMCJhZgOaXQEsO5F16KpDyy32WoOFwInYA7_PPhtTbBr_f2XqC1Q7G9YXUOrXmQqyeDtvt2ezBpePgvXVVW0brzYSsuGJgIknrKAEg/w400-h226/consolidating%20global%20state.png" width="400" /></a></div><p> </p><blockquote><p><span>“Basically, we can’t share objects between interpreters”</span></p> <p><span>– Eric Snow</span></p></blockquote><p> </p><hr /><h2 class="raw"><span>Troubles on the horizon</span></h2><p><span>The reception to Snow’s talk was positive, but a number of concerns were raised by audience members.</span></p><p><span>One potential worry is the fact that any C-extension module that wishes to be compatible with sub-interpreters will have to make changes to their design. Snow is happy to work on fixing these for the standard library, but there’s concern that end users of Python may put pressure on third-party library maintainers to provide support for multiple interpreters. Nobody wishes to place an undue burden on maintainers who are already giving up their time for free; subinterpreter support should remain an optional feature for third-party libraries.</span></p><p><span>Larry Hastings, a core developer in the audience for the talk, asked Snow what exactly the benefits of subinterpreters were compared to the existing </span><code><a href="https://docs.python.org/3/library/multiprocessing.html">multiprocessing</a></code><span><a href="https://docs.python.org/3/library/multiprocessing.html"> module</a> (allowing interpreters to be spawned in parallel processes), if sharing objects between the different interpreters would pose so many difficulties. Subinterpreters, Snow explained, hold significant speed benefits over </span><code>multiprocessing</code><span> in many respects.</span></p><p><span>Hastings also queried how well the idea of a per-interpreter GIL would interact with Sam Gross’s proposal for a version of CPython that <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html">removed the GIL entirely</a>. Snow replied that there was minimal friction between the two projects. “They’re not mutually exclusive,” he explained. Almost all the work required for a per-interpreter GIL “is stuff that’s a good idea to do anyway. It’s already making CPython faster by consolidating memory”.</span></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T13:13:00-04:00'>5/11/2022 01:13:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=3991171560132788018&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXVrvjIV5Pg-7vBlGzGgVYFJAygQ2a8qe9LXiaDwLzouLJMBbHUvl6E-XR9dLV-RbeflF7YA4C61vlgWKUpHHwfe-TiAixTknVfw2TdrUGN6RpGo6bO9aM19Rc42si-dQtuaCQF_QSZVfvOqSxOvjnwjUhe6P3jx-hWFNKt9W8NXGrHTY/w400-h228/Compiling%20to%20WASM.png' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='8071818437441379382' itemprop='postId'/> <a name='8071818437441379382'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python.html'>The 2022 Python Language Summit: Python in the browser</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-8071818437441379382' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><p><span>Python can be run on many platforms: Linux, Windows, Apple Macs, microcomputers, and even Android devices. But it’s a widely known fact that, if you want code to run in a browser, Python is simply no good – you’ll just have to turn to JavaScript.</span></p><p><span>Now, however, that may be about to change. Over the course of the last two years, and following over 60 CPython pull requests (many attached to GitHub issue </span><a href="https://github.com/python/cpython/issues/84461" rel="noopener" target="_blank"><span>#84461</span></a><span>), Core Developer Christian Heimes and contributor Ethan Smith have achieved a state where the CPython </span><code>main</code><span> branch can now be compiled to </span><a href="https://webassembly.org" rel="noopener" target="_blank"><span>WebAssembly</span></a><span>. This opens up the possibility of being able to run arbitrary Python programs clientside inside your web browser of choice.</span></p><p><span>At <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html">the 2022 Python Language Summit</a>, Heimes gave a talk updating the attendees of the progress he’s made so far, and where the project hopes to go next.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>WebAssembly basics</span></h2><p><span>WebAssembly (or “WASM”, for short), Heimes explained, is a low-level </span><a href="https://en.wikipedia.org/wiki/Assembly_language" rel="noopener" target="_blank"><span>assembly</span></a><span>-like language that can be as fast as native </span><a href="https://en.wikipedia.org/wiki/Machine_code" rel="noopener" target="_blank"><span>machine code</span></a><span>. Unlike your usual machine code, however, WebAssembly is independent from the machine it is running on. Instead, the core principle of WebAssembly is that it can be run </span><em><span>anywhere</span></em><span>, and can be run in a completely isolated environment. This leads to it being a language that is extremely fast, extremely portable, and provides minimal security risks – perfect for running clientside in a web browser.</span></p><p><span><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXVrvjIV5Pg-7vBlGzGgVYFJAygQ2a8qe9LXiaDwLzouLJMBbHUvl6E-XR9dLV-RbeflF7YA4C61vlgWKUpHHwfe-TiAixTknVfw2TdrUGN6RpGo6bO9aM19Rc42si-dQtuaCQF_QSZVfvOqSxOvjnwjUhe6P3jx-hWFNKt9W8NXGrHTY/s1105/Compiling%20to%20WASM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="628" data-original-width="1105" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXVrvjIV5Pg-7vBlGzGgVYFJAygQ2a8qe9LXiaDwLzouLJMBbHUvl6E-XR9dLV-RbeflF7YA4C61vlgWKUpHHwfe-TiAixTknVfw2TdrUGN6RpGo6bO9aM19Rc42si-dQtuaCQF_QSZVfvOqSxOvjnwjUhe6P3jx-hWFNKt9W8NXGrHTY/w400-h228/Compiling%20to%20WASM.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe_WC6ibKEMkQQTAkyJS-0N47L2GyZblm64gZnymQCFOagjRHYRStW4041pWZgXp2tR1djK4VOAFfOTUueHVyIsBrolUdprqRwMkRiMBFawhPYNdPdEQrOmnviIs06twY4QwQAygSr5Jz5OhovG1Bm3_pyqp_QOBJDloDS-luIQDrARwc/s1102/What%20is%20WASM.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="626" data-original-width="1102" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe_WC6ibKEMkQQTAkyJS-0N47L2GyZblm64gZnymQCFOagjRHYRStW4041pWZgXp2tR1djK4VOAFfOTUueHVyIsBrolUdprqRwMkRiMBFawhPYNdPdEQrOmnviIs06twY4QwQAygSr5Jz5OhovG1Bm3_pyqp_QOBJDloDS-luIQDrARwc/w400-h228/What%20is%20WASM.png" width="400" /></a></div><br /><span><br /></span><p></p><p><span>After much work, CPython now cross-compiles to WebAssembly using <a href="https://emscripten.org/">emscripten</a> through the </span><code>--with-emscripten-target=browser</code><span> flag. The CPython test suite now also passes on emscripten builds, and work is going towards adding a buildbot to CPython’s fleet of automatic robot testers, to ensure this work does not regress in the future.</span></p><p><span>Users who want to try out Python in the browser can try it out at </span><a href="https://repl.ethanhs.me/" rel="noopener" target="_blank"><span>https://repl.ethanhs.me/</span></a><span>. The work opens up exciting possibilities of being able to run PyGame clientside and adding Jupyter bindings.</span></p><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOQOZPEsaISXhU9KzTBRipRUEbfLFnqjscGY5k7zDIVBJEh95lEXAc0mMRVgur-Ddy0YSPKR704GIxMvQFG_Z9dJG-qIgJ2PuDT7_B8g26p3GUYlb-M-ATRy6SbD8O0j9qgI2C-mvGwpMCqtKZzVUI3dsbngkw-Teo-WKfoFvBLTAcJYk/s1098/Small%20demo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="623" data-original-width="1098" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOQOZPEsaISXhU9KzTBRipRUEbfLFnqjscGY5k7zDIVBJEh95lEXAc0mMRVgur-Ddy0YSPKR704GIxMvQFG_Z9dJG-qIgJ2PuDT7_B8g26p3GUYlb-M-ATRy6SbD8O0j9qgI2C-mvGwpMCqtKZzVUI3dsbngkw-Teo-WKfoFvBLTAcJYk/w400-h228/Small%20demo.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8iEqr-gFtnHybO7OJ01jeRmjvKy1kQqGt-j6-JVSvmaKvnUu4ZA07rKe5h36lBQ9Tg2eSYUWFuF4t679ZqVvkyECAcp6swAw1R6R-8IfHObWIQZ9tMfo0-z2BmyvQRmiEMJpBqI3xY4etjZhSGI5Na0d7CrErhtKpL_2dE-8X49fOGQ8/s1121/PyGame%20demo.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="636" data-original-width="1121" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8iEqr-gFtnHybO7OJ01jeRmjvKy1kQqGt-j6-JVSvmaKvnUu4ZA07rKe5h36lBQ9Tg2eSYUWFuF4t679ZqVvkyECAcp6swAw1R6R-8IfHObWIQZ9tMfo0-z2BmyvQRmiEMJpBqI3xY4etjZhSGI5Na0d7CrErhtKpL_2dE-8X49fOGQ8/w400-h228/PyGame%20demo.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p></p><hr /><h2 class="raw"><span>Support status</span></h2><p><span>It should be noted that cross-compiling to WebAssembly is still highly experimental, and not yet officially supported by CPython. Several important modules in the Python standard library are not currently included in the bundled package produced when </span><code>--with-emscripten-target=browser</code><span> is specified, leading to a number of tests needing to be skipped in order for the test suite to pass.</span></p><p><span><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6FiL8GyoOOZjbf5Riz36cJPg_E_MwFlAd5Ey7i8pp0xmfwI6bBSfB1WqMleeGPB-Xm2NROCUk5umsw0dAEHnWEwEZ56E39RzPtAgE7Z9VoTYMTQaCcCsEBisx0yAur_oW17UeO6PNUV_ahNZ-HzR-1whlZ0JC_nmiaZj4i8SkVK1RJMU/s1102/Support%20status.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="623" data-original-width="1102" height="226" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6FiL8GyoOOZjbf5Riz36cJPg_E_MwFlAd5Ey7i8pp0xmfwI6bBSfB1WqMleeGPB-Xm2NROCUk5umsw0dAEHnWEwEZ56E39RzPtAgE7Z9VoTYMTQaCcCsEBisx0yAur_oW17UeO6PNUV_ahNZ-HzR-1whlZ0JC_nmiaZj4i8SkVK1RJMU/w400-h226/Support%20status.png" width="400" /></a></div><br /><p style="text-align: center;"><br /></p><p><span>Nonetheless, the future’s bright. Only a few days after Heimes’s talk, Peter Wang, CEO at Anaconda, announced the launch of </span><a href="https://anaconda.cloud/pyscript-python-in-the-browser" rel="noopener" target="_blank"><em><span>PyScript</span></em></a><span> in a <a href="https://anaconda.cloud/pyscript-pycon2022-peter-wang-keynote">PyCon keynote address</a>. PyScript is a tool that allows Python to be called from within HTML, and to call JavaScript libraries from inside Python code – potentially enabling a website to be written entirely in Python.</span></p><p><span>PyScript is currently built on top of </span><a href="https://pyodide.org/en/stable/" rel="noopener" target="_blank"><em><span>Pyodide</span></em></a><span>, a third-party project bringing Python to the browser, on which work began before Heimes started his work on the CPython </span><code>main</code><span> branch. With Heimes’s modifications to Python 3.11, this effort will only become easier.</span></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T13:11:00-04:00'>5/11/2022 01:11:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=8071818437441379382&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='8520' itemprop='blogId'/> <meta content='5147535327834720965' itemprop='postId'/> <a name='5147535327834720965'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_2.html'>The 2022 Python Language Summit: Performance Improvements by the Faster CPython team</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5147535327834720965' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><p><span>Python 3.11, if you haven’t heard, is fast. Over the past year, Microsoft has </span><a href="https://developers.slashdot.org/story/21/05/17/0225252/microsoft-funds-a-team-with-guido-van-rossum-to-double-the-speed-of-python" rel="noopener" target="_blank"><span>funded a team</span></a><span> – led by core developers Mark Shannon and Guido van Rossum – to work full-time on making CPython faster. With additional funding from Bloomberg, and help from a wide range of other contributors from the community, </span><a href="https://docs.python.org/3.11/whatsnew/3.11.html#faster-cpython" rel="noopener" target="_blank"><span>the results have borne fruit</span></a><span>. On the pyperformance benchmarks </span><a href="https://github.com/faster-cpython/ideas/blob/main/main-vs-310.rst" rel="noopener" target="_blank"><span>at the time of the beta release</span></a><span>, Python 3.11 was around 1.25x faster than Python 3.10, a phenomenal achievement.</span></p><p><span>But there is more still to be done. At <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html">the 2022 Python Language Summit</a>, Mark Shannon presented on where the Faster CPython project aims to go next. The future’s fast.</span></p><p><span><br /></span></p><hr /><p><span>The first problem Shannon raised was a problem of measurements. In order to know how to make Python faster, we need to know how slow Python is currently. But how slow at doing </span><em><span>what</span></em><span>, exactly?</span></p><p><span>Good benchmarks are vital for a project that aims to optimise Python for general usage. For that, the Faster CPython team needs the help of the community at large. The project “needs more benchmarks,” Shannon said – it needs to understand more precisely what the user base at large is using Python for, how they’re doing it, and what makes it slow at the moment (if it is slow!).</span></p><p><span>A benchmark, Shannon explained, is “just a program that we can time”. Anybody with a benchmark – or even just a suggestion for a benchmark! – that they believe is representative of a larger project they’re working on is invited to submit them to the issue tracker at the </span><a href="https://github.com/python/pyperformance/issues" rel="noopener" target="_blank"><span>python/pyperformance repository</span></a><span> on GitHub.</span></p><p><span><br /></span></p><hr /><p><span>Nonetheless, the Faster CPython team has plenty to be getting on with in the meantime.</span></p><p><span>Much of the optimisation work in 3.11 has been achieved through the implementation of </span><a href="https://peps.python.org/pep-0659/" rel="noopener" target="_blank"><span>PEP 659</span></a><span>, a “specializing adaptive interpreter”. The adaptive interpreter that Shannon and his team have introduced tracks individual bytecodes at various points in a program’s execution. When it spots an opportunity, a bytecode may be “quickened”: this means that a slow bytecode, that can do many things, is replaced by the interpreter with a more specialised bytecode that is very good at doing one specific thing. The work on PEP 659 has now largely been done, but major parts, such as dynamic specialisations of for-loops and binary operations, are still to be completed.</span></p><p><span>Shannon noted that Python also has essentially the same memory consumption in 3.11 as it did in 3.10. This is something he’d like to work on: a smaller memory overhead generally means fewer <a href="https://docs.python.org/3.6/c-api/intro.html#objects-types-and-reference-counts">reference-counting</a> operations in the virtual machine, a lower <a href="https://devguide.python.org/garbage_collector/">garbage-collection</a> overhead, and smoother performance as a result of it all.</span></p><p><span>Another big remaining avenue for optimisations is the question of C extensions. CPython’s easy interface with C is its major advantage over other Python implementations such as <a href="https://www.pypy.org/">PyPy</a>, where incompatibilities with C extensions are one of the biggest hurdles for adoption by users. The optimisation work that has been done in CPython 3.11 has largely ignored the question of extension modules, but Shannon now wants to open up the possibility of exposing low-level function APIs to the virtual machine, reducing the overhead time of communicating between Python code and C code.</span></p><h2 class="raw"><br /><hr style="font-size: medium; font-weight: 400;" /></h2><h2 class="raw"><span>Is that a JIT I see on the horizon?</span></h2><p><span>Lastly, but certainly not least, Shannon said, “everybody wants a JIT compiler… even if it doesn’t make sense yet”.</span></p><p><span>A JIT (“just-in-time”) compiler is the name given for a compiler that dynamically detects where performance bottlenecks exist in a program as the program is running. Once these bottlenecks have been identified, the JIT compiles these parts of the program on-the-fly into native <a href="https://en.wikipedia.org/wiki/Machine_code">machine code</a> in order to speed things up. It’s a similar idea to Shannon’s PEP 659, but goes much further, since the specialising adaptive interpreter never goes beyond the bytecode level.</span></p><p><span>The idea of using a JIT compiler for Python is hardly new. <a href="https://www.pypy.org">PyPy</a>’s JIT compiler is the major source of the large performance gains the project has over CPython in some areas. Third-party projects, such as </span><a href="https://github.com/tonybaloney/Pyjion" rel="noopener" target="_blank"><span>pyjion</span></a><span> and </span><a href="https://github.com/numba/numba" rel="noopener" target="_blank"><span>numba</span></a><span>, bring just-in-time compilation to CPython that’s just a </span><code>pip install</code><span> away. Integrating a JIT into the core of CPython, however, would be materially different.</span></p><p><span>Shannon has historically voiced scepticism about the wisdom of introducing a JIT compiler into CPython itself, and said that work on introducing one is still some way off. A JIT, according to Shannon, will probably not arrive until 3.13 at the earliest, given the amount of lower-hanging fruit that is still to be worked on. The first step towards a JIT, he explained, would be to implement a </span><em><span>trace interpreter</span></em><span>, which would allow for better testing of concepts and lay the groundwork for future changes.</span></p><p><span><br /></span></p><p><span></span></p><hr /><h2 class="raw"><span>Playing nicely with the other Python projects</span></h2><p><span>The gains Shannon’s team has achieved are hugely impressive, and likely to benefit the community as a whole in a profound way. But various problems lie on the horizon. Sam Gross’s <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html">proposal for a version of CPython without the Global Interpreter Lock</a> (the </span><code>nogil</code><span> fork) has potential for speeding up multithreaded Python code in very different ways to the Faster CPython team’s work – but it could also be problematic for some of the optimisations that have already been implemented, many of which assume that the GIL exists. Eric Snow’s <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html">dream of achieving multiple subinterpreters within a single process</a>, meanwhile, will have a smaller performance impact on single-threaded code compared to <code>nogil</code>, but could still create some minor complications for Shannon’s team.</span></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_2.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_2.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T13:09:00-04:00'>5/11/2022 01:09:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=5147535327834720965&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://i.imgur.com/TnMpocv.png' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='6085994158078700604' itemprop='postId'/> <a name='6085994158078700604'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_60.html'>The 2022 Python Language Summit: Upstreaming optimisations from Cinder</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-6085994158078700604' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><p><span>In May 2021, the team at Instagram made waves in the world of Python by open-sourcing </span><a href="https://github.com/facebookincubator/cinder" rel="noopener" target="_blank"><span>Cinder, a performance-oriented fork of CPython</span></a><span>.</span></p><p><span>Cinder is a version of CPython 3.8 with a ton of optimisations added to improve speed across a wide range of metrics, including “eager evaluation of coroutines”, a <a href="https://engineering.fb.com/2022/05/02/open-source/cinder-jits-instagram/">just-in-time compiler</a>, and an “experimental bytecode compiler” that makes use of <a href="https://peps.python.org/pep-0484/">PEP 484</a> </span><a href="https://docs.python.org/3/library/typing.html" rel="noopener" target="_blank"><span>type annotations</span></a><span>.</span></p><p><span>Now, the engineers behind Cinder are looking to upstream many of these changes so that CPython itself can benefit from these optimisations. At<a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html"> the 2022 Python Language Summit</a>, Itamar Ostricher, an engineer at Instagram, presented on Cinder’s optimisations relating to async tasks and coroutines.</span></p><p><span><br /></span></p><hr /><h2 data-id="Asyncio-refresher" id="Asyncio-refresher"><span>Asyncio refresher</span></h2><p><span>Consider the following (contrived) example. Here, we have a function, </span><code>IO_bound_function</code><span>, which is dependent on some kind of external input in order to finish what it’s doing (for example, this might be a web request, or an attempt to read from a file, etc.). We also have another function, </span><code>important_other_task</code><span>, which we want to be run in the same event loop as </span><code>IO_bound_function</code></p><pre><code class="python hljs"><div class="wrapper"> <div class="code"><span class="hljs-keyword">import</span> asyncio <span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">IO_bound_function</span>(): <span class="hljs-string">"""This function could finish immediately... or not!"""</span> <span class="hljs-comment"># Body of this function here</span> <span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">important_other_task</span>(): <span class="hljs-keyword">await</span> asyncio.sleep(<span class="hljs-number">5</span>) <span class="hljs-built_in">print</span>(<span class="hljs-string">'Task done!'</span>) <span class="hljs-keyword">async</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">main</span>(): <span class="hljs-keyword">await</span> asyncio.gather( IO_bound_function(), important_other_task() ) <span class="hljs-built_in">print</span>(<span class="hljs-string">"All done!"</span>) <span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>: asyncio.run(main) </div><div class="code"><br /></div></div></code></pre><p><code>IO_bound_function</code><span> could take a long time to complete – but it could also complete immediately. In an asynchronous programming paradigm, we want to ensure that if it takes a long time to complete, the function doesn’t hold up the rest of the program. Instead, </span><code>IO_bound_function</code><span> will yield execution to the other thing scheduled in the event loop, </span><code>important_other_task</code><span>, letting this coroutine take control of execution for a period.</span></p><p><span>So far so good – but what if </span><code>IO_bound_function</code><span> finishes what it’s doing immediately? In that eventuality, we’re creating a coroutine object for no reason at all, since the coroutine will never have to suspend execution and will never have to reclaim control of the event loop at any future point in time.</span></p><p><span><br /></span></p><p><span></span></p><hr /><h2 data-id="Call-me-maybe" id="Call-me-maybe"><a href="https://www.youtube.com/watch?v=fWNaR-rxAic" rel="noopener" target="_blank"><span>Call me maybe?</span></a></h2><p><span>The team at Instagram saw this as an optimisation opportunity. At the “heart” of many of their async-specific improvements, Itamar explained, is an extension to Python’s </span><a href="https://docs.python.org/3/c-api/call.html#the-vectorcall-protocol" rel="noopener" target="_blank"><span>vectorcall protocol</span></a><span>: a new </span><code>_Py_AWAITED_CALL_MARKER</code><span> flag, which enables a callee to know that a call is being awaited by a caller.</span></p><p><span><br /></span></p><p style="text-align: center;"><img height="149" loading="lazy" src="https://i.imgur.com/TnMpocv.png" width="400" /></p><p><span><br /></span></p><p><span>The addition of this flag means that <a href="https://docs.python.org/3/glossary.html#term-awaitable">awaitables</a> can sometimes be </span><em><span>eagerly evaluated</span></em><span>, and coroutine objects often do not need to be constructed at all.</span></p><p><span><br /></span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhAcfwuy6nDewCEqg0CVeiNrntoJtCMbdd8jc_SA1HMpI4IoFuiqb-cM4l1gmrKU5F8r3z4lkp50iDJ_P-2OJgDgQV1QGqEPSCif43BSlKPl_SST00pm7ApSLGvP4iC7WiV82V5FJ8JjcRuluJW-pZfCQ-9kuQxoue4yU5uXAmSmrPZPFc" style="margin-left: 1em; margin-right: 1em;"><img data-original-height="540" data-original-width="960" height="225" src="https://blogger.googleusercontent.com/img/a/AVvXsEhAcfwuy6nDewCEqg0CVeiNrntoJtCMbdd8jc_SA1HMpI4IoFuiqb-cM4l1gmrKU5F8r3z4lkp50iDJ_P-2OJgDgQV1QGqEPSCif43BSlKPl_SST00pm7ApSLGvP4iC7WiV82V5FJ8JjcRuluJW-pZfCQ-9kuQxoue4yU5uXAmSmrPZPFc=w400-h225" width="400" /></a></div><br /><br /><p></p><p>Ostricher reported that Instagram had seen performance gains of around 5% in their async-heavy workloads as a result of this optimisation.</p><p><br /></p><hr /><h2 data-id="Pending-questions" id="Pending-questions"><span>Pending questions</span></h2><p><span>Significant questions remain about whether these optimisations can be merged into the </span><code>main</code><span> branch of CPython, however. Firstly, exact performance numbers are hard to come by: the benchmark Ostricher presented does not isolate Cinder’s async-specific optimisations.</span></p><p><span>More important might be the issue of </span><em><span>fairness</span></em><span>. If some awaitables in an event loop are eagerly evaluated, this might change the effective priorities in an event loop, potentially creating backwards-incompatible changes with CPython’s current behaviour.</span></p><p><span>Lastly, there are open questions about whether this conflicts with a big change to </span><code>asyncio</code><span> that has just been made in Python 3.11: the introduction of </span><em><span><a href="https://github.com/python/cpython/issues/90908">task groups</a></span></em><span>. Task groups – a concept similar to </span><a href="https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/" rel="noopener" target="_blank"><span>“nurseries”</span></a><span> in </span><em><span><a href="https://trio.readthedocs.io/en/stable/">Trio</a></span></em><span>, a popular third-party async framework – are a <a href="https://realpython.com/python311-exception-groups/#asynchronous-task-groups-in-python-311">major evolution</a> in </span><code>asyncio</code><span>’s API. But “it’s not completely clear how the Cinder optimisations might apply to Task Groups,” Ostricher noted.</span></p><p><span>Ostricher’s talk was well received by the audience, but it was agreed that discussion with the maintainers of other async frameworks such as </span><em><span>Trio</span></em><span> was essential in order to move forward. Guido van Rossum, creator of Python, opined that he could “get over the fairness issue”. The issue of compatibility with task groups, however, may prove more complicated.</span></p><p><span>Given the newness of task groups in </span><code>asyncio</code><span>, there remains a high degree of uncertainty as to how this feature will be used by end users. Without knowing the potential use cases, it is hard to comment on whether and how optimisations can be made in this area.</span></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_60.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_60.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T13:03:00-04:00'>5/11/2022 01:03:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=6085994158078700604&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-qmK_xOXbhlof7e04ZTSpKQcOoIe4ZYuFTwQzt2t10lEzZrbhkLpuc6nrTlN6hlGBm9724wQj6swRxPSG0ZrleuJbn8UNsepWvdJ3gg2rFWo-dNJMvkPGqkCyDWR6f398kkaHCbW9uxFOF9X5_HAgKJsMWPBnru27a1U5UYCNa5FUS3I/w400-h330/Picture2.png' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='6040691758423529930' itemprop='postId'/> <a name='6040691758423529930'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-f.html'>The 2022 Python Language Summit: F-Strings in the grammar</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-6040691758423529930' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><p><span><a href="https://realpython.com/python-f-strings/">Formatted string literals</a>, known as “f-strings” for short, were first introduced in Python 3.6 via </span><a href="https://peps.python.org/pep-0498/" rel="noopener" target="_blank"><span>PEP 498</span></a><span>. Since then, they’ve swiftly become one of the most popular features of modern Python.</span></p><p><span>At <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html">the 2022 Python Language Summit</a>, Pablo Galindo Salgado presented on exciting new possibilities for improving the implementation of f-strings by incorporating f-string parsing into the grammar of Python itself.</span></p><p><span style="font-size: xx-small;"><br /></span></p><hr /><h2 class="raw">F-strings: the current situation</h2><p><span>Here’s the f-string we all know and love:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code"><span class="hljs-string">f"Interpolating an arbitrary expression into a string: <span class="hljs-subst">{<span class="hljs-number">1</span> + <span class="hljs-number">1</span>}</span>."</span> </div></div></code></pre><p><span>At runtime, the expression between the braces will be evaluated (the result’s </span><code>2</code><span>, for those wondering). </span><code>str()</code><span> will then be called on the result of the evaluated expression, and the result of </span><em><span>that</span></em><span> will then be interpolated into the string at the desired place.</span></p><p><span>The following diagram summarises the code behind this runtime magic:</span></p><p><span><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-qmK_xOXbhlof7e04ZTSpKQcOoIe4ZYuFTwQzt2t10lEzZrbhkLpuc6nrTlN6hlGBm9724wQj6swRxPSG0ZrleuJbn8UNsepWvdJ3gg2rFWo-dNJMvkPGqkCyDWR6f398kkaHCbW9uxFOF9X5_HAgKJsMWPBnru27a1U5UYCNa5FUS3I/s683/Picture2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="563" data-original-width="683" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-qmK_xOXbhlof7e04ZTSpKQcOoIe4ZYuFTwQzt2t10lEzZrbhkLpuc6nrTlN6hlGBm9724wQj6swRxPSG0ZrleuJbn8UNsepWvdJ3gg2rFWo-dNJMvkPGqkCyDWR6f398kkaHCbW9uxFOF9X5_HAgKJsMWPBnru27a1U5UYCNa5FUS3I/w400-h330/Picture2.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p><span>That’s right: the current implementation for f-strings relies on “around 1,400 lines of manually written parser code in C”. This is </span><em><span>entirely separate</span></em><span> to the parsing logic that exists elsewhere for deconstructing all other Python code.</span></p><p><span>According to Salgado, while this code has now been extensively battle-tested, it is still ridden with tiny bugs. The complexity of the code here also makes it very difficult to make changes to the code without introducing </span><em><span>new</span></em><span> bugs, which in turn makes it hard to work on improving error messages – a </span><a href="https://docs.python.org/3/whatsnew/3.10.html#better-error-messages" rel="noopener" target="_blank"><span>major goal of Salgado’s</span></a><span> over recent years.</span></p><p><span><br /></span></p><blockquote> <p><span>“The technical term for this is </span><em><span>not ideal</span></em><span>”</span></p> <p><span>– Pablo Galindo Salgado, on the current state of f-string parsing</span></p></blockquote><p><br /></p><hr /><h2 class="raw">What the <code>f</code>?</h2><p><span>How do we know that an f-string is an f-string? “As humans,” Salgado noted, we know an f-string is an f-string “because the string starts with </span><code>f</code><span>”.</span></p><p><span>Sadly, CPython’s parser is not yet quite as smart. The parser, currently, does not have the wherewithal to distinguish f-strings from other strings. Instead, when parsing f-strings, the interpreter does the following dance:</span></p><p><span><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXpT-JsqSaT0MGYiFotckz1KWs7EWo7wPSdtb-4iQjhPdDjN5ZPyuRGAvHtNe4Cg8LBNWFqsdnyEOkN6wgDYeQW3zKcbCDCNjgWZwQn_9q4wYANNsON598m93z4oUUDjG_sKOOanjTWaqfk-9TDjVFQ_x2jagKOSkynDBu6PowJLVRl68/s960/Memray%20lightning%20talk.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="960" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXpT-JsqSaT0MGYiFotckz1KWs7EWo7wPSdtb-4iQjhPdDjN5ZPyuRGAvHtNe4Cg8LBNWFqsdnyEOkN6wgDYeQW3zKcbCDCNjgWZwQn_9q4wYANNsON598m93z4oUUDjG_sKOOanjTWaqfk-9TDjVFQ_x2jagKOSkynDBu6PowJLVRl68/w400-h225/Memray%20lightning%20talk.png" width="400" /></a></div><p><br /></p><p><span>Since Python 3.9, however, CPython is equipped with a </span><a href="https://peps.python.org/pep-0617/" rel="noopener" target="_blank"><span>shiny new PEG parser</span></a><span>, which can be taught all sorts of advanced and complicated things. Salgado now proposes to move f-string parsing logic from the dedicated C file into CPython’s formal grammar, enabling f-string parsing to happen at the same time as the parsing for the rest of a Python file.</span></p><p><span>Salgado, along with others who are working on the project with him, is currently working on fixing “89876787698 tiny error message differences”, explaining, “This is the hard part. We need feedback – we need to know if it’s actually worth doing at this point.”</span></p><p><span>Eric V. Smith, the creator of f-strings, and a member of the audience for the talk, is a strong supporter of the project. Smith explained that the original design had been chosen due to a desire to make life simple for code editor tools such as </span><a href="https://www.redhat.com/en/topics/middleware/what-is-ide">IDEs</a>, which might have struggled to parse f-strings if this design had been chosen initially. But he had been "surprised", he said, at how well Salgado's proposal had been received among the authors of these tools when he had recently sought feedback on it.</p><p><span>Smith plans to continue gathering feedback from IDE maintainers over the coming months.</span></p><p><span><br /></span></p><p><span></span></p><hr /><h2 class="raw"><span>Potential benefits</span></h2><p><span>As well as simplifying the code and making it more maintainable, moving f-string parsing into the grammar holds a number of exciting (and/or horrifying) possibilities. For example, this is just about the maximum level of f-string nesting you can currently achieve in Python:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span></div><div class="code"><span class="hljs-string">f"""a<span class="hljs-subst">{<span class="hljs-string">f'''b<span class="hljs-subst">{<span class="hljs-string">f"c<span class="hljs-subst">{<span class="hljs-string">f'd <span class="hljs-subst">{<span class="hljs-number">1</span>+<span class="hljs-number">2</span>=}</span>'</span>}</span>"</span>}</span>'''</span>}</span>"""</span> </div></div></code></pre><p><span>But with f-strings in the grammar… the possibilities are endless.</span></p><p><span>On a more serious note, Salgado noted that the following is a common source of frustration for Python developers:</span></p><pre><code class="python hljs"><div class="wrapper"><div class="gutter linenumber"><span></span> <span></span></div><div class="code"><span class="hljs-meta">>>> </span>my_list_of_strings = [<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'c'</span>] <span class="hljs-meta">>>> </span><span class="hljs-string">f'Here is a list: <span class="hljs-subst">{"\n".join(my_list_of_strings)}</span>'</span> File <span class="hljs-string">"<stdin>"</span>, line <span class="hljs-number">1</span> <span class="hljs-string">f'Here is a list: <span class="hljs-subst">{"\n".join(my_list_of_strings)}</span>'</span> ^ SyntaxError: f-string expression part cannot include a backslash </div><div class="code"><br /></div></div></code></pre><p><span>But by having f-strings as part of the grammar, there would no longer be any need for this restriction.</span></p><h2 class="raw"><span><br /></span></h2><div><span><hr /></span></div><h2 class="raw"><span>Reception</span></h2><p><span>The proposal was extremely enthusiastically received. “It would be </span><em><span>huge</span></em><span> if we could get syntax errors pointing to the correct place like with normal Python code,” commented Eric Snow.</span></p><blockquote> <p><span>I’m all for it.</span><br /> <span>– Guido van Rossum, Core Developer and creator of Python</span></p></blockquote><p> </p><blockquote> <p><span>We are all in agreement. You should just do it.</span><br /> <span>– Thomas Wouters, Core Developer and Steering Council member</span></p></blockquote><p> </p><blockquote> <p><span>You can spend the next ten minutes implementing it.</span><br /> <span>– 艁ukasz Langa, Core Developer and CPython Developer-in-Residence</span></p> </blockquote></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-f.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-f.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T12:59:00-04:00'>5/11/2022 12:59:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=6040691758423529930&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='8520' itemprop='blogId'/> <meta content='2477564712113740684' itemprop='postId'/> <a name='2477564712113740684'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html'>The 2022 Python Language Summit: Python without the GIL</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-2477564712113740684' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-enabled comment-inner" data-hard-breaks="true" id="doc"><p><span>If you peruse the archives of language-summit blogs, you’ll find that one theme comes up </span><a href="https://lwn.net/Articles/689548/" rel="noopener" target="_blank"><span>again</span></a><span> </span><a href="https://lwn.net/Articles/723514/" rel="noopener" target="_blank"><span>and</span></a><span> </span><a href="https://lwn.net/Articles/754577/" rel="noopener" target="_blank"><span>again</span></a><span>: the dream of Python without the GIL. Continuing this venerable tradition, Sam Gross kicked off <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html">the 2022 Language Summit </a>by giving the attendees an update on </span><code>nogil</code><span>, a project that took the Python community by storm when it was first announced in October 2021.</span></p><p><span>The GIL, or <a href="https://realpython.com/python-gil/">“Global Interpreter Lock”</a>, is the key feature of Python that prevents true concurrency between threads. This is another way of saying that it makes it difficult to do multiple tasks simultaneously while only running a single Python process. Previously the main cheerleader for removing the GIL was Larry Hastings, with his famous “Gilectomy” project. The Gilectomy project was ultimately abandoned due to the fact that it made single-threaded Python code significantly slower. But after seeing Gross’s proof-of-concept fork in October, Hastings wrote in <a href="https://mail.python.org/archives/list/python-dev@python.org/message/CCGH6COYQGCAFZWD32ROUOHRSE4BUL3P/">an email to the python-dev mailing list</a>:</span></p><p><span><br /></span></p><blockquote> <p><span>Sam contacted me privately some time ago to pick my brain a little. But honestly, Sam didn’t need any help<span face="Arial, Helvetica, sans-serif" style="background-color: white; color: #4a4a4a; font-size: 18px;">–</span>he’d already taken the project further than I’d ever taken the Gilectomy.</span></p></blockquote><p><br /></p><hr /><h2 class="raw"><span>The current status of </span><code>nogil</code></h2><p><span>Since releasing his <a href="https://github.com/colesbury/nogil">proof-of-concept fork</a> in October – based on an alpha version of Python 3.9 – Gross stated that he’d been working to rebase the </span><code>nogil</code><span> changes onto 3.9.10.</span></p><p><span>3.9 had been chosen as a target for now, as reaching a level of early adoption was important in order to judge whether the project as a whole would be viable. Early adopters would not be able to use the project effectively if third-party packages didn’t work when using </span><code>nogil</code><span>. There is still much broader support for Python 3.9 among third-party packages than for Python 3.10, and so Python 3.9 still made more sense as a base branch for now rather than 3.10 or </span><code>main</code><span>.</span></p><p><span>Gross’s other update was that he had made a change in his approach with regard to thread safety. In order to make Python work effectively without the GIL, a lot of code needs to have new locks added to it in order to ensure that it is still thread-safe. Adding new locks to existing code, however, can be very difficult, as there is potential for large slowdowns in some areas. Gross’s solution had been to invent a new kind of lock, one that is “more Gilly”.</span></p><p><br /></p><hr /><h2 class="raw"><span>The proposal</span></h2><p><span>Gross came to the Summit with a proposal: to introduce a new compiler flag in Python 3.12 that would disable the GIL.</span></p><p><span>This is a slight change to Gross’s initial proposal from October, where he brought up the idea of a runtime flag. A compiler flag, however, reduces the risk inherent in the proposal: “You have more of a way to back out.” Additionally, using a compiler flag avoids thorny issues concerning preservation of </span><a href="https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface" rel="noopener" target="_blank"><span>C ABI</span></a><span> stability. “You can’t do it with a runtime flag,” Gross explained, “But there’s precedent for changing the ABI behind a compiler flag”.</span></p><p><br /></p><hr /><h2 class="raw"><span>Reception</span></h2><p><span>Gross’s proposal was greeted with a mix of excitement and robust questioning from the assembled core developers.</span></p><p><span>Carol Willing queried whether it might make more sense for </span><code>nogil</code><span> to carry on as a separate fork of CPython, rather than for Gross to aim to merge his work into the </span><code>main</code><span> branch of CPython itself. Gross, however, responded that this “was not a path to success”.</span></p><blockquote> <p><span>"A lot of the value of Python is the ecosystem, not just the language… CPython really leads the way in terms of the community moving as a block.</span></p> <p><span>"Removing the GIL is a </span><em><span>really</span></em><span> transformative step. Most Python programs just don’t use threads at the moment if they want to run on multiple cores. If </span><code>nogil</code><span> is to be a success, the community as a whole has to buy into it."</span></p> <p><span>– Sam Gross</span></p> </blockquote><p><span>Samuel Colvin, maintainer of <a href="https://pydantic-docs.helpmanual.io">the </a></span><code><a href="https://pydantic-docs.helpmanual.io">pydantic</a></code><span><a href="https://pydantic-docs.helpmanual.io"> library</a>, expressed disappointment that the new proposal was for a compiler flag, rather than a runtime flag. “I can’t help thinking that the level of adoption would be massively higher” if it was possible to change the setting from within Python, Colvin commented.</span></p><p><span>There was some degree of disagreement as to what the path forward from here should be. Gross appeared to be seeking a high-level decision about whether </span><code>nogil</code><span> was a viable way forward. The core developers in attendance, however, were reluctant to give an answer without knowing the low-level costs. “We need to lay out a plan of </span><em><span>how</span></em><span> to proceed,” remarked Pablo Galindo Salgado. “Just creating a PR with 20,000 lines of code changed is infeasible.”</span></p><p><span>Barry Warsaw and Itamar Ostricher both asked Gross about the impact </span><code>nogil</code><span> could have on third-party libraries if they wanted to support the new</span><span> mode</span><span>. Gross responded that the impact on many libraries would be minimal – no impact at all to a library like </span><code><a href="https://scikit-learn.org/stable/">scikit-learn</a></code><span>, and perhaps only 15 lines of code for </span><code><a href="https://numpy.org">numpy</a></code><span>. Gross had received considerable interest from scientific libraries, he said, so was confident that the pressure to build separate C extensions to support </span><code>nogil</code><span> mode would not be unduly burdensome. Carol Willing encouraged Gross to attend scientific-computing conferences, to gather more feedback from that community.</span></p><p><span>There was also a large amount of concern from the attendees about the impact the introduction of </span><code>nogil</code><span> could have on CPython development. Some worried that introducing </span><code>nogil</code><span> mode could mean that the number of tests run in CI would have to double. Others worried that the maintenance burden would significantly increase if two separate versions of CPython were supported simultaneously: one with the GIL, and one without.</span></p><p><span>Overall, there was still a large amount of excitement and curiosity about </span><code>nogil</code><span> mode from the attendees. However, significant questions remain unresolved regarding the next steps for the project.</span></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T12:58:00-04:00'>5/11/2022 12:58:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=2477564712113740684&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfmyxKVWCxGVu8bDOqripPODzPu4TZ-R_B-7kVi4NPMfXb54aDre8seaOZWkKfgaE_gacSbimQUu74yNDCLfXzrwBnEp4Er3818hcRDohbI1AkSe1GvGVsmreydutt5LEjAchdnVnS3SjMnuFA5vFv50mwlwTXwtgimCKH_v8L_kOWwDo/w400-h225/Irit%20-%20PR%20issue%20and%20backlog-page-003.jpg' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='5425929228522651431' itemprop='postId'/> <a name='5425929228522651431'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-dealing.html'>The 2022 Python Language Summit: Dealing with CPython's issue and PR backlog</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5425929228522651431' itemprop='description articleBody'> <div class="markdown-body container-fluid comment-inner comment-enabled" data-hard-breaks="true" id="doc"><blockquote> <p><span>“Any noise annoys an oyster, but a noisy noise annoys an oyster most.”</span></p> <p><span>– Tongue twister, </span><em><span>author unknown</span></em></p> </blockquote><p><span>As the Python programming language continues to grow in popularity, so too does the accumulation of issues and pull requests (“PRs”) on the CPython GitHub repository. At time of writing (morning of 7th May, 2022), the total stands at 7,027 <a href="https://github.com/python/cpython/issues">open issues</a>, and 1,471 <a href="https://github.com/python/cpython/pulls">pull requests</a>. At <a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html">the 2022 Python Language Summit</a>, CPython Core Developer Irit Katriel gave a talk on possible ways forward for dealing with the backlog.</span></p><p><span><br /></span></p><hr /><p><span>Historically, there has been reluctance among CPython’s team of core developers to close issues or PRs that may be of dubious worth. </span><span>BPO-539907</span><span> was presented to the audience as an issue that had remained open on the issue tracker for over 20 years. The example is an extreme one, but represents a pattern that anybody who has scrolled through the CPython issue tracker will surely have seen before:</span></p><p><span><br /></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfmyxKVWCxGVu8bDOqripPODzPu4TZ-R_B-7kVi4NPMfXb54aDre8seaOZWkKfgaE_gacSbimQUu74yNDCLfXzrwBnEp4Er3818hcRDohbI1AkSe1GvGVsmreydutt5LEjAchdnVnS3SjMnuFA5vFv50mwlwTXwtgimCKH_v8L_kOWwDo/s3000/Irit%20-%20PR%20issue%20and%20backlog-page-003.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1688" data-original-width="3000" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfmyxKVWCxGVu8bDOqripPODzPu4TZ-R_B-7kVi4NPMfXb54aDre8seaOZWkKfgaE_gacSbimQUu74yNDCLfXzrwBnEp4Er3818hcRDohbI1AkSe1GvGVsmreydutt5LEjAchdnVnS3SjMnuFA5vFv50mwlwTXwtgimCKH_v8L_kOWwDo/w400-h225/Irit%20-%20PR%20issue%20and%20backlog-page-003.jpg" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><p><span>Anyone with experience in triaging issue trackers in open source will know that it is not always easy to close an issue. People on the internet do not always take kindly to being told that something they believe to be a bug is, in fact, intended behaviour.</span></p><p><span>Low-quality feature requests can be even harder to tackle, and can be broadly split into three buckets. The first bucket holds feature requests that simply make no sense, or else would have actively harmful impacts – these can be fairly easily closed. The second bucket holds feature requests that would add maintenance costs, but would realistically add little value to end users. These can often lead to tiresome back-and-forths – something one person may see as a large problem in a piece of software may, ultimately, cause few problems for the majority of users.</span></p><p><span>The feature requests that can linger on an issue tracker for twenty years, however, are usually those in the third bucket: features that everybody can agree might be nice if, in an ideal world, they were implemented – but that nobody, ultimately, has the time or motivation to work on.</span></p><p><span><br /></span></p><hr /><p><span>Katriel’s contention is that leaving an issue open on the tracker for 20 years serves no one and that, instead, we should think harder about what an issue tracker is actually </span><em><span>for</span></em><span>.</span></p><p><span>If the proposed </span><code>tkinter</code><span> lock from BPO-539907 is ever implemented, Katriel, argues, “it’s not because of the twenty-year-old issue – it’s because somebody will discover the need for it.” Rather than only closing issues that have obvious defects, we should flip the script, and become far more willing to close issues if they serve no obvious purpose. Issues should only be kept </span><em><span>open</span></em><span> if they serve an obvious purpose in helping further CPython’s development. Instead of asking “Why should we close this?”, we should instead ask, “Why should we keep this open?”</span></p><p><span>Citing a </span><a href="https://sundaylettersfromsam.substack.com/p/bonus-post-noisy-monitors?s=r" rel="noopener" target="_blank"><span>recent blog post</span></a><span> by Sam Schillace, Katriel argues that not only do issues such as BPO-539907 (newly renamed as </span><span>GH-36387</span><span>, for those keeping tabs) serve little purpose – they also do active harm to the CPython project. Schillace argues that the problem of the “noisy monitor” – a term he uses for any kind of feedback system where it becomes impossible to tell the signal from the noise – is “one of the most pernicious, and common, patterns that engineering teams fall prey to”. Leaving low-quality issues on a tracker, Shillace argues, wastes the time of developers and triagers, and “obscures both newer quality issues as well as the overall drift of the product.”</span></p><p><span><br /></span></p><blockquote> <p><span>“It’s far better… to keep the tool clean for the things that matter.”</span></p> <p><span>– Sam Schillace, </span><em><span>Noisy Monitors</span></em></p></blockquote><p> </p><hr /><p><span>No one has done more work than Katriel over the past few years to keep the issue tracker healthy, and her presentation was well received by the audience of core devs and triagers. The question of where now to proceed, however, is harder to tackle.</span></p><p><span>Pablo Galindo Salgado, an expert on CPython’s PEG parser, and the chief architect behind the “Better error messages” project in recent years, noted that he received “many, many issues” relating to possible changes to the parser and improvements to error messages. “Every time you close an issue,” he said, “People demand an explanation.” Arguing that maintainer time is “the most valuable resource” in open-source software, Salgado said that the easiest option was often just to leave it open.</span></p><p><span>However, hard though it may be to close an issue, ignoring open issues for an extended period of time also does a disservice to contributors. Itamar Ostricher – not a CPython core developer, but an experienced software engineer who has worked for many years at Meta – said that the contributor experience was “often confusing”. “Is this an issue where a PR would be accepted if I wrote one? Does a core dev want to work on it?” Ostricher asked. Or is it just a bad idea?</span></p><p><span>Ned Deily, release manager for Python 3.6 and 3.7, agreed, and argued that CPython needed to become more consistent in how core devs treat issues and PRs. Some modules, like </span><code>tkinter</code><span>, have been “ownerless” for a long time, Deily argued. This can create a chicken-and-egg problem. If a module has no maintainer, the solution is to add more maintainers. But a contributor can only become a maintainer if they demonstrate their worth through a series of merged PRs. And if a module has no active maintainer, there may be no core devs who feel they have sufficient expertise to review and merge a PR relating to the unmaintained module. So the contributor can never become a core developer (as their PRs will never be merged), and the module will never gain a new maintainer.</span></p><p><span><br /></span></p><hr /><h2 class="raw"><span>Where now?</span></h2><p><span>Various solutions were proposed to improve the situation. Katriel thought it would be good to introduce a new “Accepted” label, that could be added by a triager or a core developer. The idea is that the presence of the label signifies that the core developer team is not waiting for any further information from the issue filer: the bug report (or feature request) has been acknowledged as valid.</span></p><p><span>Many attendees noted that the problem was in many ways a social problem rather than a technical problem: the core development team needed a fundamental change in mindset if they were to seriously tackle the issue backlog. Senthil Kumaran argued that we should “err on the side of closing things”. Jelle Zijlstra similarly argued that we needed to reach a place where it was understood to be “okay” to close a feature request that had been open for many years with no activity.</span></p><p><span>There was also, however, interest in improving workflow automation. Christian Heimes discussed the difficulty of closing an issue or PR if you are a core developer with English as a second language. Crafting the nuances of a rejection notice so that it is polite but also clear can be a challenging task. Ideas around automated messages from bots or canned responses were discussed.</span></p><p><span><br /></span></p><hr /><p><span>The enormity of the task at hand is clear. Unfortunately, there is probably not one easy fix that will solve the problem.</span></p><p><span>Things are already moving in a better direction, however, in many respects. 艁ukasz Langa, CPython’s <a href="https://pyfound.blogspot.com/2021/07/ukasz-langa-is-inaugural-cpython.html">Developer-In-Residence</a>, has been having a huge impact in stabilising the number of open issues. The CPython triage team, a group of volunteers helping the core developers maintain CPython, <a href="https://discuss.python.org/t/six-new-triagers/">has also been significantly expanded</a> in recent months, increasing the workforce available to triage and close issues and PRs.</span></p><p><a href="https://peps.python.org/pep-0594/" rel="noopener" target="_blank"><span>PEP 594</span></a><span>, deprecating several standard-library modules that have been effectively unmaintained for many years, also led to a large number of issues and PRs being closed in recent months. And the transition to GitHub issues itself, which only took place a few weeks ago, appears to have imbued the triage team with a new sense of energy.</span></p><p><span>Discussion continues on Discourse about further potential ways forward:</span></p><ul> <li><a href="https://discuss.python.org/t/proposal-canned-explanations-for-issue-pr-closure-decisions-language-summit-follow-up/" rel="noopener" target="_blank"><span>Proposal: canned explanations for issue/PR closure decisions (Language Summit follow up)</span></a></li> <li><a href="https://discuss.python.org/t/gaps-in-maintenance-coverage-language-summit-follow-up/" rel="noopener" target="_blank"><span>Gaps in maintenance coverage (Language Summit follow up)</span></a></li> <li><a href="https://discuss.python.org/t/triaging-reviewing-fixing-issues-and-prs/" rel="noopener" target="_blank"><span>Triaging/reviewing/fixing issues and PRs</span></a></li> </ul></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-dealing.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-dealing.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T12:52:00-04:00'>5/11/2022 12:52:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=5425929228522651431&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi39i4NZfa6DNAbjgDoqq2wUONPUqg5-LfNf_zvmTVhS6VRjfjBwF-BFCci0SGg6g25kVQJd6tMrhkHIgYKE_Te5H3hCQoL4JQ4B2ZPqId0ACcIueyfVZvKhBESZAyVRb_vKsOc84eXwm2HJ4VMVtFLKoeV3oFRkDpOiz5YDajaRJDp0g/w400-h283/CPython-Language-Summit-2022-0.jpg' itemprop='image_url'/> <meta content='8520' itemprop='blogId'/> <meta content='5702920683321123202' itemprop='postId'/> <a name='5702920683321123202'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html'>The 2022 Python Language Summit</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-5702920683321123202' itemprop='description articleBody'> <p>Every year, just before the start of PyCon US, around 30 core developers, triagers, and special guests gather for the Python Language Summit: an all-day event of talks where the future direction of Python is discussed. The summit in 2022 was the first in-person summit since 2019, due to disruption caused by the coronavirus pandemic in 2020-21.</p><p>This year's summit was covered by Alex Waygood.</p><p><br /></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi39i4NZfa6DNAbjgDoqq2wUONPUqg5-LfNf_zvmTVhS6VRjfjBwF-BFCci0SGg6g25kVQJd6tMrhkHIgYKE_Te5H3hCQoL4JQ4B2ZPqId0ACcIueyfVZvKhBESZAyVRb_vKsOc84eXwm2HJ4VMVtFLKoeV3oFRkDpOiz5YDajaRJDp0g/s824/CPython-Language-Summit-2022-0.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="582" data-original-width="824" height="283" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgi39i4NZfa6DNAbjgDoqq2wUONPUqg5-LfNf_zvmTVhS6VRjfjBwF-BFCci0SGg6g25kVQJd6tMrhkHIgYKE_Te5H3hCQoL4JQ4B2ZPqId0ACcIueyfVZvKhBESZAyVRb_vKsOc84eXwm2HJ4VMVtFLKoeV3oFRkDpOiz5YDajaRJDp0g/w400-h283/CPython-Language-Summit-2022-0.jpg" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><i>This year's Language Summit attendees</i></td></tr></tbody></table><p><br /></p><hr /><ul style="text-align: left;"><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html">Python without the GIL</a></b>: A talk by Sam Gross</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html">Reaching a per-interpreter GIL</a></b>: A talk by Eric Snow</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_2.html">The "Faster CPython" project: 3.12 and beyond</a></b>: A talk by Mark Shannon</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python.html">WebAssembly: Python in the browser and beyond</a></b>: A talk by Christian Heimes</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-f.html">F-strings in the grammar</a>:</b> A talk by Pablo Galindo Salgado</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_60.html">Cinder Async Optimisations</a></b>: A talk by Itamar Ostricher</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-dealing.html">The issue and PR backlog</a></b>: A talk by Irit Katriel</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_11.html">The path forward for immortal objects</a></b>: A talk by Eddie Elizondo and Eric Snow</li><li><b><a href="https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit.html">Lightning talks</a></b>, featuring short presentations by Carl Meyer, Thomas Wouters, Kevin Modzelewski, Samuel Colvin and Larry Hastings</li></ul><p></p> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/18392244184145876843' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/18392244184145876843' rel='author' title='author profile'> <span itemprop='name'>Alex Waygood</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-11T12:49:00-04:00'>5/11/2022 12:49:00 PM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-980528170'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=5702920683321123202&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> Labels: <a href='https://pyfound.blogspot.com/search/label/pycon' rel='tag'>pycon</a> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> </div></div> <div class="date-outer"> <h2 class='date-header'><span>Tuesday, May 10, 2022</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='8520' itemprop='blogId'/> <meta content='4995680598546958886' itemprop='postId'/> <a name='4995680598546958886'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://pyfound.blogspot.com/2022/05/no-starch-press-has-released-all-python.html'>No Starch Press has released an all-Python Humble Bundle!</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-4995680598546958886' itemprop='description articleBody'> <p><a href="https://nostarch.com/">No Starch Press</a>, an indie tech-book publisher and Community sponsor of the PSF, just announced a partnership with Humble Bundle that lets you pay what you want for all-Python DRM-free ebook titles for Python beginners to pros. And a share of the proceeds from the bundle goes to the PSF!</p><p>The “<a href="https://www.humblebundle.com/books/python-no-starch-press-books">Python, by No Starch Press</a>” bundle runs now through May 23rd and benefits the PSF as well as Hacker Initiative, a public 501(c)(3) organization for hackers, created by NSP founder Bill Pollock.<br /></p><p> The bundle includes picks for all levels like <i>Python Crash Course</i> (Eric Matthes), <i>Automate the Boring Stuff with Python</i> (Al Sweigart), and <i>Doing Math with Python </i>(Amit Saha). The promotion has a pay-what-you-want model, so you can choose a pricing tier for up to 18 ebooks, then decide how much of your purchase goes to the featured causes.</p><p>Pricing starts at $1 for<i> Python Playground</i> (Mahesh Venkitachalam) + <i>Doing Math with Python</i>, or starting at $30 you can get all 18 Python ebooks! </p><p><a href="https://www.humblebundle.com/books/python-no-starch-press-books">Check it out</a> and happy reading!<br /></p> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <meta content='https://www.blogger.com/profile/06125752284896762014' itemprop='url'/> <a class='g-profile' href='https://www.blogger.com/profile/06125752284896762014' rel='author' title='author profile'> <span itemprop='name'>Loren Crary</span> </a> </span> </span> <span class='post-timestamp'> at <meta content='https://pyfound.blogspot.com/2022/05/no-starch-press-has-released-all-python.html' itemprop='url'/> <a class='timestamp-link' href='https://pyfound.blogspot.com/2022/05/no-starch-press-has-released-all-python.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2022-05-10T11:23:00-04:00'>5/10/2022 11:23:00 AM</abbr></a> </span> <span class='post-comment-link'> </span> <span class='post-icons'> <span class='item-control blog-admin pid-1348026682'> <a href='https://www.blogger.com/post-edit.g?blogID=8520&postID=4995680598546958886&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://pyfound.blogspot.com/search?updated-max=2022-06-07T08:00:00-04:00&max-results=2&reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'>Newer Posts</a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='https://pyfound.blogspot.com/search?updated-max=2022-05-10T11:23:00-04:00&max-results=2' id='Blog1_blog-pager-older-link' title='Older Posts'>Older Posts</a> </span> <a class='home-link' href='https://pyfound.blogspot.com/'>Home</a> </div> <div class='clear'></div> <div class='blog-feeds'> <div class='feed-links'> Subscribe to: <a class='feed-link' href='https://pyfound.blogspot.com/feeds/posts/default' target='_blank' type='application/atom+xml'>Posts (Atom)</a> </div> </div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> <div class='sidebar section' id='sidebar-right-1'><div class='widget Text' data-version='1' id='Text1'> <h2 class='title'>Mission</h2> <div class='widget-content'> <span style="font-size: 125%;font-size:125%;"><i>The mission of the <a href="https://www.python.org/psf/">Python Software Foundation</a> is to promote, protect, and advance the Python programming language, and to support and facilitate the growth of a diverse and international community of Python programmers.</i></span> </div> <div class='clear'></div> </div><div class='widget LinkList' data-version='1' id='LinkList1'> <div class='widget-content'> <ul> <li><a href='https://www.python.org/psf-landing/'>Python Software Foundation</a></li> <li><a href='https://www.python.org/psf/grants/'>Grants Program</a></li> <li><a href='https://www.python.org/psf/membership/'>Membership</a></li> <li><a href='https://www.python.org/community/awards/'>Awards</a></li> <li><a href='https://www.python.org/psf/records/board/minutes/'>Meeting Minutes</a></li> </ul> <div class='clear'></div> </div> </div><div class='widget Image' data-version='1' id='Image1'> <h2>PSF Sponsors</h2> <div class='widget-content'> <a href='https://www.python.org/psf/sponsors/'> <img alt='PSF Sponsors' height='143' id='Image1_img' src='https://blogger.googleusercontent.com/img/a/AVvXsEiagchpTRkriKoEe2Cqh2Bd5mX7Un4EYG-fq2Gdwx-Jx5scs09-0bmLVT89ewlhrQsiaJVE6nUU1Z0UkZFu0KUM2f82CiXXGsY_mg0JRq8iUtt_Rob_rcWX9meUjM2ql0XMoYFwO7dtt8T3cHO5oGfxo3HPk-9Lz358AlCHMDRAo5fgBXTuEuo=s302' width='302'/> </a> <br/> <span class='caption'>A big thank you to the above PSF sponsors for supporting our mission!</span> </div> <div class='clear'></div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Blog Archive</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2025/'> 2025 </a> <span class='post-count' dir='ltr'>(6)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2025/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2025/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2025/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(58)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/12/'> December </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/11/'> November </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/07/'> July </a> <span class='post-count' dir='ltr'>(7)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/06/'> June </a> <span class='post-count' dir='ltr'>(16)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2024/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/'> 2023 </a> <span class='post-count' dir='ltr'>(37)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/08/'> August </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/06/'> June </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/05/'> May </a> <span class='post-count' dir='ltr'>(12)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2023/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/'> 2022 </a> <span class='post-count' dir='ltr'>(35)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/06/'> June </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> ▼  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/05/'> May </a> <span class='post-count' dir='ltr'>(12)</span> <ul class='posts'> <li><a href='https://pyfound.blogspot.com/2022/05/pycon-jp-association-awarded-psf.html'>PyCon JP Association Awarded the PSF Community Ser...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit.html'>The 2022 Python Language Summit: Lightning talks</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_11.html'>The 2022 Python Language Summit: Achieving immorta...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-per.html'>The 2022 Python Language Summit: A per-interpreter...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python.html'>The 2022 Python Language Summit: Python in the bro...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_2.html'>The 2022 Python Language Summit: Performance Impro...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_60.html'>The 2022 Python Language Summit: Upstreaming optim...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-f.html'>The 2022 Python Language Summit: F-Strings in the ...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-python_11.html'>The 2022 Python Language Summit: Python without th...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit-dealing.html'>The 2022 Python Language Summit: Dealing with CPyt...</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/the-2022-python-language-summit_01678898482.html'>The 2022 Python Language Summit</a></li> <li><a href='https://pyfound.blogspot.com/2022/05/no-starch-press-has-released-all-python.html'>No Starch Press has released an all-Python Humble ...</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2022/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/'> 2021 </a> <span class='post-count' dir='ltr'>(42)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/12/'> December </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/11/'> November </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/06/'> June </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/05/'> May </a> <span class='post-count' dir='ltr'>(12)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/04/'> April </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2021/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/'> 2020 </a> <span class='post-count' dir='ltr'>(51)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/12/'> December </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/05/'> May </a> <span class='post-count' dir='ltr'>(10)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/04/'> April </a> <span class='post-count' dir='ltr'>(11)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/03/'> March </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2020/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/'> 2019 </a> <span class='post-count' dir='ltr'>(45)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/12/'> December </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/08/'> August </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/06/'> June </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/05/'> May </a> <span class='post-count' dir='ltr'>(11)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/02/'> February </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2019/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/'> 2018 </a> <span class='post-count' dir='ltr'>(31)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/12/'> December </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/10/'> October </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/05/'> May </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2018/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(32)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/12/'> December </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/10/'> October </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/09/'> September </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/07/'> July </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2017/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(27)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/05/'> May </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2016/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(67)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/11/'> November </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/10/'> October </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/06/'> June </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/04/'> April </a> <span class='post-count' dir='ltr'>(13)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/03/'> March </a> <span class='post-count' dir='ltr'>(14)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/02/'> February </a> <span class='post-count' dir='ltr'>(9)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2015/01/'> January </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(14)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2014/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/'> 2013 </a> <span class='post-count' dir='ltr'>(18)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/03/'> March </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2013/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/'> 2012 </a> <span class='post-count' dir='ltr'>(21)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/12/'> December </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/05/'> May </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2012/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/'> 2011 </a> <span class='post-count' dir='ltr'>(55)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/10/'> October </a> <span class='post-count' dir='ltr'>(7)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/09/'> September </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/05/'> May </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/04/'> April </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/03/'> March </a> <span class='post-count' dir='ltr'>(13)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2011/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/'> 2010 </a> <span class='post-count' dir='ltr'>(35)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/12/'> December </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/07/'> July </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/06/'> June </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/04/'> April </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2010/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/'> 2009 </a> <span class='post-count' dir='ltr'>(21)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/09/'> September </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/07/'> July </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/05/'> May </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2009/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/'> 2008 </a> <span class='post-count' dir='ltr'>(23)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/08/'> August </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/05/'> May </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/03/'> March </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2008/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/'> 2007 </a> <span class='post-count' dir='ltr'>(26)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/12/'> December </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/10/'> October </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2007/01/'> January </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/'> 2006 </a> <span class='post-count' dir='ltr'>(39)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/12/'> December </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/11/'> November </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/10/'> October </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/05/'> May </a> <span class='post-count' dir='ltr'>(7)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/04/'> April </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> ►  </span> </a> <a class='post-count-link' href='https://pyfound.blogspot.com/2006/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> </div> </div> <div class='clear'></div> </div> </div></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='sidebar no-items section' id='sidebar-right-2-1'></div> </td> <td class='columns-cell'> <div class='sidebar no-items section' id='sidebar-right-2-2'></div> </td> </tr> </tbody> </table> <div class='sidebar no-items section' id='sidebar-right-3'></div> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='foot no-items section' id='footer-2-1'></div> </td> <td class='columns-cell'> <div class='foot no-items section' id='footer-2-2'></div> </td> </tr> </tbody> </table> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3' name='Footer'><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/1455187647-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY4RV0GhD1cOoLWNMlovs7-1QklB5g:1743447207300';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d8520','//pyfound.blogspot.com/2022/05/','8520'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '8520', 'title': 'Python Software Foundation News', 'url': 'https://pyfound.blogspot.com/2022/05/', 'canonicalUrl': 'https://pyfound.blogspot.com/2022/05/', 'homepageUrl': 'https://pyfound.blogspot.com/', 'searchUrl': 'https://pyfound.blogspot.com/search', 'canonicalHomepageUrl': 'https://pyfound.blogspot.com/', 'blogspotFaviconUrl': 'https://pyfound.blogspot.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': false, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'UA-55961911-3', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': false, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Python Software Foundation News - Atom\x22 href\x3d\x22https://pyfound.blogspot.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Python Software Foundation News - RSS\x22 href\x3d\x22https://pyfound.blogspot.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Python Software Foundation News - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/8520/posts/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/6c9901d4a96a9be5', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'archive', 'pageName': '05/01/2022 - 06/01/2022', 'pageTitle': 'Python Software Foundation News: 05/01/2022 - 06/01/2022'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Python Software Foundation News', 'description': '\xa0\xa0News from the Python Software Foundation', 'url': 'https://pyfound.blogspot.com/2022/05/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2022, 'month': 5, 'rangeMessage': 'Showing posts from May, 2022'}}}]); _WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/4200661376-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/1964470060-lightbox_bundle.css'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_TextView', new _WidgetInfo('Text1', 'sidebar-right-1', document.getElementById('Text1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_LinkListView', new _WidgetInfo('LinkList1', 'sidebar-right-1', document.getElementById('LinkList1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_ImageView', new _WidgetInfo('Image1', 'sidebar-right-1', document.getElementById('Image1'), {'resize': true}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); </script> </body> </html>