Congratulations!

[Valid Atom 1.0] This is a valid Atom 1.0 feed.

Recommendations

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

Source: http://reinout.vanrees.org/weblog/atom.xml

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <feed xmlns="http://www.w3.org/2005/Atom"
  3.      xmlns:dc="http://purl.org/dc/elements/1.1/"
  4.      xml:base="http://reinout.vanrees.org/" xml:lang="en">
  5.  <link rel="self"
  6.        href="http://reinout.vanrees.org/weblog/atom.xml" />
  7.  <link href="http://reinout.vanrees.org/weblog/"
  8.        rel="alternate" type="text/html" />
  9.  
  10.  <div xmlns="http://www.w3.org/1999/xhtml">
  11.    <a href="http://www.atomenabled.org/feedvalidator/check.cgi?url=http%3A%2F%2Freinout.vanrees.org%2Fweblog%2Fatom.xml">
  12.      <img title="Validate my Atom feed" width="88"
  13.           height="31"
  14.           src="http://www.atomenabled.org/feedvalidator/images/valid-atom.png"
  15.           alt="[Valid Atom]" border="0px" />
  16.    </a>
  17.    <p>
  18.      <span>
  19.        This is an Atom formatted XML site feed. It is intended to be viewed in
  20.        a Newsreader or syndicated to another site. Please visit
  21.      </span>
  22.      <a href="http://www.atomenabled.org/">Atom Enabled</a>
  23.      <span>
  24.        for more info.
  25.      </span>
  26.    </p>
  27.  </div>
  28.  
  29.  <title type="html">Reinout van Rees' weblog</title>
  30.  <subtitle>Python, grok, books, history, faith, etc.</subtitle>
  31.  <updated>2009-04-04T21:44:00+01:00</updated>
  32.  <id>urn:syndication:a55644db8591c020bd38852775819a9a</id>
  33.  
  34.  
  35.  <entry>
  36.    <title>Python Leiden (NL) meetup: Rendering spatial data in 3d using zarr, jax, babylon.js and DuckDB - Jesse K.V.</title>
  37.    <link rel="alternate" type="text/html"
  38.          href="http://reinout.vanrees.org/weblog/2025/03/27/3-rendering-3d.html" />
  39.      <id>http://reinout.vanrees.org/weblog/2025/03/27/3-rendering-3d.html</id>
  40.      <author>
  41.        <name>Reinout van Rees</name>
  42.      </author>
  43.      <published>2025-03-27T00:00:00+01:00</published>
  44.      <updated>2025-03-27T21:06:00+01:00</updated>
  45.  
  46.      
  47.      <category term="pun" />
  48.      
  49.      <category term="python" />
  50.      
  51.  
  52.      <content type="html"><![CDATA[
  53.        <div class="document">
  54. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2025/03/27/">my summaries</a> of
  55. the second <a class="reference external" href="https://pythonleiden.nl/">Python Leiden (NL) meetup</a> in
  56. Leiden, NL).</p>
  57. <p>He's working with civil engineering, hydrology and weather data. And... he wanted to toy
  58. with 3D models. His example site: <a class="reference external" href="https://topography.jessekv.com/">https://topography.jessekv.com/</a> . You can click almost
  59. anywhere in the world and get the upstream catchment. (I checked it: yes, it seems to
  60. work pretty well!)</p>
  61. <p>He runs all requests through a single asyncio python thread. As a personal challenge he
  62. wanted it to handle the heavy load of a <em>hacker news</em> post. In the end, it worked
  63. fine. One async python thread was more than enough.</p>
  64. <p>One of the tricks he used was to preprocess as much as reasonable so that most clicks
  65. are direct lookups in a database (vector data). Depending on the size of the selected
  66. area, he uses more detailed rasters for small areas and coarser ones for big areas.</p>
  67. <p>He wanted a mostly-working prototype quickly, so he experimented with LLMs. Generating
  68. math code was mostly bad, but the UI code was OK.</p>
  69. <p>He used <a class="reference external" href="https://duckdb.org/">duckdb</a> with a spatial extension. Duckdb uses GDAL
  70. vector routines. This is what he used to pre-process the catchment areas on his M1 mac
  71. laptop. Afterwards, he exported it to postgres. Postgres is much more optimised for
  72. actual production use.</p>
  73. <p>Duckdb doesn't always work perfectly, but if you're able to define your workload in such
  74. a way (parallelised) that you stay within the limits of your memory, you can get real
  75. good performance out of it.</p>
  76. <p>Duckdb's file-based approach is also handy. Just like sqlite's files. Easy for
  77. experimenting.</p>
  78. <p><a class="reference external" href="https://zarr.dev/">zarr</a> is what he used for pre-processing the 3D landscape. Zarr is
  79. efficient for storing large arrays of gridded data. Zarr is way nicer than
  80. <tt class="docutils literal">netcdf</tt>. It is designed to leverage the linux page cache. And you store compressed
  81. data in memory. Storing on S3 is also well-integrated.</p>
  82. <p><a class="reference external" href="https://docs.jax.dev/en/latest/">jax</a> is an easy way to take numpy/scipy to make it
  83. run in parallel. <tt class="docutils literal"><span class="pre">JAX-metal</span></tt> is a jax backend that runs on his M1 macbook's
  84. <strong>GPU</strong>. Processing is aligned to chuncks for more efficient reads and writes.</p>
  85. <p>For landcover, he used <tt class="docutils literal">jax.scipy.stats.mode</tt> and for elevation
  86. <tt class="docutils literal">jax.numpy.nanmean</tt>. (<tt class="docutils literal">NaN</tt>: not-a-number: elevation models are made with radar
  87. technology and water areas reflect radar, resulting in NaN).</p>
  88. <p>A <strong>useful trick</strong> he used was to introduce a bit of wait time for some expensive
  89. operations to make sure his service wouldn't get flooded with requests. Simply waiting a
  90. few seconds and then popping up a dialog &quot;you're going to download 400MB, y/n?&quot; already
  91. helped.</p>
  92. </div>
  93.  
  94.        ]]>
  95.      </content>
  96.  
  97.    </entry>
  98.    
  99.  <entry>
  100.    <title>Python Leiden (NL) meetup: how to use uv for dependency management - Michiel Beijen</title>
  101.    <link rel="alternate" type="text/html"
  102.          href="http://reinout.vanrees.org/weblog/2025/03/27/2-uv.html" />
  103.      <id>http://reinout.vanrees.org/weblog/2025/03/27/2-uv.html</id>
  104.      <author>
  105.        <name>Reinout van Rees</name>
  106.      </author>
  107.      <published>2025-03-27T00:00:00+01:00</published>
  108.      <updated>2025-03-27T21:28:00+01:00</updated>
  109.  
  110.      
  111.      <category term="pun" />
  112.      
  113.      <category term="python" />
  114.      
  115.      <category term="django" />
  116.      
  117.  
  118.      <content type="html"><![CDATA[
  119.        <div class="document">
  120. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2025/03/27/">my summaries</a> of
  121. the second <a class="reference external" href="https://pythonleiden.nl/">Python Leiden (NL) meetup</a> in
  122. Leiden, NL).</p>
  123. <p><a class="reference external" href="https://docs.astral.sh/uv/">uv</a> is the new python packaging solution that everybody
  124. should be using. He demoed it in a standard demo django wagtail project that still
  125. had a <tt class="docutils literal">requirements.txt</tt>. Creating a virtualenv and doing a <tt class="docutils literal">pip install</tt> worked,
  126. but it took a bit of time.</p>
  127. <p>Next, he tried the venv/pip compatibility layer of <tt class="docutils literal">uv</tt>. So <tt class="docutils literal">uv venv</tt> and <tt class="docutils literal">uv pip
  128. install <span class="pre">-r</span> requirements.txt</tt>. Oh... <tt class="docutils literal">python <span class="pre">-m</span> venv .venv</tt> took 3 seconds, and <tt class="docutils literal">uv
  129. venv</tt> 0.04 seconds. Wow. The <tt class="docutils literal">uv pip</tt> was also much faster. Wow.</p>
  130. <p>&quot;Faster&quot; is nice in development, but also when running your test in a CI enviroment
  131. (like github actions).</p>
  132. <p><tt class="docutils literal">uv</tt> can also manage your python installations. It downloads a stand-alone python for
  133. you when needed, for instance if you need a version you don't have locally.</p>
  134. <p>Lastly, he added a <tt class="docutils literal">pyproject.toml</tt> and put the dependencies from <tt class="docutils literal">requirements.txt</tt>
  135. into the pyproject.toml instead. Calling <tt class="docutils literal">uv run manage.py</tt> automatically activates
  136. the virtualenv, install everything and run manage.py just like you'd have called
  137. <tt class="docutils literal">python manage.py</tt>.</p>
  138. <p>Installing it in such a way creates an <tt class="docutils literal">uv.lock</tt> file with all the pinned packages
  139. just such as uv downloaded them. The file should be checked in. The dependencies only
  140. say &quot;I want <tt class="docutils literal">whitenoise</tt> and don't care what version&quot;, but the <tt class="docutils literal">uv.lock</tt> tells all
  141. your colleages (or your server..) which version you've installed, keeping everything in
  142. sync.</p>
  143. <p>Dependency scanners also support <tt class="docutils literal">uv.lock</tt>. At least, &quot;renovate&quot; already supports it
  144. and &quot;dependabot&quot; support is underway.</p>
  145. <p>Handy: <tt class="docutils literal">uv tool install <span class="pre">your-tool</span></tt> for installing some tool like &quot;pre-commit&quot; in its
  146. own virtualenv somewhere and make it available globally. <tt class="docutils literal">uvx <span class="pre">your-tool</span></tt> installs the
  147. tool temporarily for just one command. And with <tt class="docutils literal">uv add <span class="pre">--script</span> <span class="pre">your-script.py</span>
  148. <span class="pre">some-dependency</span></tt> you can add dependencies to single-file scripts. Running the script
  149. with <tt class="docutils literal">uv run <span class="pre">your-script.py</span></tt> installs those dependencies for the duration of the
  150. script.</p>
  151. </div>
  152.  
  153.        ]]>
  154.      </content>
  155.  
  156.    </entry>
  157.    
  158.  <entry>
  159.    <title>Python Leiden (NL) meetup: serialisation in Python - John Labelle</title>
  160.    <link rel="alternate" type="text/html"
  161.          href="http://reinout.vanrees.org/weblog/2025/03/27/1-serialisation.html" />
  162.      <id>http://reinout.vanrees.org/weblog/2025/03/27/1-serialisation.html</id>
  163.      <author>
  164.        <name>Reinout van Rees</name>
  165.      </author>
  166.      <published>2025-03-27T00:00:00+01:00</published>
  167.      <updated>2025-03-27T21:06:00+01:00</updated>
  168.  
  169.      
  170.      <category term="pun" />
  171.      
  172.      <category term="python" />
  173.      
  174.  
  175.      <content type="html"><![CDATA[
  176.        <div class="document">
  177. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2025/03/27/">my summaries</a> of
  178. the second <a class="reference external" href="https://pythonleiden.nl/">Python Leiden (NL) meetup</a> in
  179. Leiden, NL).</p>
  180. <p>Nice subtitle for the talk: &quot;python serialisation: this ain't your father's
  181. cruesli&quot;... :-)</p>
  182. <p>He wants to show us how dangerous it is to de-serialize content provided by someone
  183. else. His examples are at <a class="reference external" href="https://github.com/airza/deserialization_labs">https://github.com/airza/deserialization_labs</a></p>
  184. <p>Serialisation: converting a data structure living in memory into data you can store on
  185. disk or send over. Deserialisation is converting it back into a python object. There are
  186. interoperable formats like json and xml. Most languages have their own specific
  187. methods: python has <tt class="docutils literal">pickle</tt>.</p>
  188. <p>Serialising a dict or list is often easy. <tt class="docutils literal"><span class="pre">json.dumps({&quot;some&quot;:</span> <span class="pre">&quot;structure&quot;})</span></tt> But what
  189. if you've got some non-standard data structure like a python object? json serialisation
  190. won't work out of the box. And if you've got huge data structures, json (being
  191. human-readable) is slow and huge.</p>
  192. <p>Pickle stores python objects in some binary format on disk. Fun fact: pickle was added
  193. to python in 1995, json only exists since 2006. I'll paste one of his examples to make
  194. clear how picle works:</p>
  195. <pre class="literal-block">
  196. import pickle
  197. from tsukimi import Tsukimi
  198. cat = Tsukimi(&quot;Fluffy&quot;, &quot;Empty&quot;)
  199. pickle.dump(cat, open(&quot;tsukimi.pickle&quot;, &quot;wb&quot;))
  200. </pre>
  201. <p>Deserialising works like this:</p>
  202. <pre class="literal-block">
  203. import pickle
  204. cat = pickle.load(open('tsukimi.pickle', 'rb'))
  205. print(cat.fur)
  206. print(cat.brain)
  207. </pre>
  208. <p>Pickle just stores the name of the class it needs to re-create plus the contents of the
  209. attributes. So not the methods or so.</p>
  210. <p>Pickle is explained here: <a class="reference external" href="https://docs.python.org/3/library/pickle.html">https://docs.python.org/3/library/pickle.html</a> . It has a nice
  211. warning right at the top: <em>Warning: The pickle module is not secure. Only unpickle data
  212. you trust.</em></p>
  213. <p>Pickle stores all attributes by default, if you don't want that you can define a
  214. special <tt class="docutils literal">__reduce__()</tt> function that specifies just the attributes you want and the
  215. name of the class that can restore them. But... the name of that class is just looked
  216. up, there's no validation. So you can also pass something that's not the name of your
  217. class, but something like <tt class="docutils literal">os.system</tt> which just calls <em>anything</em> on the command
  218. line...:</p>
  219. <pre class="literal-block">
  220. import os
  221. import pickle
  222. class EvilCat:
  223.    def __reduce__(self):
  224.        return os.system, ('export &gt; version.txt',)
  225. evil = EvilTsukimi()
  226. pickle.dump(evil, open(&quot;evil.pickle&quot;, &quot;wb&quot;))
  227. </pre>
  228. <p>If the code that loads this pickle reads the version.txt (as in the exercise that he had
  229. us run), you suddenly see all the server's environ variables.</p>
  230. <p>So: <strong>never</strong> let people give you pickles. Use json for user input. Or protobuf.</p>
  231. <p>Pytorch (a pydata library) uses pickles. They recently started overwriting the
  232. unpickler's functionality, but he showed some ways to get around its &quot;limitations&quot;.</p>
  233. <p>He recommended looking at
  234. <a class="reference external" href="https://github.com/b4rdia/HackTricks/tree/master/generic-methodologies-and-resources/python/bypass-python-sandboxes">https://github.com/b4rdia/HackTricks/tree/master/generic-methodologies-and-resources/python/bypass-python-sandboxes</a></p>
  235. </div>
  236.  
  237.        ]]>
  238.      </content>
  239.  
  240.    </entry>
  241.    
  242.  <entry>
  243.    <title>Python Leiden (NL) meetup: python in applied mathematics - Tobias Datema</title>
  244.    <link rel="alternate" type="text/html"
  245.          href="http://reinout.vanrees.org/weblog/2025/01/27/2-maths-study.html" />
  246.      <id>http://reinout.vanrees.org/weblog/2025/01/27/2-maths-study.html</id>
  247.      <author>
  248.        <name>Reinout van Rees</name>
  249.      </author>
  250.      <published>2025-01-27T00:00:00+01:00</published>
  251.      <updated>2025-01-27T21:14:00+01:00</updated>
  252.  
  253.      
  254.      <category term="pun" />
  255.      
  256.      <category term="python" />
  257.      
  258.  
  259.      <content type="html"><![CDATA[
  260.        <div class="document">
  261. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/tags/pun.html">my summaries</a> of
  262. the first <a class="reference external" href="https://pythonleiden.nl/">Python Leiden (NL) meetup</a> in
  263. Leiden, NL).</p>
  264. <p>Tobias studied <em>applied mathematics</em> at Delft University.</p>
  265. <p>One of the fields he used python for was <strong>graph theory</strong>. A graph consists of points
  266. (&quot;vertices&quot;) connected by lines (&quot;edges&quot;). It is a large field with many real world
  267. projects like social networks and logistics. He showed a demo he made with <a class="reference external" href="https://networkx.org/">networkx</a>, a python library that makes it real easy to do these kinds of
  268. graph calculations.</p>
  269. <p>Graphs need to be shown. He used <a class="reference external" href="https://pyviz.org/">pyviz</a> for that by converting
  270. the networkx graph to the format understood by pyviz.</p>
  271. <p>Another field is <strong>machine learning</strong>. He did an experiment with a simulated
  272. self-driving car. He used a library that handles the basics like &quot;reacting to a closed
  273. line on the road&quot; and &quot;measuring the distance to the dashed line on the road&quot;. The
  274. simulation is shown in a visual form, which makes it funny to look at.</p>
  275. <p>In his study, python was also handy for statistics and numerical analysis.</p>
  276. </div>
  277.  
  278.        ]]>
  279.      </content>
  280.  
  281.    </entry>
  282.    
  283.  <entry>
  284.    <title>Python Leiden (NL) meetup: fawltydeps - Johan Herland</title>
  285.    <link rel="alternate" type="text/html"
  286.          href="http://reinout.vanrees.org/weblog/2025/01/27/1-fawltydeps.html" />
  287.      <id>http://reinout.vanrees.org/weblog/2025/01/27/1-fawltydeps.html</id>
  288.      <author>
  289.        <name>Reinout van Rees</name>
  290.      </author>
  291.      <published>2025-01-27T00:00:00+01:00</published>
  292.      <updated>2025-01-27T21:15:00+01:00</updated>
  293.  
  294.      
  295.      <category term="pun" />
  296.      
  297.      <category term="python" />
  298.      
  299.  
  300.      <content type="html"><![CDATA[
  301.        <div class="document">
  302. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/tags/pun.html">my summaries</a> of
  303. the first <a class="reference external" href="https://pythonleiden.nl/">Python Leiden (NL) meetup</a> in
  304. Leiden, NL).</p>
  305. <p><a class="reference external" href="https://github.com/tweag/FawltyDeps">FawltyDeps</a> is a python dependency
  306. checker. &quot;Finding undeclared and unused dependencies in your notebooks and projects&quot;.</p>
  307. <p><strong>Note by Reinout</strong>: since 2009 I'm one of the maintainers of <a class="reference external" href="https://pypi.org/project/z3c.dependencychecker/">z3c.dependencychecker</a>.... also a python dependency checker
  308. :-) So this talk interested me a lot, as I didn't know yet about fawltydeps.</p>
  309. <p>A big problem in science is the &quot;replication crisis&quot;. Lots of research cannot actually
  310. be reproduced when you try it...  Data science is part of this problem. Reproducing your
  311. jupyter notebook for instance.</p>
  312. <p>Someone looked at 22k+ jupyter notebooks. Only 70% had declared their dependencies, 46%
  313. could actually install the dependencies and <em>only 5%</em> actually could be
  314. run. <tt class="docutils literal">ModuleNotFoundError</tt> and <tt class="docutils literal">ImportError</tt> were the number 1 and 3 in the list of
  315. exceptions!</p>
  316. <p>What is a dependency? For instance &quot;numpy&quot;, if you have a <tt class="docutils literal">import numpy as np</tt> in your
  317. file. Numpy isn't in the python standard library, you have to install it first.</p>
  318. <p>You can specify dependencies in <tt class="docutils literal">setup.py</tt>, <tt class="docutils literal">pyproject.toml</tt>, <tt class="docutils literal">requirements.txt</tt>
  319. and so. If you import something and don't specify it, it is an &quot;undeclared
  320. dependency&quot;. When you later on remove an import and don't adjust your
  321. <tt class="docutils literal">requirements.txt</tt>, you have an &quot;unused dependency&quot;. That's not immediately fatal, but
  322. it might take up unnecessary space.</p>
  323. <p>FawltyDeps was started to help with this problem: find undeclared and unused
  324. dependencies. It reports them. You can ask for a more detailed report with line numbers
  325. where the dependencies were found.</p>
  326. <p>FawltyDeps supports most dependency declaration locations. requirements.txt, setup.py,
  327. pyproject, conda, etc. And it works with plain python files, notebooks, most python
  328. versions and most OSs. You can configure it on the commandline and in config
  329. files. There's even a handy command to add an example config to your <tt class="docutils literal">pyproject.toml</tt>.</p>
  330. <p>Handy: you can add it as a pre-commit hook (<a class="reference external" href="https://pre-commit.com">https://pre-commit.com</a>). And: there's a
  331. <a class="reference external" href="https://github.com/tweag/FawltyDeps-action">ready-made github action</a> for it,
  332. including good reporting.</p>
  333. <p>Fawltydeps has to deal with several corner cases:</p>
  334. <ul class="simple">
  335. <li>Package names that don't match what you import. <tt class="docutils literal">import sklearn</tt> and the dependency
  336. <tt class="docutils literal"><span class="pre">scikit-learn</span></tt>.</li>
  337. <li>Or <tt class="docutils literal">setuptools</tt> that provides both <tt class="docutils literal">setuptools</tt> and <tt class="docutils literal">pkg_resources</tt>.</li>
  338. <li>For this it looks at various locations for installed packages to help figure out those
  339. mappings. It helps if you've installed FawltyDeps in your project's virtualenv.</li>
  340. <li>You can add your own custom mappings in your configuration to help FawltyDeps.</li>
  341. <li>You can exclude directories.</li>
  342. <li>There's a default list of &quot;tool&quot; packages that FawltyDeps doesn't complain about if
  343. you include them as dependency without importing them. Ruff, black, isort: those kinds
  344. of tools.</li>
  345. <li>Django projects can have dependencies that aren't actually imported. You can ignore
  346. those in the config to prevent them to be imported.</li>
  347. <li>At the moment, extra dependencies (like <tt class="docutils literal">[test]</tt> or <tt class="docutils literal">[dev]</tt> dependencies) are just
  348. handled as part of the whole set of dependencies.</li>
  349. </ul>
  350. </div>
  351.  
  352.        ]]>
  353.      </content>
  354.  
  355.    </entry>
  356.    
  357.  <entry>
  358.    <title>New upcoming Dutch python meetup: Leiden (NL)</title>
  359.    <link rel="alternate" type="text/html"
  360.          href="http://reinout.vanrees.org/weblog/2025/01/16/python-leiden.html" />
  361.      <id>http://reinout.vanrees.org/weblog/2025/01/16/python-leiden.html</id>
  362.      <author>
  363.        <name>Reinout van Rees</name>
  364.      </author>
  365.      <published>2025-01-16T00:00:00+01:00</published>
  366.      <updated>2025-01-16T11:05:00+01:00</updated>
  367.  
  368.      
  369.      <category term="python" />
  370.      
  371.      <category term="django" />
  372.      
  373.      <category term="pun" />
  374.      
  375.  
  376.      <content type="html"><![CDATA[
  377.        <div class="document">
  378. <p>Important things first: 27 January there's a <a class="reference external" href="https://www.meetup.com/python-leiden-user-group/events/305358713/">python meetup in Leiden (NL)</a> of the <strong>new</strong>
  379. <a class="reference external" href="https://pythonleiden.nl/">python Leiden user group</a>.</p>
  380. <p>Meetup groups come and go, often depending on one or two people or on a company that
  381. organises it. And yes, meetup.com has basically cornered the market, at least in my
  382. experience.</p>
  383. <p>There used to be a &quot;PUN&quot;, python usergroup Nederland, meeting that would be held in
  384. various cities, depending on the company that hosted it in turn. (For those in NL: Den
  385. Haag, Zoetermeer, Rotterdam, Utrecht, Veenendaal, Arnhem, Amsterdam, ...). Managed via a
  386. mailinglist, as meetup.com didn't exist yet. Later lots of python and/or django
  387. <em>meetup.com</em>-based-meetups were organised. To me, it felt a bit weird that all of them
  388. seemed to be <em>city-oriented</em>. Amsterdam python meetup (3 different ones), Amsterdam
  389. django meetup, Utrecht (2x), Eindhoven, Rotterdam. I went to many of them, mostly it is
  390. just an hour of travel by public transport :-)</p>
  391. <p>I like going to those meetups. You get a <strong>feel</strong> for what people are doing with
  392. python. You get ideas. You learn about libaries (sometimes even from the standard
  393. library) that you didn't know about. New python tricks. For me, it is a great method to
  394. keep up-to-date on what's possible and on what people are enthousiastic about.</p>
  395. <p>At the moment, the number of python meetups in the Netherlands seems a bit low. Perhaps
  396. I'm missing something? (I see there's a pydata one in Amsterdam that I missed.) The last
  397. two I attended were the nice <a class="reference external" href="https://www.meetup.com/nl-nl/pyutrecht/">PyUtrecht</a>
  398. ones. So: I'll be attending the Leiden one :-)</p>
  399. <p>(Note: I'm talking about meetups, we're blessed with two one-day python conferences in the
  400. Netherlands. <a class="reference external" href="https://pygrunn.org/">pygrunn</a> in May and <a class="reference external" href="https://pycon-nl.org/">pycon NL</a> in October.)</p>
  401. </div>
  402.  
  403.        ]]>
  404.      </content>
  405.  
  406.    </entry>
  407.    
  408.  <entry>
  409.    <title>Pycon NL: The zen of polymorphism - Brett Slatkin</title>
  410.    <link rel="alternate" type="text/html"
  411.          href="http://reinout.vanrees.org/weblog/2024/10/10/9_-polymorphism.html" />
  412.      <id>http://reinout.vanrees.org/weblog/2024/10/10/9_-polymorphism.html</id>
  413.      <author>
  414.        <name>Reinout van Rees</name>
  415.      </author>
  416.      <published>2024-10-10T00:00:00+01:00</published>
  417.      <updated>2024-10-10T14:50:00+01:00</updated>
  418.  
  419.      
  420.      <category term="pycon" />
  421.      
  422.      <category term="python" />
  423.      
  424.  
  425.      <content type="html"><![CDATA[
  426.        <div class="document">
  427. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2024/10/10/index.html">my summaries</a> of
  428. the one-day <a class="reference external" href="https://pycon-nl.org/">Pycon NL</a> conference in
  429. Utrecht, NL).</p>
  430. <p>Brett is the writer of the <a class="reference external" href="https://effectivepython.com/">effective python</a> book.</p>
  431. <p>As an example, he picked a calculator that can add and multiply integers. The numbers,
  432. the operators: everything is an object in his example. You can do it with one big
  433. function, object oriented or with dynamic dispatch.</p>
  434. <p>One <strong>big function</strong>: just a big old recursive function with a lot of if/else. Just
  435. something to get started. Once you add more operators (&quot;power of&quot;, &quot;square root&quot;), the
  436. if/else quickly gets out of hand and becomes much to long and unreadable.</p>
  437. <p>And lets say you don't only want to do the calculation, but you only want to have a
  438. nicely printed version of the calculation. Suddenly your only choice is to copy/paste
  439. the entire big function and change the calculation to print statements. And then you
  440. need to keep the two in sync...</p>
  441. <p>Second try: <strong>object oriented programming</strong>. Polymorphism. A generic <tt class="docutils literal">Operator</tt> class
  442. with a <tt class="docutils literal">calculate()</tt> method. Then subclasses called <tt class="docutils literal">Add</tt>, <tt class="docutils literal">Multiply</tt>, etc.</p>
  443. <p>Python does a magical thing: you can just call <tt class="docutils literal">calculate()</tt> on whatever
  444. operator. Python handles part of the if/else for you. It calls the right calculate
  445. method. That's one of the nice things about OO programming.</p>
  446. <p>Also nice: adding the printing functionality means adding a print method on the various
  447. classes. The rest of the code can remain the same. Nice.</p>
  448. <p>But... it is easy to imagine that the objects grow and grow and grow. Instead of a &quot;god
  449. function&quot; you get a &quot;god object&quot; with tens of methods... An object does a lot of things,
  450. so the one object probably needs multiple libraries. If all the formatting-related code
  451. would have been in one file, only that file would have needed the formatting
  452. library. With OO code, you tend to have a file per object, so every file needs every
  453. library and functionality is split over multiple files.</p>
  454. <p>OO advantages: behavior next to data, easy to add more methods, avoids dispatching
  455. duplication. Drawbacks: behaviour spread over classes, scattered dependencies,
  456. dispatching is magical.</p>
  457. <p><strong>Dynamic dispatching</strong>. Python has <tt class="docutils literal">from functools import singledispatch</tt>, since a
  458. long time. It isn't widely known. Only one person at the conference had used it in
  459. anger! You can use it like this:</p>
  460. <pre class="literal-block">
  461. &#64;singledispatch
  462. def my_print(value):
  463.    print(&quot;not implemented&quot;)
  464.  
  465. &#64;my_print.register(int)
  466. def _(value):
  467.    print(f&quot;Integer: {value}&quot;)
  468.  
  469. &#64;my_print.register(str)
  470. ...
  471. </pre>
  472. <p>So... you can have a function with multiple implementations for specific types. You can
  473. have pretty dumb classes (dataclasses?) and register a <tt class="docutils literal">calculate()</tt> method for each
  474. type. That way similar behavior can be kept together in the same file.</p>
  475. <p>So... you get a lot of the benefits of OO programming without lots of the drawbacks.</p>
  476. <p>Dynamic dispatch advantages: simple classes, functionality is grouped, isolated
  477. dependencies, code organized on correct axis. Downsides: data and behavior separate,
  478. less encapsulation, a bit more friction when adding new classes. When you add a class,
  479. you have to remember which functions you need to add in which files.</p>
  480. <p>Another drawback is that the functions tend to poke around a bit in the objects in a way
  481. that's not really clean, but... we're using python so objects aren't as sacrosanct as in
  482. other languages and we're dependent upon our own good behavior anyway :-)</p>
  483. <p>His summary:</p>
  484. <ul class="simple">
  485. <li>One big function: fine to start, but quickly deteriorates.</li>
  486. <li>OO: good when classes share behaviurs and when larger systems are strongly
  487. interconnected.</li>
  488. <li>Dynamic dispatch: good when data types are shared, but larger systems are indipendent.</li>
  489. <li>Mixing OO and dynamic dispatch: good when both <em>cohesion in the small</em> and <em>system
  490. decoupling in the large</em> are needed.</li>
  491. </ul>
  492. </div>
  493.  
  494.        ]]>
  495.      </content>
  496.  
  497.    </entry>
  498.    
  499.  <entry>
  500.    <title>Pycon NL: From state machines to event-sourced systems - Lukáš Ševčík</title>
  501.    <link rel="alternate" type="text/html"
  502.          href="http://reinout.vanrees.org/weblog/2024/10/10/9-fintech.html" />
  503.      <id>http://reinout.vanrees.org/weblog/2024/10/10/9-fintech.html</id>
  504.      <author>
  505.        <name>Reinout van Rees</name>
  506.      </author>
  507.      <published>2024-10-10T00:00:00+01:00</published>
  508.      <updated>2024-10-10T13:49:00+01:00</updated>
  509.  
  510.      
  511.      <category term="pycon" />
  512.      
  513.      <category term="python" />
  514.      
  515.  
  516.      <content type="html"><![CDATA[
  517.        <div class="document">
  518. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2024/10/10/index.html">my summaries</a> of
  519. the one-day <a class="reference external" href="https://pycon-nl.org/">Pycon NL</a> conference in
  520. Utrecht, NL).</p>
  521. <p>Full title: <em>Events in fintech: from state machines to event-sourced systems</em>.</p>
  522. <p>He works at kiwi.com, a payment processor. They recently refactored their systems to be
  523. more event-based.</p>
  524. <p>Previously, they used state machines. A payment/customer/whatever can be in several
  525. well-defined states. Between states (but not necessarily between all states) there are
  526. transitions.</p>
  527. <p>Advantages of state machines: they're simple. Easy to understand. They're
  528. efficient. Easy to test: just states and transitions.</p>
  529. <p>Disadvantages: there's no inherent history. That's sometimes bad, as it is hard to
  530. answer &quot;why is my payment in this state?!?&quot; There's also lack of context. And changing a
  531. state machine can be hard.</p>
  532. <p>Some problems they encountered: race conditions. Two states are started for the same
  533. account. One gets a +15, the other a -20. As the states don't know about each other, the
  534. resulting account balance can be incorrect.</p>
  535. <p>Now on to <strong>events</strong>. Event sourcing / event driven architecture is what he called
  536. it. You start with a command &quot;withdraw money, amount = 15&quot;. This gets placed in a queue
  537. and gets processed. The processing results in another event &quot;15 has been removed&quot; that
  538. gets send to the database.</p>
  539. <p>Events are <strong>immutable facts</strong> about things that have happened in the system. They are
  540. always in the past tense and include all relevant data. And: avoid internal implemention
  541. details if possible.</p>
  542. <p>&quot;Event sourcing&quot;: you can re-construct the current state of the system by looking at all
  543. the events. The current state has a source: the accumulation of all events. Great for
  544. having a complete audit trail. You can also reconstruct past states (&quot;you have
  545. programmatic access to the past&quot; :-) ). You also have the possibility to actually solve
  546. race conditions that occurred.</p>
  547. <p>If you have the time, you can even go towards the <a class="reference external" href="https://martinfowler.com/bliki/CQRS.html">CQRS</a> pattern (command query responsibility
  548. segregation).</p>
  549. <p>There are <strong>challenges</strong> of event sourcing. Eventual consistency: if you encounter a
  550. problem, you can fix it. But the fix changes history, so the system is &quot;eventual
  551. consistent&quot;, not &quot;really really always consistent&quot;.  Also: there are higher storage
  552. requirements. Complexity also is higher.</p>
  553. <p>The challenges have possible solutions. The &quot;saga pattern&quot; has start and end events. You
  554. could also try some locking mechanism. An &quot;optimistic concurrency control&quot;. Not always
  555. possible, but handy: &quot;idempotent events&quot;, events that you can apply a couple of times
  556. after each other without doing any harm.</p>
  557. </div>
  558.  
  559.        ]]>
  560.      </content>
  561.  
  562.    </entry>
  563.    
  564.  <entry>
  565.    <title>Pycon NL: Using PyPI trusted publishing for ansible releases - Anwesha Das</title>
  566.    <link rel="alternate" type="text/html"
  567.          href="http://reinout.vanrees.org/weblog/2024/10/10/8-pypi-trusted-publishing.html" />
  568.      <id>http://reinout.vanrees.org/weblog/2024/10/10/8-pypi-trusted-publishing.html</id>
  569.      <author>
  570.        <name>Reinout van Rees</name>
  571.      </author>
  572.      <published>2024-10-10T00:00:00+01:00</published>
  573.      <updated>2024-10-10T13:14:00+01:00</updated>
  574.  
  575.      
  576.      <category term="pycon" />
  577.      
  578.      <category term="python" />
  579.      
  580.  
  581.      <content type="html"><![CDATA[
  582.        <div class="document">
  583. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2024/10/10/index.html">my summaries</a> of
  584. the one-day <a class="reference external" href="https://pycon-nl.org/">Pycon NL</a> conference in
  585. Utrecht, NL).</p>
  586. <p>Using software is easy, releasing software is harder.</p>
  587. <p>Originally trained as a laywer, she wondered why software had to be released so
  588. often. As a lawyer, she had to work with laws sometimes already written in 1860 :-)
  589. Nowadays she is the release manager of ansible.</p>
  590. <p>Ansible is ansible-core in combination with 95+ different python modules called
  591. collections.</p>
  592. <p>Originally, releasing to the python package index, pypi, wasn't really safe. Every
  593. person doing the release needed some <tt class="docutils literal">__token__</tt> in their <tt class="docutils literal"><span class="pre">~/.pypirc</span></tt>. This can be
  594. compromised. And the token can be overscoped. And... can you be sure that every person
  595. doing the release is doing it in a safe way? That the person's laptop is secure enough?</p>
  596. <p>Pypi now allows you to use <strong>trusted publishing</strong>. OIDC, &quot;openID connect&quot;, is used
  597. behind the scenes to connect pypi to github/gitlab/etc. It is a way to create
  598. short-lived tokens to upload to pypi from a github/gitlab job.</p>
  599. <p>A specific github repository and specific github action within that repository is set up
  600. as &quot;trusted&quot; by one of the maintainers of the project on pypi. The github action will,
  601. when uploading, use the OIDC mechanism to request a short-lived access token from
  602. pypi. It then uses the token to upload the release to pypi.</p>
  603. <p>(<strong>Personal note</strong>: I'm using it myself for a couple of projects and it works like a
  604. charm).</p>
  605. <p>Ansible's own release github action is here:
  606. <a class="reference external" href="https://github.com/ansible-community/ansible-build-data/blob/main/.github/workflows/ansible-release.yml">https://github.com/ansible-community/ansible-build-data/blob/main/.github/workflows/ansible-release.yml</a></p>
  607. </div>
  608.  
  609.        ]]>
  610.      </content>
  611.  
  612.    </entry>
  613.    
  614.  <entry>
  615.    <title>Pycon NL: Strategies for avoiding package.json for fullstack python devs - Donatas Rasiukevicius</title>
  616.    <link rel="alternate" type="text/html"
  617.          href="http://reinout.vanrees.org/weblog/2024/10/10/7-fullstack-python-package-json.html" />
  618.      <id>http://reinout.vanrees.org/weblog/2024/10/10/7-fullstack-python-package-json.html</id>
  619.      <author>
  620.        <name>Reinout van Rees</name>
  621.      </author>
  622.      <published>2024-10-10T00:00:00+01:00</published>
  623.      <updated>2024-10-10T12:31:00+01:00</updated>
  624.  
  625.      
  626.      <category term="pycon" />
  627.      
  628.      <category term="python" />
  629.      
  630.      <category term="django" />
  631.      
  632.  
  633.      <content type="html"><![CDATA[
  634.        <div class="document">
  635. <p>(One of <a class="reference external" href="https://reinout.vanrees.org/weblog/2024/10/10/index.html">my summaries</a> of
  636. the one-day <a class="reference external" href="https://pycon-nl.org/">Pycon NL</a> conference in
  637. Utrecht, NL).</p>
  638. <p>In 2024, what is a fullstack python dev? Well, python. Database
  639. administrator. Integrator with external services. A bit of terraform or kubernetes. AWS
  640. clicky-clicky expert. And a bit of frontend.</p>
  641. <p>So the frontend is only a small part of your job. You have a <tt class="docutils literal">package.json</tt> that makes
  642. no sense to you, so you just <tt class="docutils literal">npm install</tt> it and download the <em>entire</em> internet into
  643. your local <tt class="docutils literal">node_modules/</tt> folder. But somehow it seems to work.</p>
  644. <p>The frontend? You have frameworks. More frameworks. Meta-frameworks that framework your
  645. frameworks. Frameworks don't make things simpler, they just move the complexity
  646. somewhere else. If you use django's ORM, you don't have to deal with the complexity of
  647. SQL. But in exchange you have to learn the django ORM.</p>
  648. <p>He wants to look at three layers:</p>
  649. <ul class="simple">
  650. <li>Markup / html.</li>
  651. <li>Styling / css / design systems.</li>
  652. <li>Interactivity / javascript.</li>
  653. </ul>
  654. <p><strong>Markup and html</strong>. On one hand you can have bindings. &quot;Fasthtml&quot;, for instance. A
  655. mapping from python to html. <tt class="docutils literal">return <span class="pre">Div(H1(&quot;hurray&quot;))</span></tt>. You just move the complexity.</p>
  656. <p>Or &quot;native web components&quot;. You have custom <tt class="docutils literal"><span class="pre">&lt;star-rating&gt;</span></tt> elements that get
  657. translated into actual html. You need specific javascript code for this, so it isn't
  658. really portable between frameworks.</p>
  659. <p>Another alternative: templating. <tt class="docutils literal">Jinja2</tt> is used in most programming languages. You
  660. can do some templating, but it quickly gets unreadable.</p>
  661. <p>All these solutions are great in their own way, but also suck in their own way.</p>
  662. <p><strong>Styling/css</strong>. This is an area that actually saw a lot of improvements in the last
  663. years! CSS now supports variables out of the box, so no need for &quot;sass&quot; or so anymore.</p>
  664. <p>You used to use bootstrap, jquery and a few other things and try to style your divs and
  665. spans. You don't need to do that anymore: there is more than just span and div
  666. nowadays. <strong>Classless</strong>: you use html's new elements such as <tt class="docutils literal">&lt;article&gt;</tt> and get
  667. something not-too-bad out of the box. You don't use custom class statemens anymore.</p>
  668. <p>CSS has its own utility frameworks now, like tailwind. He dislikes tailwind (just use a
  669. style on your element...). For the rest, css seems in pretty good shape.</p>
  670. <p><strong>Interactivity/javascript</strong>. Javascript <em>used</em> to be essential for things like hovers
  671. and tooltips. But: that's build into html/css now! No need for javascript for this.</p>
  672. <p>You could look at web assembly. <a class="reference external" href="https://pyscript.net/">https://pyscript.net/</a> for running python in the
  673. browser. Nice. But you need to know both the internal browser API and the webassembly
  674. bindings and get python to run... He looks at this field about once every half year to
  675. see if it is ready for normal use.</p>
  676. <p>HTMX could be nice. <a class="reference external" href="https://htmx.org/">https://htmx.org/</a> . Interactivity for your html page with
  677. auto-replacing of certain parts of the page without you needing to do javascript. It is
  678. pretty popular, but he found lots of the functionality pretty hard to use. After two
  679. years, he found out he used only one part of it most of the time. So he wrote some small
  680. javascript thingy to do just one simple kind of replacement.</p>
  681. <p>Interactivity: most of it sucks.</p>
  682. <p><strong>Summary</strong>: there is no one silver bullet for your project. In many cases you're going
  683. to benefit from building something yourself. So: if there's no silver bullet, just
  684. produce a lot of regular bullets. Small custom self-made one-offs.</p>
  685. </div>
  686.  
  687.        ]]>
  688.      </content>
  689.  
  690.    </entry>
  691.    
  692.  
  693. </feed>

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 Atom 1.0" 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=http%3A//reinout.vanrees.org/weblog/atom.xml

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