<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Pradyun Gedam</title><link>https://pradyunsg.me/</link><description>Recent content on Pradyun Gedam</description><generator>Hugo</generator><language>en</language><lastBuildDate>Tue, 21 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://pradyunsg.me/index.xml" rel="self" type="application/rss+xml"/><item><title>About Me</title><link>https://pradyunsg.me/about/</link><pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/about/</guid><description>&lt;p&gt;I am a software engineer, who likes to work on improving the experience of using
software for other humans. I have a keen interest in open source software, with
deep experience with developer tooling and technical writing &amp;amp; communication.&lt;/p&gt;
&lt;p&gt;I wear many hats in open source software spaces, including maintaining critical
projects that serve as the foundational digital infrastructure for the ecosystem
of the &lt;a href="https://en.wikipedia.org/wiki/Python_(programming_language)"&gt;Python programming language&lt;/a&gt;, making it easier to create good technical
documentation websites and being involved in community events.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I am a software engineer, who likes to work on improving the experience of using
software for other humans. I have a keen interest in open source software, with
deep experience with developer tooling and technical writing &amp; communication.</p>
<p>I wear many hats in open source software spaces, including maintaining critical
projects that serve as the foundational digital infrastructure for the ecosystem
of the <a href="https://en.wikipedia.org/wiki/Python_(programming_language)">Python programming language</a>, making it easier to create good technical
documentation websites and being involved in community events.</p>
<p>My current day job is to make it easier for software developers to write
software in Python; as part of <a href="https://www.bloomberg.com/company/values/tech-at-bloomberg/python/">Bloomberg Engineering</a>’s Python Infrastructure
team.</p>
<hr>
<p>This page is where I document stuff that I am responsible for, am involved in,
etc. For things like work experience and education, see <a href="https://www.linkedin.com/in/pradyunsg/">Linkedin</a>.</p>
<h2 id="open-source-software">Open Source Software</h2>
<p>I contribute to a <em>lot</em> of open source software projects.</p>

<div class="about-list">
  
  
  
  
  <div class="about-item"><div class="about-item--context"><a href="#pip" id="pip">2016 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pypa/pip/"><span>pip</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        The standard package manager for Python, for installing and managing libraries
that aren&rsquo;t included in Python&rsquo;s standard library.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#python-packaging-authority" id="python-packaging-authority">2016 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://www.pypa.io/"><span>Python Packaging Authority</span></a></div><div class="about-item--detail">
        Member
      </div><div class="about-item--description">
        Maintain tooling that serves foundational digital infrastructure for the Python packaging ecosystem.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#toml" id="toml">2018 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/toml-lang/toml/"><span>TOML</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        Configuration file format, with an emphasis on simplicity. It is used in many
places, including Python&rsquo;s <code>pyproject.toml</code> file and Rust&rsquo;s <code>cargo.toml</code>
file.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#python-package-index" id="python-package-index">2019 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pypi/"><span>Python Package Index</span></a></div><div class="about-item--detail">
        Moderator
      </div><div class="about-item--description">
        Serves as the primary repository of software for the Python programming language.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#vendoring" id="vendoring">2019 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyunsg/vendoring"><span>vendoring</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        Command line tool for vendoring Python Packages. It is designed specifically
for pip&rsquo;s use case.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#pyproject-hooks" id="pyproject-hooks">2019 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pypa/pyproject-hooks"><span>pyproject-hooks</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        Library providing the basic functionality to help write tooling that generates
distribution files from Python projects.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#furo" id="furo">2020 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyunsg/furo/"><span>Furo</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        Documentation theme for <a href="https://www.sphinx-doc.org/en/master/">Sphinx</a>-based (technical) documentation, designed
to emphasize on the content while still providing capable navigation around
the documentation.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#sphinx-inline-tabs" id="sphinx-inline-tabs">2020 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyunsg/sphinx-inline-tabs"><span>Sphinx Inline Tabs</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        <a href="https://www.sphinx-doc.org/en/master/">Sphinx</a> plugin that provides simple and easy-to-use tabs for inline
content; for use in technical documentation.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#installer" id="installer">2020 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyunsg/installer"><span>installer</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        Library for installing Python &ldquo;wheel&rdquo; distributions, serving as building
block for Python package/dependency management tooling.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#sphinx-themes-gallery" id="sphinx-themes-gallery">2020 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://sphinx-themes.org/"><span>Sphinx Themes Gallery</span></a></div><div class="about-item--detail">
        Maintainer, Curator
      </div><div class="about-item--description">
        The canonical gallery of HTML themes available for the Sphinx documentation
generator. Also, <a href="https://github.com/sphinx-themes/sphinx-themes.org/pull/19">the home of my best PR, in terms of numbers</a>.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#executable-books" id="executable-books">2021 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://executablebooks.org/"><span>Executable Books</span></a></div><div class="about-item--detail">
        Member
      </div><div class="about-item--description">
        Collaborate to enable executable books with Jupyter, building upon the Sphinx ecosystem.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#flit" id="flit">2021 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pypa/flit/"><span>Flit</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        Simplified packaging of Python modules and scripts. It tries to require less
thought about packaging and help you avoid common mistakes.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#sphinx-theme-builder" id="sphinx-theme-builder">2021 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyunsg/sphinx-theme-builder"><span>Sphinx Theme Builder</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        Simplified packaging and development workflow for Sphinx themes, by building
upon existing de-facto standard tooling.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#spack" id="spack">2022 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/spack/spack"><span>Spack</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        Spack is a multi-platform package manager that builds and installs multiple
versions and configurations of software.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#sphinx-autobuild" id="sphinx-autobuild">2023 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/sphinx-doc/sphinx-autobuild"><span>sphinx-autobuild</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        Rebuild Sphinx documentation on changes, with live-reload in the browser.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#cpython" id="cpython">2023 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/python/cpython"><span>CPython</span></a></div><div class="about-item--detail">
        Core Developer
      </div><div class="about-item--description">
        The Python programming language. (became triager in 2022)
      </div></div>
  </div>
  
</div>

<h2 id="community-organisation-and-engagement">Community Organisation and Engagement</h2>

<div class="about-list">
  
  
  
  
  <div class="about-item"><div class="about-item--context"><a href="#pycon-us-packaging-summit" id="pycon-us-packaging-summit">2020 - Now</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>PyCon US</span></div><div class="about-item--description">
        Co-chair of the (annual) Python Packaging Summit at PyCon US.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#python-packaging-governance" id="python-packaging-governance">2025/2026</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Python Packaging Governance</span></div><div class="about-item--description">
        Co-authored <a href="https://peps.python.org/pep-0772/">PEP 772</a> that establishes a Python Packaging Council.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#gsoc-2020" id="gsoc-2020">2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Google Summer of Code</span></div><div class="about-item--description">
        Mentored a student who worked on pip.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#pep-609" id="pep-609">2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Python Packaging Governance</span></div><div class="about-item--description">
        Co-authored <a href="https://peps.python.org/pep-0609/">PEP 609</a> that set up a governance structure for Python Packaging Authority (PyPA).
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#pycon-india-2019" id="pycon-india-2019">2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>PyCon India</span></div><div class="about-item--description">
        Volunteered at the conference, mentor at Open Source sprint.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#pyconf-hyderabad-2019" id="pyconf-hyderabad-2019">2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>PyConf Hyderabad</span></div><div class="about-item--description">
        Volunteered at the conference, mentor at Open Source sprint.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#pycon-us-2019" id="pycon-us-2019">2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>PyCon US</span></div><div class="about-item--description">
        Volunteered at the conference, participant at the &ldquo;Python Packaging Mini-Summit&rdquo; and in the development sprints.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#gsoc-2017" id="gsoc-2017">2017</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Google Summer of Code</span></div><div class="about-item--description">
        I learnt a lot working toward introducing a better dependency resolver in pip.
      </div></div>
  </div>
  
</div>

<h2 id="recognition">Recognition</h2>

<div class="about-list">
  
  
  
  
  <div class="about-item"><div class="about-item--context"><a href="#python-software-foundation-fellow" id="python-software-foundation-fellow">2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://pyfound.blogspot.com/2019/08/python-software-foundation-fellow.html"><span>Python Software Foundation Fellow</span></a></div><div class="about-item--description">
        Recognized as a fellow by the Python Software Foundation for my significant
contributions to the Python community.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#google-open-source-peer-bonus" id="google-open-source-peer-bonus">2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://opensource.googleblog.com/2019/04/google-open-source-peer-bonus-winners.html"><span>Google Open Source Peer Bonus</span></a></div><div class="about-item--description">
        Recognized as an external-to-Google individual who has made exceptional
contributions to open source.
      </div></div>
  </div>
  
</div>

<h2 id="talks">Talks</h2>
<p>I am an experienced public speaker, having presented at numerous conferences and
meetups on topics related to Python and software development. My talks have
covered a range of subjects, such as open source project management,
documentation best practices, UX design, and Python packaging.</p>

<div class="about-list">
  
  
  
  
  <div class="about-item"><div class="about-item--context"><a href="#python-packaging-at-bloomberg" id="python-packaging-at-bloomberg">Oct 2023</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Python packaging at Bloomberg</span></div><div class="about-item--detail">
        Sponsor Talk: PackagingCon 2023
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#python-and-bloomberg-an-open-source-duo" id="python-and-bloomberg-an-open-source-duo">April 2023</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Python and Bloomberg: An Open Source Duo</span></div><div class="about-item--detail">
        Sponsor Talk: PyCon US 2023
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#growing-pains-of-an-open-source-project" id="growing-pains-of-an-open-source-project">Oct 2022</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Growing pains of an open source project</span></div><div class="about-item--detail">
        Keynote: DjangoCon EU 2022
      </div><div class="about-item--description">
        <a href="https://pradyunsg.me/talks/slides/2022-djangocon-eu.pdf">Slides</a>, <a href="https://www.youtube.com/watch?v=TRK6C09JHVc">Video</a>
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#how-to-write-horrible-documentation" id="how-to-write-horrible-documentation">May 2021</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>How to write horrible documentation</span></div><div class="about-item--detail">
        Talk: PyIstanbul Python Hour #128
      </div><div class="about-item--description">
        <a href="https://pradyunsg.me/talks/slides/2021-pyistanbul.pdf">Slides</a>, <a href="https://www.youtube.com/watch?v=D3MXX9bIbXk">Video</a>
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#ux-contributions-to-pip-pythons-package-installer" id="ux-contributions-to-pip-pythons-package-installer">Feb 2021</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>UX contributions to pip, Python&rsquo;s package installer</span></div><div class="about-item--detail">
        Panel: FOSDEM 2021
      </div><div class="about-item--description">
        <a href="https://ftp.fau.de/fosdem/2021/D.design/improving_the_usability_of_pip_the_python_package_manager.mp4">Video</a>
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#improving-pip-for-all-users" id="improving-pip-for-all-users">Feb 2021</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Improving pip for all users</span></div><div class="about-item--detail">
        Panel: FOSDEM 2021
      </div><div class="about-item--description">
        <a href="https://mirrors.dotsrc.org/fosdem/2021/D.python/python_pip.mp4">Video</a>
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#how-pip-works-internally" id="how-pip-works-internally">Apr 2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>How pip works internally</span></div><div class="about-item--detail">
        Talk: HydPy Meetup
      </div><div class="about-item--description">
        <a href="https://www.youtube.com/watch?v=U4lBdGfkKxg">Video</a>
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#rethinking-python-packaging-a-thought-experiment" id="rethinking-python-packaging-a-thought-experiment">Dec 2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Rethinking Python Packaging - a thought experiment</span></div><div class="about-item--detail">
        Talk: PyConf Hyderabad
      </div><div class="about-item--description">
        <a href="https://pradyunsg.me/talks/slides/2019-pyconf-hyd.pdf">Slides</a>
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#python-packaging-where-we-are-and-where-were-headed" id="python-packaging-where-we-are-and-where-were-headed">Oct 2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>Python Packaging - where we are and where we&rsquo;re headed</span></div><div class="about-item--detail">
        Talk: PyCon India 2019
      </div><div class="about-item--description">
        <a href="https://pradyunsg.me/talks/slides/2019-python-packaging-overview.pdf">Slides</a>, <a href="https://www.youtube.com/watch?v=1WRRBrPpxhw">Video</a>
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#how-did-i-get-here" id="how-did-i-get-here">Aug 2019</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><span>How did I get here?</span></div><div class="about-item--detail">
        Keynote: PyCon Korea
      </div><div class="about-item--description">
        <a href="https://pradyunsg.me/talks/slides/2019-pycon-korea.pdf">Slides</a>, <a href="https://www.youtube.com/watch?v=dvN3XH2Jtr4">Video</a>
      </div></div>
  </div>
  
</div>

<h2 id="interviews--features">Interviews &amp; Features</h2>
<p>In a variety of interviews and podcast appearances, I have had the opportunity
to discuss my work in the Python community as well as my insights and
experiences as an open source developer.</p>

<div class="about-list">
  
  
  
  
  <div class="about-item"><div class="about-item--context"><a href="#talk-python-to-me" id="talk-python-to-me">Feb 2022</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://talkpython.fm/episodes/show/354/sphinx-myst-and-python-docs-in-2022"><span>Talk Python To Me</span></a></div><div class="about-item--detail">
        Episode 354
      </div><div class="about-item--description">
        Invited to a panel on &ldquo;Sphinx, MyST, and Python Docs in 2022&rdquo;, an area of the Python
ecosystem that I&rsquo;ve become deeply involved in.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#pydev-of-the-week" id="pydev-of-the-week">Nov 2021</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://www.blog.pythonlibrary.org/2021/11/29/pydev-of-the-week-pradyun-gedam/"><span>PyDev of the Week</span></a></div><div class="about-item--description">
        Interviewed about my work in the Python ecosystem, journey as the &ldquo;PyDev of the
week&rdquo;.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#podcast.%255C_%255C_init%255C_%255C_" id="podcast.%5C_%5C_init%5C_%5C_">May 2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://www.pythonpodcast.com/pip-resolver-dependency-management-episode-264/"><span>Podcast.__init__</span></a></div><div class="about-item--detail">
        Episode 264
      </div><div class="about-item--description">
        Invited to a panel discussion about on pip&rsquo;s next-generation dependency resolver, a
project that I worked on.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#sourcesort" id="sourcesort">May 2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://sourcesort.com/interview/pradyun-gedam-pip"><span>SourceSort</span></a></div><div class="about-item--detail">
        Episode 264
      </div><div class="about-item--description">
        <p>Interviewed as part of an ongoing series of &ldquo;Interviews with open source maintainers
and developers&rdquo; by SourceSort.</p>
<p>Update Nov 2022: The original blog post is now a broken link. :(<br>
Thankfully, I <a href="https://hackmd.io/@pradyunsg/rkp9AAD9B">keep extensive notes</a>.</p>

      </div></div>
  </div>
  
</div>

<h2 id="older-projects">Older Projects</h2>
<p>These are projects that I have stepped away from.</p>

<div class="about-list">
  
  
  
  
  <div class="about-item"><div class="about-item--context"><a href="#materialism" id="materialism">2020 - 2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyun/materialism"><span>materialism</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        An attempt at creating a theme for Sphinx, based off of <a href="https://squidfunk.github.io/mkdocs-material/">mkdocs-material</a>.
This was the final piece to motivate me to write Furo.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#sphinx-mkdocs-theme" id="sphinx-mkdocs-theme">2020 - 2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyun/sphinx-mkdocs-theme"><span>sphinx-mkdocs-theme</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        An attempt at writing a compatibility layer between <a href="https://www.sphinx-doc.org/en/master/">Sphinx</a> and themes
written for <a href="https://www.mkdocs.org/">MkDocs</a> (specifically, <a href="https://squidfunk.github.io/mkdocs-material/">mkdocs-material</a>). This led to me
starting work on <code>materialism</code>.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#virtualenv" id="virtualenv">2018 - 2021</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pypa/virtualenv"><span>virtualenv</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        A tool for creating isolated &ldquo;virtual&rdquo; Python environments.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#json.minify" id="json.minify">2017 - 2021</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/getify/JSON.minify"><span>JSON.minify</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        A minifier algorithm for JSON to remove comments and whitespace, implemented
in multiple programming languages.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#alias-tips" id="alias-tips">2017 - 2021</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/djui/alias-tips"><span>alias-tips</span></a></div><div class="about-item--detail">
        Maintainer
      </div><div class="about-item--description">
        Zsh plugin to help users remember shell aliases defined in their
shell configuration.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#zazo" id="zazo">2016 - 2020</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyunsg/zazo"><span>Zazo</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        An initial attempt to design a dependency resolver, outside of pip,
for pip.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#sublime-rainbow-theme" id="sublime-rainbow-theme">2016 - 2016</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyun/Sublime-Rainbow-Theme"><span>Sublime Rainbow Theme</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        An adaptive UI theme for Sublime Text 2/3 that changed colors based on the
active colour scheme. This concept is now shipped as part of Sublime Text,
as the &ldquo;Adaptive&rdquo; theme.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#nose-html-report" id="nose-html-report">2014 - 2015</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyun/nose-html-report"><span>nose-html-report</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        Generate an HTML report for a <code>nose</code> test suite run.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#py2c" id="py2c">2013 - 2016</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyun/Py2C"><span>Py2C</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        An optimistic teenager&rsquo;s learning ground for parsers, language design,
API design, how languages differ and transpilation.
      </div></div>
  </div>
  
  <div class="about-item"><div class="about-item--context"><a href="#stack2py" id="stack2py">2013 - 2013</a></div>

    <div class="about-item--content">
      <div class="about-item--title"><a class="about-item--link" href="https://github.com/pradyun/stack2py"><span>stack2py</span></a></div><div class="about-item--detail">
        Creator
      </div><div class="about-item--description">
        A Python library interact with to Stack Exchange&rsquo;s API.
      </div></div>
  </div>
  
</div>

]]></content:encoded></item><item><title>Improving my dotfiles manager with pipx and inline dependency metadata</title><link>https://pradyunsg.me/blog/2024/05/31/python-scripts-with-pipx-bash/</link><pubDate>Fri, 31 May 2024 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2024/05/31/python-scripts-with-pipx-bash/</guid><description>&lt;p&gt;I have a (somewhat unnecessarily) custom setup for managing my dotfiles and I made a nice improvement to it today.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;The dotfiles are managed by a Python script. In broad strokes, the script will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;read a TOML file&lt;/li&gt;
&lt;li&gt;locate the configured paths&lt;/li&gt;
&lt;li&gt;create symlinks, based on custom marker text in the filenames, for files in subdirectories under the configured paths&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there&amp;rsquo;s a conflict (i.e. two configured paths provide the same symlink target location), the TOML file contains the resolution for it (i.e. specifies one of the paths as the &amp;ldquo;winner&amp;rdquo; for that file). If a resolution doesn&amp;rsquo;t exist, the script errors out.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I have a (somewhat unnecessarily) custom setup for managing my dotfiles and I made a nice improvement to it today.</p>
<h2 id="how-it-works">How it works</h2>
<p>The dotfiles are managed by a Python script. In broad strokes, the script will:</p>
<ul>
<li>read a TOML file</li>
<li>locate the configured paths</li>
<li>create symlinks, based on custom marker text in the filenames, for files in subdirectories under the configured paths<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></li>
</ul>
<p>If there&rsquo;s a conflict (i.e. two configured paths provide the same symlink target location), the TOML file contains the resolution for it (i.e. specifies one of the paths as the &ldquo;winner&rdquo; for that file). If a resolution doesn&rsquo;t exist, the script errors out.</p>
<p>This setup exists mainly to allow me to have work-only dotfiles managed in work&rsquo;s VCS with all their corporate stuff while keeping them separate yet cooperative with my dotfiles managed publicly on GitHub.</p>
<h2 id="the-problem">The problem</h2>
<p>Now, this effectively means that my dotfiles manager is a Python script. It also has a bunch of dependencies (specifically, <code>rich</code> because I like colors and <code>tomli</code> because it should probably run on all supported Python versions).</p>
<p>This usually means that you need to create a virtual environment to run it. That&rsquo;s gotten a bit tedious and fragile given how frequently I keep changing my Python installations (gotta keep up with the latest and greatest!).</p>
<h2 id="the-solution">The solution</h2>
<h3 id="the-implementation">The implementation</h3>
<p>I figured out a way to ensure that the script can be run without needing to manage a virtual environment myself. Now, it can be run on any machine with a working <code>curl</code>, <code>bash</code>, <code>python3</code> and the ability to download from <a href="https://github.com">https://github.com</a>. It also gracefully triggers MacOS&rsquo; prompt for &ldquo;Hey, do you want to install our developer tooling stuff?&rdquo; (XCode Command Line Tools, via the <code>python3</code> shim they install on a new Mac).</p>
<p>This is made possible by <code>pipx</code>, inline dependency metadata and Python&rsquo;s zipapps. There are also a few shenanigans to make this script a valid Bash script and a valid Python script. A <code>&quot;&quot;&quot;&quot;true</code> serves as our little gem of polyglot magic to make that possible.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<h3 id="how-it-works-bash">How it works: Bash</h3>
<p>Let me show you the script first, with Bash&rsquo;s syntax highlighting:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/usr/bin/env bash
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># /// script</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># requires-python = &#34;&gt;=3.8&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># dependencies = [</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#   &#34;rich&#34;,</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#   &#34;tomli&#34;,</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># ]</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># ///</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;&#34;</span>true
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> ! -f <span style="color:#e6db74">&#39;/tmp/pipx-dotfiles.pyz&#39;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>  echo <span style="color:#e6db74">&#34;Downloading pipx...&#34;</span>
</span></span><span style="display:flex;"><span>  curl --proto <span style="color:#e6db74">&#39;=https&#39;</span> --tlsv1.2 -sSLf https://github.com/pypa/pipx/releases/latest/download/pipx.pyz -o /tmp/pipx-dotfiles.pyz
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span>python3 /tmp/pipx-dotfiles.pyz run <span style="color:#e6db74">&#34;</span>$0<span style="color:#e6db74">&#34;</span> -- <span style="color:#e6db74">&#34;</span>$@<span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span>exit
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">import rich
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">print(rich.__version__)
</span></span></span></code></pre></div><p>From Bash&rsquo;s perspective, this script has a bunch of comments, then a few commands, and then an <code>exit</code>.</p>
<p>The way Bash processes a script is by reading it as a buffer and executing it before moving on. This allows Bash scripts containing syntax issues to be run, as long as the syntax issue is somewhere that isn&rsquo;t being read by Bash (i.e. after the point of exit). We&rsquo;re definitely using that since the Python code (which is not valid Bash syntax) is present after the <code>exit</code>.</p>
<p>To Bash, our little gem of magic (<code>&quot;&quot;&quot;&quot;true</code>) is the same as a <code>true</code> command since it&rsquo;s a bunch of empty strings concatenated together with <code>true</code>. And, <code>true</code> is used as a no-op command (it exits with code 0 and does nothing else).<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup> It is treated the same as a <code>true</code> on its own line and Bash proceeds with the rest of the logic as a regular Bash script.</p>
<p>The rest of the logic in the Bash script is to download <code>pipx</code>&rsquo;s zipapp (if it&rsquo;s not already downloaded) and then run the script itself with <code>python3 &lt;pipx-zipapp&gt; run &lt;script&gt; -- &lt;any arguments passed to the script&gt;</code>.</p>
<h3 id="how-it-works-zipapp">How it works: zipapp</h3>
<p>Wait, a zipapp?</p>
<p>So, that&rsquo;s a fun Python feature: it can execute a zip file as if it were a script. Python will look for a <code>__main__.py</code> in the zip file and, if it&rsquo;s there, the <code>__main__.py</code> as if it were a script. See <a href="https://docs.python.org/3/library/zipapp.html">the documentation</a> if you want to learn more about this.</p>
<p>In this case, the <code>pipx</code> maintainers create a maintain a zipapp and attach it to their GitHub releases. By using GitHub&rsquo;s <code>latest</code> release URL, we can fetch the zipapp for the latest release (with a redirect, hence the <code>-L</code> to <code>curl</code>) without much additional complexity.</p>
<h3 id="how-it-works-pipx-run">How it works: pipx run</h3>
<p><code>pipx run</code> enables running a script with the dependencies being installed by <code>pipx</code> in a cached virtual environment that is managed by <code>pipx</code>.</p>
<p>Notably, it supports <a href="https://peps.python.org/pep-0723/">PEP 723</a> (inline script metadata) which enables declaring dependency information inline. This is what the <code>/// script</code> and <code>///</code> are serving as markers for. The <code>requires-python</code> and <code>dependencies</code> are bits of metadata that <code>pipx</code> will use to determine what needs to be present for running the script.</p>
<p>Assuming you&rsquo;re on a compatible Python, <code>pipx</code> will parse that chunk, install the dependencies in a cached virtual environment and then run the script within that virtual environment. This means that the dependencies are installed by <code>pipx</code> and can/will be reused across multiple runs of the script by <code>pipx</code>.</p>
<h3 id="how-it-works-python">How it works: Python</h3>
<p>Let&rsquo;s look at the script again, this time with Python&rsquo;s syntax highlighting:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e">#!/usr/bin/env bash</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># /// script</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># requires-python = &#34;&gt;=3.8&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># dependencies = [</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#   &#34;rich&#34;,</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#   &#34;tomli&#34;,</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># ]</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># ///</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;&#34;true
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">if [[ ! -f &#39;/tmp/pipx-dotfiles.pyz&#39; ]]; then
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">  echo &#34;Downloading pipx...&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">  curl --proto &#39;=https&#39; --tlsv1.2 -sSLf https://github.com/pypa/pipx/releases/latest/download/pipx.pyz -o /tmp/pipx-dotfiles.pyz
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">fi
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">python3 /tmp/pipx-dotfiles.pyz run &#34;$0&#34; -- &#34;$@&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">exit
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> rich
</span></span><span style="display:flex;"><span>print(rich<span style="color:#f92672">.</span>__version__)
</span></span></code></pre></div><p>From Python&rsquo;s perspective, this script has a bunch of comments, then a docstring, and then the whole Python script.</p>
<p>To Python, our little gem of magic (<code>&quot;&quot;&quot;&quot;true</code>) is the start of a multiline string which starts with the content <code>&quot;true\n</code>. This is valid Python syntax, and Python will happily treat it as the start of the string literal. The end of the string literal is the next <code>&quot;&quot;&quot;</code> it encounters, which is the one at the end of the Bash parts of the script.</p>
<p>This means that the Bash script is treated as a multiline string by Python. It&rsquo;s treated as the docstring of the Python script. I am not too concerned about that since this is a script that doesn&rsquo;t need a docstring.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><code>symlink</code> with periods around it based on where in the file it shows up&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I learned about this approach from <a href="https://stackoverflow.com/q/15190055/1931274">this StackOverflow question</a>.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>It is possible to put almost any valid Bash syntax after the 4 double quotes (like, you can start an <code>if</code> statement, or something else) as long as you don&rsquo;t have whitespace between the 4th double quote and the keyword/CLI tool name. I just didn&rsquo;t like how that stuff looked so I went with <code>true</code> on that line.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>pip 24.1 betas -- help us test a major upcoming change!</title><link>https://pradyunsg.me/blog/2024/05/13/pip-24-1-betas/</link><pubDate>Mon, 13 May 2024 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2024/05/13/pip-24-1-betas/</guid><description>&lt;p&gt;The pip team has released &lt;a href="https://pypi.org/project/pip/24.1b1/"&gt;pip 24.1b1&lt;/a&gt; which contains a &lt;a href="https://pip.pypa.io/en/latest/news/#b1-2024-05-06"&gt;lot of significant improvements and bug fixes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to highlight a major change in this blog post: the removal of support for &amp;ldquo;legacy&amp;rdquo; versions and dependency specification, or as I like to call it, nonsensical versions and dependencies. We&amp;rsquo;re releasing this as a beta to get feedback from the community on how this change affects their workflows.&lt;/p&gt;
&lt;h2 id="nonsensical-versions-and-dependencies"&gt;Nonsensical versions and dependencies&lt;/h2&gt;
&lt;p&gt;For a bunch of historical reasons, pip has allowed many arbitrary strings as versions and dependency specification. There&amp;rsquo;s so many kinds of bad behaviours that this &amp;ldquo;feature&amp;rdquo; has enabled.&lt;/p&gt;</description><content:encoded><![CDATA[<p>The pip team has released <a href="https://pypi.org/project/pip/24.1b1/">pip 24.1b1</a> which contains a <a href="https://pip.pypa.io/en/latest/news/#b1-2024-05-06">lot of significant improvements and bug fixes</a>.</p>
<p>I&rsquo;d like to highlight a major change in this blog post: the removal of support for &ldquo;legacy&rdquo; versions and dependency specification, or as I like to call it, nonsensical versions and dependencies. We&rsquo;re releasing this as a beta to get feedback from the community on how this change affects their workflows.</p>
<h2 id="nonsensical-versions-and-dependencies">Nonsensical versions and dependencies</h2>
<p>For a bunch of historical reasons, pip has allowed many arbitrary strings as versions and dependency specification. There&rsquo;s so many kinds of bad behaviours that this &ldquo;feature&rdquo; has enabled.</p>
<p>My favourite example is <a href="https://github.com/pypa/packaging/issues/530">one I wrote back in 2022</a> on the <code>packaging</code><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> project&rsquo;s issue tracker:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> packaging<span style="color:#f92672">.</span>version<span style="color:#f92672">.</span>parse(<span style="color:#e6db74">&#34;This is a completely random string&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;</span>LegacyVersion(<span style="color:#e6db74">&#39;This is a completely random string&#39;</span>)<span style="color:#f92672">&gt;</span>
</span></span></code></pre></div><p>Or providing weird version comparisons:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> packaging<span style="color:#f92672">.</span>version<span style="color:#f92672">.</span>parse(<span style="color:#e6db74">&#34;1.0&#34;</span>) <span style="color:#f92672">&gt;</span> packaging<span style="color:#f92672">.</span>version<span style="color:#f92672">.</span>parse(<span style="color:#e6db74">&#34;99999.0.whatever&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">True</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> packaging<span style="color:#f92672">.</span>version<span style="color:#f92672">.</span>parse(<span style="color:#e6db74">&#34;1.0&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;</span>Version(<span style="color:#e6db74">&#39;1.0&#39;</span>)<span style="color:#f92672">&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> packaging<span style="color:#f92672">.</span>version<span style="color:#f92672">.</span>parse(<span style="color:#e6db74">&#34;99999.0.whatever&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;</span>LegacyVersion(<span style="color:#e6db74">&#39;99999.0.whatever&#39;</span>)<span style="color:#f92672">&gt;</span>
</span></span></code></pre></div><p>Or hiding mistakes in dependency declarations:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-py" data-lang="py"><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> all_dependencies <span style="color:#f92672">=</span> [
</span></span><span style="display:flex;"><span><span style="color:#f92672">...</span>     <span style="color:#e6db74">&#34;package == 1&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">...</span>     <span style="color:#e6db74">&#34;another-package&#34;</span>,
</span></span><span style="display:flex;"><span><span style="color:#f92672">...</span>     <span style="color:#e6db74">&#34;yet-another-package&#34;</span>,
</span></span><span style="display:flex;"><span>]
</span></span><span style="display:flex;"><span><span style="color:#f92672">&gt;&gt;&gt;</span> [packaging<span style="color:#f92672">.</span>requirements<span style="color:#f92672">.</span>Requirement(s) <span style="color:#66d9ef">for</span> s <span style="color:#f92672">in</span> all_dependencies]
</span></span><span style="display:flex;"><span>[<span style="color:#f92672">&lt;</span>Requirement(<span style="color:#e6db74">&#39;package==1another-package&#39;</span>)<span style="color:#f92672">&gt;</span>, <span style="color:#f92672">&lt;</span>Requirement(<span style="color:#e6db74">&#39;yet-another-package&#39;</span>)<span style="color:#f92672">&gt;</span>]
</span></span></code></pre></div><p>Over a decade ago, the Python packaging ecosystem adopted <a href="https://peps.python.org/pep-0440/">PEP 440</a> which defined a standard for versions and dependency specification. While this standard has been adopted by basically every single tool in the ecosystem, support for &ldquo;legacy&rdquo; versions and requirements has been maintained even though it has caused a lot of user confusion and bugs in the Python ecosystem.</p>
<h2 id="getting-rid-of-the-nonsense">Getting rid of the nonsense</h2>
<p>Over the course of the last decade, across multiple projects in the Python packaging ecosystem, many PyPA projects have been working to make this behaviour not possible. The package index, <a href="https://pypi.org">https://pypi.org</a>, has not accepted uploads with bad versions for many years now and is also enforcing validity of the requirements on all uploads. The tooling that generate packages (build-backends) also now refuse to generate packages with such bad metadata in them.</p>
<p>This effort has been undertaken by many people across the Python packaging ecosystem, and I&rsquo;m very grateful for all the work that has gone into this. It regularly surprises me how much work goes into making sure that the foundational pieces of Python&rsquo;s packaging ecosystem are improving, even absent any institutional investment into it.</p>
<p>This pip release marks the next major step in the direction of improving behaviours in this area: updating the package installer to stop accepting such packages. Starting with this pip release, pip will refuse to install packages with bad versions or dependency specification and will ignore any files with such bad versions or dependency specification during the dependency resolution step.</p>
<h2 id="where-we-cant-see-the-nonsense">Where we can&rsquo;t see the nonsense</h2>
<p>While a substantial amount of effort has been put into making sure pip can work correctly when enforcing correctness around these versions and dependency specification, we want to be cautious in rolling out this change. There are many places that Python is used where we can&rsquo;t access the packages (e.g. private package indexes hosting proprietary code), and thus can&rsquo;t ensure that packages have appropriate metadata in those spaces.</p>
<p>We&rsquo;re releasing this as a beta to get feedback from the community on any issues that might arise from this change. This will help us better understand how this change affects user workflows and what actionable guidance can be provided to users in various contexts.</p>
<h2 id="help-us-test-the-changes">Help us test the changes</h2>
<p>We&rsquo;re looking for feedback from Python users on this beta release. Notably, we&rsquo;d like for users who are using package indexes other than PyPI to test their workflows against this beta release of pip and provide us with feedback.</p>
<p>You can let us know about issues related to this change on pip&rsquo;s issue tracker (please check for duplicates before filing, and use reactions rather than saying &ldquo;me too&rdquo;!). Please also feel welcome to tell us about the good stuff, like if this release made dependency resolves quicker &ndash; we like hearing about that too! :)</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>While there&rsquo;s a lot of people who have worked on things I mentioned in this blog post, I can&rsquo;t really list them all here &ndash; you know who you are, and thank you for all the work you&rsquo;ve done toward this as well as the other cool things you&rsquo;ve worked on.</p>
<p>I do want to thank Paul Moore, Stéphane Bidoul, Richard Si and Pavithra Eswaramoorthy for reviewing various drafts of this post and providing feedback on it.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Listen, software engineers are great at naming things. This is obviously the Python package providing shared common implementations of Python packaging standards for Python packaging tools. And, yes, it&rsquo;s hosted on the Python package index.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Making GitHub Notifications UI slightly nicer for bulk triage</title><link>https://pradyunsg.me/blog/2024/03/17/github-notifications-userstyles/</link><pubDate>Sun, 17 Mar 2024 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2024/03/17/github-notifications-userstyles/</guid><description>&lt;p&gt;I&amp;rsquo;m someone who gets a &lt;em&gt;lot&lt;/em&gt; of GitHub notifications &amp;ndash; this week had &amp;gt;100 individual notifications.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;The &amp;ldquo;new&amp;rdquo; GitHub Notifications UI&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; was based on &lt;a href="https://octobox.io/"&gt;Octobox&lt;/a&gt;. It was a step in the right direction to help with my notification &amp;ldquo;workload&amp;rdquo;, although I recognise that it was not perceived as such by many others.&lt;/p&gt;
&lt;p&gt;That said, they copied over the exact same design issue I had with Octobox: the action buttons are on the completely opposite side from where my attention is.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m someone who gets a <em>lot</em> of GitHub notifications &ndash; this week had &gt;100 individual notifications.</p>
<h2 id="the-problem">The problem</h2>
<p>The &ldquo;new&rdquo; GitHub Notifications UI<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> was based on <a href="https://octobox.io/">Octobox</a>. It was a step in the right direction to help with my notification &ldquo;workload&rdquo;, although I recognise that it was not perceived as such by many others.</p>
<p>That said, they copied over the exact same design issue I had with Octobox: the action buttons are on the completely opposite side from where my attention is.</p>
<p><img alt="Vanilla GitHub Notification UI entry, showing the action icons in their default location" loading="lazy" src="/media/github-notifications-2024-vanilla.png"></p>
<p>I am going to scan and read the content of the notification, which is left aligned and very close to the <em>left</em> edge. All the action buttons are on the <em>right</em> edge. This makes it difficult when trying to triage notifications, especially when I&rsquo;m trying to do so in bulk where stuff like &ldquo;oh, this is not gonna need my attention&rdquo; requires me to drag my cursor over to the other side of the page.</p>
<p>If there&rsquo;s a keyboard shortcut for this, I don&rsquo;t know it and I don&rsquo;t want to learn it anyway. I want to be able to use the mouse to do what I need here because that&rsquo;s how I use a computer.</p>
<h2 id="the-solution">The solution</h2>
<p>I wrote a blurb of CSS to remove this annoyance.</p>
<p><img alt="Modified GitHub Notification UI row, showing the moved action icons" loading="lazy" src="/media/github-notifications-2024-modified.png"></p>
<p>It moves the action buttons toward the left side, so that I can quickly triage notifications without having to move my cursor across the screen. It also moves the text describing the content that the notification is for (repository and notification subject) to accommodate for the buttons.</p>
<p>If you know me, you know that I will animate moving text to different locations. In the end, this was fairly easy to achieve in this case.</p>
<p><img alt="Three rows in the modified GitHub Notification UI row, showcasing the animation associated with hovering over a specific notification" loading="lazy" src="/media/github-notifications-2024-modified.gif"></p>
<p>I&rsquo;ve been using this for quite a few months now.</p>
<h2 id="the-stylesheet">The stylesheet</h2>
<p>Recently, while screen sharing with a friend, they asked me about my GitHub notifications doing this really cool thing. That&rsquo;s when I realised that I had completely forgotten that this was something I had been injecting into the page. I shared it with them and realised that some other people might find this useful too.</p>
<p>If you also find this change to be an improvement, the CSS blurb that needs to be injected is provided below. You can add this via <a href="https://github.com/refined-github/refined-github">Refined GitHub</a>&rsquo;s preferences page or use a more generic extension like <a href="https://add0n.com/stylus.html">Stylus</a> to inject this into the GitHub Notifications page.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-css" data-lang="css"><span style="display:flex;"><span>.<span style="color:#a6e22e">notification-list-item-actions</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">right</span>: <span style="color:#66d9ef">unset</span> <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">left</span>: <span style="color:#ae81ff">4</span><span style="color:#66d9ef">rem</span> <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">padding</span>: <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">8</span><span style="color:#66d9ef">px</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">notifications-list-item</span>:<span style="color:#a6e22e">hover</span> .<span style="color:#a6e22e">note</span>.<span style="color:#a6e22e">notification-list-item-hide-on-hover</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">visibility</span>: <span style="color:#66d9ef">visible</span> <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">notifications-list-item</span> .<span style="color:#a6e22e">notification-list-item-link</span> <span style="color:#f92672">[</span><span style="color:#f92672">id</span><span style="color:#f92672">^=</span><span style="color:#e6db74">&#34;notification&#34;</span><span style="color:#f92672">]</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">margin-left</span>: <span style="color:#ae81ff">0</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">transition</span>: <span style="color:#66d9ef">margin-left</span> <span style="color:#ae81ff">100</span><span style="color:#66d9ef">ms</span> cubic-bezier(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0.8</span>, <span style="color:#ae81ff">0.2</span>, <span style="color:#ae81ff">1</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">notifications-list-item</span>:<span style="color:#a6e22e">hover</span>
</span></span><span style="display:flex;"><span>  .<span style="color:#a6e22e">notification-list-item-link</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">[</span><span style="color:#f92672">id</span><span style="color:#f92672">^=</span><span style="color:#e6db74">&#34;notification&#34;</span><span style="color:#f92672">]</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">margin-left</span>: <span style="color:#ae81ff">8</span><span style="color:#66d9ef">rem</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">notification-list-item-link</span> <span style="color:#f92672">&gt;</span> :<span style="color:#a6e22e">nth-child</span><span style="color:#f92672">(</span><span style="color:#f92672">1</span><span style="color:#f92672">)</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">align-self</span>: <span style="color:#66d9ef">unset</span> <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">notifications-list-item</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&gt;</span> <span style="color:#f92672">div</span>:<span style="color:#a6e22e">nth-child</span><span style="color:#f92672">(</span><span style="color:#f92672">1</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&gt;</span> <span style="color:#f92672">div</span>:<span style="color:#a6e22e">nth-child</span><span style="color:#f92672">(</span><span style="color:#f92672">1</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&gt;</span> <span style="color:#f92672">div</span>:<span style="color:#a6e22e">nth-child</span><span style="color:#f92672">(</span><span style="color:#f92672">1</span><span style="color:#f92672">)</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">align-self</span>: <span style="color:#66d9ef">unset</span> <span style="color:#75715e">!important</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Does it count as new if it&rsquo;s been around since <a href="https://github.blog/2020-02-25-your-new-web-notifications-experience-is-here/">2020</a>?&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Choreographing a release process for my PyPI packages</title><link>https://pradyunsg.me/blog/2024/01/27/package-release-workflow/</link><pubDate>Sat, 27 Jan 2024 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2024/01/27/package-release-workflow/</guid><description>&lt;p&gt;I maintain quite a few Python packages and they all have development workflows as well as release processes that are different in various ways.&lt;/p&gt;
&lt;p&gt;This is basically my research document as I am exploring what I want the release process (and supporting development workflow) to look like for the Python packages I maintain, so that I can reduce the overhead caused by the various differences in these projects as well as the need to make all these decisions myself. I&amp;rsquo;m posting this publicly so that I can get feedback from a few people I know about this and whether they think it makes sense.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I maintain quite a few Python packages and they all have development workflows as well as release processes that are different in various ways.</p>
<p>This is basically my research document as I am exploring what I want the release process (and supporting development workflow) to look like for the Python packages I maintain, so that I can reduce the overhead caused by the various differences in these projects as well as the need to make all these decisions myself. I&rsquo;m posting this publicly so that I can get feedback from a few people I know about this and whether they think it makes sense.</p>
<p>None of this is related to the whole &ldquo;what build-backend/environment management/script runner tool should I use&rdquo; situation but rather it&rsquo;s everything &ldquo;around&rdquo; that. I&rsquo;m not going into the test running or documentation building aspects here, &ldquo;just&rdquo; the mechanics around making a package release.</p>
<h2 id="my-design-goals">My design goals</h2>
<p>This is basically &ldquo;what I want&rdquo; in terms of using existing communication channels, ensuring consistency and the development workflow.</p>
<ul>
<li>Have the version number managed as-is in the source tree.</li>
<li>Have the version number be <code>{last_release+1}.dev{N}</code> during development.</li>
<li>Have a git tag pointing to the commit with a release&rsquo;s code.</li>
<li>Have a changelog auto-generated based on the Git history or source tree.</li>
<li>Include the changelog in the documentation at the release tag.</li>
<li>Publish to pypi.org via Trusted Publishers, triggered automatically but requiring manual approval<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</li>
<li>Publish a GitHub release.
<ul>
<li>Include the changelog in the GitHub release description.</li>
<li>Include the release files on the GitHub release.</li>
</ul>
</li>
<li>The git tag and GitHub release must not be published if the release cannot be uploaded to PyPI.</li>
<li>Releasing to PyPI requires a manual approval even after PR merge.</li>
</ul>
<h2 id="what-those-design-goals-imply">What those design goals imply</h2>
<ul>
<li>changelog:
<ul>
<li>needs to be maintained in Markdown, specifically the intersection of <a href="https://github.github.com/gfm/">GFM</a> and <a href="https://myst-parser.readthedocs.io/en/latest/">MyST</a>.</li>
<li>needs to be generated <em>before</em> making the commit that the release would be tagged on, since the documentation within the release should contain the generated changelog.</li>
<li>needs to only describe what happened between this release and the last one (so that it makes sense in the GitHub releases UI).</li>
</ul>
</li>
<li>PyPI release:
<ul>
<li>needs to happen on GitHub Actions, and the release needs to be triggered by a git tag (with protection rules on git tags).</li>
<li>needs to also upload the files to GitHub release.</li>
</ul>
</li>
<li>version number:
<ul>
<li>need a figure out the logic for bumping to next development version.</li>
<li>need some way to detect when a PR changes the version number and determine the commit that should trigger a release.</li>
</ul>
</li>
</ul>
<h2 id="lets-figure-out-the-details-now">Let&rsquo;s figure out the details now</h2>
<p>The specific flow that seems to be needed here is:</p>
<ul>
<li>Merge a PR that bumps the release version.</li>
<li>The merge will trigger a &ldquo;release&rdquo; workflow that has the ability to push a commit (containing the changelog) and trigger a different &ldquo;publish&rdquo; workflow.</li>
<li>The triggered &ldquo;publish&rdquo; workflow needs approval to run and has the ability to publish to PyPI, push a git tag, publish a GitHub release and include the description as well as release files<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</li>
</ul>
<h3 id="changelog-is-not-the-same-everywhere">Changelog is not the same everywhere</h3>
<p>Well, the changelog in documentation needs to do some things that the GitHub UI would do for &ldquo;free&rdquo;: have a link to the original diff between releases and a link to individual PRs in changelog entries.</p>
<p>Additionally, the changelog in documentation should also have a preview when looking at &ldquo;latest&rdquo; documentation, to communicate how things would work.</p>
<h3 id="deciding-on-how-to-detect-version-number-changes">Deciding on how to detect version number changes</h3>
<p>There&rsquo;s basically 2 options here:</p>
<ul>
<li>Try to look at the source of truth that lives in the source code (like <code>src/package/__init__.py -&gt; __version__</code> / <code>pyproject.toml -&gt; project.version</code>).</li>
<li>Look at the relevant PR and bump the version based on some immutable thing about the PR.</li>
</ul>
<p>I think the first is a better experience, since it&rsquo;s a bit more intuitive &ndash; the version number changed and a release was automatically made. With this, an obvious place to make the release tag would be the &ldquo;first&rdquo; commit that bumps the version, which would need to vary based on merge strategy&hellip;</p>
<ul>
<li>merge commit: Use the merge commit into <code>main</code>, that has the multiple parents.</li>
<li>squash merges: Use the first commit that bumps the version.</li>
<li>rebase merges: Use the first commit that bumps the version&hellip; but wait&hellip;</li>
</ul>
<h4 id="oh-heck-rebase-merges">Oh heck, rebase merges</h4>
<p>Ohk, let&rsquo;s think through this. I have a PR that contains 3 commits:</p>
<ul>
<li><code>3pstrel</code> Awesome change after the version bump</li>
<li><code>2verbmp</code> Version bump</li>
<li><code>1prerel</code> Awesome change before the version bump</li>
<li><code>0staquo</code> (main) Status quo</li>
</ul>
<p>Assuming that this is rebase-merged, I <em>think</em> the release commit should be based on top of <code>2verbmp</code>. But, the only way to have it make sense with <code>3pstrel</code> is to have the release commit be based on <code>2verbmp</code> and then later to do a merge commit &ndash; which defeats the point of rebase merges (linear history).</p>
<p>I guess there&rsquo;s 2 options here:</p>
<ul>
<li>Detect such cases and error out.</li>
<li>Don&rsquo;t bother merging back the release tag commit.</li>
</ul>
<p>If we don&rsquo;t merge back the release tag commit, then the release process needs to not require <em>any</em> code change other than the version bump. The changelog needs to be managed out-of-tree somehow (eg: in git?). I like having the ability to update a changelog entry that was contributed by a fly-by contributor after the PR has been merged, so this is a no-go for me.</p>
<p>In terms of detecting such cases, I guess I could have a GitHub Actions check that there isn&rsquo;t a commit in the PR after one that bumps the version.</p>
<h4 id="looking-at-the-source-of-truth">Looking at the source of truth</h4>
<p>Doing a quick search on the internet for how to find when a line has changed with git, I found <a href="https://stackoverflow.com/questions/13692072/git-blame-committed-line">a useful StackOverflow question</a> which points me to <code>git log -L &lt;range&gt;:&lt;file&gt;</code>. Trying it out on pip tells me this is a good option:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh-session" data-lang="sh-session"><span style="display:flex;"><span>❯ git ls -L 3,3:src/pip/__init__.py -q
</span></span><span style="display:flex;"><span>c0cce3ca6 Bump for development [Stéphane Bidoul]
</span></span><span style="display:flex;"><span>e3dc91dad (tag: 23.3) Bump for release [Stéphane Bidoul]
</span></span><span style="display:flex;"><span>b6a267059 Bump for development [Paul Moore]
</span></span><span style="display:flex;"><span>a3c2c43c5 (tag: 23.2) Bump for release [Paul Moore]
</span></span><span style="display:flex;"><span>2fd3e408d Bump for development [Paul Moore]
</span></span><span style="display:flex;"><span>6424ac460 (tag: 23.1) Bump for release [Paul Moore]
</span></span><span style="display:flex;"><span>d21af1c98 Bump for development [Pradyun Gedam]
</span></span><span style="display:flex;"><span>368c7b4c5 (tag: 23.0) Bump for release [Pradyun Gedam]
</span></span><span style="display:flex;"><span>c8ae28001 Bump for development [Paul Moore]
</span></span><span style="display:flex;"><span>0a76da3a9 (tag: 22.3) Bump for release [Paul Moore]
</span></span><span style="display:flex;"><span>2132eb4cd Bump for development [Stéphane Bidoul]
</span></span><span style="display:flex;"><span>8e7e76e60 (tag: 22.2) Bump for release [Stéphane Bidoul]
</span></span><span style="display:flex;"><span>88d565cc3 Bump for development [Pradyun Gedam]
</span></span><span style="display:flex;"><span>3c953322c (tag: 22.1) Bump for release [Pradyun Gedam]
</span></span><span style="display:flex;"><span>6012b48e5 Bump for development [Pradyun Gedam]
</span></span><span style="display:flex;"><span>9b203d5af (tag: 22.1b1) Bump for release [Pradyun Gedam]
</span></span><span style="display:flex;"><span>0a916125e Bump for development [Pradyun Gedam]
</span></span><span style="display:flex;"><span>1742af7bd (tag: 22.0) Bump for release [Pradyun Gedam]
</span></span><span style="display:flex;"><span>2bf32f5f9 Bump for development [Pradyun Gedam]
</span></span><span style="display:flex;"><span>abec8a701 (tag: 21.3) Bump for release [Pradyun Gedam]
</span></span><span style="display:flex;"><span>[...]
</span></span></code></pre></div><p>And, that the existing automation around pip releases is quite nice.</p>
<p>I still need to figure out how to gracefully handle changes to the source of truth for versions as well as moving it around without logical changes (eg: editing the docstring, or changing quoting etc).</p>
<p>Oh, this reminded me about pip&rsquo;s releases&hellip;</p>
<h3 id="lets-think-about-pip">Let&rsquo;s think about pip</h3>
<p>I&rsquo;m not the only one who makes the calls on this but I think it would be nice to move pip to Trusted Publishers for publishing releases. Looking at the documented pip process, the main things that&rsquo;d <strong>need</strong> to different if it adopted this release process would be:</p>
<ol>
<li>Update <code>get-pip.py</code>&rsquo;s GitHub repository to reflect the new pip release on PyPI.</li>
<li>Update an AUTHORS file.</li>
</ol>
<p>Those don&rsquo;t seem particularly bad. For 1, we&rsquo;d need to tweak the generation logic over on <code>get-pip.py</code> to listen for <code>repository_dispatch</code> and <a href="https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#create-a-repository-dispatch-event">trigger that event</a> manually with the relevant payload and that&rsquo;ll need <code>pypa/pip</code> to store an access token to <code>pypa/get-pip</code> that is only exposed for that specific trigger, which&hellip; seems doable.</p>
<h2 id="what-needs-to-be-created">What needs to be created?</h2>
<ul>
<li>3 GitHub Actions reusable workflows for individual &ldquo;tasks&rdquo;
<ul>
<li>A &ldquo;release&rdquo; workflow that determines if a release needs to be made and triggers the &ldquo;publish&rdquo; workflow via a <code>workflow_dispatch</code>.</li>
<li>A &ldquo;publish&rdquo; workflow that does all the mechanics of making the release.</li>
<li>A &ldquo;release-check&rdquo; workflow that checks the commit situation to protect against &ldquo;commit after version bump&rdquo; edge cases.</li>
</ul>
</li>
<li>1 GitHub Actions reusable workflow for consolidated handling in project CI, to enable the project&rsquo;s <code>release.yml</code> to be a short file that&rsquo;s &ldquo;just&rdquo; <code>on: [...]</code> and <code>uses: [...]</code>.</li>
</ul>
<h2 id="naming-the-second-hardest-problem-in-computer-science">Naming: The second hardest problem in computer science</h2>
<p>I feel like I should come up with a name for this, because it&rsquo;d make communicating about this easier for me and because this workflow <em>feels</em> like it would be useful to more than just me.</p>
<p>This is automation that makes a release when it detects by a version change in source code and publishes to PyPI and GitHub, with an auto-generated changelog.</p>
<p>For now, this is a problem for future me and depends on whether he decides that he needs to maintain another piece of reusable software.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>With a few too many &ldquo;critical&rdquo; (i.e. top 1% packages) on PyPI, including literally pip, I think an extra step to ensure that it&rsquo;s a bit harder to take-over things unilaterally seems reasonable to me.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>If you&rsquo;re an SBOM/SLSA person, this is also where I&rsquo;d like to include some sort of attestation/provenance information but there isn&rsquo;t any clear-enough documentation that I could find for how to do this. Please email me if you know of a solution (<code>mail@{this domain}</code>).&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>PDM does not implement PEP 582, at the time of writing</title><link>https://pradyunsg.me/blog/2023/01/21/pdm-does-not-implement-pep-582/</link><pubDate>Sat, 21 Jan 2023 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2023/01/21/pdm-does-not-implement-pep-582/</guid><description>&lt;p&gt;Note: I&amp;rsquo;ve updated this to reflect &lt;em&gt;how&lt;/em&gt; this happened, on recommendation from PDM&amp;rsquo;s author.&lt;/p&gt;
&lt;p&gt;PDM &lt;a href="https://github.com/pdm-project/pdm/tree/c0974672a17be965ddcb0e191d35df08ad0c4b6e#highlights-of-features"&gt;claims to implement PEP 582&lt;/a&gt;. However, if you look at what it implements, it is &lt;a href="https://github.com/pdm-project/pdm/blob/c0974672a17be965ddcb0e191d35df08ad0c4b6e/src/pdm/pep582/sitecustomize.py#L11"&gt;something completely different&lt;/a&gt; from &lt;a href="https://peps.python.org/pep-0582/#example"&gt;the standard&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="pdms-file-system-structure"&gt;PDM&amp;rsquo;s file system structure&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;root&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; __pypackages__
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 3.10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bottle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myscript.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PDM will scan for the &lt;code&gt;__pypackages__&lt;/code&gt; directory up to 5 folders above the &amp;ldquo;current&amp;rdquo; one.&lt;/p&gt;
&lt;h2 id="pep-582s-file-system-structure"&gt;PEP 582&amp;rsquo;s file system structure&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&amp;lt;root&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; __pypackages__
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; lib
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; python3.10
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; site-packages
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; bottle
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; myscript.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;PEP 582 says that the &lt;code&gt;__pypackages__&lt;/code&gt; directory should be next to the script being executed, and there&amp;rsquo;s no discovery logic &amp;ldquo;above&amp;rdquo; the script.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Note: I&rsquo;ve updated this to reflect <em>how</em> this happened, on recommendation from PDM&rsquo;s author.</p>
<p>PDM <a href="https://github.com/pdm-project/pdm/tree/c0974672a17be965ddcb0e191d35df08ad0c4b6e#highlights-of-features">claims to implement PEP 582</a>. However, if you look at what it implements, it is <a href="https://github.com/pdm-project/pdm/blob/c0974672a17be965ddcb0e191d35df08ad0c4b6e/src/pdm/pep582/sitecustomize.py#L11">something completely different</a> from <a href="https://peps.python.org/pep-0582/#example">the standard</a>.</p>
<h2 id="pdms-file-system-structure">PDM&rsquo;s file system structure</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>&lt;root&gt;
</span></span><span style="display:flex;"><span>    __pypackages__
</span></span><span style="display:flex;"><span>        3.10
</span></span><span style="display:flex;"><span>            bottle
</span></span><span style="display:flex;"><span>    myscript.py
</span></span></code></pre></div><p>PDM will scan for the <code>__pypackages__</code> directory up to 5 folders above the &ldquo;current&rdquo; one.</p>
<h2 id="pep-582s-file-system-structure">PEP 582&rsquo;s file system structure</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>&lt;root&gt;
</span></span><span style="display:flex;"><span>    __pypackages__
</span></span><span style="display:flex;"><span>        lib
</span></span><span style="display:flex;"><span>            python3.10
</span></span><span style="display:flex;"><span>                site-packages
</span></span><span style="display:flex;"><span>                    bottle
</span></span><span style="display:flex;"><span>    myscript.py
</span></span></code></pre></div><p>PEP 582 says that the <code>__pypackages__</code> directory should be next to the script being executed, and there&rsquo;s no discovery logic &ldquo;above&rdquo; the script.</p>
<h2 id="how-did-this-happen">How did this happen?</h2>
<p>PDM implemented a draft PEP. Draft PEPs are not final, and are subject to changes. However, PDM cannot evolve with the PEP since that means frequent breakages to the user experience as the standard evolves.</p>
<p>This leads to a situation where PDM is advertising implementing a (draft) PEP, while not implementing that PEP since the draft has evolved.</p>
<h2 id="why-does-this-matter">Why does this matter?</h2>
<p>Well, outside of the issues with implementing draft proposals in workflow tooling, I think this is reflective of the issues with the competitive nature of the Python packaging ecosystem&rsquo;s workflow tooling space.</p>
<p>I&rsquo;m willing to trust that PDM&rsquo;s authors are well intentioned and didn&rsquo;t intentionally aim to end up with &ldquo;false advertising&rdquo; in the first feature the project lists in the README.</p>
<p>Besides, I only took a closer look at this because I was talking to one of PEP 582&rsquo;s authors recently, and <a href="https://lwn.net/SubscriberLink/920132/cb4d6c0f07b54952/">LWN</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> linked to someone on the internet was claiming that PDM is a solution to Python packaging.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Which&hellip; in case someone from LWN ends up reading this: I think that was a bad editorial choice.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Thoughts on the Python packaging ecosystem</title><link>https://pradyunsg.me/blog/2023/01/21/thoughts-on-python-packaging/</link><pubDate>Sat, 21 Jan 2023 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2023/01/21/thoughts-on-python-packaging/</guid><description>&lt;p&gt;My response to the discussion topic posed in &lt;a href="https://discuss.python.org/t/python-packaging-strategy-discussion-part-1/22420?u=pradyunsg"&gt;Python Packaging Strategy Discussion Part 1&lt;/a&gt; had become quite long, so I decided to move it to write a blog post instead. This post then started absorbing various draft posts I&amp;rsquo;ve had on this topic since this blog was started, morphing to include my broader thoughts on where we are today.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: I&amp;rsquo;ve updated this to cover an aspect of the recent LWN article on the topic as well.&lt;/p&gt;</description><content:encoded><![CDATA[<p>My response to the discussion topic posed in <a href="https://discuss.python.org/t/python-packaging-strategy-discussion-part-1/22420?u=pradyunsg">Python Packaging Strategy Discussion Part 1</a> had become quite long, so I decided to move it to write a blog post instead. This post then started absorbing various draft posts I&rsquo;ve had on this topic since this blog was started, morphing to include my broader thoughts on where we are today.</p>
<p><em>Note</em>: I&rsquo;ve updated this to cover an aspect of the recent LWN article on the topic as well.</p>
<h2 id="tldr">TL;DR</h2>
<p>This post is a bit long, so here&rsquo;s the key points I&rsquo;m making:</p>
<ul>
<li>The Python packaging ecosystem <em>unintentionally</em> became the type of competitive space that it is today.</li>
<li>The community needs to make an explicit decision if it should continue operating under the model that led to status quo.</li>
<li>Pick from N different tools that do N different things is a good model.</li>
<li>Pick from N ~equivalent choices is a <em>really bad</em> user experience.</li>
<li>Picking a default doesn&rsquo;t make other approaches illegal.</li>
<li>Communication about the Python packaging ecosystem is fragmented, and we should improve that.</li>
</ul>
<hr>
<details>
<summary>My experience around Python Packaging</summary>
<p>At the time of writing:</p>
<ul>
<li>I&rsquo;m a maintainer on pip, installer, resolvelib, packaging, flit, Spack (allegedly), sphinx-theme-builder, pyproject-hooks, and more.</li>
<li>I&rsquo;m a moderator on PyPI.</li>
<li>I&rsquo;ve contributed in varying manners to setuptools, wheel, warehouse (i.e. PyPI), pipenv, Poetry, packaging.python.org, build, and more.</li>
<li>As a maintainer on pip, I&rsquo;m a member of the Python Packaging Authority (PyPA).</li>
<li>I&rsquo;ve co-authored multiple <a href="https://peps.python.org/topic/packaging/">Packaging PEPs</a>, including the <a href="https://www.python.org/dev/peps/pep-0609/">PyPA&rsquo;s Governance Model</a>.</li>
<li>I&rsquo;ve been the PEP-Delegate on multiple Packaging PEPs, trusted to make decisions on behalf of the community.</li>
</ul>
</details>
<!-- Python packaging has quite a reputation of being ridiculously difficult to get right, understand and work with. It would not be a stretch to say that the packaging and distribution story for Python is one of the main sources of pain for many users. -->
<h2 id="python-users-are-not-software-engineers">Python users are <em>not</em> software engineers</h2>
<p>Many of the users who write Python code are <em>not</em> primarily full-time software engineers or &ldquo;developers&rdquo;. They are not particularly interested in this aspect of their job. They&rsquo;re using Python as a tool to get their job done. They&rsquo;re not interested in the details of how the tool works, or even how complicated things are under the hood.</p>
<p>As Thea (Stargirl) Flowers <a href="https://hachyderm.io/@stargirl/109697057391904145">said recently</a>:</p>
<blockquote>
<p>The reason there are so many tools for managing Python dependencies is because Python is not a monoculture and different folks need different things.</p>
</blockquote>
<h2 id="user-expectations-for-a-default-workflow">User expectations for a &ldquo;default&rdquo; workflow</h2>
<p>A class of users expect a packaging tool that provides a cohesive experience (like npm (NodeJS), cargo (Rust), gem (Ruby), pub (Dart), dotnet (C#/.NET), etc) &ndash; a single tool that provides a build system, dependency manager, publishing, running project-specific tasks/scripts, etc. I&rsquo;ve referred to this as &ldquo;workflow tool&rdquo; in this post.</p>
<p>Certain other ecosystems have this in their &ldquo;default&rdquo; tool, providing a much more streamlined experience for users. I have first hand experience of this for NodeJS and Rust, where they have a single tool that users invoke to do the majority of their work:</p>
<ul>
<li>create a new project.</li>
<li>install/manage dependencies.</li>
<li>run their project w/ those dependencies.</li>
<li>test their project.</li>
<li>publish their project.</li>
<li>more?!</li>
</ul>
<p>Today, each of these pieces is a separate tool for Python and doesn&rsquo;t have a strict 1:1 mapping to the &ldquo;best practices&rdquo;/&ldquo;secure&rdquo; workflows. This is at odds with the expectations that these users have. This class of users, by and large, want consolidation and a single-tool experience.</p>
<p>We know that this class of users exists because we have:</p>
<ul>
<li>a number of popular tools that are attempting to provide this experience.</li>
<li>results from user surveys we&rsquo;ve done<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> <a href="https://drive.google.com/file/d/1U5d5SiXLVkzDpS0i1dJIA4Hu5Qg704T9/view">clearly indicate this</a> as well.</li>
<li>had multiple community members say this in multiple ways, across multiple channels.</li>
</ul>
<h2 id="flexibility-leads-to-complexity">Flexibility leads to complexity</h2>
<p>Brian Skinn <a href="https://discuss.python.org/t/packaging-vision-and-strategy-next-steps/21513/8?u=pradyunsg">said recently</a>:</p>
<blockquote>
<p>You can package darn near anything in Python, even though it may take figuring out a complicated three-step-and-a-hop process to get there… and I suspect that this has been part of what’s enabled Python to grow into its “second best programming language for every task” aphorism.</p>
</blockquote>
<p>I think there&rsquo;s some truth to that. <a href="https://packaging.python.org/en/latest/overview/">&ldquo;An Overview of Packaging for Python&rdquo;</a> on packaging.python.org expresses a similar tone as well:</p>
<blockquote>
<p>Packaging in Python has a bit of a reputation for being a bumpy ride. This impression is mostly a byproduct of Python’s versatility.</p>
</blockquote>
<p>I do want to contrast this with the fact that the overview page takes over 3000 words, to provide the &ldquo;high-level&rdquo; overview for how one can approach packaging a Python project. It doesn&rsquo;t even touch the specifics of configuration or provide any specific workflow guidance with that much digital ink.</p>
<p>The bumpy ride reputation is not misplaced, and is the most frequent user complaint (more on this later). There are consequences to the degree of flexibility afforded to users by the Python packaging ecosystem:</p>
<ul>
<li>every Python project has to make multiple decisions about how they want to do certain things</li>
<li>every Python user has to make choices for how they wanna manage their Python installation and workflow tools</li>
<li>it leads to multiple ways to achieve the same thing when trying to use Python packaging tools, with some of these ways being subtly wrong</li>
<li>it leads to a larger surface area of behaviours of existing/established tools that users rely upon.</li>
<li>it makes it much more likely that new users hit edge cases and paper-cuts, that more-experienced developers won&rsquo;t hit because they have adapted their workflow to avoid certain failure modes over time.</li>
</ul>
<p>The flexibility is <em>great</em> to have when you need it but, without a &ldquo;default&rdquo; workflow, it serves to create more user confusion than it resolves. It contributes to the bumpy ride reputation and to the perceived complexity.</p>
<h2 id="placing-the-python-packaging-ecosystem-on-the-community-spectrum">Placing the Python packaging ecosystem on the community spectrum</h2>
<p>When I was reading <a href="https://www.harihareswara.net/posts/2022/the-community-spectrum-caring-to-combative-insight-from-alex-bayley/">&ldquo;The community spectrum: caring to combative&rdquo; - Insight From Alex Bayley</a> on <a href="https://www.harihareswara.net/">Sumana Harihareswara&rsquo;s blog</a>, it flagged something amusing to me. I recommend reading the article, but I&rsquo;ll quote a portion that provides sufficient context for the rest of this post.</p>
<blockquote>
<p>The Competitive Spectrum describes communities as being:</p>
<ul>
<li><strong>Caring</strong>: members are motivated by helping each other.</li>
<li><strong>Collaborative</strong>: members share goals and help each other to achieve them.</li>
<li><strong>Cordial</strong>: members have their own goals which do not conflict with each other.</li>
<li><strong>Competitive</strong>: members share the same goals, and compete against each other to achieve them.</li>
<li><strong>Combative</strong>: members must achieve their goals by preventing others from being doing so.</li>
</ul>
</blockquote>
<h3 id="pypa-and-conda">PyPA and Conda</h3>
<p>Within this spectrum, I think the relationship between Conda and PyPA projects is definitely collaborative.</p>
<p>The two groups of maintainers have worked together to solve problems that affect both groups. Conda packages are often built up from Python packages that are built with PyPA tools. Heck, at the time of writing, <a href="https://github.com/jezdez/">one of</a> the <a href="https://gist.github.com/jezdez/6222d1ba8b10d734d003492e58041687">founders of the PyPA</a> currently <a href="https://github.com/conda-incubator/governance/blob/0fa0e84f690e628fe7a232bb52938409b2fbc1e3/steering.csv?plain=1#L14">sits on the Conda Steering Council</a>.</p>
<h3 id="python-build-backends">Python build-backends</h3>
<p>The goal of enabling pyproject.toml-based builds<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> was to move Python packaging from a collaborative (or at least, cordial) model, to a competitive model for the build mechanisms.</p>
<p>The stated goal of PEP 517 is:</p>
<blockquote>
<p>The goal of this PEP is get distutils-sig out of the business of being a gatekeeper for Python build systems. If you want to use distutils, great; if you want to use something else, then that should be easy to do using standardized methods.</p>
</blockquote>
<p>Moving to a competitive model for build mechanisms was intended to enable the ecosystem to move away from the &ldquo;only one way&rdquo; of building Python packages (the quote is from the Zen of Python) <em>because</em> the <a href="https://peps.python.org/pep-0517/#abstract">implementation we had of &ldquo;only one way&rdquo; was exceedingly difficult to evolve</a>.</p>
<h3 id="poetry--pdm--hatch--pyflow--etc">Poetry / PDM / Hatch / PyFlow / etc</h3>
<p>These tools are firmly in a competitive model. They&rsquo;re competing for users. They&rsquo;re competing to be the &ldquo;best&rdquo; solution to the &ldquo;workflow&rdquo; problem. They&rsquo;re, arguably, even competing for contributors.</p>
<p>Other than the obvious sign that these tools can&rsquo;t be used together on the same codebase (mostly), this can be seen in other aspects of these projects:</p>
<ul>
<li>the way they&rsquo;re marketed/documented &ndash; they have an incentive to invest in this, because they&rsquo;re competing for users and good-looking/flashy documentation is a good way to attract users.</li>
<li>the way they do community management: some have dedicated community Discord servers, mention $tool-specific ecosystems, have their own $tool plugin ecosystems, etc.</li>
<li>the way their users advocate for them as the one-true-solution on the internet :)</li>
</ul>
<p>This competition also leads to incentives for projects to do things like implementing <a href="https://github.com/pypa/hatch/commit/fea611be96f79559ecf227d2a68b6dfbf3b3c2ec">draft standards that are not accepted or settled</a> and <a href="https://pradyunsg.me/blog/2023/01/21/pdm-does-not-implement-pep-582/">claims that standards are implemented, even when the implementation does not match the standard</a>.</p>
<h2 id="unintended-competition">Unintended competition</h2>
<p>In my opinion, ending up with multiple competing workflow tools in the Python ecosystem was not an intentional choice by any individual or group.</p>
<p>While providing alternatives to distutils/setuptools was the intent of pyproject.toml-based build systems, I don&rsquo;t think it was intended nor was there ever consensus that we wanted to end up with an ecosystem of competing tools which <em>use</em> the pyproject.toml-based build system <em>and</em> provide an end-to-end workflow.</p>
<p>I don&rsquo;t see any discussion of such tooling in the corresponding mailing list discussions and the PEPs certainly don&rsquo;t talk about trying to enable building alternative <em>workflow</em>-related tooling. There&rsquo;s extensive discussion about the technical design of the final solution and on many aspects of &ldquo;how to build distribution files&rdquo;, but there&rsquo;s no discussion about how competing workflow tools would be enabled.</p>
<p>Another reason is&hellip; well&hellip; let&rsquo;s dig into some &ldquo;history&rdquo;. The Python Packaging Authority has <a href="https://www.pypa.io/en/latest/future/">publicly written goals</a> for them:</p>
<blockquote>
<ul>
<li>Although it’s still being defined, to work towards a “Meta-Packaging” system that:
<ul>
<li>Clearly delineates the phases of distribution</li>
<li>Allows for multiple interacting tools vs one monolithic tool</li>
<li>Specifically allows for alternative build systems, i.e. a “MetaBuild” system.</li>
</ul>
</li>
</ul>
</blockquote>
<p>These goals were <a href="https://github.com/pypa/pypa.io/blob/2ddc43fa4871e83365b8f43da19b7dc573b67ebd/source/future.rst">written in a different &ldquo;era&rdquo; of Python packaging</a>, before PEP 516/517/518 were being debated, when the ecosystem was still in an entirely collaborative/cordial model (on the other side of a combative era<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>), and when the &ldquo;Python ecosystem&rdquo; was much smaller than it is today<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>.<sup id="fnref:5"><a href="#fn:5" class="footnote-ref" role="doc-noteref">5</a></sup></p>
<p>The intent was to enable the ecosystem to build multiple tools that interacted with each other and allow for alternative build tooling to solve problems that were difficult to solve with distutils/setuptools.</p>
<p>A competitive ecosystem for workflow tooling is an unintended consequence of the pyproject.toml-based build system. The PyPA&rsquo;s focus on standardisation made it easier to build workflow tooling that interacted with other packages, with no mechanisms to check whether these tools are reciprocating on interoperability.</p>
<h2 id="on-existing-workflow-tools">On existing workflow tools</h2>
<p>I expect the most relevant people already know this, but I&rsquo;ll state it explicitly: I have a lot of respect for the work done by the authors and/or maintainers of tooling like Poetry, PDM, Hatch, Pipenv, PyFlow, etc. I think they each, individually, contribute meaningfully and positively to the ecosystem.</p>
<p>The most popular workflow tools for Python handle the underlying details for the user and give them a single unified tool that has <code>install</code> / <code>publish</code> / <code>run</code> commands. They also provide functionality that the &ldquo;default&rdquo; tools do not (eg: environment-agnostic lockfiles, automated environment management etc). Serving as an end-to-end tool enables them to trim the scope and define it as they deem appropriate.</p>
<p>Conda also does this to a certain extent, by tying the <a href="https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html">environment management and package management together</a> into a single tool, but it also operates on a different level than these tools &ndash; packaging &ldquo;everything&rdquo; rather than just Python packages.</p>
<h3 id="the-reasons-for-the-existence-of-workflow-tools">The reasons for the existence of workflow tools</h3>
<p>Some/all of the &ldquo;workflow tools&rdquo; that exist today because the &ldquo;default&rdquo; tooling did not cover more of the user&rsquo;s workflow with a single piece.</p>
<ul>
<li>Pipenv&rsquo;s <code>Pipfile</code> was <a href="https://github.com/pypa/pip/issues/1795#issuecomment-261661124">created with the express goal of being for pip</a><sup id="fnref:6"><a href="#fn:6" class="footnote-ref" role="doc-noteref">6</a></sup>.</li>
<li>Poetry was <a href="https://github.com/python-poetry/poetry/blob/a5d6333f27f261458ba5abe3e30cbf452fa7a10f/README.md#why">created to provide a single config file with a single tool experience, and a better dependency resolution model</a>.</li>
<li>Hatch was <a href="https://github.com/pypa/hatch/blob/4202965f4a4b1d86e6c7de1224a359217df45314/README.rst">created as &ldquo;a productivity tool designed to make your workflow easier and more efficient, while also reducing the number of other tools you need to know.&rdquo;</a>.</li>
<li>PDM was <a href="https://github.com/pdm-project/pdm/commit/06391eca0bed7b879af1bc84c1c737c99646741e">created as a &ldquo;Python package manager with PEP 582 support&rdquo;</a> (which is notable, given that <a href="https://pradyunsg.me/blog/2023/01/21/pdm-does-not-implement-pep-582/">PDM does not implement PEP 582</a>).</li>
</ul>
<p>These tools have <em>all</em> now dropped that language from their documentation (or at least evolved it) to reflect that they&rsquo;re now focused on providing a complete and unified experience for the user. This can be seen by the fact that they&rsquo;ve all gone ahead and invented their own build-backends (except Pipenv, which is maintaining a fork of pip within it), since providing a complete and unified experience requires that the tool also controls how projects are built.</p>
<p>Now, to state the obvious, the folks who created these tools are not fools who like to create work for themselves or enjoy reinventing the wheel. They created because they felt that the existing tooling wasn&rsquo;t meeting their needs <em>and</em> that there was no clear path to improving the pre-existing tooling to meet those needs. Each of these tools solves the problem by making different calls for what the right trade-offs are.</p>
<p>I am certain that it is not possible to create a single &ldquo;workflow&rdquo; tool for Python software. What we have today, an ecosystem of tooling where each makes different design choices and technical trade-offs, is a part of why Python is as widespread as it is today. This flexibility and availability of choice is, however, both a blessing and a curse. That&rsquo;s actually a great segue to talk about&hellip;</p>
<h2 id="pip-a-privileged-player">pip: A privileged player</h2>
<p>Today, <code>pip</code> is uniquely positioned within in the Python packaging ecosystem. It is the only<sup id="fnref:7"><a href="#fn:7" class="footnote-ref" role="doc-noteref">7</a></sup> piece of the Python packaging tooling that ships with Python, and is guaranteed<sup id="fnref:8"><a href="#fn:8" class="footnote-ref" role="doc-noteref">8</a></sup> to be installed in every environment. Nearly every Python user<sup id="fnref:9"><a href="#fn:9" class="footnote-ref" role="doc-noteref">9</a></sup> who wishes to share code (or use shared code) uses it today, directly or indirectly.</p>
<p>The fact that I&rsquo;ve added 3 footnotes in the last paragraph is a symptom of <em>something</em> and I&rsquo;m not sure if it&rsquo;s a good thing or a bad thing.</p>
<h2 id="pip-a-disadvantaged-player">pip: A disadvantaged player</h2>
<p>This point is easier to make with an example, let&rsquo;s take lockfiles: it&rsquo;s technically feasible to implement an arbitrary lockfile format in pip, that evolves with pip, in lock-step with it (something of this sort is implemented already in the form of pip-tools).</p>
<p>Given the privileged position that pip has within the ecosystem (i.e. ships with the language), whatever it does would become the de-facto standard and commercial tools/IDEs will add support for that model much quicker (eg: requirements.txt) than something similar from PDM, Poetry, Pipenv etc.</p>
<p>Now, on the face of it, this is a completely different direction from PyPA&rsquo;s model of &ldquo;interoperability standards through concensus&rdquo; because, effectively, whatever pip implements would become a de-facto standard for what the ecosystem and tooling supports.</p>
<p>On the other hand, if we focus on designing for interoperability through concensus before implementing functionality in pip, implementing vital workflow improvements is now blocked on an exhaustingly long process of a non-iterative, waterfall-style design process. Further, an interoperable lockfile format also has to try to satisfy needs of tools that use completely different resolution models, <em>even</em> semantically incorrect ones<sup id="fnref:10"><a href="#fn:10" class="footnote-ref" role="doc-noteref">10</a></sup>.</p>
<p>Taking a slightly iterative approach of &ldquo;we&rsquo;ll cover the more complicated case later&rdquo; caused <a href="https://peps.python.org/pep-0665/">the last proposal for a lockfile format standard</a> to be rejected after months of discussion.</p>
<p>We&rsquo;re in a state where the process for adding new functionality to our default &ldquo;out of the box&rdquo; experience is designed to be both very difficult and very &ldquo;energy&rdquo; intensive &ndash; leading to it being pretty slow. The reason the default tooling doesn&rsquo;t improve is that making meaningful improvements to it is blocked on trying to cater to all workflows; in ways that alternative tooling is not.</p>
<p>The effect of this is that our &ldquo;out of the box&rdquo; experience is always going to be worse than the experience with other tools in the ecosystem. In a competitive ecosystem, is that what we want? Heck, at that point, do we even want to be in a competitive ecosystem?</p>
<h2 id="on-build-backends-tied-to-workflow-tools">On build-backends tied to workflow tools</h2>
<p>Hatchling, pdm-backend and poetry-core are all examples of this. Flit/flit-core is another slightly-weaker example of this<sup id="fnref:11"><a href="#fn:11" class="footnote-ref" role="doc-noteref">11</a></sup>. They each have build-backends that are either (a) tied to a particular workflow tool in some way or (b) promoted along with a workflow tool.</p>
<p>The build backends are all solving the &ldquo;build a wheel from Python code&rdquo; problem, but with different user experiences tacked onto them. Building multiple tools that solve the same problem is duplicated effort.</p>
<p>Part of the problem here is that these tools (except for PDM) are not built with interoperability in their design, and these tools have basically little to no incentive to take on the complexities of providing interoperability.</p>
<p>Flit can only be used with flit_core, and <code>flit build</code> doesn&rsquo;t build the same artefacts as <code>python -m build</code> would.</p>
<p>Hatch is tied to hatchling, and <a href="https://github.com/pypa/hatch/issues/507">&ldquo;it would be an extraordinary amount of effort&rdquo;</a> to support using a different build-backend for your project when using Hatch.<sup id="fnref:12"><a href="#fn:12" class="footnote-ref" role="doc-noteref">12</a></sup></p>
<p>Poetry has its own dependency specification format, and the corresponding build-backend enables it to build packages that use that format.</p>
<p>PDM is better on this front, in that it has greater backend-agnostic behaviours to it. However, pdm-backend is undergoing a rewrite to <a href="https://discuss.python.org/t/python-packaging-strategy-discussion-part-1/22420/141?u=pradyunsg">&ldquo;provide a similar extensible interface to hatchling&rdquo;</a>.</p>
<p>These were all made possible by the explicit focus of the PyPA on designing an interoperability model &ndash; i.e. Unix-like approach &ndash; which these tools have used to create tool-specific build-backends. :)</p>
<p>While trying to enforce that one way of building packages/managing dependencies for all Python users is not feasible&hellip; having 4 build-backends that all handle pure-Python packages with the same file holding their configuration, while providing slightly different user experiences is <em>also</em> not a good place to be in IMO.</p>
<h2 id="pick-from-n-equivalent-choices-is-really-bad-ux">Pick from N ~equivalent choices is really bad UX</h2>
<p>When you package Python software, a user has to make a lot of choices. There are a <em>lot</em>, and I do mean a <em>lot</em>, of &ldquo;A vs B&rdquo; comparisons that you can make when it comes to figuring out the scaffolding for packaging and distributing Python software.</p>
<p>The problem with not making a default recommendation for these largely-inconsequential choices is that it means that <em>every</em> user has to make these choices. Instead of making a choice once and then being able to build upon that as an ecosystem, we keep moving in circles on these topics because we&rsquo;ve got two groups now and picking either choice means that the other group is unhappy.</p>
<p>This also leads to the same problems being solved twice &ndash; there&rsquo;s duplicated effort and duplicated documentation. Each project will design their own approach and there&rsquo;s incentive for projects to try to &ldquo;out-compete&rdquo; each other by providing more features or by providing better documentation, rather than contributing to improving a common corpus.</p>
<p>This is how, for example, we end up with <a href="https://packaging.python.org">packaging.python.org</a> not having <a href="https://packaging.python.org/en/latest/specifications/declaring-project-metadata/">a standard structure for declaring metadata that is implemented by ~every build-backend</a> documented, even though there was <em>extensive</em> documentation for the same in multiple tools&rsquo; own documentation for months. Each of those tools&rsquo; authors have had incentives to document it for their users and it was easier to do so in their own documentation, where they don&rsquo;t have to worry about the concerns of other tools or &ldquo;being generic enough&rdquo;.</p>
<h2 id="not-a-pypa-project">&ldquo;not a PyPA project&rdquo;</h2>
<p>The <em>only</em> reason various Python packaging projects (notably, Poetry and PDM) are not PyPA projects is because they&rsquo;ve never asked to become one.</p>
<p>As it stands, the PyPA views itself as a big umbrella. Basically, any established Python packaging project that asks to be included, will be accepted. If Poetry and PDM ever asked to join, as it stands, there&rsquo;s no version of this timeline where the existing PyPA members say no.</p>
<p>From the discussions I&rsquo;ve had, the reasons have ranged from some sense of maintaining control (which doesn&rsquo;t really have <a href="https://github.com/pypa/pipenv/issues/607#issuecomment-330878876">good precedence</a>), to logistical issues like GitHub Actions queues, as well as a sense of being able to &ldquo;be successful without the tag&rdquo;.</p>
<p>Also, to say that these tools are &ldquo;are not participating in the PyPA&rdquo;<sup id="fnref:13"><a href="#fn:13" class="footnote-ref" role="doc-noteref">13</a></sup> is incorrect. PDM&rsquo;s whole <a href="https://github.com/pdm-project/pdm/blob/c0974672a17be965ddcb0e191d35df08ad0c4b6e/README.md?plain=1#L5">pitch <em>today</em></a> is that it is &ldquo;A modern Python package and dependency manager supporting the latest PEP standards&rdquo;. Poetry&rsquo;s authors somewhat regularly interact with the interoperability discussions, and its original author has even co-authored a PEP.</p>
<h2 id="on-the-python-packaging-authority">On the Python Packaging Authority</h2>
<p>I think there&rsquo;s a need to reconsider what the Python Packaging Authority should be trying to do and what it even is. We&rsquo;ve been cruising on the premise that we&rsquo;re maintaining foundational tools and designing for interoperability is the &ldquo;right&rdquo; model for the Python packaging ecosystem. I&rsquo;m not sure that&rsquo;s the case.</p>
<p>Between the user surveys, having a $work role where I&rsquo;m directly influencing user workflows beyond the installer, spending time helping out with scientific Python tooling and with <a href="https://www.pyopensci.org/">pyOpenSci</a>, and the discussions in the strategy thread&hellip; I&rsquo;m starting to think that our current approach is not working and is harmful<sup id="fnref:14"><a href="#fn:14" class="footnote-ref" role="doc-noteref">14</a></sup> unintentionally. Each projects&rsquo; maintainers effectively decide on different aspects of the overall UX. Each project acts as its own project. There is no broader guiding &ldquo;roadmap&rdquo;. Making decisions about how the default tooling of the ecosystem works is &ldquo;not appropriate&rdquo; for our process to hashing out technical design proposals. There is no &ldquo;blessed&rdquo; tool and yet there are defaults, things that ship with the Python standard library and PyPA recommendations.</p>
<p>I&rsquo;m not sure what the right answer is, but I don&rsquo;t think we&rsquo;re in a good place right now. Here&rsquo;s where we are:</p>
<ul>
<li>even co-operating tools are viewed as being in competition with each other</li>
<li>interoperability standards that are written but are not enforced
<ul>
<li>on the principle of &ldquo;consenting adults&rdquo; or &ldquo;be permissive in what you accept&rdquo;</li>
<li>for backwards compatibility reasons</li>
<li>because &ldquo;we should trust the XYZ authors to do the right thing&rdquo;</li>
<li>difficult to answer basic questions like &ldquo;what can a source distribution file be named&rdquo; because the standard says one thing while the tools do something else because &ldquo;the author prefers that&rdquo;</li>
<li>implemented and publicized as features in tools, despite not being something that is &ldquo;accepted&rdquo;</li>
<li>absolutely ignored by tool authors &ldquo;because it&rsquo;s not a priority&rdquo;</li>
</ul>
</li>
<li>duplicated effort because multiple tools are competing</li>
<li>users are confused about what to use, what is deprecated, what is the &ldquo;right&rdquo; way to do things etc and there is no authoritative answer</li>
<li>say that PEPs are not documentation but, also, go read this PEP for the details on how this feature works because that&rsquo;s the only place we wrote it.</li>
<li>no clear answer for step 0 questions like where should I put by .py files relative to my pyproject.toml file</li>
<li>a lack of willingness to draw a line in the sand and say &ldquo;this is the way things are done&rdquo; because &ldquo;what if someone finds a better way in the future&rdquo;</li>
<li>we don&rsquo;t pick one of two ~equivalent choices because &ldquo;they&rsquo;re both valid workflows&rdquo;</li>
<li>there is <strong>no</strong> agreed upon direction for the ecosystem</li>
</ul>
<h2 id="we-dont-need-more-generic-build-backends-today">We don&rsquo;t need <em>more</em> &ldquo;generic&rdquo; build-backends today</h2>
<p>With <a href="https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html">setuptools gaining pyproject.toml configuration support</a> and <a href="https://packaging.python.org/en/latest/specifications/declaring-project-metadata/">a standard structure for declaring metadata that is implemented by ~every build-backend</a>, there isn&rsquo;t a significant difference between the various tools for pure-Python packages.</p>
<p>There are only so many ways to construct a <code>.zip</code> file containing a bunch of pure-Python files + metadata. The only real difference is in the user experience, and the user experience is largely determined by the tooling that invokes the build-backend.</p>
<p>Building more build-backends that are intended to be extended (beyond what we already have, between <code>hatchling</code>, <code>pdm-backend</code> and <code>setuptools</code>) feels unnecessary to me; and we might already have one too many options for this.</p>
<h2 id="on-pip-as-a-workflow-tool">On pip as a workflow tool</h2>
<p>Donald Stufft has <a href="https://github.com/pypa/pip/issues/6041#issuecomment-516470124">said</a> on pip&rsquo;s issue tracker:</p>
<blockquote>
<p>All that being said, I think trying to follow the &ldquo;unix philosophy&rdquo; is a mistake and is actually a pretty poor UX. Yea a lot of nerds grok it because we&rsquo;ve caused enough collective brain damage by being forced to use it over time and it works better for the typical unix tools because they generally just come preinstalled. I think it would just add additional complexity to an already confusing landscape of tools for our end users.</p>
</blockquote>
<p>And, Paul Moore has <a href="https://discuss.python.org/t/adding-a-non-metadata-installer-only-dev-dependencies-table-to-pyproject-toml/20106/10?u=pradyunsg">said</a>:</p>
<blockquote>
<p>At some point, I do think that pip needs to make a firm decision on whether it’s a development workflow tool or just an installer</p>
</blockquote>
<p>And, I think that now is the time to make that decision.</p>
<p>The <a href="https://discuss.python.org/t/python-packaging-strategy-discussion-part-1/22420?u=pradyunsg">recent strategy discussion</a> is sprawling and has largely operated with the assumption that pip is not something that can become a &ldquo;workflow tool&rdquo;. I think that&rsquo;s an incorrect assumption.</p>
<p>Personally, I&rsquo;ve wanted pip to cover more aspects of the user&rsquo;s workflow <a href="https://github.com/pypa/pip/issues/5407#issuecomment-389621303">since before PEP 517 was implemented</a>, which was around the time <a href="http://pradyunsg.me/gsoc-2017/05/05/green-light/">I started getting involved in Python</a><sup id="fnref:15"><a href="#fn:15" class="footnote-ref" role="doc-noteref">15</a></sup>. Improving the &ldquo;base&rdquo; tool to cover more use cases is <strong>not</strong> a bad idea &ndash; it&rsquo;s helpful for most user personas. Outside of blessing another tool, this is the path of least resistance that we can take to getting to a better state.</p>
<p>Do I think there&rsquo;s a significant amount of work needed for making pip into a workflow tool?</p>
<p>Yes.</p>
<p>Do I think that the amount of energy that&rsquo;s gone into Poetry/Hatch/Pipenv/PDM development, collectively, would have made more than a meaningful dent on this issue?</p>
<p>Yes.</p>
<p>Do I think that, at this point, blessing another tool is a good idea?</p>
<p>Maybe. We&rsquo;ve built a competitive ecosystem, and I don&rsquo;t think we can just &ldquo;pick one&rdquo; of the &ldquo;new things&rdquo; and expect that to be the end of it.</p>
<p>Did we ever have sufficient buy-in + capacity to do this with pip, along with contributor experiences that would facilitate this?</p>
<p>No. That&rsquo;s been a part of the problem &ndash; we&rsquo;ve made it fairly tractable to &ldquo;build your own&rdquo; in a sandbox that lets you ignore the need to support entire swaths of workflows, and that&rsquo;s something you can&rsquo;t compete with easily for contributor experience. And, when the alternative is &ldquo;spend a few months trying to implement something in a &rsquo;legacy&rsquo; codebase, while catering to needs that you don&rsquo;t have, also convince a bunch of people with limited availability that your idea is a good one and wait for them to review what you wrote&rdquo;, it&rsquo;s not surprising that we end up with a bunch of &ldquo;new things&rdquo; and have multiple groups building multiple workflow tools.</p>
<p>We <em>still</em> don&rsquo;t have agreement that this is the direction that we, as a community, want pip to go.</p>
<h2 id="on-user-facing-communication">On user-facing communication</h2>
<p>There&rsquo;s no single place where users can go to get information about the Python packaging ecosystem &ndash; either on how it&rsquo;s evolving or what the functional best-practices are <em>today</em>. We either (a) don&rsquo;t have them documented or (b) don&rsquo;t have a good approach to communicating about this to end users.</p>
<p>There&rsquo;s a cost to this.</p>
<p>LWN <a href="https://lwn.net/SubscriberLink/920132/cb4d6c0f07b54952/">recently</a> directed readers to a blog post<sup id="fnref:16"><a href="#fn:16" class="footnote-ref" role="doc-noteref">16</a></sup> that claims that the strategy discussion is evidence that &ldquo;PyPA must be destroyed&rdquo;, implies that there&rsquo;s &ldquo;ivory towers of packaging tool maintainers&rdquo;, that &ldquo;half of the discussion participants did not even bother reading what the people think&rdquo; based on a misunderstanding of how the discussions have occurred<sup id="fnref:17"><a href="#fn:17" class="footnote-ref" role="doc-noteref">17</a></sup> and that the Python Packaging User Survey somehow happened in a vacuum (it was <a href="https://discuss.python.org/t/rfc-survey-to-help-define-a-python-packaging-vision-and-strategy/15658">extensively</a> <a href="https://discuss.python.org/t/your-feedback-required-python-packaging-user-survey/18070">discussed</a> with lots of input from PyPA members).</p>
<p>That blog post has captured the current discourse around Python packaging and set the tone: one painting the volunteers who currently maintain the tooling as being &ldquo;vs reality&rdquo;.</p>
<p>This is exactly the sort of thing that happens when there&rsquo;s no authoritative voice in the space: the vacuum will be filled by someone else on the internet, who will likely be making sensational claims that aren&rsquo;t being validated before being repeated.</p>
<h2 id="on-formal-ux-analysis">On formal UX analysis</h2>
<p>This has been mentioned in multiple places and has come up in the past in other contexts around Python Packaging.</p>
<p>I think doing &ldquo;full UX analysis&rdquo; is going to be forbiddingly difficult. Don&rsquo;t get me wrong: a complete UX review of the Python Packaging ecosystem would be <em>awesome</em> as part of a coordinated effort to make progress on the fundamental problems here.</p>
<p>Something like this is unlikely to happen because there&rsquo;s a <em>really</em> motivated UX expert with a <em>lot</em> of volunteer time to donate. We&rsquo;d basically need an enormous cheque for work that&rsquo;s&hellip; &ldquo;understand Python packaging really well and figure out a path to making it better&rdquo;. That&rsquo;s a difficult thing to tell a funder to throw money at.</p>
<p>Notably, there are a lot of stakeholders here: the easiest &ldquo;persona&rdquo; to identify is the maintainers of the tools themselves. After that, it starts to become fuzzy quickly. There&rsquo;s redistributors, end users, Linux OS distros, Linux-specific non-OS package managers, cross-platform distributions, direct users, corporate users who have their own internal packaging systems, or like astronomers, students, statisticians, business analysts, and more.</p>
<p>Breaking the UX problem into a smaller piece, like a single point from the <a href="https://discuss.python.org/t/python-packaging-strategy-discussion-part-1/22420/16?u=pradyunsg">dimensions we could unify</a>, makes this a much more meaningfully sized piece for seeking funding toward. Even then, it&rsquo;ll still probably only be available to be funded by the larger wallets and likely need to be a part of a project that has some other deliverables.</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>I&rsquo;d like to thank the following people for reviewing drafts of this post at various stages and providing valuable feedback: Donald Stufft, Kushal Das, and Pavithra Eswaramoorthy.</p>
<p>Also, I would&rsquo;ve appreciated if the discourse on this wasn&rsquo;t moving along at the speed that it&rsquo;s been moving after <a href="https://discuss.python.org/t/python-packaging-strategy-discussion-part-1/22420/16?u=pradyunsg">I publicly committed to writing this</a>. And, yes, I&rsquo;m aware that some of the things I&rsquo;ve said here are conclusions that been reached by the broader group on that thread.</p>
<p>Finally, I do have more thoughts; especially on how to get to a better place, but ~6k words is about as long as I want to go here.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I&rsquo;m <em>very</em> happy that we have done this.</p>
<p>I&rsquo;d initially discussed the idea of surveying users specifically on Python Packaging things to Shamika, <a href="https://pyfound.blogspot.com/2021/04/the-psf-is-hiring-python-packaging.html">the Python Packaging Project Manager</a>, in late 2021, in an video call with her.</p>
<p>I&rsquo;m very grateful for the work that Shamika and many others have put toward this; the 2021 Python Developer Survey included a <a href="https://lp.jetbrains.com/python-developers-survey-2021/#PythonPackaging">full section on Python Packaging</a> (some are questions that I&rsquo;d suggested!) and there&rsquo;s been a dedicated <a href="https://drive.google.com/file/d/1U5d5SiXLVkzDpS0i1dJIA4Hu5Qg704T9/view">2022 Python Packaging Survey</a> which has some extremely valuable data.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>That&rsquo;s what the cool kids say now &ndash; it&rsquo;s a bit of a mouthful, but it&rsquo;s more accurate than PEP 517, and better than PEP 517/518/621/660-based build systems. ;)&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>I&rsquo;m referring to distutils2 / setuptools / distribute.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p><a href="https://insights.stackoverflow.com/survey/2015#tech-lang">The 2013/2014/2015 StackOverflow survey results</a> are a fun trip down technology history. PHP is more popular than Python. &ldquo;Node.js and AngularJS are busting out&rdquo;. &ldquo;Java is still the #1 server side language&rdquo;.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:5">
<p>The PyPA goals should really be updated, once the dust has settled around the whole strategy discussion.&#160;<a href="#fnref:5" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:6">
<p>Before an individual with a <a href="https://github.com/pypa/pipenv/issues/607#issuecomment-330878876">controlling attitude</a> got involved and made some <a href="https://github.com/pypa/pipfile/pull/138">overzealous marketing claims</a>, and&hellip; <a href="https://vorpus.org/blog/why-im-not-collaborating-with-kenneth-reitz/">then this was published</a>.&#160;<a href="#fnref:6" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:7">
<p><a href="https://github.com/python/cpython/pull/101039">Setuptools is not gonna installed by default in a <code>venv</code>, starting with Python 3.12</a> and only shipped with Python because it was needed by pip, prior to pyproject.toml-based builds being a thing.&#160;<a href="#fnref:7" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:8">
<p>Yes, I know about Linux distros that break things. Yes, I know that you have a <code>--without-pip</code> (or equivalent) flag on venv/virtualenv. They&rsquo;re both edge cases in this context, <em>not</em> the norm.&#160;<a href="#fnref:8" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:9">
<p><a href="https://lp.jetbrains.com/python-developers-survey-2021/#text-530">&ldquo;90% of developers report they use pip to install Python packages&rdquo;</a> and even those who just use Conda/Poetry/PDM etc will end up using pip under the hood.&#160;<a href="#fnref:9" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:10">
<p>Poetry&rsquo;s dependency resolver and lockfile operates under the assumption that <em>all</em> files for a package + version are going to have the exact same metadata. While it is a choice that Poetry can make, because it&rsquo;s &ldquo;opinionated&rdquo;, it&rsquo;s not something that other tools can do.</p>
<p>Notably, it&rsquo;s an incorrect assumption; baked in because PyPI&rsquo;s rough-draft-became-production implementation of metadata handling treated metadata from the first wheel uploaded to PyPI as the releases&rsquo; metadata.&#160;<a href="#fnref:10" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:11">
<p>I <a href="https://pradyunsg.me/about/#flit">may be biased</a> but it&rsquo;s worth noting that Flit is part of <em>why</em> PEP 517 happened.&#160;<a href="#fnref:11" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:12">
<p>Clarified on the <a href="https://discord.com/channels/803025117553754132/964878415914213436/1063852982459957248">PyPA Discord</a> as:</p>
<blockquote>
<p>&ldquo;basically adding a dependency on the PEP 517 library and having a conditional that if the build backend is not Hatchling then use that&rdquo;</p>
</blockquote>
<p>That doesn&rsquo;t seem like an &ldquo;extraordinary&rdquo; amount of work to me, but I&rsquo;m not familiar with the Hatch codebase and I am willing to trust @ofek&rsquo;s judgement here.&#160;<a href="#fnref:12" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:13">
<p>I&rsquo;m absolutely looking at LWN&rsquo;s summary here. More on this later.&#160;<a href="#fnref:13" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:14">
<p>unintentionally. I don&rsquo;t think anyone came out thinking &ldquo;We should design for a bad UX&rdquo; but here we are.&#160;<a href="#fnref:14" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:15">
<p>If you clicked the link and think like me: yes, I checked, I did reasonably well in my Data Structures and Algorithms course.&#160;<a href="#fnref:15" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:16">
<p>In case someone from LWN ends up reading this: I think directing readers toward the post and repeating claims from it were bad editorial choices. Tacking on &ldquo;(opinionated)&rdquo; once is grossly insufficient, given the inaccuracy of claims in the post as well as the one you&rsquo;ve repeated.&#160;<a href="#fnref:16" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:17">
<p>Those links are in &ldquo;Summary of discussions&rdquo; &ndash; discussions that most participants have already participated in. Plus, I&rsquo;m pretty sure Discourse doesn&rsquo;t count middle-clicks.&#160;<a href="#fnref:17" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>How the Python Packaging community is organised</title><link>https://pradyunsg.me/blog/2023/01/14/python-packaging-organisation/</link><pubDate>Sat, 14 Jan 2023 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2023/01/14/python-packaging-organisation/</guid><description>&lt;p&gt;The way the Python packaging community is organised is something that I&amp;rsquo;ve
explained in multiple places, in multiple contexts. I figure that it&amp;rsquo;ll be
useful to actually write it down in a single place, so that I don&amp;rsquo;t have to
repeat myself.&lt;/p&gt;
&lt;h2 id="the-python-packaging-authority"&gt;The Python Packaging Authority&lt;/h2&gt;
&lt;p&gt;The Python Packaging Authority (PyPA) is a fairly loose group of projects that
happen to be related to Python packaging. While the PyPA has a formal
&lt;a href="https://peps.python.org/pep-0609/"&gt;governance&lt;/a&gt; model, there&amp;rsquo;s no &amp;ldquo;oversight&amp;rdquo; or
&amp;ldquo;enforcement&amp;rdquo; on projects that are part of the PyPA &amp;ndash; they are only required to
adopt the PSF Code of Conduct and to be accepted by the existing members.&lt;/p&gt;</description><content:encoded><![CDATA[<p>The way the Python packaging community is organised is something that I&rsquo;ve
explained in multiple places, in multiple contexts. I figure that it&rsquo;ll be
useful to actually write it down in a single place, so that I don&rsquo;t have to
repeat myself.</p>
<h2 id="the-python-packaging-authority">The Python Packaging Authority</h2>
<p>The Python Packaging Authority (PyPA) is a fairly loose group of projects that
happen to be related to Python packaging. While the PyPA has a formal
<a href="https://peps.python.org/pep-0609/">governance</a> model, there&rsquo;s no &ldquo;oversight&rdquo; or
&ldquo;enforcement&rdquo; on projects that are part of the PyPA &ndash; they are only required to
adopt the PSF Code of Conduct and to be accepted by the existing members.</p>
<p>Functionally, each PyPA project is free to do what it wants. The only real
benefit of being a PyPA project is the ability to use the PSF as a fiscal
sponsor and the ability to say that it&rsquo;s a &ldquo;PyPA project&rdquo;.</p>
<p>Practically, the PyPA serves as <a href="https://discuss.python.org/t/what-is-the-pypa/12297/2?u=pradyunsg">&ldquo;a body to hammer out &amp; maintain
interoperability specifications&rdquo;</a> for Python packaging. The
PyPA also includes foundational tools that are used in the Python packaging
ecosystem, like <code>pip</code> and <code>setuptools</code>.</p>
<h2 id="relationship-with-core-python">Relationship with &ldquo;Core Python&rdquo;</h2>
<p>(I&rsquo;m using &ldquo;Core Python&rdquo; to refer to the Python language and standard library,
as maintained by the CPython Core Developers, also known as <a href="https://peps.python.org/pep-0013/#the-core-team">&ldquo;core
team&rdquo;</a> for Python)</p>
<p>As of the time of writing, Core Python&rsquo;s involvement in Python Packaging (in a
<a href="https://peps.python.org/pep-0632/">post-distutils</a> world) is fairly limited.
The interpreter and Python standard library provide the following pieces, around
the packaging ecosystem:</p>
<ul>
<li>
<p>Shipping <code>ensurepip</code> and <code>venv</code> in the standard library.</p>
<ul>
<li><code>venv</code> supports creating a virtual environment with pip and
setuptools<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> installed in it.</li>
<li><code>ensurepip</code> provides copies of <code>pip</code> and
<code>setuptools</code><sup id="fnref1:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> that are used by <code>venv</code>, and
allows bootstrapping the packaging tooling for Python.</li>
</ul>
</li>
<li>
<p>&ldquo;site-packages&rdquo; directories on the import path.</p>
<ul>
<li><code>site</code> adds site-packages (&ldquo;global&rdquo; and &ldquo;user&rdquo;) to the import path.</li>
<li><code>site</code> respects the presence of a <code>pyvenv.cfg</code> file (used by <code>venv</code>) to mark
a virtual environment, influencing which site-packages it adds to the import
path.</li>
</ul>
</li>
<li>
<p><code>sysconfig</code> provides relevant paths for placing files and build configuration
for the interpreter.</p>
</li>
<li>
<p>a <a href="https://docs.python.org/3/c-api/stable.html">stable ABI</a> for the C API, for
building extensions compatible across Python 3.x (x &gt;= 2).</p>
</li>
</ul>
<h3 id="delegation-of-python-packaging-ecosystem-decisions">Delegation of Python packaging ecosystem decisions</h3>
<p>The Python Steering Council delegates the decision making for the packaging
ecosystem to the Python Packaging Authority (PyPA). This is done through
<a href="https://github.com/python/steering-council/blob/main/process/standing-delegations.md#pypa-delegations">standing delegations</a> to specific PyPA members on specific
aspects of Python Packaging. The PyPA is, like CPython Core Developers, a group
of volunteers who maintain various bits and pieces of the Python packaging
ecosystem.</p>
<p>The CPython Core Developers and the PyPA are not the same group of people, but
there is meaningful overlap between the two groups. There are 85 &ldquo;active&rdquo;
CPython Core Developers<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> and 50+ (public) PyPA
members<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. Off the top of my head, I can count 5 people who are
active in both CPython and one or more PyPA projects.</p>
<h2 id="a-bit-of-history">A bit of history</h2>
<p>From <a href="https://www.pypa.io/en/latest/history/">https://www.pypa.io/en/latest/history/</a>:</p>
<blockquote>
<p>2011-02-28: The Python Packaging Authority (PyPA) is created to take over the
maintenance of pip and virtualenv from Ian Bicking, led by Carl Meyer, Brian
Rosner and Jannis Leidel. Other proposed names were “ianb-ng”, “cabal”, “pack”
and “Ministry of Installation”.</p>
</blockquote>
<p>As &ldquo;Ministry of Installation&rdquo; likely implies, these names were <a href="https://discuss.python.org/t/what-is-the-pypa/12297/6?u=pradyunsg">chosen partly in
jest</a>. The name stuck and, those who started using Python <em>after</em> this
name was picked, ended up treating the name at face value. PyPA projects
essentially serves as <em>all</em> of the packaging infrastructure for Python making it
the de facto authority.</p>
<p>Over time, &ldquo;Authority&rdquo; in PyPA did end up being backed by real authority: the
standing delegations from the elected Python Steering Council, ceding control of
certain kinds of Python Enhancement Proposals (PEPs) to specific PyPA members.
There&rsquo;s <a href="https://www.pypa.io/en/latest/specifications/">formal processes</a>, <a href="https://peps.python.org/topic/packaging/">formal interoperability
specifications</a> as Python PEPs and a <a href="https://peps.python.org/pep-0609/">formal governance
model</a>.</p>
<p>To quote <a href="https://discuss.python.org/t/what-is-the-pypa/12297/2?u=pradyunsg">Thomas Kluyver</a>:</p>
<blockquote>
<p>You don’t get much more authoritative than that without an army.</p>
</blockquote>
<h2 id="what-about-non-pypa-projects">What about non-PyPA projects?</h2>
<p>Since PyPA&rsquo;s inception, there have been non-PyPA projects related to Python
packaging (eg: buildout is older than pip). By and large, there isn&rsquo;t any sort
of antagonistic relationship between PyPA and non-PyPA projects. PyPA and
non-PyPA project maintainers have often worked together on various things, and
many <a href="https://packaging.python.org/en/latest/key_projects/#non-pypa-projects">non-PyPA projects are listed as &ldquo;key projects&rdquo;</a> for Python
packaging.</p>
<p>For example, at the time of writing, the two most popular non-PyPA projects are
Conda and Poetry. Both of these rely on the interoperability specifications
and/or tools that the PyPA works on (<a href="https://conda-forge.org/docs/maintainer/adding_pkgs.html#use-pip">conda</a>,
<a href="https://python-poetry.org/docs/pyproject/#poetry-and-pep-517">poetry</a>) to do what they do.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Setuptools is gonna be removed, starting with Python 3.12.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a>&#160;<a href="#fnref1:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Based on the number of eligible votes in the last SC election:
<a href="https://peps.python.org/pep-8104/#results">https://peps.python.org/pep-8104/#results</a>. &ldquo;active&rdquo; is determined as
described in <a href="https://peps.python.org/pep-0013/#membership">Python Language Governance</a> document.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Based on public folks listed in <a href="https://github.com/orgs/pypa/people">https://github.com/orgs/pypa/people</a> (not all
are active though, and there&rsquo;s active folks who are not members of the
GitHub org but have access to the various repositories).&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Excellent error messages from command line tools, according to ChatGPT</title><link>https://pradyunsg.me/blog/2023/01/02/chatgpt-fun-with-error-messages/</link><pubDate>Mon, 02 Jan 2023 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2023/01/02/chatgpt-fun-with-error-messages/</guid><description>&lt;p&gt;In late Dec 2022, I played around with &lt;a href="https://openai.com/blog/chatgpt/"&gt;ChatGPT&lt;/a&gt; in an evening.&lt;/p&gt;
&lt;p&gt;Since it was on the top of my mind&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;, I decided try to
nudge ChatGPT into the direction of giving me a useful answer about error
message design for command line tools.&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Now, tell me what an excellent error message from a command line tool should
contain.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;An excellent error message from a command line tool should contain the
following elements:&lt;/p&gt;</description><content:encoded><![CDATA[<p>In late Dec 2022, I played around with <a href="https://openai.com/blog/chatgpt/">ChatGPT</a> in an evening.</p>
<p>Since it was on the top of my mind<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, I decided try to
nudge ChatGPT into the direction of giving me a useful answer about error
message design for command line tools.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup></p>
<blockquote>
<p><strong>Now, tell me what an excellent error message from a command line tool should
contain.</strong></p>
<p>An excellent error message from a command line tool should contain the
following elements:</p>
<ol>
<li>
<p>A clear and concise description of the error: The error message should
explain what went wrong and why the command failed.</p>
</li>
<li>
<p>A suggestion for how to fix the error: If possible, the error message
should provide a suggestion for how the user can fix the error and try the
command again.</p>
</li>
<li>
<p>The error code: It can be helpful to include an error code or other
identifier that can be used to look up more information about the error.</p>
</li>
<li>
<p>The context in which the error occurred: Providing information about the
context in which the error occurred (e.g., the command that was being run,
the arguments that were provided) can help the user understand the root
cause of the error and how to fix it.</p>
</li>
<li>
<p>A link to additional resources: If there are additional resources that can
help the user understand and fix the error (e.g., documentation, forums),
it can be helpful to include a link to these resources in the error
message.</p>
</li>
</ol>
</blockquote>
<p>I&rsquo;ll admit this was mildly impressive on the first skim-read. Looking closer, it
became clear that the response is actually flawed in multiple ways and the model
made some assumptions that are not <em>completely</em> accurate.</p>
<p>Overall, this is amusing enough to me that I decided to document it here.</p>
<h2 id="further-reading">Further reading</h2>
<ul>
<li><a href="https://abnormalsecurity.com/blog/double-edged-sword-of-chatgpt">https://abnormalsecurity.com/blog/double-edged-sword-of-chatgpt</a></li>
<li><a href="https://stackoverflow.com/help/gpt-policy">https://stackoverflow.com/help/gpt-policy</a></li>
<li><a href="https://twitter.com/emilymbender/status/1603039301864157184">https://twitter.com/emilymbender/status/1603039301864157184</a></li>
<li><a href="https://mastodon.social/@Gargron/109469945447325370">https://mastodon.social/@Gargron/109469945447325370</a> ;)</li>
</ul>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I am currently working on a library to help achieve a great UX around errors
(with a focus on command line tools), based off of my work around <a href="https://github.com/pypa/pip/issues/10421"><code>pip</code>&rsquo;s
error message improvements</a>, <a href="https://sphinx-theme-builder.readthedocs.io/en/latest/errors/"><code>sphinx-theme-builder</code> error
message design</a> and all the reading/research I&rsquo;ve been doing on
this topic&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I&rsquo;m intentionally <em>not</em> publishing the full context of the conversation &ndash;
you&rsquo;ll have to wait until I release the library to read the final form of
the blurb I used with ChatGPT as a prompt here. :)&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>A mistake in a recent website update</title><link>https://pradyunsg.me/blog/2023/01/01/mistake-in-recent-website-update/</link><pubDate>Sun, 01 Jan 2023 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2023/01/01/mistake-in-recent-website-update/</guid><description>A false claim was made on the about page for a few days.</description><content:encoded><![CDATA[<h2 id="what-i-messed-up">What I messed up</h2>
<p>On Dec 27th 2022 ~9pm UTC, I <a href="https://github.com/pradyunsg/pradyunsg.github.io/commit/0eabd336d0a47f7c5d969e19d6f7fcd2a6d01918">published an update</a> to the &ldquo;about&rdquo;
page on this website that (wrongly) claimed:</p>
<blockquote>
<p>My work has been recognised by the Python Software Foundation, and I have been
awarded the PSF Community Service Award in 2020.</p>
</blockquote>
<p>I haven&rsquo;t received the <a href="https://www.python.org/community/awards/psf-awards/">PSF Community Service Award</a>. It wasn&rsquo;t mentioned in the
listing below this sentence, of the various awards I&rsquo;ve received and the
community work I&rsquo;ve involved in.</p>
<p>This stayed up for roughly 4 days, until Dec 31st 2022 ~6pm UTC, when I <a href="https://github.com/pradyunsg/pradyunsg.github.io/commit/74cbf8659461221ee30dca6c133f0604b98695fa">noticed
it and removed it</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<h2 id="how-this-happened">How this happened</h2>
<p>I recently <a href="https://github.com/pradyunsg/pradyunsg.github.io/commit/5d3577220759dcf9cbded1e5303ca0464abdd805">updated</a> various pages on this website. I also
updated the about page, to use a nicer design, data model and layout.</p>
<p>This sentence was a part of a multi-sentence suggestion I had created using <a href="https://openai.com/blog/chatgpt/">a
large language model</a>, similarly to how I&rsquo;d come up with sentences for
some of other other sections on the page. I had pasted this specific suggestion
into the document with the intent of removing this sentence and using the rest
of it. I, however, stepped away from the computer before doing so.</p>
<p>I came back to this a few days later and, without looking carefully, committed
the whole thing and published it before closing the editor window.</p>
<h2 id="what-im-doing-about-it">What I&rsquo;m doing about it</h2>
<p>I don&rsquo;t think anyone noticed this mistake except for me, so this might&rsquo;ve just
been <a href="https://en.wikipedia.org/wiki/Victimless_crime">a &ldquo;victimless crime&rdquo;</a>.
However, I tend to hold myself to a high standard when it comes representing my
own work accurately, and this doesn&rsquo;t hold up to that.</p>
<p>There isn&rsquo;t much I can do about this now, except to apologise for the mistake
and document the fact that I&rsquo;d made this mistake &ndash; which is what this post is.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>The context around why my initial reaction was &ldquo;LOL&rdquo; is that I&rsquo;d just read
<a href="https://arxiv.org/abs/2211.03622">https://arxiv.org/abs/2211.03622</a>.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Wheels are faster, even for pure Python packages</title><link>https://pradyunsg.me/blog/2022/12/31/wheels-are-faster-pure-python/</link><pubDate>Sat, 31 Dec 2022 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2022/12/31/wheels-are-faster-pure-python/</guid><description>&lt;p&gt;When installing with pip (or from PyPI in general), wheels are &lt;em&gt;much&lt;/em&gt; faster
than source distributions, &lt;em&gt;even&lt;/em&gt; for pure-Python projects.&lt;/p&gt;
&lt;p&gt;Packages with native code are a clearer win, because the wheel file will contain
pre-compiled binaries for the platform you&amp;rsquo;re installing on. This means that you
don&amp;rsquo;t need to have a compiler and non-Python build dependencies installed, and
you don&amp;rsquo;t need to wait for the compiler to do its thing.&lt;/p&gt;</description><content:encoded><![CDATA[<p>When installing with pip (or from PyPI in general), wheels are <em>much</em> faster
than source distributions, <em>even</em> for pure-Python projects.</p>
<p>Packages with native code are a clearer win, because the wheel file will contain
pre-compiled binaries for the platform you&rsquo;re installing on. This means that you
don&rsquo;t need to have a compiler and non-Python build dependencies installed, and
you don&rsquo;t need to wait for the compiler to do its thing.</p>
<h2 id="the-quick-answer">The quick answer</h2>
<p>Installing from a wheel is analogous to unpacking a zip file. When installing
from a source distribution, pip will actually build a wheel <em>from</em> the source
distribution and then install using that wheel. It&rsquo;s the same operation at the
end of the day, but there&rsquo;s a bunch of extra &ldquo;work&rdquo; involved in building a wheel
from a source distribution (which contributes to making things slower).</p>
<h2 id="the-picture-answer">The picture answer</h2>



<div class="goat svg-container ">
  
    <svg
      xmlns="http://www.w3.org/2000/svg"
      font-family="Menlo,Lucida Console,monospace"
      
        viewBox="0 0 464 777"
      >
      <g transform='translate(8,16)'>
<path d='M 0,0 L 176,0' fill='none' stroke='currentColor'></path>
<path d='M 176,16 L 336,16' fill='none' stroke='currentColor'></path>
<path d='M 0,32 L 80,32' fill='none' stroke='currentColor'></path>
<path d='M 80,32 L 176,32' fill='none' stroke='currentColor'></path>
<path d='M 256,96 L 432,96' fill='none' stroke='currentColor'></path>
<path d='M 256,144 L 336,144' fill='none' stroke='currentColor'></path>
<path d='M 336,144 L 432,144' fill='none' stroke='currentColor'></path>
<path d='M 256,192 L 448,192' fill='none' stroke='currentColor'></path>
<path d='M 256,240 L 336,240' fill='none' stroke='currentColor'></path>
<path d='M 336,240 L 448,240' fill='none' stroke='currentColor'></path>
<path d='M 256,288 L 448,288' fill='none' stroke='currentColor'></path>
<path d='M 256,336 L 336,336' fill='none' stroke='currentColor'></path>
<path d='M 336,336 L 448,336' fill='none' stroke='currentColor'></path>
<path d='M 256,384 L 432,384' fill='none' stroke='currentColor'></path>
<path d='M 256,432 L 336,432' fill='none' stroke='currentColor'></path>
<path d='M 336,432 L 432,432' fill='none' stroke='currentColor'></path>
<path d='M 256,480 L 432,480' fill='none' stroke='currentColor'></path>
<path d='M 256,528 L 336,528' fill='none' stroke='currentColor'></path>
<path d='M 336,528 L 432,528' fill='none' stroke='currentColor'></path>
<path d='M 0,560 L 216,560' fill='none' stroke='currentColor'></path>
<path d='M 224,576 L 336,576' fill='none' stroke='currentColor'></path>
<path d='M 0,592 L 80,592' fill='none' stroke='currentColor'></path>
<path d='M 80,592 L 216,592' fill='none' stroke='currentColor'></path>
<path d='M 0,640 L 176,640' fill='none' stroke='currentColor'></path>
<path d='M 0,672 L 80,672' fill='none' stroke='currentColor'></path>
<path d='M 80,672 L 176,672' fill='none' stroke='currentColor'></path>
<path d='M 0,720 L 176,720' fill='none' stroke='currentColor'></path>
<path d='M 0,752 L 176,752' fill='none' stroke='currentColor'></path>
<path d='M 0,0 L 0,32' fill='none' stroke='currentColor'></path>
<path d='M 0,560 L 0,592' fill='none' stroke='currentColor'></path>
<path d='M 0,640 L 0,672' fill='none' stroke='currentColor'></path>
<path d='M 0,720 L 0,752' fill='none' stroke='currentColor'></path>
<path d='M 80,32 L 80,544' fill='none' stroke='currentColor'></path>
<path d='M 80,592 L 80,624' fill='none' stroke='currentColor'></path>
<path d='M 80,672 L 80,704' fill='none' stroke='currentColor'></path>
<path d='M 176,0 L 176,16' fill='none' stroke='currentColor'></path>
<path d='M 176,16 L 176,32' fill='none' stroke='currentColor'></path>
<path d='M 176,640 L 176,672' fill='none' stroke='currentColor'></path>
<path d='M 176,720 L 176,752' fill='none' stroke='currentColor'></path>
<path d='M 216,560 L 216,592' fill='none' stroke='currentColor'></path>
<path d='M 256,96 L 256,144' fill='none' stroke='currentColor'></path>
<path d='M 256,192 L 256,240' fill='none' stroke='currentColor'></path>
<path d='M 256,288 L 256,336' fill='none' stroke='currentColor'></path>
<path d='M 256,384 L 256,432' fill='none' stroke='currentColor'></path>
<path d='M 256,480 L 256,528' fill='none' stroke='currentColor'></path>
<path d='M 336,16 L 336,80' fill='none' stroke='currentColor'></path>
<path d='M 336,144 L 336,176' fill='none' stroke='currentColor'></path>
<path d='M 336,240 L 336,272' fill='none' stroke='currentColor'></path>
<path d='M 336,336 L 336,368' fill='none' stroke='currentColor'></path>
<path d='M 336,432 L 336,464' fill='none' stroke='currentColor'></path>
<path d='M 336,528 L 336,576' fill='none' stroke='currentColor'></path>
<path d='M 432,96 L 432,144' fill='none' stroke='currentColor'></path>
<path d='M 432,384 L 432,432' fill='none' stroke='currentColor'></path>
<path d='M 432,480 L 432,528' fill='none' stroke='currentColor'></path>
<path d='M 448,192 L 448,240' fill='none' stroke='currentColor'></path>
<path d='M 448,288 L 448,336' fill='none' stroke='currentColor'></path>
<path d='M 80,544 L 80,552' fill='none' stroke='currentColor'></path>
<polygon points='96.000000,544.000000 84.000000,538.400024 84.000000,549.599976' fill='currentColor' transform='rotate(90.000000, 80.000000, 544.000000)'></polygon>
<path d='M 80,624 L 80,632' fill='none' stroke='currentColor'></path>
<polygon points='96.000000,624.000000 84.000000,618.400024 84.000000,629.599976' fill='currentColor' transform='rotate(90.000000, 80.000000, 624.000000)'></polygon>
<path d='M 80,704 L 80,712' fill='none' stroke='currentColor'></path>
<polygon points='96.000000,704.000000 84.000000,698.400024 84.000000,709.599976' fill='currentColor' transform='rotate(90.000000, 80.000000, 704.000000)'></polygon>
<polygon points='232.000000,576.000000 220.000000,570.400024 220.000000,581.599976' fill='currentColor' transform='rotate(180.000000, 224.000000, 576.000000)'></polygon>
<path d='M 336,80 L 336,88' fill='none' stroke='currentColor'></path>
<polygon points='352.000000,80.000000 340.000000,74.400002 340.000000,85.599998' fill='currentColor' transform='rotate(90.000000, 336.000000, 80.000000)'></polygon>
<path d='M 336,176 L 336,184' fill='none' stroke='currentColor'></path>
<polygon points='352.000000,176.000000 340.000000,170.399994 340.000000,181.600006' fill='currentColor' transform='rotate(90.000000, 336.000000, 176.000000)'></polygon>
<path d='M 336,272 L 336,280' fill='none' stroke='currentColor'></path>
<polygon points='352.000000,272.000000 340.000000,266.399994 340.000000,277.600006' fill='currentColor' transform='rotate(90.000000, 336.000000, 272.000000)'></polygon>
<path d='M 336,368 L 336,376' fill='none' stroke='currentColor'></path>
<polygon points='352.000000,368.000000 340.000000,362.399994 340.000000,373.600006' fill='currentColor' transform='rotate(90.000000, 336.000000, 368.000000)'></polygon>
<path d='M 336,464 L 336,472' fill='none' stroke='currentColor'></path>
<polygon points='352.000000,464.000000 340.000000,458.399994 340.000000,469.600006' fill='currentColor' transform='rotate(90.000000, 336.000000, 464.000000)'></polygon>
<text text-anchor='middle' x='16' y='20' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='16' y='660' fill='currentColor' style='font-size:1em'>U</text>
<text text-anchor='middle' x='24' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='24' y='580' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='24' y='660' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='24' y='740' fill='currentColor' style='font-size:1em'>I</text>
<text text-anchor='middle' x='32' y='20' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='32' y='580' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='32' y='660' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='32' y='740' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='40' y='580' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='40' y='660' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='40' y='740' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='48' y='20' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='48' y='580' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='48' y='660' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='48' y='740' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='56' y='20' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='56' y='580' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='56' y='660' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='56' y='740' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='64' y='20' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='64' y='580' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='64' y='740' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='72' y='20' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='72' y='580' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='72' y='660' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='72' y='740' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='80' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='80' y='660' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='80' y='740' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='88' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='88' y='580' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='88' y='660' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='88' y='740' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='96' y='20' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='96' y='52' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='96' y='68' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='96' y='580' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='96' y='660' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='104' y='52' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='104' y='68' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='104' y='580' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='104' y='660' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='104' y='740' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='112' y='20' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='112' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='112' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='112' y='580' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='112' y='740' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='120' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='120' y='52' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='120' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='120' y='660' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='120' y='740' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='128' y='20' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='128' y='68' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='128' y='580' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='128' y='660' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='128' y='740' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='136' y='20' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='136' y='580' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='136' y='660' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='136' y='740' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='144' y='20' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='144' y='580' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='144' y='660' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='144' y='740' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='152' y='20' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='152' y='580' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='152' y='740' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='160' y='20' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='160' y='580' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='176' y='580' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='184' y='580' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='192' y='580' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='200' y='580' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='272' y='212' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='272' y='308' fill='currentColor' style='font-size:1em'>(</text>
<text text-anchor='middle' x='280' y='116' fill='currentColor' style='font-size:1em'>U</text>
<text text-anchor='middle' x='280' y='132' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='280' y='212' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='280' y='308' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='280' y='404' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='280' y='420' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='280' y='500' fill='currentColor' style='font-size:1em'>D</text>
<text text-anchor='middle' x='280' y='516' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='288' y='116' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='288' y='132' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='288' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='288' y='228' fill='currentColor' style='font-size:1em'>C</text>
<text text-anchor='middle' x='288' y='308' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='288' y='324' fill='currentColor' style='font-size:1em'>P</text>
<text text-anchor='middle' x='288' y='404' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='288' y='420' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='288' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='288' y='516' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='296' y='116' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='296' y='212' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='296' y='228' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='296' y='308' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='296' y='324' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='296' y='404' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='296' y='500' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='296' y='516' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='304' y='116' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='304' y='132' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='304' y='228' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='304' y='324' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='304' y='404' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='304' y='420' fill='currentColor' style='font-size:1em'>g</text>
<text text-anchor='middle' x='304' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='312' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='312' y='132' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='312' y='212' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='312' y='228' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='312' y='308' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='312' y='324' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='312' y='420' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='312' y='500' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='312' y='516' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='320' y='116' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='320' y='132' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='320' y='212' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='320' y='228' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='320' y='308' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='320' y='324' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='320' y='404' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='320' y='420' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='320' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='320' y='516' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='328' y='132' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='328' y='212' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='328' y='228' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='328' y='308' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='328' y='324' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='328' y='404' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='328' y='420' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='328' y='516' fill='currentColor' style='font-size:1em'>p</text>
<text text-anchor='middle' x='336' y='116' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='336' y='132' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='336' y='212' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='336' y='308' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='336' y='324' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='336' y='404' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='336' y='420' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='336' y='500' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='336' y='516' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='344' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='344' y='132' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='344' y='212' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='344' y='228' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='344' y='308' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='344' y='324' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='344' y='404' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='344' y='420' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='344' y='500' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='344' y='516' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='352' y='52' fill='currentColor' style='font-size:1em'>f</text>
<text text-anchor='middle' x='352' y='68' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='352' y='116' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='352' y='132' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='352' y='212' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='352' y='228' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='352' y='308' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='352' y='404' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='352' y='420' fill='currentColor' style='font-size:1em'>t</text>
<text text-anchor='middle' x='352' y='500' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='352' y='516' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='360' y='52' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='360' y='68' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='360' y='116' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='360' y='132' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='360' y='212' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='360' y='228' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='360' y='308' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='360' y='324' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='360' y='404' fill='currentColor' style='font-size:1em'>-</text>
<text text-anchor='middle' x='360' y='420' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='360' y='500' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='360' y='516' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='368' y='52' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='368' y='68' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='368' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='368' y='132' fill='currentColor' style='font-size:1em'>y</text>
<text text-anchor='middle' x='368' y='212' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='368' y='228' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='368' y='308' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='368' y='324' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='368' y='404' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='368' y='500' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='368' y='516' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='376' y='52' fill='currentColor' style='font-size:1em'>m</text>
<text text-anchor='middle' x='376' y='68' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='376' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='376' y='228' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='376' y='324' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='376' y='404' fill='currentColor' style='font-size:1em'>a</text>
<text text-anchor='middle' x='376' y='420' fill='currentColor' style='font-size:1em'>w</text>
<text text-anchor='middle' x='384' y='68' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='384' y='132' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='384' y='212' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='384' y='308' fill='currentColor' style='font-size:1em'>b</text>
<text text-anchor='middle' x='384' y='324' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='384' y='404' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='384' y='420' fill='currentColor' style='font-size:1em'>h</text>
<text text-anchor='middle' x='384' y='500' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='384' y='516' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='392' y='68' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='392' y='116' fill='currentColor' style='font-size:1em'>c</text>
<text text-anchor='middle' x='392' y='132' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='392' y='212' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='392' y='228' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='392' y='308' fill='currentColor' style='font-size:1em'>u</text>
<text text-anchor='middle' x='392' y='324' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='392' y='404' fill='currentColor' style='font-size:1em'>k</text>
<text text-anchor='middle' x='392' y='420' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='392' y='500' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='392' y='516' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='400' y='116' fill='currentColor' style='font-size:1em'>o</text>
<text text-anchor='middle' x='400' y='132' fill='currentColor' style='font-size:1em'>r</text>
<text text-anchor='middle' x='400' y='212' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='400' y='228' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='400' y='308' fill='currentColor' style='font-size:1em'>i</text>
<text text-anchor='middle' x='400' y='404' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='400' y='420' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='400' y='500' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='400' y='516' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='408' y='116' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='408' y='212' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='408' y='228' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='408' y='308' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='408' y='324' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='408' y='404' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='408' y='420' fill='currentColor' style='font-size:1em'>l</text>
<text text-anchor='middle' x='408' y='516' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='416' y='116' fill='currentColor' style='font-size:1em'>e</text>
<text text-anchor='middle' x='416' y='212' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='416' y='308' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='416' y='324' fill='currentColor' style='font-size:1em'>n</text>
<text text-anchor='middle' x='416' y='404' fill='currentColor' style='font-size:1em'>d</text>
<text text-anchor='middle' x='424' y='212' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='424' y='308' fill='currentColor' style='font-size:1em'>s</text>
<text text-anchor='middle' x='424' y='324' fill='currentColor' style='font-size:1em'>v</text>
<text text-anchor='middle' x='432' y='212' fill='currentColor' style='font-size:1em'>)</text>
<text text-anchor='middle' x='432' y='308' fill='currentColor' style='font-size:1em'>)</text>
</g>

    </svg>
  
</div>
<h2 id="the-wordy-answer">The wordy answer</h2>
<p>When installing from a wheel, pip will fetch the wheel file, and then unpack it.
That&rsquo;s it. There&rsquo;s nothing else to do.</p>
<p>When installing from a source distribution, pip will fetch the source
distribution, unpack it to a temporary directory, (potentially) create a build
environment and install build-dependencies in that environment, make a
subprocess call (or multiple) to the build-backend to get it to generate a wheel
file. The build environment and unpacked sources are then deleted. We now have a
wheel file which will then be handled like any other wheel file.</p>
<h2 id="further-reading">Further reading</h2>
<ul>
<li><a href="https://pip.pypa.io/en/stable/reference/build-system/">How pip builds packages from source</a></li>
<li><a href="https://packaging.python.org/en/latest/specifications/binary-distribution-format/">Specification of the wheel format</a></li>
<li><a href="https://installer.pypa.io/">Installer</a>&rsquo;s <a href="https://github.com/pypa/installer/blob/0.6.0/src/installer/_core.py#L64">installation logic</a> code, if you&rsquo;re inclined that way</li>
<li><a href="https://pypackaging-native.github.io/">pypackaging-native</a>: &ldquo;a collection of content about key Python packaging
topics and issues for projects using native code&rdquo; (which is what made me write
this post)</li>
</ul>
]]></content:encoded></item><item><title>OSS Work update #18</title><link>https://pradyunsg.me/blog/2022/09/30/oss-update-18/</link><pubDate>Fri, 30 Sep 2022 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2022/09/30/oss-update-18/</guid><description>Oh hey, backfilling is fun.</description><content:encoded><![CDATA[<h2 id="work-i-did-jun-2022">Work I did (Jun 2022)</h2>
<h3 id="software">Software</h3>
<ul>
<li>sphinx-theme-builder: 0.2.0a15 release.</li>
<li>sphinx-basic-ng: 0.0.1a12 release.</li>
<li>Furo: 2022.06.04 and 2022.06.21 releases.</li>
<li>Documentation improvements to pip.</li>
<li>Made progress on moving pip away from distutils usage, unblocking Python
3.12&rsquo;s distutils removal.</li>
<li><code>sphinx-theme-builder</code> got a bunch of updates.</li>
<li><code>sphinx-basic-ng</code> got a bunch of updates.</li>
<li>Improve <code>sphinx-theme-builder</code> usability for downstream redistributors.</li>
<li>Significantly simplified the default configuration file template in Sphinx,
which eventually got released in Sphinx 5.1.</li>
<li>Worked on getting pip&rsquo;s test isolation to behave correctly without virtualenv
&lt;= 16 (from ~2019).</li>
<li>Worked on Sphinx 5 compatibility for various bits of the Sphinx ecosystem that
I maintain.</li>
<li>Spent a decent amount of time working on Lutra.</li>
<li>Built CPython documentation with Lutra.</li>
</ul>
<h3 id="community">Community</h3>
<ul>
<li>Getting the Packaging PEPs into a consistent state.</li>
<li>Start moving Python Packaging standards to packaging.python.org.</li>
<li>Engage in a discussion about Bokeh moving off of <code>setup.py</code>.</li>
<li>Get PEP 668 over the line and&hellip; it&rsquo;s accepted!</li>
<li>Start poking at PEP 625, to get the ball rolling on that again.</li>
<li>General contributions to executable books and Sphinx.</li>
<li>Gather a first round of feedback, on CPython documentation built with Lutra.</li>
</ul>
<h2 id="general-notes">General Notes</h2>
<p>This was backfilled in Sept 2022.</p>
]]></content:encoded></item><item><title>OSS Work update #17</title><link>https://pradyunsg.me/blog/2022/07/29/oss-update-17/</link><pubDate>Fri, 29 Jul 2022 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2022/07/29/oss-update-17/</guid><description>Oh hey, backfilling is fun.</description><content:encoded><![CDATA[<h2 id="work-i-did-may-2022">Work I did (May 2022)</h2>
<h3 id="software">Software</h3>
<ul>
<li>Release pip 22.1!</li>
<li>Lots of bugfixes for pip 22.1!</li>
<li>Make some progress on improving pip&rsquo;s build system logic.</li>
<li>Make improvements to Furo, switching it to use <code>sphinx-basic-ng</code>.</li>
</ul>
<h3 id="community">Community</h3>
<ul>
<li>Remotely attend PyCon US Sprints.</li>
<li>Attend and engage in the Python Documentation Community meeting.</li>
<li>Collaborate on setting up a &ldquo;Packaging PEPs&rdquo; pages on
<a href="https://peps.python.org/">https://peps.python.org/</a>.</li>
<li>PEP 691 (adding a JSON-based API to Python Package Indexes) went through its
initial round of discussions. I co-authored this PEP.</li>
<li>More work on getting PEP 668 (externally managed environments) ready for a
decision. I co-authored this PEP.</li>
</ul>
<h2 id="general-notes">General notes</h2>
<p>This month was a vacation month, and it shows! I got to meet family and friends,
and had a generally relaxed few weeks.</p>
]]></content:encoded></item><item><title>OSS Work update #16</title><link>https://pradyunsg.me/blog/2022/07/28/oss-update-16/</link><pubDate>Thu, 28 Jul 2022 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2022/07/28/oss-update-16/</guid><description>April was a somewhat relaxed month.</description><content:encoded><![CDATA[<h2 id="work-i-did-april-2022">Work I did (April 2022)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Release pip 22.1.b1</li>
<li>Release Furo 2022.04.07</li>
<li>Release release-helper 1.0.0</li>
<li>Improve the presentation of upgrade prompts from pip.</li>
<li>Some exploratory work for how much effort it would be, to remove
<code>setup.py install</code> calls from pip&rsquo;s codebase.</li>
<li>Some exploratory work for adding a &ldquo;Track: Packaging&rdquo; to Python PEPs.</li>
<li>Some exploratory work for automating adding maintainers/committers to PyPA,
with the information being stored in a Git repository with history.</li>
<li>Did an &ldquo;open source responsibility audit&rdquo;, to check what I&rsquo;ve committed to
responsibility for and for what things I should step down.</li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>PyCon US Packaging Summit planning.</li>
<li>Poke a few more people about PEP 668 (externally managed environments).</li>
<li>Started writing a PEP for &ldquo;default&rdquo; extras (i.e. optional dependencies that
get installed by default).</li>
<li>Interviewed as part of a post about
<a href="https://builtin.com/software-engineering-perspectives/package-managers">Package Managers</a></li>
</ul>
<h2 id="general-notes">General notes</h2>
<p>My plans for attending PyCon US changed very close to the event date, since
PyCon announced that there will be <a href="https://pycon.blogspot.com/2022/04/important-venue-information-update.html">a co-located event does not have any
published masking or vaccination requirements</a>. I&rsquo;m pretty
bummed out about that. Thankfully, everyone involved in the trip
planning/booking has been understanding.</p>
<p>PyCon US is wrapping up, as I write this. I imagine there&rsquo;s gonna be a bunch of
folks with a bunch of energy contributing to various projects, something I look
forward to!</p>
]]></content:encoded></item><item><title>OSS Work update #15</title><link>https://pradyunsg.me/blog/2022/04/08/oss-update-15/</link><pubDate>Fri, 08 Apr 2022 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2022/04/08/oss-update-15/</guid><description>Woah, time flies!</description><content:encoded><![CDATA[<h2 id="work-i-did">Work I did</h2>
<p>Things have been fairly bumpy over the last little while.</p>
<h3 id="dec-2021">Dec 2021</h3>
<h4 id="technical">Technical</h4>
<ul>
<li>sphinx-basic-ng: release alpha 8</li>
<li>sphinx-theme-builder: release alpha 12</li>
<li>pip: Significant usability improvements
<ul>
<li>Much better cleaner error presentation style, providing additional context
in build-time error messages.</li>
<li>Abort immediately on metadata generation failure instead of backtracking.</li>
</ul>
</li>
<li>installer: Preserve executable bits, bringing it closer to behaving
appropriately.</li>
<li>installer: Improve the documentation.</li>
<li>pip: Start rewriting the build isolation logic.</li>
<li>oldest-supported-numpy: Improve testing setup for dependency declarations.</li>
<li>pydata-sphinx-theme: Rework the theme&rsquo;s build system, to use
<code>sphinx-theme-builder</code>.</li>
<li>pyproject-hooks: Create and scaffold the project, as a migration path for
<code>pep517</code>.</li>
<li>Started working on a tool to make writing these easier for me.</li>
</ul>
<h4 id="communication">Communication</h4>
<ul>
<li>Initiated the conversation for starting the Python packaging summit at PyCon.</li>
<li>Nudged Discourse
<a href="https://meta.discourse.org/t/move-footnotes-to-a-standard-plugin/210112">to enable the footnotes plugin on all hosted instances</a>.</li>
<li>Reworked PyPI support&rsquo;s limit request templates.</li>
<li>Became a maintainer on <a href="https://github.com/pypa/flit">Flit</a>.</li>
</ul>
<h3 id="jan-2022">Jan 2022</h3>
<h4 id="technical-1">Technical</h4>
<ul>
<li>pip: Release 22.0.</li>
<li>Furo: Immaculate Indigo release.</li>
<li>sphinx-inline-tabs: Release beta 11.</li>
<li>sphinx-basic-ng: Release alpha 9.</li>
<li>sphinx-theme-builder: Release alpha 13.</li>
<li>pip: Significantly improve how errors in subprocesses are presented.</li>
<li>Sphinx: change &ldquo;permalink to this headline&rdquo; to &ldquo;permalink to this heading&rdquo;.</li>
<li>pydata-sphinx-theme: Improve presentation and styling of the scaffolding.</li>
</ul>
<h4 id="communication-1">Communication</h4>
<ul>
<li>Release management and change management for pip 22.0.</li>
<li>Discussion with the Packaging Project manager about rolling out changes.</li>
<li>Moving externally managed environments PEP forward.</li>
</ul>
<h3 id="feb-2022">Feb 2022</h3>
<h4 id="technical-2">Technical</h4>
<ul>
<li>✨ Furo: Jazzy Jasmine and Keen Kobi releases, with major improvements.</li>
<li>pip: Release 22.0 bugfixes.</li>
<li>installer: Release 0.5.0</li>
<li>pip: Make more improvements to pip&rsquo;s documentation.</li>
<li>pip: Get the fix for Windows upgrade protection logic landed.</li>
<li>sphinx-themes.org: Rework the &ldquo;Kitchen Sink&rdquo;.</li>
</ul>
<h4 id="communication-2">Communication</h4>
<ul>
<li>Poke at PEP 668, to check that there&rsquo;s still interest.</li>
<li>Get the ball rolling for the Packaging Summit at PyCon US 2022.</li>
<li>Move <code>installer</code> into the PyPA umbrella.</li>
</ul>
<h3 id="mar-2022">Mar 2022</h3>
<h4 id="technical-3">Technical</h4>
<ul>
<li>sphinx-theme-builder: Release alpha 14.</li>
<li>installer: Release 0.5.1.</li>
<li>Python: Upgrade the pip version that&rsquo;s bundled with latest bugfix releases-</li>
<li>Lutra: Publicly release the source code under MIT.</li>
<li>pip: Explore changing wheel installation logic to use <code>installer</code>.</li>
<li>pip: Explore changing pyproject.toml build system to use <code>build</code>.</li>
<li>pip: Make progress on the broader build logic refactor.</li>
<li>pip: Make more improvements to pip&rsquo;s documentation.</li>
<li>pip: Improve the pip upgrade prompt presentation.</li>
<li>dotfiles: Completely rework my dotfiles setup, allowing &ldquo;merging&rdquo; multiple
repositories.</li>
</ul>
<h4 id="communication-3">Communication</h4>
<ul>
<li>Update the PyPA recommendations around pipenv, to better reflect the current
state of the project.</li>
<li>Make a public proposal about adopting the concept of &ldquo;Teams&rdquo; (from PEP 8015).</li>
<li>Ask publicly about blockers for dropping pip&rsquo;s legacy resolver.</li>
</ul>
<h2 id="what-next">What next?</h2>
<p>There&rsquo;s PyCon US close to the end of the month! That&rsquo;s the first in-person event
that I&rsquo;ve bought tickets for since 2020!</p>
<p>There&rsquo;s going to be a Python Packaging Summit, at PyCon US this year &ndash; I&rsquo;m one
of the organisers. I am also going to be at the event for sprints.</p>
<h2 id="other-commitments">Other commitments</h2>
<p>A full time job that pays my bills. :)</p>
]]></content:encoded></item><item><title>Pradyun Gedam</title><link>https://pradyunsg.me/stuff/</link><pubDate>Sun, 27 Feb 2022 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/stuff/</guid><description>&lt;p&gt;The information on this page has been consolidated into &lt;a href="../about/"&gt;this page&lt;/a&gt;.&lt;/p&gt;</description><content:encoded>&lt;p>The information on this page has been consolidated into &lt;a href="../about/">this page&lt;/a>.&lt;/p>
</content:encoded></item><item><title>OSS Work update #14</title><link>https://pradyunsg.me/blog/2021/12/12/oss-update-14/</link><pubDate>Sun, 12 Dec 2021 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2021/12/12/oss-update-14/</guid><description>Making things look better and work better!</description><content:encoded><![CDATA[<h2 id="work-i-did">Work I did</h2>
<p>These last two months have been fairly dense!</p>
<h3 id="oct-2021">Oct 2021</h3>
<h4 id="technical">Technical</h4>
<ul>
<li>pip: 21.3 release.</li>
<li>packaging: 21.1 release.</li>
<li>sphinx-basic-ng: alpha7 release.</li>
<li>resolvelib: 0.8.0 release.</li>
<li>installer: 0.4.0 release.</li>
<li>installer: 0.3.0 release.</li>
<li>pip: Some benchmarking to see get a better idea of how stuff performs.</li>
<li>pip: Start working on adding diagnostic details to pip&rsquo;s error messages.</li>
<li>pip: Documentation improvements.</li>
<li>vendoring: Rework the license fetching mechanism, to utilise wheels whenever
possible.</li>
<li>installer: Modernise the project, and add Python 3.10 support.</li>
<li>sphinx-basic-ng: Make some tweaks and improvements.</li>
<li>sphinx-themes.org: Some TLC for the site.</li>
<li>sphinx-design: Contribute improvements to tab presentation.</li>
<li>Lutra: settle down on a name for my second Sphinx theme.</li>
</ul>
<h4 id="communication">Communication</h4>
<ul>
<li>PEP 655: More discussions. :)</li>
<li>Help psf/black settle down on a stability policy.</li>
<li>Build consensus on adopting rich in pip, amongst maintainers and various
community members.</li>
</ul>
<h3 id="november-2021">November 2021</h3>
<h4 id="technical-1">Technical</h4>
<ul>
<li>sphinx-theme-builder is now a thing! 🎉
<ul>
<li>Furo and <code>pydata-sphinx-theme</code> have adopted it!</li>
</ul>
</li>
<li>pip: Adopt rich! 🎉
<ul>
<li>pip will now use rich&rsquo;s progress bar!</li>
</ul>
</li>
<li>Lutra: More progress on the Sphinx theme.</li>
<li>sphinx-basic-ng: Adapt as I learn things from implementing Lutra.</li>
<li>Sphinx: Start working on dropping vendored jQuery and underscore.js.</li>
<li>pyproject-hooks: New project!</li>
</ul>
<h4 id="communication-1">Communication</h4>
<ul>
<li>Be the <a href="https://www.blog.pythonlibrary.org/2021/11/29/pydev-of-the-week-pradyun-gedam/">PyDev of the week</a>! 🎉</li>
<li>PEP 655: More discussions. :)</li>
<li>Ensure that pygments and rich are OK with being vendored in pip.</li>
<li>Discuss and explore how pip should behave in environments without setuptools.</li>
<li>Start moving away from packages using PEP numbers, as their name.</li>
</ul>
<h2 id="general-notes">General notes</h2>
<p>The work for improving error messages in pip is coming along really nicely! This
has been a great mix of frustratingly-difficult and visually-pleasing work that
I&rsquo;m glad I&rsquo;m able to do.</p>
<p><img loading="lazy" src="https://user-images.githubusercontent.com/3275593/141511663-e41a6e7c-162c-435d-b271-7b36aed21024.png"></p>
<p>As a reminder, the next <a href="https://www.volunteeramnestyday.net">Volunteer Responsibility Amnesty Day</a> is <em>almost</em> here!
If you are someone who volunteers for things, consider participating and
checking in with yourself on December 21, 2021.</p>
<h2 id="what-next">What next?</h2>
<p>Well, I&rsquo;m gonna take a break from OSS during the holidays.</p>
<ul>
<li>pip: Continue working on the diagnostic errors effort.</li>
<li>Sphinx: More progress on $theme-I-am-writing.</li>
<li>Sphinx: Make some progress on the jQuery / UnderscoreJS rewrite.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>A full time job that pays my bills. :)</p>
]]></content:encoded></item><item><title>OSS Work update #13</title><link>https://pradyunsg.me/blog/2021/10/09/oss-update-13/</link><pubDate>Sat, 09 Oct 2021 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2021/10/09/oss-update-13/</guid><description>New hardware + more time = more stuff done!</description><content:encoded><![CDATA[<p>It&rsquo;s been a while since I posted one of these!</p>
<h2 id="work-i-did">Work I did</h2>
<p>This has been a fairly productive few months, despite all the things that have
been happening outside of my open-source-related responsibilities.</p>
<h3 id="july-2021">July 2021</h3>
<h4 id="technical">Technical</h4>
<ul>
<li>installer: 0.2.3 release!</li>
<li>packaging: 21.0 release!</li>
<li>sphinx-basic-ng: Alpha 6 release.</li>
<li>pip: Make progress on the documentation revamp project.</li>
<li>pip: Make progress on adopting black.</li>
<li>Furo: More Sphinx 4 compatibility stuff.</li>
<li>Furo: Refactored most of the stylesheets.</li>
<li>Furo: Implemented and released dark mode toggle, which was a heavily requested
feature.</li>
<li>Furo: Improve accessibility by adding appropriate labels across the site,
improving constrast ratios across the board and validating the keyboard-only
navigation story.</li>
</ul>
<h4 id="communication">Communication</h4>
<ul>
<li>Lots of PR reviews across all of GitHub!</li>
<li>Onboard a new contributor (<a href="https://github.com/DiddiLeija">@DiddiLeija</a>) to pip.</li>
<li>Collaborate on the lockfile standardisation effort (became PEP 655).</li>
<li>Help with ComputeCanada&rsquo;s setup for providing optimised wheels to their users.</li>
<li>Sphinx: experiment with improving the documentation site.</li>
</ul>
<h3 id="august-2021">August 2021</h3>
<h4 id="technical-1">Technical</h4>
<ul>
<li>Furo: First stable release!</li>
<li>sphinx-inline-tabs: Release beta10!</li>
<li>pip: More progress on the documentation revamp project.</li>
<li>pip: Migrate automatic merge conflict label mechanisms.</li>
<li>pip: Improve deprecation helpers.</li>
<li>pip: Improve issue filing experience.</li>
<li>Furo: Add support for sphinx-design elements.</li>
</ul>
<h4 id="communication-1">Communication</h4>
<ul>
<li>Poke at the PEP 655 discussion.</li>
<li>Poke at the GPU-optimised wheels discussion.</li>
<li>sphinx-design: Provide feedback on the initial iteration.</li>
<li>TOML: newline normalisation discussion.</li>
<li>pip: Drive discussion and resolve the black adoption story.</li>
<li>Furo: user support, helping out with their usage and docs.</li>
</ul>
<h3 id="sept-2021">Sept 2021</h3>
<h4 id="technical-2">Technical</h4>
<ul>
<li>pip: Lots of PR reviews and issue tracker trimming.</li>
<li>pip: More progress on documentation revamp.</li>
<li>Furo: Rework presentation of API documentation.</li>
<li>Furo: General polishing, based on issues reported by users.</li>
<li>installer: Work on modernising the codebase.</li>
<li>installer: Land the PRs that users have filed for this.</li>
<li>vendoring: Improve behaviours, for patching and import rewriting.</li>
</ul>
<h4 id="communication-2">Communication</h4>
<ul>
<li>pip: Discussion and kickoff of the effort to improve error messages.</li>
<li>pip: Pick up the release manager duties for 21.3 (Oct 2021).</li>
<li>installer: Communicate around the support promises for EoL Python.</li>
<li>Furo: user support, helping out with their usage and docs.</li>
<li>Executable Books: Get involved in the governance discussions.</li>
</ul>
<h2 id="general-notes">General notes</h2>
<p>I&rsquo;m really excited about the progress on the pip documentation revamp. I&rsquo;m
particularly happy with how the <a href="https://pip.pypa.io/en/latest/reference/build-system/">Build System Interface</a> section has come
together.</p>
<p><a href="https://www.volunteeramnestyday.net">Volunteer Responsibility Amnesty Day</a> is on the next solstice: December
21, 2021. If you volunteer for things, consider participating and checking in
with yourself.</p>
<h2 id="what-next">What next?</h2>
<ul>
<li>PEP 655: Help out with the rewrite.</li>
<li>pip: 21.3 release!</li>
<li>pip: Wind down the documentation rewrite effort.</li>
<li>pip: Make progress on the diagnostic errors effort.</li>
<li>installer: Make last EoL Python release.</li>
<li>Sphinx: More progress on $theme-I-am-writing.</li>
<li>Poke and check what&rsquo;s up with the Python Documentation Workgroup.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>A full time job that pays my bills. :)</p>
]]></content:encoded></item><item><title>OSS Work update #12</title><link>https://pradyunsg.me/blog/2021/07/03/oss-update-12/</link><pubDate>Sat, 03 Jul 2021 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2021/07/03/oss-update-12/</guid><description>A whole lot of logistics.</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month.
<a href="/blog/2021/05/07/oss-update-11/">Here&rsquo;s the April post</a>.</p>
<h2 id="work-i-did-1-may-2021---30-jun-2021">Work I did (1 May 2021 - 30 Jun 2021)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Made significant progress on pip&rsquo;s documentation rewrite.</li>
<li>More progress on <a href="https://github.com/pradyunsg/installer">installer</a>&rsquo;s usability.</li>
<li>Finally completed the restructuring of pip&rsquo;s distribution via <a href="https://bootstrap.pypa.io/">https://bootstrap.pypa.io/</a>. Shoutout to @ewdurbin who did most of the magic here. :)</li>
<li>A lot of issue tracker triage (and mostly saying no) for <a href="https://pradyunsg.me/furo">Furo</a>.</li>
<li>Sphinx 4 compatibility for <a href="https://pradyunsg.me/furo">Furo</a>.</li>
<li>Wrote my own VS Code editor UI theme, finally.</li>
<li>Sphinx: More progress on $theme-I-am-writing.</li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>PyPA logistics for moving pipx and cibuildwheel.</li>
<li>Passively involved in the editable installs standardisation process.</li>
</ul>
<p>If you wanna talk to me on a weekend, I&rsquo;m still doing open <a href="https://calendly.com/pradyunsg/weekend-time">social weekends</a>. :)</p>
<h2 id="general-notes">General notes</h2>
<p>Nothing to say here this time.</p>
<h2 id="what-next">What next?</h2>
<p>Some more wrapping up of ongoing projects, since I actually didn&rsquo;t really do
that as much as I&rsquo;d hoped for.</p>
<h3 id="technical-1">Technical</h3>
<ul>
<li>Make further progress on pip&rsquo;s documentation rewrite.</li>
<li>installer: Finalise and make a stable release.</li>
<li>Sphinx: Continue iterating on <code>sphinx-basic-ng</code>.</li>
<li>Sphinx: Continue iterating on $theme-I-am-writing.</li>
<li>Sphinx: Continue iterating on the PEP 517 backend.</li>
</ul>
<h3 id="communication-1">Communication</h3>
<ul>
<li>Spend time on the Python lockfile standardisation effort.</li>
<li>Help with the July pip release.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>A full time job, that pays my bills. :)</p>
]]></content:encoded></item><item><title>OSS Work update #11</title><link>https://pradyunsg.me/blog/2021/05/07/oss-update-11/</link><pubDate>Fri, 07 May 2021 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2021/05/07/oss-update-11/</guid><description>Release all the things!</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month.
<a href="/blog/2021/04/03/oss-update-10/">Here&rsquo;s the March post</a>.</p>
<h2 id="work-i-did-1-apr-2021---30-apr-2021">Work I did (1 Apr 2021 - 30 Apr 2021)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Initial release of <a href="https://github.com/pradyunsg/sphinx-basic-ng/">sphinx-basic-ng</a> is out!</li>
<li>Initial release of <a href="https://github.com/pradyunsg/installer">installer</a> is out!</li>
<li>Revamped <a href="https://sphinx-themes.org/">sphinx-themes.org</a>!</li>
<li>Made progress on the &ldquo;sister theme&rdquo; for <a href="https://pradyunsg.me/furo">Furo</a>. Picked a name for it too!</li>
<li>Made progress on a PEP 517 build backend for Sphinx themes, and told a
few relevant folks about it.</li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>My <a href="https://calendly.com/pradyunsg/weekend-time">social weekends</a> are still a thing, and have been great so far! If
you wanna talk to me on a weekend, click that link. :)
<ul>
<li>Continuing to collaborate on designing a lockfile format for Python.</li>
</ul>
</li>
<li>Got involved in discussions about modernising the Python documentation theme.</li>
<li>Got involved in discussions about new tutorial in the Sphinx documentation.</li>
<li>Did some post-pip-release fire fighting. :)</li>
</ul>
<h2 id="general-notes">General notes</h2>
<p>Nothing to say here this time.</p>
<h2 id="what-next">What next?</h2>
<p>I&rsquo;m going to try to wrap up the big things I started over the last few months.</p>
<h3 id="technical-1">Technical</h3>
<ul>
<li>installer: Finalise and make a stable release.</li>
<li>Sphinx: Continue iterating on <code>sphinx-basic-ng</code>.</li>
<li>Sphinx: Continue iterating on $theme-I-am-writing.</li>
<li>Sphinx: Continue iterating on the PEP 517 backend.</li>
</ul>
<h3 id="communication-1">Communication</h3>
<ul>
<li>Speak at a few local meetups, remotely.</li>
<li>Spend time on the Python lockfile standardisation effort.</li>
<li>Spend time on the Python documentation improvement effort.</li>
<li>Spend time on the Sphinx tutorial and documentation improvement effort.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>A full time job, that pays my bills. :)</p>
]]></content:encoded></item><item><title>Revamping my personal website</title><link>https://pradyunsg.me/blog/2021/04/09/revamping-this-site/</link><pubDate>Fri, 09 Apr 2021 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2021/04/09/revamping-this-site/</guid><description>Hopping onto the hype train and migrating to Hugo.</description><content:encoded><![CDATA[<p>I made an impulse decision to rework my personal website, to port it
over to <a href="https://gohugo.io/">Hugo</a>, and away from <a href="https://jekyllrb.com/">Jekyll</a>. This is now built using the
<a href="https://adityatelange.me/blog/papermod-went-viral/">recently-viral</a> <a href="https://adityatelange.github.io/hugo-PaperMod/">PaperMod</a> theme for Hugo.</p>
<p>I took the opportunity to refresh/revamp the site structure, which
worked out pretty well too.</p>
<p>Some notes from doing this transition:</p>
<ul>
<li>Hugo&rsquo;s separation of content vs templates is GREAT.</li>
<li>Hugo&rsquo;s documentation is exceedingly beginner unfriendly. :(</li>
<li>Hugo&rsquo;s support for <code>{date}-{slug}.md</code> files is&hellip; difficult to
discover.</li>
<li><code>redirect_from</code> == <code>aliases</code></li>
<li>I couldn&rsquo;t search Hugo&rsquo;s changelog, which makes it difficult to figure
out whether something you&rsquo;re reading from a 2018 issue was removed.</li>
<li>&ldquo;Why is this like this&rdquo; and other variants were spoken 17 times, in
the span of 5 hours.</li>
</ul>
]]></content:encoded></item><item><title>OSS Work update #10</title><link>https://pradyunsg.me/blog/2021/04/03/oss-update-10/</link><pubDate>Sat, 03 Apr 2021 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2021/04/03/oss-update-10/</guid><description>More (new) Sphinx stuff and rewriting other things.</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month.
<a href="/blog/2021/02/27/oss-update-9/">Here&rsquo;s the Feb post</a>.</p>
<h2 id="work-i-did-1-mar-2021---31-mar-2021">Work I did (1 Mar 2021 - 31 Mar 2021)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Started writing a PEP 517 build backend for Sphinx themes.</li>
<li>Started writing <a href="https://github.com/pradyunsg/sphinx-basic-ng/">sphinx-basic-ng</a>, an attempt at modernising the
Sphinx theme ecosystem.</li>
<li>Released new versions of <a href="https://pypi.org/project/sphinx-autobuild">sphinx-autobuild</a>.</li>
<li>More updates to <a href="https://pradyunsg.me/furo">Furo</a>.</li>
<li>Made progress on <a href="https://github.com/pradyunsg/installer">installer</a>&rsquo;s implementation.</li>
<li>Made progress on pip&rsquo;s <a href="https://github.com/pypa/pip/issues/9475">documentation rewrite</a>.</li>
<li>Started work on rewriting <a href="https://pypi.org/project/scripttest">ScriptTest</a>, to pay down pip&rsquo;s technical debt.</li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>Talking to relevant folks about <code>toml</code> on PyPI (and moving it to&hellip; a specific GitHub repository).</li>
<li>Finally sat down and did an &ldquo;open source responsibility audit&rdquo;.</li>
<li>My [social weekends] are still a thing, and has been great so far!</li>
<li>Still collaborating on designing a lockfile format for Python.</li>
<li>Added to <a href="https://executablebooks.org/en/latest/">The Executable Book Project</a>&rsquo;s GitHub organisation! ^&gt;^</li>
<li>Chatted with a few people about the state of Python and pip on Debian.</li>
</ul>
<h2 id="general-notes">General notes</h2>
<p>Looking back, I think I picked up a couple of new projects based on
random brain waves I had! That&rsquo;s perfectly timed, because I&rsquo;ve decided
to pivot away from my earlier approach of &ldquo;yay, more responsibility!&rdquo;.</p>
<h2 id="what-next">What next?</h2>
<p>This is getting increasingly harder to decide on, as my free time
chunks are becoming smaller and I&rsquo;m picking up bigger projects. :)</p>
<h3 id="technical-1">Technical</h3>
<ul>
<li>Sphinx Theme PEP 517 stuff: Make the initial release.</li>
<li>sphinx-basic-ng: Make the first usable release.</li>
<li>pip: Clear some of the backlog on the pull request front.</li>
<li>pip: More progress on the documentation rewrite.</li>
</ul>
<h3 id="communication-1">Communication</h3>
<ul>
<li>Spend more time looking into the Python lockfile standardisation effort.</li>
<li>Write a blog post, on automated code formatting.</li>
<li>Find more speaking opportunities, to talk about things that aren&rsquo;t Python packaging!</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>A full time job, that pays my bills. :)</p>
]]></content:encoded></item><item><title>OSS Work update #9</title><link>https://pradyunsg.me/blog/2021/02/27/oss-update-9/</link><pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2021/02/27/oss-update-9/</guid><description>&lt;p&gt;Alrighty! Let&amp;rsquo;s start doing this again.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Alrighty! Let&rsquo;s start doing this again.</p>
<p>The plan is to get
back to doing these roughly once a month again.</p>
<h2 id="work-i-did-1-jan-2021---26-feb-2021">Work I did (1 Jan 2021 - 26 Feb 2021)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Published the last version of pip that supports Python 2! 🎉</li>
<li>Published a few releases of <a href="https://pradyunsg.me/furo">Furo</a> &ndash; a Sphinx theme I wrote.</li>
<li>Made some (unreleased) changes to <a href="https://pypi.org/p/sphinx-autobuild">sphinx-autobuild</a>.</li>
<li>Made some more progress on <a href="https://github.com/pradyunsg/installer">installer</a> &ndash; a reusable library for Python (wheel) package installation.</li>
<li>Rewrote <a href="https://github.com/pypa/get-pip"><code>get-pip.py</code></a> and the generation pipeline for it.</li>
<li>Started a rewrite of pip&rsquo;s documentation.
<a href="https://github.com/pypa/pip/pull/9474">I&rsquo;d love to get some feedback on this.</a></li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>I&rsquo;m experimenting with a new thing: <a href="http://calendly.com/pradyunsg">social weekends</a>!</li>
<li>I presented 2 talks at FOSDEM: in the <a href="https://fosdem.org/2021/schedule/track/python/">Python devroom</a> and
<a href="https://fosdem.org/2021/schedule/track/open_source_design/">Open Source Design devroom</a>. Shout-out to Bernard Tyers, for all the help and
the bazillion reminders to make sure I do all the things on time. :)</li>
<li>Collaborating on designing a lockfile format for Python, that can hopefully
be standardised for interoperability.</li>
</ul>
<h2 id="general-notes">General notes</h2>
<p>Onboarding in a new company, relocating internationally, settling into a new
space has been&hellip; well, it&rsquo;s all been a very interesting learning experience.</p>
<p>Given the fairly strict lockdown and the percentage of people wearing masks
in my locality, I&rsquo;ve spent a <em>lots</em> of time indoors. Looking forward to the
social weekends experiment I&rsquo;m doing.</p>
<h2 id="what-next">What next?</h2>
<h3 id="technical-1">Technical</h3>
<ul>
<li>pip: Work on the documentation rewrite, hopefully to get it ready in time for
the next release.</li>
<li>pip: Clear some of the backlog on the pull request front.</li>
<li>pip: General discussions for new features and enhancements.</li>
<li>TOML: Work on writing that the compliance test suite.</li>
<li>TOML: Bring <code>toml</code> for Python back from the dead.</li>
<li>Furo: Make the first stable release.</li>
<li>Start work on the other Sphinx theme I have in mind.</li>
</ul>
<h3 id="communication-1">Communication</h3>
<ul>
<li>Spend more time looking into the Python lockfile standardisation effort.</li>
<li>Catch up on the Python-on-Debian saga, and see how I can contribute
constructively.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>Oh, I have a full time job at Bloomberg now. :)</p>]]></content:encoded></item><item><title>Catching up</title><link>https://pradyunsg.me/blog/2020/12/08/catchup/</link><pubDate>Tue, 08 Dec 2020 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2020/12/08/catchup/</guid><description>&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m actually &lt;em&gt;really good&lt;/em&gt; at procrastinating things when I&amp;rsquo;m uncomfortable.&lt;br&gt;
- me, back in Feb 2020&lt;/p&gt;
&lt;/blockquote&gt;</description><content:encoded><![CDATA[<blockquote>
<p>I&rsquo;m actually <em>really good</em> at procrastinating things when I&rsquo;m uncomfortable.<br>
- me, back in Feb 2020</p>
</blockquote>
<h2 id="prelude">Prelude</h2>
<p>As you&rsquo;re likely aware, the human world has been quite a different place since my last post here. My transition to this change wasn&rsquo;t super smooth, but hey, it could&rsquo;ve been a lot worse. My mental health has definitely had a really fun roller coaster ride. I have been fortunate enough to be able to stay safe <em>and</em> also work remotely with some wonderful folks over this time.</p>
<h2 id="i-wrapped-up-my-3-month-gsoc-project-after-3-years">I wrapped up my 3 month GSoC project, after 3 years</h2>
<p>As you might know, <a href="https://mail.python.org/pipermail/distutils-sig/2017-February/030083.html">I&rsquo;ve been working on pip&rsquo;s dependency resolver since 2017</a>, which was originally my Google Summer of Code project. There is now a public pip release that uses a new, written-from-the-ground-up dependency resolver, that replaces the old pseudo-dependency-resolver it had. 🎉</p>
<p>A large part of why this project was finally pushed over the line was that the Packaging-WG at the Python Software Foundation was able to secure funding toward this, from Mozilla (through its <a href="https://www.mozilla.org/en-US/moss/">Mozilla Open Source Support</a> Awards) and the <a href="https://chanzuckerberg.com/eoss/">Chan Zuckerberg Initiative</a>.</p>
<p>Huge thanks to Bernard Tyers, Ernest W. Durbin III, Georgia Bullen, Nicole Harris, Paul Moore, Sumana Harihareshwara and Tzu-Ping Chung for being amazing colleagues (and friends!) as we worked on this together.</p>
<h2 id="i-have-a-college-degree-now">I have a college degree now</h2>
<p>Hurray! I made it out of that place. As a faculty once told me, &ldquo;you got to where you are <em>despite</em> this college, not because of it&rdquo;.</p>
<p>My college has made me sign paperwork that prohibits me from speaking out against university management (something that should speak for itself). Here&rsquo;s a link to a relevant <a href="https://en.wikipedia.org/w/index.php?title=Vellore_Institute_of_Technology&amp;oldid=992345564#Controversies">section on Wikipedia</a>.</p>
<p>Update: I had to change the link above to a permalink to a specific version of the document, because the linked section was edited out the day I put up this post.</p>
<h2 id="i-mentored-a-gsoc-student">I mentored a GSoC student</h2>
<p>I mentored <a href="https://mcsinyx.github.io">Raphael McSinyx</a>, who worked on pip, exploring speedups to pip&rsquo;s dependency resolution process. You can read more about their work in his <a href="https://mcsinyx.github.io/gsoc2020/">final GSoC report</a>.</p>
<h2 id="i-relocated-for-a-job">I relocated for a job</h2>
<p>I am now working at Bloomberg Engineering as, currently, a part of the Python Infrastructure team in London.</p>
<p>I&rsquo;m officially no longer living in my parent&rsquo;s home. Onward to new adventures, I guess.</p>
<h2 id="i-am-doing-sphinx-y-things-now">I am doing Sphinx-y things now</h2>
<p>I made a Sphinx documentation theme: <a href="https://pradyunsg.me/furo/">Furo</a>, modernised <a href="https://sphinx-themes.github.io/sphinx-themes.org/">sphinx-themes.org</a> and am collaborating with the amazing folks of the <a href="https://executablebooks.org/en/latest/">Executable Books</a> project.</p>
<h2 id="i-went-to-san-francisco">I went to San Francisco</h2>
<p><a href="https://chanzuckerberg.com/science/meetings/#essential-open-source-software-for-science-kickoff-meeting">CZI conducted an EOSS kickoff meeting</a>, bringing lots of members of their first cohort of 32 EOSS grantees into one room. This included me!</p>
<p>It was a really well conducted event, and the room was filled with brilliant people. I felt like a squirrel in a room full of elephants.</p>
<p>This happened <em>right before</em> COVID-19 was deemed serious enough to care about it. It was the last trip I had in the before-times, and it was definitely a good one.</p>]]></content:encoded></item><item><title>Testing the next-gen pip dependency resolver</title><link>https://pradyunsg.me/blog/2020/03/27/pip-resolver-testing/</link><pubDate>Fri, 27 Mar 2020 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2020/03/27/pip-resolver-testing/</guid><description>&lt;p&gt;This is an attempt to summarize the broader software architecture around dependency resolution in pip and how testing is being done around this area.&lt;/p&gt;
&lt;p&gt;The motivation behind writing this, is to make sure all the developers working on this project are on the same page, and to have a written record about the state of affairs.&lt;/p&gt;
&lt;h2 id="architecture"&gt;Architecture&lt;/h2&gt;
&lt;p&gt;The &amp;ldquo;legacy&amp;rdquo; resolver in pip, is implemented as part of pip&amp;rsquo;s codebase and has been a part of it for many years. It&amp;rsquo;s very tightly coupled with the existing code, isn&amp;rsquo;t easy to work with and has severe backward compatibility concerns with modifying directly &amp;ndash; which is why we&amp;rsquo;re implementing a separate &amp;ldquo;new&amp;rdquo; resolver in this project, instead of trying to improve the existing one.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This is an attempt to summarize the broader software architecture around dependency resolution in pip and how testing is being done around this area.</p>
<p>The motivation behind writing this, is to make sure all the developers working on this project are on the same page, and to have a written record about the state of affairs.</p>
<h2 id="architecture">Architecture</h2>
<p>The &ldquo;legacy&rdquo; resolver in pip, is implemented as part of pip&rsquo;s codebase and has been a part of it for many years. It&rsquo;s very tightly coupled with the existing code, isn&rsquo;t easy to work with and has severe backward compatibility concerns with modifying directly &ndash; which is why we&rsquo;re implementing a separate &ldquo;new&rdquo; resolver in this project, instead of trying to improve the existing one.</p>
<p>The &ldquo;new&rdquo; resolver that is under development, is not implemented as part of pip&rsquo;s codebase; not completely anyway. We&rsquo;re using an abstraction that separates all the metadata-generation-and-handling stuff vs the core algorithm. This allows us to work on the core algorithm logic (i.e. the NP-hard search problem) separately from pip-specific logic (eg. download, building etc). The abstraction and core algorithm are written/maintained in <a href="https://github.com/sarugaku/resolvelib">https://github.com/sarugaku/resolvelib</a> right now. The pip-specific logic for implementing the &ldquo;other side&rdquo; of the abstraction is in <a href="https://github.com/pypa/pip/tree/master/src/pip/_internal/resolution/resolvelib">https://github.com/pypa/pip/tree/master/src/pip/_internal/resolution/resolvelib</a>.</p>
<h2 id="testing">Testing</h2>
<p>In terms of testing, we have dependency-resolution-related tests in both resolvelib and pip.</p>
<h3 id="resolvelib">resolvelib</h3>
<p>The tests in resolvelib are intended more as &ldquo;check if the algorithm does things correctly&rdquo; and even contains tests that are agnostic to the Python ecosystem (eg. we&rsquo;ve borrowed tests from Ruby, Swift etc). The goal here is to make sure that the core algorithm we implement is capable of generating correct answers (for example: not getting stuck in looping on the same &ldquo;requirement&rdquo;, not revisiting rejected nodes etc).</p>
<h3 id="pip">pip</h3>
<p>The tests in pip is where I&rsquo;ll start needing more words to explain what&rsquo;s happening. :)</p>
<h4 id="yaml-based-tests">YAML-based tests</h4>
<p>We have &ldquo;YAML&rdquo; tests which I&rsquo;d written back in 2017, as a format to easily write tests for pip&rsquo;s new resolver when we implement it. However, since we didn&rsquo;t have a need for it to be working completely back then (there wasn&rsquo;t a new resolver to test with it!), the &ldquo;harness&rdquo; for running these tests isn&rsquo;t complete and would likely need some work to be as feature complete as we&rsquo;d want it to be, for writing good tests.</p>
<p>YAML tests: <a href="https://github.com/pypa/pip/tree/master/tests/yaml">https://github.com/pypa/pip/tree/master/tests/yaml</a><br>
YAML test &ldquo;harness&rdquo;: <a href="https://github.com/pypa/pip/blob/master/tests/functional/test_yaml.py">https://github.com/pypa/pip/blob/master/tests/functional/test_yaml.py</a> and <a href="https://github.com/pypa/pip/blob/master/tests/lib/yaml_helpers.py">https://github.com/pypa/pip/blob/master/tests/lib/yaml_helpers.py</a></p>
<h4 id="new-resolver-tests">&ldquo;new&rdquo; resolver tests</h4>
<h5 id="unit-tests">unit tests</h5>
<p>We have some unit tests for the new resolver implementation. These cover very basic &ldquo;sanity checks&rdquo; to ensure it follows the &ldquo;contract&rdquo; of the abstraction, like &ldquo;do the candidates returned by a requirement actually satisfy that requirement?&rdquo;. These likely don&rsquo;t need to be touched, since they&rsquo;re fairly well scoped and test fairly low-level details (i.e. ideal for unit tests).</p>
<p>New resolver unit tests: <a href="https://github.com/pypa/pip/tree/master/tests/unit/resolution_resolvelib">https://github.com/pypa/pip/tree/master/tests/unit/resolution_resolvelib</a></p>
<h5 id="functional-tests">functional tests</h5>
<p>We also have &ldquo;new resolver functional tests&rdquo;, which are written as part of the current work. These exist since how-to-work-with-YAML-tests was not an easy question to answer and there needs to be work done (both on the YAML format, as well as the YAML test harness) to flag which tests should run with which resolver (both, only legacy, only new) and make it possible to put run these tests in CI easily.</p>
<p>New resolver functional tests: <a href="https://github.com/pypa/pip/blob/master/tests/functional/test_new_resolver.py">https://github.com/pypa/pip/blob/master/tests/functional/test_new_resolver.py</a></p>
<h4 id="test_installpy">test_install*.py</h4>
<p>These files test all the functionality of the install command (like: does it use the right build dependencies, does it download the correct files, does it write the correct metadata etc). There might be some dependency-resolution-related tests in <code>test_install*.py</code> files.</p>
<p>These files contain a lot of tests so, ideally, at some point, someone would go through and de-duplicate tests from this as well.</p>
<h2 id="how-can-you-help">How can you help?</h2>
<p>If you use pip, there are a multiple ways that you can help us!</p>
<ul>
<li>
<p>First and most fundamentally, <a href="https://bit.ly/pip-ux-studies">please help us understand how you use pip by <strong>talking with our user experience researchers</strong></a>. You can do this right now! You can take a survey, or have a researcher interview you over a video call. <a href="https://bit.ly/pip-ux-studies">Please sign up and spread the word</a> to anyone who uses pip (even a little bit).</p>
</li>
<li>
<p>Right now, even before we release the new resolver as a beta, you can help by <strong>running <code>pip check</code> on your current environment</strong>. This will report if you have any inconsistencies in your set of installed packages. Having a clean installation will make it much less likely that you will hit issues when the new resolver is released (and may address hidden problems in your current environment!). If you run <code>pip check</code> and run into stuff you can’t figure out, please <a href="https://pip.pypa.io/">ask for help in our issue tracker or chat</a>.</p>
</li>
</ul>
<hr>
<p>Thanks to Paul Moore and Tzu-Ping for help in reviewing and writing this post,
as well as Sumana Harihareswara for suggesting to put this up on my blog!</p>
]]></content:encoded></item><item><title>OSS Work update #8</title><link>https://pradyunsg.me/blog/2020/02/19/oss-update-8/</link><pubDate>Wed, 19 Feb 2020 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2020/02/19/oss-update-8/</guid><description>&lt;p&gt;I&amp;rsquo;m trying to post these roughly once a month. &lt;a href="https://pradyunsg.me/blog/2020/01/10/oss-update-7/"&gt;Here&amp;rsquo;s the January post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I am working on open source projects, as part of an internship at &lt;a href="https://fossee.in/"&gt;FOSSEE&lt;/a&gt; and as a part of &lt;a href="https://wiki.python.org/psf/Pip2020DonorFundedRoadmap"&gt;grant-funded work on pip&amp;rsquo;s dependency resolver&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="work-i-did-jan-6---feb-5"&gt;Work I did (Jan 6 - Feb 5)&lt;/h2&gt;
&lt;h3 id="technical"&gt;Technical&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Co-worked with another developer, in person, for 1 week, on pip!&lt;/li&gt;
&lt;li&gt;Triaged pip&amp;rsquo;s issue tracker (a lot).&lt;/li&gt;
&lt;li&gt;Spend some time improving pip&amp;rsquo;s test suite infrastructure.&lt;/li&gt;
&lt;li&gt;Investigated Python 2 usage, to identify anomalies.&lt;/li&gt;
&lt;li&gt;Helped with virtualenv 20.0 release (kinda!).&lt;/li&gt;
&lt;li&gt;Invested effort to improve pip&amp;rsquo;s test suite&lt;/li&gt;
&lt;li&gt;Helped aggregate test cases for pip&amp;rsquo;s next generation resolver.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="communication"&gt;Communication&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Managed the pip 20.0 release fiasco.&lt;/li&gt;
&lt;li&gt;Helped the UX folks get started with working on pip.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="additional-notes-on-challenges"&gt;Additional notes on challenges&lt;/h2&gt;
&lt;p&gt;January has been a very productive month.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month. <a href="/blog/2020/01/10/oss-update-7/">Here&rsquo;s the January post</a>.</p>
<p>I am working on open source projects, as part of an internship at <a href="https://fossee.in/">FOSSEE</a> and as a part of <a href="https://wiki.python.org/psf/Pip2020DonorFundedRoadmap">grant-funded work on pip&rsquo;s dependency resolver</a>.</p>
<h2 id="work-i-did-jan-6---feb-5">Work I did (Jan 6 - Feb 5)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Co-worked with another developer, in person, for 1 week, on pip!</li>
<li>Triaged pip&rsquo;s issue tracker (a lot).</li>
<li>Spend some time improving pip&rsquo;s test suite infrastructure.</li>
<li>Investigated Python 2 usage, to identify anomalies.</li>
<li>Helped with virtualenv 20.0 release (kinda!).</li>
<li>Invested effort to improve pip&rsquo;s test suite</li>
<li>Helped aggregate test cases for pip&rsquo;s next generation resolver.</li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>Managed the pip 20.0 release fiasco.</li>
<li>Helped the UX folks get started with working on pip.</li>
</ul>
<h2 id="additional-notes-on-challenges">Additional notes on challenges</h2>
<p>January has been a very productive month.</p>
<p>Most of the challenges have been the logistics around work, not the work as
such.</p>
<p>My health has been pretty good and there&rsquo;s a certain flow to my work that I&rsquo;m
enjoying now. Turns out, if you like what you&rsquo;re doing, you tend to be pretty
productive! :)</p>
<p>As long as I remember to push my blog posts to the repository, they&rsquo;ll actually
go live on the day they&rsquo;re supposed to.</p>
<h2 id="goals-for-february-2020">Goals for February 2020</h2>
<h3 id="technical-1">Technical</h3>
<ul>
<li>Internal Cleansing: AKA Technical debt down payment.</li>
<li>Issue triage: Triage a fair number of issues on pip&rsquo;s issue tracker.</li>
<li>Technical Documentation: improving pip&rsquo;s technical documentation, for contributors and developers</li>
</ul>
<h3 id="communication-1">Communication</h3>
<ul>
<li>Help all the other contractors to get up to &ldquo;full speed&rdquo; for working on pip</li>
<li>Get PyPA to participate in GSoC 2020</li>
<li>Python Packaging Summit at PyCon US 2020: help organization.</li>
<li>Move forward on Python Packaging Governance</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>None.</p>
<h2 id="help-us">Help us</h2>
<p>How can you help us?</p>
<ul>
<li>provide test cases where the latest released version of pip (19.3.1, at the time of writing) fails to resolve dependencies properly (on <a href="https://github.com/pradyunsg/zazo/issues">zazo&rsquo;s issue tracker</a>). They will help us design and test the new resolver.</li>
<li>talk with your company about becoming a PSF sponsor. The <a href="https://wiki.python.org/psf/Fundable%20Packaging%20Improvements">Fundable Packaging Improvements page</a> lists fairly well-scoped projects that would happen much faster if we get funding to achieve them.</li>
<li>Have an <a href="https://python.zulipchat.com/#narrow/stream/218659-pip-development/topic/Talk.20to.20Bernard!">interview with our UX expert</a>, who is working to improve usability of Python Packaging tooling.</li>
</ul>
]]></content:encoded></item><item><title>OSS Work update #7</title><link>https://pradyunsg.me/blog/2020/01/10/oss-update-7/</link><pubDate>Fri, 10 Jan 2020 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2020/01/10/oss-update-7/</guid><description>&lt;p&gt;I&amp;rsquo;m trying to post these roughly once a month. &lt;a href="https://pradyunsg.me/blog/2019/12/11/oss-update-6/"&gt;Here&amp;rsquo;s the December post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I am working on open source projects, as part of an internship at &lt;a href="https://fossee.in/"&gt;FOSSEE&lt;/a&gt; and as a part of grant-funded work on pip&amp;rsquo;s dependency resolver.&lt;/p&gt;
&lt;h2 id="work-i-did-dec-11---jan-5"&gt;Work I did (Dec 11 - Jan 5)&lt;/h2&gt;
&lt;h3 id="technical"&gt;Technical&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Wrore and adopted &lt;code&gt;vendoring&lt;/code&gt; for use in pip.
&lt;ul&gt;
&lt;li&gt;Initiated conversation for pipenv to switch to it too.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Made progress toward TOML 1.0, via useful clarifications in the specification&lt;/li&gt;
&lt;li&gt;Continued tackling pip’s build logic refactoring.
&lt;ul&gt;
&lt;li&gt;Refactoring of pip&amp;rsquo;s wheel building logic.&lt;/li&gt;
&lt;li&gt;Designing a &amp;ldquo;package builder&amp;rdquo; library &amp;ndash; figuring out what Python Packaging&amp;rsquo;s &amp;ldquo;build&amp;rdquo; step should look like to end users.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Started reviewing virtualenv’s rewrite.&lt;/li&gt;
&lt;li&gt;PR Reviews: ~25, including improvements to pip’s installation logic, better wheel-related error messages and more.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="communication"&gt;Communication&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A few release manager-y things:
&lt;ul&gt;
&lt;li&gt;(I&amp;rsquo;ll be the release manager for pip 20.0)&lt;/li&gt;
&lt;li&gt;Identified tasks that need to happen prior to pip&amp;rsquo;s release.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Discussions on discuss.python.org:
&lt;ul&gt;
&lt;li&gt;Giving pip an API
&lt;a href="https://discuss.python.org/t/2833"&gt;https://discuss.python.org/t/2833&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Python Packaging in GSoC 2020
&lt;a href="https://discuss.python.org/t/2830"&gt;https://discuss.python.org/t/2830&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PyPA governance PEP
&lt;a href="https://discuss.python.org/t/2619"&gt;https://discuss.python.org/t/2619&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Discussions on issue trackers:
&lt;ul&gt;
&lt;li&gt;New Resolver: technical choices
&lt;a href="https://github.com/pypa/pip/issues/7406"&gt;https://github.com/pypa/pip/issues/7406&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Switch to a dedicated tool for vendoring pip&amp;rsquo;s dependencies
&lt;a href="https://github.com/pypa/pip/pull/7485"&gt;https://github.com/pypa/pip/pull/7485&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Provided helper/starter for pip&amp;rsquo;s UX review work.&lt;/li&gt;
&lt;li&gt;Onboarded a new triager to pip: Welcome Stéphane Bidoul! :)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="additional-notes-on-challenges"&gt;Additional notes on challenges&lt;/h2&gt;
&lt;p&gt;December was fairly productive, until the end of the month, when the holidays
came in and I also wasn&amp;rsquo;t in the best of health.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month. <a href="/blog/2019/12/11/oss-update-6/">Here&rsquo;s the December post</a>.</p>
<p>I am working on open source projects, as part of an internship at <a href="https://fossee.in/">FOSSEE</a> and as a part of grant-funded work on pip&rsquo;s dependency resolver.</p>
<h2 id="work-i-did-dec-11---jan-5">Work I did (Dec 11 - Jan 5)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Wrore and adopted <code>vendoring</code> for use in pip.
<ul>
<li>Initiated conversation for pipenv to switch to it too.</li>
</ul>
</li>
<li>Made progress toward TOML 1.0, via useful clarifications in the specification</li>
<li>Continued tackling pip’s build logic refactoring.
<ul>
<li>Refactoring of pip&rsquo;s wheel building logic.</li>
<li>Designing a &ldquo;package builder&rdquo; library &ndash; figuring out what Python Packaging&rsquo;s &ldquo;build&rdquo; step should look like to end users.</li>
</ul>
</li>
<li>Started reviewing virtualenv’s rewrite.</li>
<li>PR Reviews: ~25, including improvements to pip’s installation logic, better wheel-related error messages and more.</li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>A few release manager-y things:
<ul>
<li>(I&rsquo;ll be the release manager for pip 20.0)</li>
<li>Identified tasks that need to happen prior to pip&rsquo;s release.</li>
</ul>
</li>
<li>Discussions on discuss.python.org:
<ul>
<li>Giving pip an API
<a href="https://discuss.python.org/t/2833">https://discuss.python.org/t/2833</a></li>
<li>Python Packaging in GSoC 2020
<a href="https://discuss.python.org/t/2830">https://discuss.python.org/t/2830</a></li>
<li>PyPA governance PEP
<a href="https://discuss.python.org/t/2619">https://discuss.python.org/t/2619</a></li>
</ul>
</li>
<li>Discussions on issue trackers:
<ul>
<li>New Resolver: technical choices
<a href="https://github.com/pypa/pip/issues/7406">https://github.com/pypa/pip/issues/7406</a></li>
<li>Switch to a dedicated tool for vendoring pip&rsquo;s dependencies
<a href="https://github.com/pypa/pip/pull/7485">https://github.com/pypa/pip/pull/7485</a></li>
</ul>
</li>
<li>Provided helper/starter for pip&rsquo;s UX review work.</li>
<li>Onboarded a new triager to pip: Welcome Stéphane Bidoul! :)</li>
</ul>
<h2 id="additional-notes-on-challenges">Additional notes on challenges</h2>
<p>December was fairly productive, until the end of the month, when the holidays
came in and I also wasn&rsquo;t in the best of health.</p>
<p>I couldn&rsquo;t come up with a good talk topic for PyCon US 2020. :/</p>
<h2 id="goals-for-january-2020">Goals for January 2020</h2>
<h3 id="technical-1">Technical</h3>
<ul>
<li>Onboard and co-work with a developer, on pip.</li>
<li>Triage pip&rsquo;s issue tracker. A lot.</li>
<li>Spend some time improving pip&rsquo;s test suite infrastructure.</li>
<li>Investigate Python 2 usage from PyPI, to identify anomalies.</li>
</ul>
<h3 id="communication-1">Communication</h3>
<ul>
<li>Ensure pip 20.0&rsquo;s release goes well (I&rsquo;m the release manager).
<ul>
<li>Yay automation that I worked on a little while back!</li>
</ul>
</li>
<li>I&rsquo;ll be very active on PSF&rsquo;s Zulip instance, as part of the grant-funded work on pip&rsquo;s resolver.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>None.</p>
<h2 id="help-us">Help us</h2>
<p>How can you help us?</p>
<ul>
<li>provide test cases where the latest released version of pip (19.3.1, at the time of writing) fails to resolve dependencies properly (on <a href="https://github.com/pradyunsg/zazo/issues">zazo&rsquo;s issue tracker</a>). They will help us design and test the new resolver.</li>
<li>talk with your company about becoming a PSF sponsor. The <a href="https://wiki.python.org/psf/Fundable%20Packaging%20Improvements">Fundable Packaging Improvements page</a> lists fairly well-scoped projects that would happen much faster if we get funding to achieve them.</li>
</ul>
]]></content:encoded></item><item><title>OSS Work update #6</title><link>https://pradyunsg.me/blog/2019/12/11/oss-update-6/</link><pubDate>Wed, 11 Dec 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/12/11/oss-update-6/</guid><description>&lt;p&gt;I&amp;rsquo;m trying to post these roughly once a month. &lt;a href="https://pradyunsg.me/blog/2019/11/06/oss-update-5/"&gt;Here&amp;rsquo;s the November post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This update has been a little late, since I have been traveling and recovering from an illness.&lt;/p&gt;
&lt;p&gt;I also have good news: I will be working on open source projects related to Python Packaging (full time) starting early Dec 2019 till May/Jun 2020.&lt;/p&gt;
&lt;h2 id="work-i-did-nov-6---dec-10"&gt;Work I did (Nov 6 - Dec 10)&lt;/h2&gt;
&lt;h3 id="technical"&gt;Technical&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Worked to separate pip&amp;rsquo;s dependency vendoring logic from rest of pip
&lt;ul&gt;
&lt;li&gt;This would enable other projects that use similar mechanisms (eg. pipenv)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Made some progress for preparing for TOML&amp;rsquo;s 1.0 release&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="communication"&gt;Communication&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Finalized my internship, and got the necessary approvals at college&lt;/li&gt;
&lt;li&gt;PyConf Hyderabad 2019! (yay!)
&lt;ul&gt;
&lt;li&gt;I gave a talk: Rethinking Python Packaging &amp;ndash; a thought experiment.&lt;/li&gt;
&lt;li&gt;I ran a sprint! ~5 new contributors worked on pip!&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Initiated a [discussion for Python Packaging &lt;a href="https://discuss.python.org/t/2603"&gt;at PyCon US&lt;/a&gt; and &lt;a href="https://discuss.python.org/t/2830"&gt;in GSoC 2020&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="additional-notes-on-challenges"&gt;Additional notes on challenges&lt;/h2&gt;
&lt;p&gt;As I&amp;rsquo;d anticipated, November has been low productivity. I didn&amp;rsquo;t have much time to put toward working on &amp;ldquo;Open Source stuff&amp;rdquo;, due to various other commitments &amp;ndash; broadly: exam preparation, attending a family wedding and talk preparation for PyConf Hyderabad.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month. <a href="/blog/2019/11/06/oss-update-5/">Here&rsquo;s the November post</a>.</p>
<p>This update has been a little late, since I have been traveling and recovering from an illness.</p>
<p>I also have good news: I will be working on open source projects related to Python Packaging (full time) starting early Dec 2019 till May/Jun 2020.</p>
<h2 id="work-i-did-nov-6---dec-10">Work I did (Nov 6 - Dec 10)</h2>
<h3 id="technical">Technical</h3>
<ul>
<li>Worked to separate pip&rsquo;s dependency vendoring logic from rest of pip
<ul>
<li>This would enable other projects that use similar mechanisms (eg. pipenv)</li>
</ul>
</li>
<li>Made some progress for preparing for TOML&rsquo;s 1.0 release</li>
</ul>
<h3 id="communication">Communication</h3>
<ul>
<li>Finalized my internship, and got the necessary approvals at college</li>
<li>PyConf Hyderabad 2019! (yay!)
<ul>
<li>I gave a talk: Rethinking Python Packaging &ndash; a thought experiment.</li>
<li>I ran a sprint! ~5 new contributors worked on pip!</li>
</ul>
</li>
<li>Initiated a [discussion for Python Packaging <a href="https://discuss.python.org/t/2603">at PyCon US</a> and <a href="https://discuss.python.org/t/2830">in GSoC 2020</a>.</li>
</ul>
<h2 id="additional-notes-on-challenges">Additional notes on challenges</h2>
<p>As I&rsquo;d anticipated, November has been low productivity. I didn&rsquo;t have much time to put toward working on &ldquo;Open Source stuff&rdquo;, due to various other commitments &ndash; broadly: exam preparation, attending a family wedding and talk preparation for PyConf Hyderabad.</p>
<h2 id="goals-for-december">Goals for December</h2>
<h3 id="technical-1">Technical</h3>
<ul>
<li>Finish decoupling pip&rsquo;s dependency vendoring logic to a dedicated tool</li>
<li>Resume work on pip&rsquo;s build logic refactor
<ul>
<li>Shout out to Chris Hunt (<a href="github.com/chrahunt/">@chrahunt</a>) for keeping
things moving while I was away.</li>
</ul>
</li>
<li>Check for pip 20.0 preparedness (due Jan 2020)</li>
<li>Do issue triage on pip&rsquo;s issue tracker</li>
<li>(stretch goal) Look into further reducing fragile manual steps in pip&rsquo;s release process</li>
</ul>
<h3 id="communication-1">Communication</h3>
<ul>
<li>Catch up on November&rsquo;s discussions</li>
<li>Propose a talk at PyCon US 2020</li>
<li>Make progress on discussions related to PyCon US and GSoC 2020</li>
<li>Identify areas which (in my opinion) would be of interest in pip&rsquo;s UX review</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>There is likely some travel in late December and early January, with family. And that&rsquo;s about it in terms of planned commitments.</p>
<h2 id="help-us">Help us</h2>
<p>How can you help us?</p>
<ul>
<li>talk with your company about becoming a PSF sponsor. The <a href="https://wiki.python.org/psf/Fundable%20Packaging%20Improvements">Fundable Packaging Improvements page</a> lists fairly well-scoped projects that would happen much faster if we get funding to achieve them.</li>
<li>volunteer to <a href="https://github.com/pypa/integration-test/issues">help us build robust testing infrastructure</a></li>
<li>provide test cases where the latest released version of pip (19.3.1, at the time of writing) fails to resolve dependencies properly (on <a href="https://github.com/pradyunsg/zazo/issues">zazo&rsquo;s issue tracker</a>). They will help us design and test the new resolver.</li>
<li>help <a href="https://pip.pypa.io/en/latest/development/issue-triage/">triage pip&rsquo;s issue tracker</a>!</li>
</ul>
]]></content:encoded></item><item><title>OSS Work update #5</title><link>https://pradyunsg.me/blog/2019/11/06/oss-update-5/</link><pubDate>Wed, 06 Nov 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/11/06/oss-update-5/</guid><description>&lt;p&gt;I&amp;rsquo;m trying to post these roughly once a month. &lt;a href="https://pradyunsg.me/blog/2019/10/06/oss-update-4/"&gt;Here&amp;rsquo;s the October post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="work-i-did-oct-6---nov-5"&gt;Work I did (Oct 6 - Nov 5)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Technical&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wrapped up refactoring metadata generation within pip. (yay!)&lt;/li&gt;
&lt;li&gt;Started refactoring wheel building logic within pip.&lt;/li&gt;
&lt;li&gt;A few minor fixes/cleanup within pip.&lt;/li&gt;
&lt;li&gt;Helped out with pip 19.3&amp;rsquo;s release.&lt;/li&gt;
&lt;li&gt;Significantly simplified pip&amp;rsquo;s release processes.&lt;/li&gt;
&lt;li&gt;Reviewed &amp;gt;50 PRs.&lt;/li&gt;
&lt;li&gt;Fixed a &amp;ldquo;major&amp;rdquo; regression in pip&amp;rsquo;s detection of virtual environments.&lt;/li&gt;
&lt;li&gt;Got some work done, progressing closer to TOML 1.0.0.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Communication&lt;/strong&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month. <a href="/blog/2019/10/06/oss-update-4/">Here&rsquo;s the October post</a>.</p>
<h2 id="work-i-did-oct-6---nov-5">Work I did (Oct 6 - Nov 5)</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Wrapped up refactoring metadata generation within pip. (yay!)</li>
<li>Started refactoring wheel building logic within pip.</li>
<li>A few minor fixes/cleanup within pip.</li>
<li>Helped out with pip 19.3&rsquo;s release.</li>
<li>Significantly simplified pip&rsquo;s release processes.</li>
<li>Reviewed &gt;50 PRs.</li>
<li>Fixed a &ldquo;major&rdquo; regression in pip&rsquo;s detection of virtual environments.</li>
<li>Got some work done, progressing closer to TOML 1.0.0.</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>Summarized the progress on the build logic refactoring.</li>
<li>PyCon India 2019! (yay!)
<ul>
<li>I gave a talk!</li>
<li>I ran a sprint! ~20 contributors and just me as a mentor. (This was fun!)</li>
</ul>
</li>
<li>Figured out a lot of the details around my semster-long internship.</li>
<li>Had a chat with b.p.o. maintainers, and published a <a href="https://pradyunsg.me/blog/2019/11/02/state-of-bpo/">blog post</a> describing their plans going forward.</li>
<li>My proposed governance model for PyPA, is <a href="https://github.com/python/peps/pull/1221/">becoming a PEP</a>.</li>
</ul>
<h2 id="additional-notes-on-challenges">Additional notes on challenges</h2>
<p>Oh boi, pip&rsquo;s test suite doesn&rsquo;t like venv. The initial draft for
<a href="https://github.com/pypa/pip/pull/7155/commits/8981895b5e34de1be2a73e5fff77879c45908700">this commit message</a> was about 4x as long, and a lot less&hellip;
nice. I sunk quite a few hours across two days, into that one commit, trying
to make things work before realizing that it&rsquo;d be better to tackle fixing
the test isolation separately.</p>
<p>A <em>lot</em> of my time over the last two weeks has gone into handling a big mess,
in my hostel room caused by fungi. Even though I didn&rsquo;t cause this mess, I
have to deal with it (allergic bronchitis isn&rsquo;t making it easier).</p>
<p>Other than that though, I think everything went as I had anticipated. During
PyCon India + Diwali, I made the exact amount of progress on the &ldquo;code&rdquo;
problems as I&rsquo;d expected &ndash; None. Back in college, there was enough academic
workload to drain me by the end of the day. :)</p>
<p>Basically, I think almost all of my &ldquo;write code&rdquo;, happened on 2 or 3 days total, in this past month.</p>
<h2 id="goals-for-november">Goals for November</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Figure out a plan for refactoring pip&rsquo;s wheel building logic.</li>
<li>Make more progress on the TOML&rsquo;s compliance suite.</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>Wrap up final-semester internship search.</li>
<li>(stretch) Write a blog post using all the material that was trimmed out of my PyCon India talk &ndash; &ldquo;A checkin on Python Packaging&rdquo;.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>I have my end-sem examinations all of November (there&rsquo;s one tomorrow).</p>
<p>Overall, November is gonna be fairly &ldquo;low&rdquo; productivity. Hopefully, I would be able to make some progress in early December (I&rsquo;ll be back home!).</p>
<h2 id="help-us">Help us</h2>
<p>How can you help us?</p>
<ul>
<li>talk with your company about becoming a PSF sponsor. The <a href="https://wiki.python.org/psf/Fundable%20Packaging%20Improvements">Fundable Packaging Improvements page</a> now summarizes what bugfixes/features/projects within and outside PyPA are blocked on the new resolver, some background context, and how funding would help us get it finished faster.</li>
<li>provide test cases where the latest released version of pip (19.2.3, at the time of writing) fails to resolve dependencies properly (on <a href="https://github.com/pradyunsg/zazo/issues">zazo&rsquo;s issue tracker</a>). They will help us design and test the new resolver.</li>
<li>volunteer to <a href="https://github.com/pypa/integration-test/issues">help us build robust testing infrastructure</a></li>
<li>triage pip bugs! Around 10% of pip&rsquo;s issues have not been triaged yet and many others need of action/review.</li>
</ul>
]]></content:encoded></item><item><title>What's up with bugs.python.org?</title><link>https://pradyunsg.me/blog/2019/11/02/state-of-bpo/</link><pubDate>Sat, 02 Nov 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/11/02/state-of-bpo/</guid><description>&lt;p&gt;bugs.python.org is the issue tracker for CPython. &amp;ldquo;bpo&amp;rdquo;, as it is commonly referenced, is where implementation bugs, smaller feature requests, and documentation issues are tracked as part of Python&amp;rsquo;s development.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.python.org/dev/peps/pep-0581/"&gt;PEP 581&lt;/a&gt; proposes sunsetting bugs.python.org, in favor of GitHub issues. &amp;ldquo;Why not focus on improving Roundup / bpo?&amp;rdquo; section made me wonder: What is needed to improve Roundup / bpo? This blog post is my attempt at summarizing the state of bpo and how it could be improving in the future, based on a discussion with folks maintaining bpo.&lt;/p&gt;</description><content:encoded><![CDATA[<p>bugs.python.org is the issue tracker for CPython. &ldquo;bpo&rdquo;, as it is commonly referenced, is where implementation bugs, smaller feature requests, and documentation issues are tracked as part of Python&rsquo;s development.</p>
<p><a href="https://www.python.org/dev/peps/pep-0581/">PEP 581</a> proposes sunsetting bugs.python.org, in favor of GitHub issues. &ldquo;Why not focus on improving Roundup / bpo?&rdquo; section made me wonder: What is needed to improve Roundup / bpo? This blog post is my attempt at summarizing the state of bpo and how it could be improving in the future, based on a discussion with folks maintaining bpo.</p>
<p>I won&rsquo;t go into whether PEP 581 or PEP 595 is a better idea &ndash; that&rsquo;s something for the CPython core developers to decide on.</p>
<h2 id="what-is-that-tracker">What is that tracker?</h2>
<p>Broadly, bpo is an instance of <a href="https://roundup-tracker.org/">Roundup</a>, that is hosted by the PSF.</p>
<blockquote>
<p>Roundup is a simple-to-use and -install issue-tracking system with command-line, web and e-mail interfaces. It is based on the winning design from Ka-Ping Yee in the Software Carpentry “Track” design competition.</p>
</blockquote>
<p>By design, it is an extremely customizable platform. Roundup has a &ldquo;core&rdquo; that can run multiple issue trackers. Each of these issue trackers can contain customizations in the HTML/CSS and extensions for functionality that are specific to them.</p>
<p>When CPython moved to using Roundup, both projects were using subversion for version control. Since then, CPython moved to Mercurial (Roundup followed soon) and now CPython is on Git.</p>
<h2 id="how-is-it-all-working">How is it all working?</h2>
<p>The PSF-hosted Roundup, is actually a fork of Roundup maintained by a few folks. The fork was created for adding functionality that made it better for bpo, when the initial transition what made. There are still some functionality improvement patches today (more on this further below).</p>
<p>PSF-hosted Roundup, runs 3 issue trackers:</p>
<ul>
<li><a href="https://bugs.python.org">https://bugs.python.org</a> (or b.p.o)</li>
<li><a href="https://bugs.jython.org">https://bugs.jython.org</a></li>
<li><a href="https://issues.roundup-tracker.org">https://issues.roundup-tracker.org</a></li>
</ul>
<p><a href="https://bitbucket.org/account/user/python/projects/BPO">All the relevant repositories of the PSF</a> are in Mercurial, and hosted on BitBucket currently.</p>
<h2 id="where-are-we-headed">Where are we headed?</h2>
<p>The maintainers of bpo want to switch to using upstream Roundup, instead of our PSF fork. To that end, most of the functionality improvement patches made in the fork have been ported upstream. There is only one major thing that&rsquo;s not been integrated upstream (yet!) &ndash; GitHub integrations built as part of the GitHub migration of CPython source code.</p>
<p>There&rsquo;s an upcoming Roundup 2 release (<em>maybe</em> Q1 2020) &ndash; adding a new REST API, Python 3 support, a responsive UI and more. These would address some of the major concerns with Roundup powering bpo today. There is a plan to host a read-only test instance of Roundup 2 alpha/beta/rcs &ldquo;soon&rdquo;, for exploring new functionality and usability.</p>
<p>Broadly, from what I can tell, the plan of action is:</p>
<ol>
<li>Finalize the GitHub login patch for Roundup.</li>
<li>Port the GitHub integrations to upstream Roundup.</li>
<li>Set up the test tracker, for bugs.python.org on Roundup 2.</li>
<li>Wait for Roundup 2 release.</li>
<li>Start running bpo on a regular Roundup 2. (AKA get rid of the PSF&rsquo;s fork)</li>
<li>Move the instance code and templates, to GitHub.</li>
</ol>
<p>Steps 3 and 6 aren&rsquo;t strictly blocked on the steps before them, but this is probably the easiest order if we&rsquo;re doing things sequentially. Given that Step 6 has to happen before 1 June 2020 <sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, it is reasonable to assume this would all get done by then.</p>
<p>Once the Roundup 2 transition is completed, the documentation of the bpo instance would be improved (how it works, what the various files/folders in the repository do and so on). Along with Roundup 2&rsquo;s REST API, this should significantly reduce the barrier to contribute to bpo or to build enhancements around it.</p>
<p>Many thanks to Ezio Melotti for indulging in a very insightful conversation and for helping me write this post.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>BitBucket will <a href="https://bitbucket.org/blog/sunsetting-mercurial-support-in-bitbucket">sunset Mercurial support</a> and remove Mercurial repositories on June 1, 2020.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>OSS Work update #4</title><link>https://pradyunsg.me/blog/2019/10/06/oss-update-4/</link><pubDate>Sun, 06 Oct 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/10/06/oss-update-4/</guid><description>&lt;p&gt;I&amp;rsquo;m trying to post these roughly once a month. &lt;a href="https://pradyunsg.me/blog/2019/09/06/oss-update-3/"&gt;Here&amp;rsquo;s the September post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="work-i-did-sept-6---oct-5"&gt;Work I did (Sept 6 - Oct 5)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Technical&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Figured out a rough structure for approaching pip&amp;rsquo;s build logic refactor.&lt;/li&gt;
&lt;li&gt;Discussed and sketched a rough &amp;ldquo;goal&amp;rdquo; model for pip&amp;rsquo;s build logic, to adopt after initial cleanups and decoupling refactor work.&lt;/li&gt;
&lt;li&gt;Made significant progress on refactoring pip&amp;rsquo;s metadata handling and generation logic. (yay!)&lt;/li&gt;
&lt;li&gt;Identified a quirk in how pip&amp;rsquo;s current resolution logic, which makes it conceptually intertwined with pip&amp;rsquo;s index interaction logic (&lt;em&gt;sigh&lt;/em&gt;).
&lt;ul&gt;
&lt;li&gt;out-of-scope for the ongoing &amp;ldquo;build logic refactor&amp;rdquo;, but we do need to resolve this at some point.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Revamped pip&amp;rsquo;s linting pipeline to be&amp;hellip; simpler (i.e. better).&lt;/li&gt;
&lt;li&gt;Multiple miscellaneous fixes/cleanup to pip.&lt;/li&gt;
&lt;li&gt;A lots of PRs reviewed (&amp;gt;80).&lt;/li&gt;
&lt;li&gt;Reviewed and merged ABNF-related PRs, for TOML.&lt;/li&gt;
&lt;li&gt;Sunk a good day to debugging 500s on GitHub (it was due to emojis). :(&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Communication&lt;/strong&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month. <a href="/blog/2019/09/06/oss-update-3/">Here&rsquo;s the September post</a>.</p>
<h2 id="work-i-did-sept-6---oct-5">Work I did (Sept 6 - Oct 5)</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Figured out a rough structure for approaching pip&rsquo;s build logic refactor.</li>
<li>Discussed and sketched a rough &ldquo;goal&rdquo; model for pip&rsquo;s build logic, to adopt after initial cleanups and decoupling refactor work.</li>
<li>Made significant progress on refactoring pip&rsquo;s metadata handling and generation logic. (yay!)</li>
<li>Identified a quirk in how pip&rsquo;s current resolution logic, which makes it conceptually intertwined with pip&rsquo;s index interaction logic (<em>sigh</em>).
<ul>
<li>out-of-scope for the ongoing &ldquo;build logic refactor&rdquo;, but we do need to resolve this at some point.</li>
</ul>
</li>
<li>Revamped pip&rsquo;s linting pipeline to be&hellip; simpler (i.e. better).</li>
<li>Multiple miscellaneous fixes/cleanup to pip.</li>
<li>A lots of PRs reviewed (&gt;80).</li>
<li>Reviewed and merged ABNF-related PRs, for TOML.</li>
<li>Sunk a good day to debugging 500s on GitHub (it was due to emojis). :(</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>Reached out to quite a few folks regarding my <a href="https://twitter.com/pradyunsg/status/1174186350389661696">semester-long internship</a>.</li>
<li>Discuss goals and approaches, for pip&rsquo;s build logic refactor, with fellow pip maintainers across multiple issues on the issue tracker.</li>
<li>Had a chat w/ a pipenv maintainer, discussing the resolver code reuse situation, and some design discussion about the ongoing build logic refactoring.</li>
<li>Had multiple chats with fellow pip maintainers, discussing a rough plan and target, for the build logic refactor as well as our development workflow.</li>
<li>Polished up my proposed &ldquo;Status-Quo&rdquo; PyPA governance model.</li>
<li>Reviewed a proposal for better licensing metadata for Python Packages.</li>
</ul>
<h2 id="additional-notes-on-challenges">Additional notes on challenges</h2>
<p>I had more exams! I&rsquo;d hoped to get more work done but I hadn&rsquo;t realize that I&rsquo;d have exams over 2 weekends &ndash; Sunday, 29 Sept to Sunday, 6 Oct. (yay college)</p>
<p>In addition, I realized that my <a href="https://github.com/pypa/pip/pull/6990">initial approach</a> toward reworking pip&rsquo;s &ldquo;prepare distribution&rdquo; logic was fatally flawed because I forgot about a usecase. My discussions with pipenv and pip maintainers were very fruitful and we pooled our combined knowledge of the tooling into text documents and diagrams. We&rsquo;ve come up with a more feasible (and much better) plan than the one I had come up with on my own.</p>
<p>Recently, I read something on discuss.python.org, that just perfectly encapsulates how I feel about this stuff:</p>
<blockquote>
  <p>
    all of this stuff is really hard and there’s a lot of knowledge scattered around in people’s heads that could really do with being captured somewhere
  </p>
  <footer><cite title="Paul Moore">Paul Moore (regarding a different topic)</cite></footer>
</blockquote>
<p>Overall, I made time to work on pip this month, and made significant progress on cleaning up pip&rsquo;s metadata generation and handling logic.</p>
<h2 id="goals-for-october">Goals for October</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Wrap up refactoring metadata generation and handling in pip.</li>
<li>Work on a &ldquo;blessed&rdquo; TOML&rsquo;s compliance suite, as we prepare for TOML 1.0.</li>
<li>(stretch goal) Begin refactoring the next component &ndash; installation.</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>Update the GitHub Project board for pip&rsquo;s build logic refactor, based on the mental model built over the past few discussions.</li>
<li>Attend PyCon India:
<ul>
<li><a href="https://in.pycon.org/cfp/2019/proposals/python-packaging-where-we-are-and-where-were-headed~dGV8b/">Give a talk</a> about the state of Python Packaging.</li>
<li>Run a <a href="https://in.pycon.org/cfp/devsprint-2019/proposals/python-packaging-pip-and-more~e35nb/">sprint</a> on pip, packaging and pypa-bot (and more?).</li>
</ul>
</li>
<li>Figure out my internship situation and getting approval from my HoD for the internship I&rsquo;d be doing.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>I expect to have some time to work on pip in October, though not as much as September.</p>
<p>In mid-October, I&rsquo;ll be speaking at PyCon India 2019 (noted above) and I expect from today until my talk, almost all of my free time would be going towards that talk preparation. After that, I am expecting that I&rsquo;ll spend a few days going through the processes for approvals, at college, related to my final semester internship.</p>
<h2 id="help-us">Help us</h2>
<p>How can you help us?</p>
<ul>
<li>provide test cases where the latest released version of pip (19.2.3, at the time of writing) fails to resolve dependencies properly (on <a href="https://github.com/pradyunsg/zazo/issues">zazo&rsquo;s issue tracker</a>). They will help us design and test the new resolver.</li>
<li>talk with your company about becoming a PSF sponsor. The <a href="https://wiki.python.org/psf/Fundable%20Packaging%20Improvements">Fundable Packaging Improvements page</a> now summarizes what bugfixes/features/projects within and outside PyPA are blocked on the new resolver, some background context, and how funding would help us get it finished faster.</li>
<li>triage pip bugs! Around 10% of pip&rsquo;s issues have not been triaged yet and many others need of action/review.</li>
<li>help improve our <a href="https://pip.pypa.io/en/latest/development/issue-triage/">&ldquo;how to triage pip bugs&rdquo; guide</a>.</li>
<li>volunteer to <a href="https://github.com/pypa/integration-test/issues">help us build robust testing infrastructure</a></li>
</ul>
]]></content:encoded></item><item><title>OSS Work update #3</title><link>https://pradyunsg.me/blog/2019/09/06/oss-update-3/</link><pubDate>Fri, 06 Sep 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/09/06/oss-update-3/</guid><description>&lt;p&gt;I&amp;rsquo;m trying to post these roughly once a month. &lt;a href="https://pradyunsg.me/blog/2019/08/06/pip-update-2/"&gt;Here&amp;rsquo;s the August post&lt;/a&gt; which includes the work I was planning to do this month.&lt;/p&gt;
&lt;h2 id="work-i-did-aug-6---sept-5"&gt;Work I did (Aug 6 - Sept 5)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Technical&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Began working on splitting the code for handling of the two kinds of source distributions.&lt;/li&gt;
&lt;li&gt;Wrap up pip 19.2, with &lt;a href="https://github.com/pypa/pip/issues/6630"&gt;pip 19.2.3 release&lt;/a&gt;, unblocking Python 3.8&amp;rsquo;s final beta. Hooray!&lt;/li&gt;
&lt;li&gt;Fix documentation builds for pip, &lt;a href="https://pip.pypa.io/"&gt;on ReadTheDocs&lt;/a&gt; &amp;ndash; this took way longer to figure out than I&amp;rsquo;d expected.&lt;/li&gt;
&lt;li&gt;Multiple miscellaneous fixes that I could do in gaps between classes.&lt;/li&gt;
&lt;li&gt;Lots of PRs reviewed (30+)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In August, I wanted to get further on separating &amp;ldquo;prepare distribution&amp;rdquo; logic from the resolution logic and on turning distribution-type-specific build code into dedicated modules within the new &amp;ldquo;distributions&amp;rdquo; sub-package in pip. I didn&amp;rsquo;t get there.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m trying to post these roughly once a month. <a href="/blog/2019/08/06/pip-update-2/">Here&rsquo;s the August post</a> which includes the work I was planning to do this month.</p>
<h2 id="work-i-did-aug-6---sept-5">Work I did (Aug 6 - Sept 5)</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Began working on splitting the code for handling of the two kinds of source distributions.</li>
<li>Wrap up pip 19.2, with <a href="https://github.com/pypa/pip/issues/6630">pip 19.2.3 release</a>, unblocking Python 3.8&rsquo;s final beta. Hooray!</li>
<li>Fix documentation builds for pip, <a href="https://pip.pypa.io/">on ReadTheDocs</a> &ndash; this took way longer to figure out than I&rsquo;d expected.</li>
<li>Multiple miscellaneous fixes that I could do in gaps between classes.</li>
<li>Lots of PRs reviewed (30+)</li>
</ul>
<p>In August, I wanted to get further on separating &ldquo;prepare distribution&rdquo; logic from the resolution logic and on turning distribution-type-specific build code into dedicated modules within the new &ldquo;distributions&rdquo; sub-package in pip. I didn&rsquo;t get there.</p>
<p><strong>Communication</strong></p>
<ul>
<li>Gave a keynote at PyCon Korea! (no video links yet &ndash; will probably be <a href="https://pyvideo.org/events/pycon-korea-2019.html">here</a>)</li>
<li>The details and requirements for my final semester internship have been clarified.</li>
<li>OKed the MOSS funding proposal</li>
<li>Contributed to <a href="https://discuss.python.org/u/pradyunsg/activity">several discussions</a> on the Python discussion forum, including on better licensing metadata and PyPA governance.</li>
</ul>
<p>During this <a href="https://github.com/pradyunsg?tab=overview&amp;from=2019-07-01&amp;to=2019-07-31">month</a>, I also proposed an improvement to <code>twine check</code> (motivated by confusing output when making a pip release), made some more progress toward TOML 1.0, and worked on some of my personal tooling which broke due to a VS Code update. :)</p>
<h2 id="additional-notes-on-challenges">Additional notes on challenges</h2>
<p>Lack of time. Outside of my talk at PyCon Korea and mid-semester examinations at college, I could not find much time to work on the goals I had set for myself.
In the time that I could make, the urgency of the pip release, broken documentation build, and code review left very little time for me to make progress on foundational improvements to pip&rsquo;s codebase.</p>
<h2 id="goals-for-september">Goals for September</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Wrap up the goals I&rsquo;d set for August:
<ul>
<li>Finish splitting logic for handling on source distributions in the new &ldquo;distributions&rdquo; sub-package in pip.</li>
<li>Separate &ldquo;prepare distribution&rdquo; logic from the resolution logic.</li>
</ul>
</li>
<li>Develop a clearer mental model for pip&rsquo;s handling of distribution metadata.</li>
<li>Investigate how to adapt pip&rsquo;s distribution preparation logic to provide distribution metadata as an independent object.</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>(rolled over from August) Reach out to maintainers of pipenv, pip-tools and poetry, to have a conversation about code reuse.</li>
<li>Break down tasks, and discuss the priorities for future items for work in pip&rsquo;s build logic refactor.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>I expect to have more time to work on pip in September. There will be less academic workload (read: no exams) and I&rsquo;m not travelling this month. In mid-October, I&rsquo;ll be speaking at PyCon India 2019 <a href="https://in.pycon.org/cfp/2019/proposals/python-packaging-where-we-are-and-where-were-headed~dGV8b/">(yay!)</a> on the state of Python packaging, so I&rsquo;ll also be working on that talk this month.</p>
<h2 id="help-us">Help us</h2>
<p>I’m currently looking for 20+ week internships, for my final semester credits in college, starting in December 2019 or early January 2020. If you reckon I’d be a good addition to your team, please reach out.</p>
<p>And if you are reviewing funding requests for the Chan Zuckerberg Initiative or for Mozilla&rsquo;s Open Source Support program, I hope you&rsquo;ll approve our proposals. :)</p>
<p>Also, if you care about how Python Packaging is governed, please respond to my <a href="https://discuss.python.org/t/pypa-governance-a-status-quo-model/2221">PyPA governance proposal</a>.</p>
<p>Other than that, I have <a href="https://pradyunsg.me/blog/2019/06/23/pip-update/#help-us">the same list as in June</a>. Thanks!</p>
<p>Also, thanks to Sumana Harihareswara for help in editing.</p>
]]></content:encoded></item><item><title>OSS Work update #2</title><link>https://pradyunsg.me/blog/2019/08/06/oss-update-2/</link><pubDate>Tue, 06 Aug 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/08/06/oss-update-2/</guid><description>&lt;p&gt;I&amp;rsquo;m going to try to post these roughly once a month. &lt;a href="https://pradyunsg.me/blog/2019/06/23/pip-update/"&gt;Here&amp;rsquo;s the late June post.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="work-i-was-planning-to-do"&gt;Work I was planning to do&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Technical&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clearly determine what parts of the build system are intertwined with pip&amp;rsquo;s resolution logic.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Communication&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get confirmation from my college about required dates/duration of internships in final semester.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="work-i-did-24-june---6-aug"&gt;Work I did (24 June - 6 Aug)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Technical&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Identified portion of build system intertwined with pip&amp;rsquo;s resolver:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Get abstract distribution&amp;rdquo;:
&lt;ul&gt;
&lt;li&gt;building installable artifacts is intertwined with pip&amp;rsquo;s resolver.&lt;/li&gt;
&lt;li&gt;Specifically, the resolver currently passes information about how it would handle a distribution, to the &amp;ldquo;preparer&amp;rdquo; that fetches and builds it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Marker evaluation and handling is done by &amp;ldquo;RequirementSet&amp;rdquo; and not the resolver.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Started moving code for pip&amp;rsquo;s handling of installable artifacts into a &lt;code&gt;pip._internal.distributions&lt;/code&gt; package.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m going to try to post these roughly once a month. <a href="/blog/2019/06/23/pip-update/">Here&rsquo;s the late June post.</a></p>
<h2 id="work-i-was-planning-to-do">Work I was planning to do</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Clearly determine what parts of the build system are intertwined with pip&rsquo;s resolution logic.</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>Get confirmation from my college about required dates/duration of internships in final semester.</li>
</ul>
<h2 id="work-i-did-24-june---6-aug">Work I did (24 June - 6 Aug)</h2>
<p><strong>Technical</strong></p>
<ul>
<li>
<p>Identified portion of build system intertwined with pip&rsquo;s resolver:</p>
<ul>
<li>&ldquo;Get abstract distribution&rdquo;:
<ul>
<li>building installable artifacts is intertwined with pip&rsquo;s resolver.</li>
<li>Specifically, the resolver currently passes information about how it would handle a distribution, to the &ldquo;preparer&rdquo; that fetches and builds it.</li>
</ul>
</li>
<li>Marker evaluation and handling is done by &ldquo;RequirementSet&rdquo; and not the resolver.</li>
</ul>
</li>
<li>
<p>Started moving code for pip&rsquo;s handling of installable artifacts into a <code>pip._internal.distributions</code> package.</p>
</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>Still working on getting requirements for my final semester internship. Other students have told me that it has to be longer than 15 weeks and should start in early December, but I am seeking official word on that. I&rsquo;m working on options that would let me work on the pip resolver during the internship.</li>
</ul>
<h2 id="additional-notes-on-challenges">Additional notes on challenges</h2>
<p>No technical challenges. But I didn&rsquo;t have much time to work on this, because of college and visa paperwork (because PyCon Korea invited me to give a keynote!), and because of illness.</p>
<h2 id="goals-for-august">Goals for August</h2>
<p><strong>Technical</strong></p>
<ul>
<li>Separate &ldquo;prepare distribution&rdquo; logic from the resolution logic.</li>
<li>Split code for building various kinds of source distributions into dedicated modules within the new &ldquo;distributions&rdquo; sub-package in pip. (related cleanup)</li>
</ul>
<p><strong>Communication</strong></p>
<ul>
<li>Reach out to maintainers of pipenv, pip-tools and poetry, to have a conversation about code reuse.
<ul>
<li>I know pipenv maintainers have work that can be reused.</li>
<li>Need to identify the overlapping area between the tools, since they may require a slightly different results after resolution than pip.</li>
</ul>
</li>
<li>Work with PSF&rsquo;s Packaging Working Group on <a href="https://wiki.python.org/psf/Fundable%20Packaging%20Improvements">funding proposals</a> to get more help on the resolver testing, UX and rollout.</li>
</ul>
<h2 id="other-commitments">Other commitments</h2>
<p>I am travelling to South Korea this month, for keynoting at PyCon Korea. Immediately after that, I have college examinations from 18th-25th August, and right after that, project reviews for this semester&rsquo;s courses. So my time is pretty limited in August, but should get freer in September.</p>
<h2 id="help-us">Help us</h2>
<p>I have <a href="https://pradyunsg.me/blog/2019/06/23/pip-update/#help-us">the same list as last time</a>. Thanks!</p>
<p>Also, thanks to Sumana Harihareswara for adapting this from a separate update I&rsquo;d shared.</p>
]]></content:encoded></item><item><title>What's happening with that pip dependency resolver?</title><link>https://pradyunsg.me/blog/2019/06/23/oss-update-1/</link><pubDate>Sun, 23 Jun 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/06/23/oss-update-1/</guid><description>&lt;p&gt;I&amp;rsquo;m glad you asked.&lt;/p&gt;
&lt;h2 id="whats-up"&gt;What&amp;rsquo;s up?&lt;/h2&gt;
&lt;p&gt;Over the past few months, I&amp;rsquo;ve worked on &lt;a href="https://github.com/pradyunsg/pip/tree/resolver/make-it-inside"&gt;a prototype for a resolver in pip&lt;/a&gt;, spent some time &lt;a href="https://github.com/pypa/pip/issues/6536"&gt;planning&lt;/a&gt; what rolling out a new dependency resolver in pip might look like, and continue to &lt;a href="https://github.com/pypa/pip/projects/3"&gt;work on pip&amp;rsquo;s build logic&lt;/a&gt; to decouple it from the dependency resolution logic.&lt;/p&gt;
&lt;p&gt;The prototype has helped me better understand the relationships and contracts between various portions of the codebase. This understanding has led me to conclude that it is a worthwhile investment to better decouple the build logic from the resolution logic, &lt;em&gt;then&lt;/em&gt; introduce the abstractions defined in &lt;a href="https://pypi.org/project/resolvelib/"&gt;resolvelib&lt;/a&gt;/&lt;a href="https://github.com/pradyunsg/zazo/"&gt;zazo&lt;/a&gt;, and &lt;em&gt;then&lt;/em&gt; proceed to adopting better dependency resolution.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I&rsquo;m glad you asked.</p>
<h2 id="whats-up">What&rsquo;s up?</h2>
<p>Over the past few months, I&rsquo;ve worked on <a href="https://github.com/pradyunsg/pip/tree/resolver/make-it-inside">a prototype for a resolver in pip</a>, spent some time <a href="https://github.com/pypa/pip/issues/6536">planning</a> what rolling out a new dependency resolver in pip might look like, and continue to <a href="https://github.com/pypa/pip/projects/3">work on pip&rsquo;s build logic</a> to decouple it from the dependency resolution logic.</p>
<p>The prototype has helped me better understand the relationships and contracts between various portions of the codebase. This understanding has led me to conclude that it is a worthwhile investment to better decouple the build logic from the resolution logic, <em>then</em> introduce the abstractions defined in <a href="https://pypi.org/project/resolvelib/">resolvelib</a>/<a href="https://github.com/pradyunsg/zazo/">zazo</a>, and <em>then</em> proceed to adopting better dependency resolution.</p>
<h2 id="whats-next">What&rsquo;s next?</h2>
<p>The work on refactoring pip&rsquo;s build logic is in progress and we&rsquo;re tracking it on <a href="https://github.com/pypa/pip/projects/3">GitHub</a>. Significant technical debt has been accumulated in this part of pip&rsquo;s codebase over the years, so this is a big project that will likely take multiple months. This would/will also make it easier to <a href="https://github.com/pypa/pip/milestone/25">provide more user-friendly error messaging</a>, though that is not something that I will pursue in this project.</p>
<p>This investment will enable us to untangle pip&rsquo;s internals from the resolver, enabling pip to share code for dependency resolution with other packaging tooling (like <a href="https://github.com/pypa/pipenv/">pipenv</a> and <a href="https://github.com/ofek/hatch/">hatch</a>) and reuse the work they have done (e.g., work done on pipenv&rsquo;s resolver). This also makes a softer rollout possible, one that allows us to iterate based on feedback from users and minimize disruption.</p>
<h2 id="help-us">Help us</h2>
<p>How you can help us?</p>
<ul>
<li>
<p>triage pip bugs! Around 20% of pip&rsquo;s issues have not been triaged yet.</p>
</li>
<li>
<p><a href="https://github.com/pypa/pip/issues/6583">draft a &ldquo;how to triage pip bugs&rdquo; guide</a>.</p>
</li>
<li>
<p>provide test cases where the latest released version of pip (19.1.1, at the time of writing) fails to resolve dependencies properly (on <a href="https://github.com/pradyunsg/zazo/issues">zazo&rsquo;s issue tracker</a>). They will help us test the new resolver.</p>
</li>
<li>
<p>look at <a href="https://github.com/pypa/pip/issues/6536">New Resolver: Rollout, Feedback Loops and Development Flow</a> and help us decide: Is the feature flag approach a good idea? Is it a good idea to get rollout feedback via some mechanism other than the pip GitHub issues? Any other thoughts to help us smooth out the rollout?</p>
</li>
<li>
<p>talk with your company about becoming a PSF sponsor. The <a href="https://wiki.python.org/psf/Fundable%20Packaging%20Improvements">Fundable Packaging Improvements page</a> now summarizes what bugfixes/features/projects within and outside PyPA are blocked on the new resolver, some background context, and how funding would help us get it finished faster.</p>
</li>
<li>
<p>volunteer to <a href="https://github.com/pypa/integration-test/issues">help us build robust testing infrastructure</a></p>
</li>
</ul>
<p>Thanks to Sumana Harihareswara for (a lot of) help in writing this, and Dan Ryan for reviewing the content!</p>
]]></content:encoded></item><item><title>Is this thing on?</title><link>https://pradyunsg.me/blog/2019/06/22/is-this-thing-on/</link><pubDate>Sat, 22 Jun 2019 00:00:00 +0000</pubDate><guid>https://pradyunsg.me/blog/2019/06/22/is-this-thing-on/</guid><description>&lt;p&gt;*tap* *tap*&lt;/p&gt;
&lt;p&gt;Seems like this is reaching you.&lt;/p&gt;
&lt;p&gt;Hello there! I&amp;rsquo;m Pradyun. You probably knew that already. Thanks for
spending the time to reach this random piece of writing by me.&lt;/p&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;This blog used to be built using &lt;a href="http://jekyllrb.com/"&gt;Jekyll&lt;/a&gt; and the theme was based off
&lt;a href="https://github.com/johnotander/pixyll"&gt;Pixyll&lt;/a&gt;. The theme was heavily restyled to be more in line with how I
wanted my site to look like. I ended up making changes to almost every
element of the design, though the layout and colours were solid in
Pixyll.&lt;/p&gt;</description><content:encoded><![CDATA[<p>*tap* *tap*</p>
<p>Seems like this is reaching you.</p>
<p>Hello there! I&rsquo;m Pradyun. You probably knew that already. Thanks for
spending the time to reach this random piece of writing by me.</p>
<h2 id="acknowledgements">Acknowledgements</h2>
<p>This blog used to be built using <a href="http://jekyllrb.com/">Jekyll</a> and the theme was based off
<a href="https://github.com/johnotander/pixyll">Pixyll</a>. The theme was heavily restyled to be more in line with how I
wanted my site to look like. I ended up making changes to almost every
element of the design, though the layout and colours were solid in
Pixyll.</p>
]]></content:encoded></item></channel></rss>