Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: https://nedbatchelder.com/blog/rss.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <?xml-stylesheet type="text/xsl" href="https://nedbatchelder.com/rssfull2html.xslt" media="screen" ?>
  3.  
  4. <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/">
  5. <channel rdf:about="https://nedbatchelder.com/blog">
  6. <title>Ned Batchelder's blog</title>
  7. <link>https://nedbatchelder.com/blog</link>
  8. <description>Ned Batchelder's personal blog.</description>
  9. <dc:language>en-US</dc:language>
  10. <image rdf:resource="https://nedbatchelder.com/pix/rss-banner.gif"/>
  11. <items>
  12. <rdf:Seq>
  13. <rdf:li resource="https://nedbatchelder.com/blog/202404/my_flexbox_layout.html"/><rdf:li resource="https://nedbatchelder.com/blog/202404/try_it_functionclass_coverage_report.html"/><rdf:li resource="https://nedbatchelder.com/blog/202403/is_this_for_autistic_people.html"/><rdf:li resource="https://nedbatchelder.com/blog/202403/does_python_have_pointers.html"/><rdf:li resource="https://nedbatchelder.com/blog/202402/updated_multiparameter_interactive_jupyter_notebook.html"/><rdf:li resource="https://nedbatchelder.com/blog/202402/one_way_to_package_python_code_right_now.html"/><rdf:li resource="https://nedbatchelder.com/blog/202401/i_am_at_liberty.html"/><rdf:li resource="https://nedbatchelder.com/blog/202401/you_probably_dont_need_to_learn_c.html"/><rdf:li resource="https://nedbatchelder.com/blog/202401/randomly_subsetting_test_suites.html"/><rdf:li resource="https://nedbatchelder.com/blog/202312/coveragepy_with_sysmonitoring.html"/>
  14. </rdf:Seq>
  15. </items>
  16. </channel>
  17. <image rdf:about="https://nedbatchelder.com/pix/rss-banner.gif">
  18. <title>Ned Batchelder's blog</title>
  19. <link>https://nedbatchelder.com/blog</link>
  20. <url>https://nedbatchelder.com/pix/rss-banner.gif</url>
  21. </image>
  22. <item rdf:about="https://nedbatchelder.com/blog/202404/my_flexbox_layout.html">
  23. <title>My flexbox layout</title>
  24. <link>https://nedbatchelder.com/blog/202404/my_flexbox_layout.html</link>
  25. <dc:date>2024-04-19T06:59:32-04:00</dc:date>
  26. <dc:creator>Ned Batchelder</dc:creator>
  27. <description><![CDATA[<p>I recently had to reverse engineer the layout of this site.  I created it
  28. once upon a time, but had forgotten the details, and to save myself the work
  29. five years from now when I have to do it again, I&#8217;m noting down what I learned
  30. about how it works.</p><p>For pedagogical purposes, I made a simplified example of the layout:
  31. <a href="https://nedbatchelder.com/files/toystell.html">toystell.html</a>.  The layout depends on CSS&#8217;s
  32. <a rel="external noopener" href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox">flexbox</a> capabilities.  The full implementation on this
  33. site includes a responsive layout that changes as the width of the browser
  34. shrinks, but the simple example doesn&#8217;t include that.</p><p>There are five components to the layout: logo, banner, sidebar, content, and
  35. footer.  The skeleton of the HTML is:</p><blockquote class="code"><pre class="html"><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
  36. <br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="p">&lt;</span><span class="nt">header</span>&#xA0;<span class="na">id</span><span class="o">=</span><span class="s">&quot;banner&quot;</span><span class="p">&gt;</span>Top&#xA0;Banner<span class="p">&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
  37. <br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="p">&lt;</span><span class="nt">main</span>&#xA0;<span class="na">id</span><span class="o">=</span><span class="s">&quot;content&quot;</span><span class="p">&gt;</span>Content<span class="p">&lt;/</span><span class="nt">main</span><span class="p">&gt;</span>
  38. <br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="p">&lt;</span><span class="nt">aside</span>&#xA0;<span class="na">id</span><span class="o">=</span><span class="s">&quot;sidebar&quot;</span><span class="p">&gt;</span>Sidebar<span class="p">&lt;/</span><span class="nt">aside</span><span class="p">&gt;</span>
  39. <br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="p">&lt;</span><span class="nt">footer</span>&#xA0;<span class="na">id</span><span class="o">=</span><span class="s">&quot;footer&quot;</span><span class="p">&gt;</span>Footer<span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
  40. <br>&#xA0;&#xA0;&#xA0;&#xA0;<span class="p">&lt;</span><span class="nt">header</span>&#xA0;<span class="na">id</span><span class="o">=</span><span class="s">&quot;logo&quot;</span><span class="p">&gt;&lt;/</span><span class="nt">header</span><span class="p">&gt;</span>
  41. <br><span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
  42. <br></pre></blockquote><p>Notice that the order of the elements in the HTML isn&#8217;t the same as the order
  43. they appear on the page.  Flexbox makes this possible. We start by making the
  44. body element a centered flex container:</p><blockquote class="code"><pre class="css"><span class="nt">body</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  45. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">max-width</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">55</span><span class="kt">rem</span><span class="p">;</span><span class="w"></span>
  46. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">margin</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">0</span><span class="w">&#xA0;</span><span class="kc">auto</span><span class="w">&#xA0;</span><span class="mi">1</span><span class="kt">rem</span><span class="p">;</span><span class="w"></span>
  47. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">display</span><span class="p">:</span><span class="w">&#xA0;</span><span class="kc">flex</span><span class="p">;</span><span class="w"></span>
  48. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">flex-flow</span><span class="p">:</span><span class="w">&#xA0;</span><span class="kc">row</span><span class="w">&#xA0;</span><span class="kc">wrap</span><span class="p">;</span><span class="w"></span>
  49. <br><span class="p">}</span><span class="w"></span>
  50. <br><span class="nt">body</span><span class="w">&#xA0;</span><span class="o">&gt;</span><span class="w">&#xA0;</span><span class="o">*</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  51. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">flex</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">1</span><span class="w">&#xA0;</span><span class="mi">100</span><span class="kt">%</span><span class="p">;</span><span class="w"></span>
  52. <br><span class="p">}</span><span class="w"></span>
  53. <br></pre></blockquote><p>The container is set to hold flex items in rows that wrap.  We&#8217;re going to
  54. end up with three rows: the banner, the sidebar and content, and the footer. The
  55. default flex spec for elements in the body is to take the full width of the
  56. container, though this will only apply to the banner and footer.</p><p>First the logo is positioned absolutely with a specific height and width.
  57. It&#8217;s not participating in the flex layout at all, but the other elements will be
  58. adjusted to fit neatly around it.  It&#8217;s square, so its height and width are the
  59. width of the sidebar:</p><blockquote class="code"><pre class="css"><span class="p">:</span><span class="nd">root</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  60. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="nv">--side-width</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">10</span><span class="kt">rem</span><span class="p">;</span><span class="w"></span>
  61. <br><span class="p">}</span><span class="w"></span>
  62. <br><span class="p">#</span><span class="nn">logo</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  63. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">position</span><span class="p">:</span><span class="w">&#xA0;</span><span class="kc">absolute</span><span class="p">;</span><span class="w"></span>
  64. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">width</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--side-width</span><span class="p">);</span><span class="w"></span>
  65. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">height</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--side-width</span><span class="p">);</span><span class="w"></span>
  66. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">background-image</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nb">url</span><span class="p">(</span><span class="sx">https://placehold.co/400/orange/white?text=Logo</span><span class="p">);</span><span class="w"></span>
  67. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">background-size</span><span class="p">:</span><span class="w">&#xA0;</span><span class="kc">contain</span><span class="p">;</span><span class="w"></span>
  68. <br><span class="p">}</span><span class="w"></span>
  69. <br></pre></blockquote><p>Then the banner is added as a fixed-height flexbox item.  But if we simply do
  70. that, its left edge will be in the same position as the logo&#8217;s left edge, and
  71. they will overlap.  To prevent this and make them abut nicely, we give the
  72. banner a left margin equal to the logo&#8217;s width:</p><blockquote class="code"><pre class="css"><span class="p">:</span><span class="nd">root</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  73. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="nv">--banner-height</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">4</span><span class="kt">rem</span><span class="p">;</span><span class="w"></span>
  74. <br><span class="p">}</span><span class="w"></span>
  75. <br><span class="p">#</span><span class="nn">banner</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  76. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">order</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">1</span><span class="p">;</span><span class="w"></span>
  77. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">height</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--banner-height</span><span class="p">);</span><span class="w"></span>
  78. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">margin-left</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--side-width</span><span class="p">);</span><span class="w"></span>
  79. <br><span class="p">}</span><span class="w"></span>
  80. <br></pre></blockquote><p>Next comes the fixed-width sidebar.  The banner took the full width of the
  81. container, so the natural place for the sidebar is just under the banner at the
  82. left edge.  But we need it lower than that, just under the logo&#8217;s bottom edge.
  83. To make that work, we give it a top margin of enough to push it down:</p><blockquote class="code"><pre class="css"><span class="p">#</span><span class="nn">sidebar</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  84. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">order</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">2</span><span class="p">;</span><span class="w"></span>
  85. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">flex</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">0</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--side-width</span><span class="p">);</span><span class="w"></span>
  86. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">margin-top</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nb">calc</span><span class="p">(</span><span class="nf">var</span><span class="p">(</span><span class="nv">--side-width</span><span class="p">)</span><span class="w">&#xA0;</span><span class="o">-</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--banner-height</span><span class="p">));</span><span class="w"></span>
  87. <br><span class="p">}</span><span class="w"></span>
  88. <br></pre></blockquote><p>All of the flex items were told to take the full width, but the sidebar is
  89. our one element that has a fixed width.  The top margin is the difference
  90. between the height of the logo and the height of the banner.</p><p>The content will fit next to the sidebar under the banner just where we want
  91. it.  &#8220;flex: 1 0&#8221; means it starts with zero width, but gets all of the remaining
  92. space in the flex row, so it&#8217;s width grows to take the remaining space:</p><blockquote class="code"><pre class="css"><span class="p">#</span><span class="nn">content</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  93. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">order</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">3</span><span class="p">;</span><span class="w"></span>
  94. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">flex</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">1</span><span class="w">&#xA0;</span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
  95. <br><span class="p">}</span><span class="w"></span>
  96. <br></pre></blockquote><p>Last comes the footer.  It needs a left margin like the banner did so that it
  97. won&#8217;t overlap the sidebar, and we give the sidebar a negative bottom margin to
  98. scooch it up to avoid the height of the footer:</p><blockquote class="code"><pre class="css"><span class="p">:</span><span class="nd">root</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  99. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="nv">--footer-height</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">3</span><span class="kt">rem</span><span class="p">;</span><span class="w"></span>
  100. <br><span class="p">}</span><span class="w"></span>
  101. <br><span class="p">#</span><span class="nn">sidebar</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  102. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">margin-bottom</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nb">calc</span><span class="p">(</span><span class="mi">0</span><span class="kt">rem</span><span class="w">&#xA0;</span><span class="o">-</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--footer-height</span><span class="p">));</span><span class="w"></span>
  103. <br><span class="p">}</span><span class="w"></span>
  104. <br><span class="p">#</span><span class="nn">footer</span><span class="w">&#xA0;</span><span class="p">{</span><span class="w"></span>
  105. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">order</span><span class="p">:</span><span class="w">&#xA0;</span><span class="mi">4</span><span class="p">;</span><span class="w"></span>
  106. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">margin-left</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--side-width</span><span class="p">);</span><span class="w"></span>
  107. <br><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="k">height</span><span class="p">:</span><span class="w">&#xA0;</span><span class="nf">var</span><span class="p">(</span><span class="nv">--footer-height</span><span class="p">);</span><span class="w"></span>
  108. <br><span class="p">}</span><span class="w"></span>
  109. <br></pre></blockquote><p>I&#8217;ve skipped other parts that are in the toy sample, like how each item has
  110. carefully chosen borders to form the narrow gutters in the layout.  These are
  111. just the broad strokes of how the five big boxes negotiate the space in their
  112. unusual way.  The full site includes responsiveness, and uses
  113. <a rel="external noopener" href="https://sass-lang.com/">Sass</a> compiled to CSS to do some of the heavy lifting.</p><p>Better CSS wizards than me probably see better ways to do it, but it
  114. works.</p>
  115. ]]></description>
  116. </item>
  117. <item rdf:about="https://nedbatchelder.com/blog/202404/try_it_functionclass_coverage_report.html">
  118. <title>Try it: function/class coverage report</title>
  119. <link>https://nedbatchelder.com/blog/202404/try_it_functionclass_coverage_report.html</link>
  120. <dc:date>2024-04-15T16:02:00-04:00</dc:date>
  121. <dc:creator>Ned Batchelder</dc:creator>
  122. <description><![CDATA[<p>I&#8217;ve added experimental function and class coverage reports to coverage.py.
  123. I&#8217;d like <a href="https://github.com/nedbat/coveragepy/issues/780" rel="external noopener">feedback</a>
  124. about whether they behave the way you want them to.</p><p>I haven&#8217;t made a PyPI release.  To try the new reports, install coverage from
  125. GitHub. Be sure to include the hash:</p><blockquote class="code"><pre>$ python3 -m pip install git+https://github.com/nedbat/coveragepy@f10c455b7c8fd26352de#egg=coverage==0.0<br></pre></blockquote><p>Then run coverage and make an HTML report as you usually do.  You should
  126. have two new pages, not linked from the index page (yet).
  127. &#8220;htmlcov/function_index.html&#8221; is the function coverage report, and the classes
  128. are in &#8220;htmlcov/class_index.html&#8221;.</p><p>I had to decide how to categorize nested functions and classes. Inner
  129. functions are not counted as part of their outer functions.  Classes consist of
  130. the executable lines in their methods, but not lines outside of methods, because
  131. those lines run on import.  Each file has an entry in the function report for
  132. all of the lines outside of any function, called &#8220;(no function)&#8221;.  The class
  133. report has &#8220;(no class)&#8221; entries for lines outside of any classes.</p><p>The result should be that every line is part of one function, or the &#8220;(no
  134. function)&#8221; entry, and every line is part of one class, or the &#8220;(no class)&#8221;
  135. entry.  This is what made sense to me, but maybe there&#8217;s a compelling reason to
  136. do it differently.</p><p>The reports have a sortable column for the file name, and a sortable column
  137. for the function or class.  Where functions or classes are nested, the name is a
  138. dotted sequence, but is sorted by only the last component.  Just like the
  139. original file listing page, the new pages can be filtered to focus on areas of
  140. interest.</p><p>You can look at some sample reports:</p><ul>
  141. <li><a href="https://nedbatchelder.com/files/sample_coverage_html_beta">Usual file report</a></li>
  142. <li><a href="https://nedbatchelder.com/files/sample_coverage_html_beta/function_index.html">Function report</a></li>
  143. <li><a href="https://nedbatchelder.com/files/sample_coverage_html_beta/class_index.html">Class report</a></li>
  144. </ul><p>It would be helpful if you could give me
  145. <a href="https://github.com/nedbat/coveragepy/issues/780" rel="external noopener">feedback on the
  146. original issue</a> about some questions:</p><ul>
  147.  
  148. <li>Is it useful to have &#8220;(no function)&#8221; and &#8220;(no class)&#8221; entries or is it just
  149. distracting pedantry?  With the entries, the total is the same as the file
  150. report, but they don&#8217;t seem useful by themselves.</li>
  151.  
  152. <li>Does the handling of nested functions and classes make sense?</li>
  153.  
  154. <li>Should these reports be optional (requested with a switch) or always
  155. produced?</li>
  156.  
  157. <li>Is it reasonable to produce one page with every function? How large does a
  158. project have to get before that&#8217;s not feasible or useful?</li>
  159.  
  160. <li>And most importantly: do these reports help you understand how to improve
  161. your code?</li>
  162.  
  163. </ul><p>This is only in the HTML report for now, but we can do more in the future.
  164. Other <a href="https://github.com/nedbat/coveragepy/issues/780" rel="external noopener">ideas
  165. about improvements</a> are of course welcome.  Thanks!</p>
  166. ]]></description>
  167. </item>
  168. <item rdf:about="https://nedbatchelder.com/blog/202403/is_this_for_autistic_people.html">
  169. <title>Is this for autistic people?</title>
  170. <link>https://nedbatchelder.com/blog/202403/is_this_for_autistic_people.html</link>
  171. <dc:date>2024-03-20T11:46:00-04:00</dc:date>
  172. <dc:creator>Ned Batchelder</dc:creator>
  173. <description><![CDATA[<p>Special Olympics swimming season started this past weekend.  A new athlete
  174. joined us, a young boy I&#8217;ll call Bryan. He asked me a question that has stuck
  175. with me.</p><p>Bryan is 12 or so, with the slightly goofy look of a boy growing into his
  176. body. He has braces on his too-large teeth.  It was his first time swimming with
  177. us, so we needed to show him the locker room, how to get out to the pool, and so
  178. on. He was serious and inquisitive about all of these things that were new to
  179. him.</p><p>We got out on the deck and started stretching with the other athletes, most
  180. of whom don&#8217;t look like Bryan.  They are older and have a variety of
  181. intellectual disabilities. Bryan surveyed the group then turned to me and asked
  182. the question: &#8220;is this for autistic people?&#8221;</p><p>I had only just met Bryan. I didn&#8217;t know his formal diagnosis (or if he even
  183. had one), and I didn&#8217;t know how he thought of himself.  When he asked the
  184. question, I didn&#8217;t know if he was including himself in the category of autistic
  185. people or not, so I wanted to answer carefully.</p><p>Did he mean, &#8220;are autistic people allowed here?&#8221; or, &#8220;is this only for
  186. autistic people?&#8221; Maybe he meant, &#8220;are all of these swimmers autistic?&#8221; or even,
  187. &#8220;will being here mean I am autistic?&#8221;</p><p>I told him that it was for autistic people, that my own son Nat was here and
  188. Nat is autistic.  Bryan accepted this in his sober way and continued on with the
  189. practice.</p><p>Later I talked with his mom about the question and asked her if Bryan
  190. identified as autistic. She said that he did, but it was a recent awareness for
  191. him.  In school he&#8217;s in a typical integrated classroom.</p><p>Bryan did well at the practice, and called me &#8220;Coach Ned.&#8221;  His mom was
  192. really appreciative of the group as a whole and was clearly pleased.</p><p>I&#8217;ve been thinking about Bryan and his question: &#8220;is this for autistic
  193. people?&#8221;  He&#8217;s young, and finding his way in the world in so many ways.  We all
  194. need to figure out who we are, what groups we belong to, where we fit.  We all
  195. encounter difficulties in one way or another working all that out, and it&#8217;s
  196. a life-long process.  Bryan has a lot to work on.  I hope it isn&#8217;t too hard.</p>
  197. ]]></description>
  198. </item>
  199. <item rdf:about="https://nedbatchelder.com/blog/202403/does_python_have_pointers.html">
  200. <title>Does Python have pointers?</title>
  201. <link>https://nedbatchelder.com/blog/202403/does_python_have_pointers.html</link>
  202. <dc:date>2024-03-11T07:27:22-04:00</dc:date>
  203. <dc:creator>Ned Batchelder</dc:creator>
  204. <description><![CDATA[<p>People sometimes ask, &#8220;Does Python have pointers?&#8221;  I hate to be the typical
  205. senior engineer, but this is one of those questions where the answer is, it
  206. depends what you mean by pointer.</p><p>The classic definition of a pointer is: a variable that holds the address
  207. of something else and that you can use to work with that something else.
  208. In very broad pseudo-code, it would be something like this:
  209. </p><blockquote class="code"><pre>myvar = SOMETHING;<br>mypointer = get_address_of(myvar);<br>print(get_value_via_pointer(mypointer));<br>## output is SOMETHING<br></pre></blockquote><p>This is useful because we can use a pointer to refer to data, setting the
  210. pointer in one part of the code with whatever logic we need to decide what data
  211. it should point to. Then elsewhere we can use the pointer without having to know
  212. what it&#8217;s referring to or how the decision was made.  The pointer gives us an
  213. indirection that lets us separate concerns and write more modular code.</p><p>Many programming languages provide a pointer facility like this.  For
  214. example, in C, the get_address_of() operation is ampersand, and the
  215. get_value_via_pointer() operation is star, and our code snippet would be:</p><blockquote class="code"><pre class="c"><span class="kt">int</span><span class="w">&#xA0;</span><span class="n">myvar</span><span class="w">&#xA0;</span><span class="o">=</span><span class="w">&#xA0;</span><span class="mi">17</span><span class="p">;</span><span class="w"></span>
  216. <br><span class="kt">int</span><span class="w">&#xA0;</span><span class="o">*</span><span class="n">mypointer</span><span class="w">&#xA0;</span><span class="o">=</span><span class="w">&#xA0;</span><span class="o">&amp;</span><span class="n">myvar</span><span class="p">;</span><span class="w"></span>
  217. <br><span class="n">print_int</span><span class="p">(</span><span class="o">*</span><span class="n">mypointer</span><span class="p">);</span><span class="w">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;</span><span class="c1">//&#xA0;outputs&#xA0;17</span>
  218. <br></pre></blockquote><p>Other languages like C++, C#, Go, Rust, Pascal, and even Fortran have similar
  219. capabilities.</p><p>OK, so what about Python?  In one sense, Python doesn&#8217;t have a pointer
  220. concept like this.  You could say that get_address_of() is provided by Python&#8217;s
  221. id() function, since (in CPython at least) it returns the memory address of the
  222. data:</p><blockquote class="code"><pre class="python"><span class="n">myvar</span>&#xA0;<span class="o">=</span>&#xA0;<span class="mi">17</span>
  223. <br><span class="n">mypointer</span>&#xA0;<span class="o">=</span>&#xA0;<span class="nb">id</span><span class="p">(</span><span class="n">myvar</span><span class="p">)</span>&#xA0;&#xA0;&#xA0;<span class="c1">#&#xA0;**&#xA0;not&#xA0;useful</span>
  224. <br></pre></blockquote><p>But Python has no inverse operation: there&#8217;s no get_value_via_pointer()
  225. that can get you myvar given mypointer.</p><p>So Python doesn&#8217;t have the classic pair of operations to be able to work with
  226. pointers explicitly.  But on the other hand, <em>every</em> variable in Python
  227. is a pointer, because variables in Python are <a href="https://nedbatchelder.com/text/names1.html">names
  228. that refer to objects</a>.</p><p>In Python, our simple example looks like this:</p><blockquote class="code"><pre class="python"><span class="n">myvar</span>&#xA0;<span class="o">=</span>&#xA0;<span class="mi">17</span>
  229. <br><span class="n">mypointer</span>&#xA0;<span class="o">=</span>&#xA0;<span class="n">myvar</span>
  230. <br><span class="nb">print</span><span class="p">(</span><span class="n">mypointer</span><span class="p">)</span>&#xA0;&#xA0;&#xA0;&#xA0;<span class="c1">#&#xA0;outputs&#xA0;17</span>
  231. <br></pre></blockquote><p>When someone asks, does Python have pointers, perhaps the best answer is: it
  232. doesn&#8217;t have explicit pointers like some other languages, but everything is
  233. implicitly a pointer. So you have the power of pointers to use when you need
  234. them: you can have multiple data structures, then assign a variable to one you
  235. choose, and use the variable later.  You&#8217;ve achieved the separation of &#8220;which
  236. data&#8221; from &#8220;work with the data&#8221; that pointers provide.</p><p>Maybe this is yet another case of
  237. <a href="https://nedbatchelder.com/blog/202301/same_words_different_meanings.html">Same words, different meanings</a>.</p><p>Note:</p><ul>
  238.  
  239. <li>Some languages like C also allow pointer arithmetic to adjust a pointer from
  240. one item in an array to another. Python&#8217;s references don&#8217;t allow for that.</li>
  241.  
  242. <li>Python&#8217;s standard library provides <a rel="external noopener" href="https://docs.python.org/3/library/ctypes.html">ctypes</a>, which
  243. is great for interfacing with native C code, exposing details there including C
  244. pointers.  This does not count as Python having explicit pointers.</li>
  245.  
  246. </ul>
  247. ]]></description>
  248. </item>
  249. <item rdf:about="https://nedbatchelder.com/blog/202402/updated_multiparameter_interactive_jupyter_notebook.html">
  250. <title>Updated multi-parameter interactive Jupyter notebook</title>
  251. <link>https://nedbatchelder.com/blog/202402/updated_multiparameter_interactive_jupyter_notebook.html</link>
  252. <dc:date>2024-02-12T14:21:11-05:00</dc:date>
  253. <dc:creator>Ned Batchelder</dc:creator>
  254. <description><![CDATA[<p>A few years ago I wrote
  255. <a href="https://nedbatchelder.com/blog/201610/multiparameter_jupyter_notebook_interaction.html">Multi-parameter Jupyter notebook interaction</a>  about a
  256. Jupyter notebook. It worked at the time, but when I dusted it off recently, it
  257. didn&#8217;t.  I&#8217;ve renovated it and cleaned it up a little, and now it works
  258. again.</p><p>It&#8217;s a <a rel="external noopener" href="/code/misc/retirement_sample2.ipynb">Jupyter notebook</a> with a simulation of
  259. late-career money flows to figure out possibilities for retirement.  It uses
  260. widgets to give you sliders to adjust parameters to see how the outcome changes.
  261. It also lets you pick one of the parameters to auto-plot with multiple values,
  262. which gives a more visceral way to understand the effect different variables
  263. have.</p><div class="figurep"><a href="https://nedbatchelder.com/code/misc/retirement_sample2.ipynb"><figure><picture><source type="image/webp" srcset="https://nedbatchelder.com/iv/webp/pix/retirement_sliders2.png.webp"><img src="https://nedbatchelder.com/pix/retirement_sliders2.png" alt="Screenshot of the sliders and resulting plot of outcomes" width="1122" height="1456"></picture></figure></a></div><p>You can <a rel="external noopener" href="/code/misc/retirement_sample2.ipynb">get the notebook itself</a> if you like.</p>
  264. ]]></description>
  265. </item>
  266. <item rdf:about="https://nedbatchelder.com/blog/202402/one_way_to_package_python_code_right_now.html">
  267. <title>One way to package Python code right now</title>
  268. <link>https://nedbatchelder.com/blog/202402/one_way_to_package_python_code_right_now.html</link>
  269. <dc:date>2024-02-10T06:50:00-05:00</dc:date>
  270. <dc:creator>Ned Batchelder</dc:creator>
  271. <description><![CDATA[<p>A year or so ago, I couldn&#8217;t find a step-by-step guide to packaging a Python
  272. project that didn&#8217;t get bogged down in confusing options and choices, so I wrote
  273. my own: <a rel="external noopener" href="https://github.com/nedbat/pkgsample">pkgsample</a>.  After I wrote it, I found the
  274. <a rel="external noopener" href="https://packaging.python.org/en/latest/tutorials/packaging-projects/">PyPA Packaging Python Projects tutorial</a>, which is
  275. very good, so I never made a post here about my sample.</p><p>Since then, I&#8217;ve shown my sample to people a number of times, and they liked
  276. it, so I guess it&#8217;s helpful.  Here&#8217;s what I wrote about it back when I first created it:</p><p class="bulletsep">•    •    •</p><p>The Python packaging world is confusing.  There are decades of history and
  277. change.  There are competing tools, with new ones arriving frequently.  I don&#8217;t
  278. want to criticize anyone, let&#8217;s just take it as a fact of life right now.</p><p>But I frequently see questions from people who have written some Python code,
  279. and would like to get it packaged. They have a goal in mind, and it is not to
  280. learn about competing tools, intricate standards, or historical artifacts.
  281. They are fundamentally uninterested in the mechanics of packaging.  They just
  282. want to get their code packaged.</p><p>There are lots of pages out there that try to explain things, but they all
  283. seem to get distracted by the options, asking our poor developer to choose
  284. between alternatives they don&#8217;t understand, with no clear implications.</p><p>I&#8217;m also not criticzing the uninterested developer.  I am that developer!  I
  285. don&#8217;t know what all these things are, or how they compete and overlap: build,
  286. twine, hatch, poetry, flit, wheel, pdm, setuptools, distutils, pep517, shiv,
  287. <a rel="external noopener" href="https://packaging.python.org/en/latest/key_projects/">etc</a>, <a rel="external noopener" href="https://chadsmith.dev/python-packaging/">etc</a>.</p><p>I just want someone to tell me what to do so my code will install on users&#8217;
  288. machines.  Once that works, I can go back to fixing bugs, adding features,
  289. writing docs, and so on.</p><p>So I wrote <a rel="external noopener" href="https://github.com/nedbat/pkgsample">pkgsample</a> to be the instructions I
  290. couldn&#8217;t find.  It&#8217;s simple and stripped down, and does not ask you to make
  291. choices you don&#8217;t care about. It tells you what to do. It gives you one way to
  292. make a simple Python package that works right now. It isn&#8217;t THE way. It&#8217;s A way.
  293. It will probably work for you.</p>
  294. ]]></description>
  295. </item>
  296. <item rdf:about="https://nedbatchelder.com/blog/202401/i_am_at_liberty.html">
  297. <title>I am at liberty</title>
  298. <link>https://nedbatchelder.com/blog/202401/i_am_at_liberty.html</link>
  299. <dc:date>2024-01-30T09:08:00-05:00</dc:date>
  300. <dc:creator>Ned Batchelder</dc:creator>
  301. <description><![CDATA[<p>As of a few weeks ago, I am between gigs.  Riffing on some corporate-speak
  302. from a <a rel="external noopener" href="https://2u.com/newsroom/2u-inc-announces-leadership-transition/">recent press release</a>: &#8220;2U and I have mutually
  303. determined that 2U is laying me off.&#8221;</p><p>I feel OK about it: work was becoming increasingly frustrating, and I have
  304. some severance pay.  2U is in a tough spot as a company so at least these
  305. layoffs seemed like an actual tactic rather than another pointless
  306. please-the-investors move by companies flush with profits and cash.  2U
  307. struggling also makes being laid off a more appealing option than remaining
  308. there after a difficult cut.</p><p><a href="https://edx.org" rel="external noopener">edX</a> was a good run for me. We had a noble
  309. mission: educate the world.  The software was mostly open source
  310. (<a href="http://openedx.org" rel="external noopener">Open edX</a>), which meant our efforts could
  311. power education that we as a corporation didn&#8217;t want to pursue.</p><p>Broadly speaking, my job was to oversee how to do open source well.  I loved
  312. the mission of education combined with the mission of open source.  I loved
  313. seeing the community do things together that edX alone could not. I have many
  314. good friends at 2U and in the community. I hope they can make everything work
  315. out well, and I hope I can do a good job staying in touch with them.</p><p>I don&#8217;t know what my next gig will be.  I like writing software. I like
  316. having developers as my customers. I am good at building community both inside
  317. and outside of companies.  I am good at helping people.  I&#8217;m interested to hear
  318. ideas.</p>
  319. ]]></description>
  320. </item>
  321. <item rdf:about="https://nedbatchelder.com/blog/202401/you_probably_dont_need_to_learn_c.html">
  322. <title>You (probably) don’t need to learn C</title>
  323. <link>https://nedbatchelder.com/blog/202401/you_probably_dont_need_to_learn_c.html</link>
  324. <dc:date>2024-01-24T06:38:49-05:00</dc:date>
  325. <dc:creator>Ned Batchelder</dc:creator>
  326. <description><![CDATA[<p>On <a href="https://hachyderm.io/@nedbat/111789013210403320" rel="external noopener">Mastodon I
  327. wrote</a> that I was tired of people saying, &#8220;you should learn C so you can
  328. understand how a computer really works.&#8221; I got a lot of replies which did not
  329. change my mind, but helped me understand more how abstractions are inescapable
  330. in computers.</p><p>People made a number of claims. C was important because syscalls are defined
  331. in terms of C semantics (they are not).  They said it was good for exploring
  332. limited-resource computers like Arduinos, but most people don&#8217;t program for
  333. those. They said it was important because C is more performant, but Python
  334. programs often offload the compute-intensive work to libraries other people have
  335. written, and these days that work is often on a GPU. Someone said you need it to
  336. debug with strace, then someone said they use strace all the time and don&#8217;t know
  337. C.  Someone even said C was good because it explains why NUL isn&#8217;t allowed in
  338. filenames, but who tries to do that, and why learn a language just for that
  339. trivia?</p><p>I&#8217;m all for learning C if it will be useful for the job at hand, but you can
  340. write lots of great software without knowing C.</p><p>A few people repeated the idea that C teaches you how code &#8220;really&#8221; executes.
  341. But C is an abstract model of a computer, and modern CPUs do all kinds of things
  342. that C doesn&#8217;t show you or explain.  Pipelining, cache misses, branch
  343. prediction, speculative execution, multiple cores, even virtual memory are all
  344. completely invisible to C programs.</p><p>C is an abstraction of how a computer works, and chip makers work hard to
  345. implement that abstraction, but they do it on top of much more complicated
  346. machinery.</p><p>C is far removed from modern computer architectures: there have been 50 years
  347. of innovation since it was created in the 1970&#8217;s.  The gap between C&#8217;s model and
  348. modern hardware is the root cause of famous vulnerabilities like Meltdown and
  349. Spectre, as explained in
  350. <a href="https://dl.acm.org/doi/pdf/10.1145/3212477.3212479" rel="external noopener">C is <i>Not</i> a
  351. Low-level Language</a>.</p><p>C can teach you useful things, like how memory is a huge array of bytes, but
  352. you can also learn that without writing C programs.  People say, C teaches you
  353. about memory allocation.  Yes it does, but you can learn what that means as a
  354. concept without learning a programming language.  And besides, what will Python
  355. or Ruby developers do with that knowledge other than appreciate that their
  356. languages do that work for them and they no longer have to think about it?</p><p>Pointers came up a lot in the Mastodon replies. Pointers underpin concepts in
  357. higher-level languages, but you can
  358. <a href="https://nedbatchelder.com/text/names1.html" rel="external noopener">explain those concepts as
  359. references</a> instead, and skip pointer arithmetic, aliasing, and null pointers
  360. completely.</p><p>A question I asked a number of people: what mistakes are
  361. JavaScript/Ruby/Python developers making if they don&#8217;t know these things (C,
  362. syscalls, pointers)?&#8221;.  I didn&#8217;t get strong answers.</p><p>We work in an enormous tower of abstractions.  I write programs in Python,
  363. which provides me abstractions that C (its underlying implementation language)
  364. does not.  C provides an abstract model of memory and CPU execution which the
  365. computer implements on top of other mechanisms (microcode and virtual memory).
  366. When I made a wire-wrapped computer, I could pretend the signal travelled
  367. through wires instantaneously.  For other hardware designers, that abstraction
  368. breaks down and they need to consider the speed electricity travels.  Sometimes
  369. you need to go one level deeper in the abstraction stack to understand what&#8217;s
  370. going on. Everyone has to find the right layer to work at.</p><p><a href="https://hachyderm.io/@agocke/111791030850237121" rel="external noopener">Andy Gocke said
  371. it well</a>:</p><blockquote><div><p>When you no longer have problems at that layer, that&#8217;s when you can
  372. stop caring about that layer. I don&#8217;t think there&#8217;s a universal level of
  373. knowledge that people need or is sufficient.</p></div></blockquote><p><a href="https://toot.cat/@idlestate/111793957024682587" rel="external noopener">&#8220;like jam or
  374. bootlaces&#8221; made another excellent point</a>:</p><blockquote><div><p>There&#8217;s a big difference between &#8220;everyone should know this&#8221; and
  375. &#8220;someone should know this&#8221; that seems to get glossed over in these kinds of
  376. discussions.</p></div></blockquote><p>C can teach you many useful and interesting things.  It will make you a
  377. better programmer, just as learning any new-to-you language will because it
  378. broadens your perspective.  Some kinds of programming need C, though other
  379. languages like Rust are ably filling that role now too.  C doesn&#8217;t teach you how
  380. a computer really works. It teaches you a common abstraction of how computers
  381. work.</p><p>Find a level of abstraction that works for what you need to do.  When you
  382. have trouble there, look beneath that abstraction. You won&#8217;t be seeing how
  383. things really work, you&#8217;ll be seeing a lower-level abstraction that could be
  384. helpful.  Sometimes what you need will be an abstraction one level up.  Is your
  385. Python loop too slow? Perhaps you need a C loop. Or perhaps you need numpy array
  386. operations.</p><p>You (probably) don&#8217;t need to learn C.</p>
  387. ]]></description>
  388. </item>
  389. <item rdf:about="https://nedbatchelder.com/blog/202401/randomly_subsetting_test_suites.html">
  390. <title>Randomly sub-setting test suites</title>
  391. <link>https://nedbatchelder.com/blog/202401/randomly_subsetting_test_suites.html</link>
  392. <dc:date>2024-01-14T09:39:32-05:00</dc:date>
  393. <dc:creator>Ned Batchelder</dc:creator>
  394. <description><![CDATA[<p>I needed to run random subsets of my test suite to narrow down the cause of
  395. some mysterious behavior.  I didn&#8217;t find an existing tool that worked the way I
  396. wanted to, so I cobbled something together.</p><p>I wanted to run 10 random tests (out of 1368), and keep choosing randomly
  397. until I saw the bad behavior.  Once I had a selection of 10, I wanted to be able
  398. to whittle it down to try to reduce it further.</p><p>I tried a few different approaches, and here&#8217;s what I came up with, two tools
  399. in the coverage.py repo that combine to do what I want:</p><ul> <li>A pytest plugin (<a rel="external noopener" href="https://github.com/nedbat/coveragepy/blob/master/tests/select_plugin.py">select_plugin.py</a>) that
  400. lets me run a command to output the names of the exact tests I want to
  401. run,</li>
  402.  
  403. <li>A command-line tool (<a rel="external noopener" href="https://github.com/nedbat/coveragepy/blob/master/lab/pick.py">pick.py</a>) to select random
  404. lines of text from a file.  For convenience, blank or commented-out lines are
  405. ignored.</li>
  406.  
  407. </ul><p>More details are in the comment at the top of
  408. <a rel="external noopener" href="https://github.com/nedbat/coveragepy/blob/master/lab/pick.py">pick.py</a>, but here&#8217;s a quick example:</p><ol>
  409.  
  410. <li>Get all the test names in tests.txt.  These are pytest &#8220;node&#8221; specifications:
  411.  
  412. <blockquote class="code"><pre>pytest --collect-only | grep :: &gt; tests.txt<br></pre></blockquote>
  413. </li>
  414.  
  415. <li>Now tests.txt has a line per test node.  Some are straightforward:
  416.  
  417. <blockquote class="code"><pre>tests/test_cmdline.py::CmdLineStdoutTest::test_version<br>tests/test_html.py::HtmlDeltaTest::test_file_becomes_100<br>tests/test_report_common.py::ReportMapsPathsTest::test_map_paths_during_html_report<br></pre></blockquote>
  418.  
  419. but with parameterization they can be complicated:
  420.  
  421. <blockquote class="code"><pre>tests/test_files.py::test_invalid_globs[bar/***/foo.py-***]<br>tests/test_files.py::FilesTest::test_source_exists[a/b/c/foo.py-a/b/c/bar.py-False]<br>tests/test_config.py::ConfigTest::test_toml_parse_errors[[tool.coverage.run]\nconcurrency="foo"-not a list]<br></pre></blockquote>
  422.  
  423. </li>
  424.  
  425. <li>Run a random bunch of 10 tests:
  426.  
  427. <blockquote class="code"><pre>pytest --select-cmd="python pick.py sample 10 &lt; tests.txt"<br></pre></blockquote>
  428.  
  429. We&#8217;re using <code>--select-cmd</code> to specify the shell command that
  430. will output the names of tests.  Our command uses <code>pick.py</code>
  431. to select 10 random lines from tests.txt.
  432.  
  433. </li>
  434.  
  435. <li>Run many random bunches of 10, announcing the seed each time:
  436.  
  437. <blockquote class="code"><pre>for seed in $(seq 1 100); do<br>    echo seed=$seed<br>    pytest --select-cmd="python pick.py sample 10 $seed &lt; tests.txt"<br>done<br></pre></blockquote>
  438.  
  439. </li>
  440.  
  441. <li>Once you find a seed that produces the small batch you want, save that batch:
  442.  
  443. <blockquote class="code"><pre>python pick.py sample 10 17 &lt; tests.txt &gt; bad.txt<br></pre></blockquote>
  444.  
  445. </li>
  446.  
  447. <li>Now you can run that bad batch repeatedly:
  448.  
  449. <blockquote class="code"><pre>pytest --select-cmd="cat bad.txt"<br></pre></blockquote>
  450.  
  451. </li>
  452.  
  453. <li>To reduce the bad batch, comment out lines in bad.txt with a hash character,
  454. and the tests will be excluded. Keep editing until you find the small set of
  455. tests you want.</li>
  456.  
  457. </ol><p>I like that this works and I understand it. I like that it&#8217;s based on the
  458. bedrock of text files and shell commands.  I like that there&#8217;s room for
  459. different behavior in the future by adding to how pick.py works.  For example,
  460. it doesn&#8217;t do any bisecting now, but it could be adapted to it.</p><p>As usual, there might be a better way to do this, but this works for me.</p>
  461. ]]></description>
  462. </item>
  463. <item rdf:about="https://nedbatchelder.com/blog/202312/coveragepy_with_sysmonitoring.html">
  464. <title>Coverage.py with sys.monitoring</title>
  465. <link>https://nedbatchelder.com/blog/202312/coveragepy_with_sysmonitoring.html</link>
  466. <dc:date>2023-12-27T18:03:33-05:00</dc:date>
  467. <dc:creator>Ned Batchelder</dc:creator>
  468. <description><![CDATA[<p>New in Python 3.12 is <a rel="external noopener" href="https://docs.python.org/3/library/sys.monitoring.html">sys.monitoring</a>, a
  469. lighter-weight way to monitor the execution of Python programs.
  470. <a href="https://pypi.org/project/coverage/7.4.0" rel="external noopener">Coverage.py 7.4.0</a> now
  471. can optionally use sys.monitoring instead of
  472. <a rel="external noopener" href="https://docs.python.org/3/library/sys.html#sys.settrace">sys.settrace</a>, the facility that has underpinned
  473. coverage.py for nearly two decades.  This is a big change, both in Python and in
  474. coverage.py.  It would be great if you could try it out and provide some
  475. feedback.</p><p>Using sys.monitoring should reduce the overhead of coverage measurement,
  476. often lower than 5%, but of course your timings might be different.  One of the
  477. things I would like to know is what your real-world speed improvements are
  478. like.</p><p>Because the support is still a bit experimental, you need to define an
  479. environment variable to use it: <code>COVERAGE_CORE=sysmon</code>.
  480. Eventually, sys.monitoring will be automatically used where possible, but for
  481. now you need to explicitly request it.</p><p>Some things won&#8217;t work with sys.monitoring: plugins and dynamic contexts
  482. aren&#8217;t yet supported, though eventually they will be.  Execution will be faster
  483. for line coverage, but not yet for branch coverage.  Let me know how it works
  484. for you.</p><p>This has been in the works since at least March.  I hope I haven&#8217;t forgotten
  485. something silly in getting it out the door.</p>
  486. ]]></description>
  487. </item>
  488. </rdf:RDF>
  489.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=https%3A//nedbatchelder.com/blog/rss.xml

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda