{"title":"axju - python","link":[{"@attributes":{"href":"https:\/\/axju.de\/","rel":"alternate"}},{"@attributes":{"href":"https:\/\/axju.de\/feeds\/python.atom.xml","rel":"self"}}],"id":"https:\/\/axju.de\/","updated":"2021-04-26T20:15:00+02:00","subtitle":"Just coding stuff","entry":[{"title":"importlib.metadata","link":{"@attributes":{"href":"https:\/\/axju.de\/posts\/2021\/04\/importlibmetadata\/","rel":"alternate"}},"published":"2021-04-26T20:15:00+02:00","updated":"2021-04-26T20:15:00+02:00","author":{"name":"Axel Juraske"},"id":"tag:axju.de,2021-04-26:\/posts\/2021\/04\/importlibmetadata\/","summary":"<p class=\"first last\">I didn't notice that pkg_resources was replaced by importlib.metadata from the standard library<\/p>\n","content":"<p>Module <a class=\"reference external\" href=\"https:\/\/docs.python.org\/3\/library\/importlib.metadata.html\">importlib.metadata<\/a> has been around since Python version 3.8. And that make <strong>pkg_resources<\/strong> some kind of deprecated.\nI personally uses <strong>pkg_resources<\/strong> on two places and didn't realize that it was out of date.<\/p>\n<ol class=\"arabic simple\">\n<li>To load some entry point, if I build a pluggable package.<\/li>\n<li>Get the version number at runtime, if I uses setuptools-scm.<\/li>\n<\/ol>\n<p>Maybe in different places, but these two pop up in my head first.\nThere is also a <a class=\"reference external\" href=\"https:\/\/pypi.org\/project\/importlib-metadata\/\">package<\/a> that supplies backports of functionality for Python version smaller then 3.8<\/p>\n<div class=\"section\" id=\"load-entry-points\">\n<h2>Load entry points<\/h2>\n<p>The Python setup script provides entry points where objects can be assigned.\nIn your main package, you can search for specific entry points and load them.\nOther package can also defined this entry point, so your main package will load them too.\nIf you are interesting, I make a <a class=\"reference external\" href=\"https:\/\/youtu.be\/Po5JaNVgo-M\">small video<\/a>. Unfortunately, this video uses the old <strong>pkg_resources<\/strong> module.<\/p>\n<p>With <strong>importlib.metadata<\/strong>, the new one:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"kn\">from<\/span> <span class=\"nn\">importlib.metadata<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">entry_points<\/span>\n<span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"k\">for<\/span> <span class=\"n\">enp<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">entry_points<\/span><span class=\"p\">()[<\/span><span class=\"s1\">&#39;axju.commands&#39;<\/span><span class=\"p\">]:<\/span>\n<span class=\"o\">...<\/span>   <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">enp<\/span><span class=\"o\">.<\/span><span class=\"n\">name<\/span><span class=\"p\">)<\/span>\n<span class=\"o\">...<\/span>\n<span class=\"n\">django<\/span>\n<span class=\"n\">info<\/span>\n<span class=\"n\">show<\/span>\n<\/pre><\/div>\n<p>The old one with <strong>pkg_resources<\/strong>:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"kn\">from<\/span> <span class=\"nn\">pkg_resources<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">iter_entry_points<\/span>\n<span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"k\">for<\/span> <span class=\"n\">enp<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">iter_entry_points<\/span><span class=\"p\">(<\/span><span class=\"n\">group<\/span><span class=\"o\">=<\/span><span class=\"s1\">&#39;axju.commands&#39;<\/span><span class=\"p\">):<\/span>\n<span class=\"o\">...<\/span>   <span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">enp<\/span><span class=\"o\">.<\/span><span class=\"n\">name<\/span><span class=\"p\">)<\/span>\n<span class=\"o\">...<\/span>\n<span class=\"n\">django<\/span>\n<span class=\"n\">info<\/span>\n<span class=\"n\">show<\/span>\n<\/pre><\/div>\n<\/div>\n<div class=\"section\" id=\"retrieving-package-version-at-run-time\">\n<h2>Retrieving package version at run time<\/h2>\n<p>You can find this example on the readme file from <strong>setuptools-scm<\/strong>.<\/p>\n<p>This is how you should do it, with <strong>importlib.metadata<\/strong>:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kn\">from<\/span> <span class=\"nn\">importlib.metadata<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">version<\/span><span class=\"p\">,<\/span> <span class=\"n\">PackageNotFoundError<\/span>\n\n<span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">__version__<\/span> <span class=\"o\">=<\/span> <span class=\"n\">version<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;package-name&quot;<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">except<\/span> <span class=\"n\">PackageNotFoundError<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">__version__<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Unknown&#39;<\/span>\n<\/pre><\/div>\n<p>And you'd better avoid that:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kn\">from<\/span> <span class=\"nn\">pkg_resources<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">get_distribution<\/span><span class=\"p\">,<\/span> <span class=\"n\">DistributionNotFound<\/span>\n\n<span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">__version__<\/span> <span class=\"o\">=<\/span> <span class=\"n\">get_distribution<\/span><span class=\"p\">(<\/span><span class=\"s2\">&quot;package-name&quot;<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">version<\/span>\n<span class=\"k\">except<\/span> <span class=\"n\">DistributionNotFound<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">__version__<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;Unknown&#39;<\/span>\n<\/pre><\/div>\n<p>However, this does place a runtime dependency on <strong>setuptools<\/strong> and can add up\nto a few 100ms overhead for the package import time.<\/p>\n<\/div>\n<div class=\"section\" id=\"conclusion\">\n<h2>Conclusion<\/h2>\n<p>As you can see, these are not major changes to the source code.\nSo the problem are not the adjustments, but the fact you should read the release note.\nShame on me, I don't read them very often. I only came across this while researching for my video. But even then I did get it after the video it was published.<\/p>\n<p>The biggest source for my video was the <a class=\"reference external\" href=\"https:\/\/amir.rachum.com\/blog\/2017\/07\/28\/python-entry-points\/\">post<\/a> from Amir Rachum's Blog, which was written before the release of version 3.8. That's why he still used <strong>pkg_resources<\/strong>.<\/p>\n<div class=\"section\" id=\"memo-to-myself-read-the-release-note\">\n<h3>Memo to myself, read the release note<\/h3>\n<\/div>\n<\/div>\n","category":[{"@attributes":{"term":"python"}},{"@attributes":{"term":"python"}}]},{"title":"Python Pathlib","link":{"@attributes":{"href":"https:\/\/axju.de\/posts\/2021\/01\/python-pathlib\/","rel":"alternate"}},"published":"2021-01-29T20:15:00+01:00","updated":"2021-01-29T20:15:00+01:00","author":{"name":"Axel Juraske"},"id":"tag:axju.de,2021-01-29:\/posts\/2021\/01\/python-pathlib\/","summary":"<p class=\"first last\">I know the Pathlib is nothing new, but I only discovered in the new django default settings.<\/p>\n","content":"<p>For a long time I ignore pathlib, but then came new django release with this in\nthe default settings.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kn\">from<\/span> <span class=\"nn\">pathlib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Path<\/span>\n\n<span class=\"c1\"># Build paths inside the project like this: BASE_DIR \/ &#39;subdir&#39;.<\/span>\n<span class=\"n\">BASE_DIR<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Path<\/span><span class=\"p\">(<\/span><span class=\"vm\">__file__<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">resolve<\/span><span class=\"p\">()<\/span><span class=\"o\">.<\/span><span class=\"n\">parent<\/span><span class=\"o\">.<\/span><span class=\"n\">parent<\/span>\n<\/pre><\/div>\n<p>I researched and found these links very helpful:<\/p>\n<blockquote>\n<ul class=\"simple\">\n<li><a class=\"reference external\" href=\"https:\/\/realpython.com\/python-pathlib\/\">Real Python<\/a><\/li>\n<li><a class=\"reference external\" href=\"https:\/\/pbpython.com\/pathlib-intro.html\">Practical Business Python<\/a><\/li>\n<li><a class=\"reference external\" href=\"https:\/\/docs.python.org\/3\/library\/pathlib.html\">Python Docs<\/a><\/li>\n<\/ul>\n<\/blockquote>\n<p>For more information check this out. I don't want to explain it in detail, just\ngive an example.<\/p>\n<div class=\"section\" id=\"everything-is-an-object\">\n<h2>Everything is an object<\/h2>\n<p>The old days I uses the os.path module to work with paths. To check if a file\nexist I run this:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"kn\">import<\/span> <span class=\"nn\">os<\/span>\n<span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">path<\/span> <span class=\"o\">=<\/span> <span class=\"s1\">&#39;pyth\/to\/my\/file&#39;<\/span>\n<span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">path<\/span><span class=\"o\">.<\/span><span class=\"n\">isfile<\/span><span class=\"p\">(<\/span><span class=\"n\">path<\/span><span class=\"p\">)<\/span>\n<span class=\"kc\">False<\/span>\n<\/pre><\/div>\n<p>There the path is a string. With the <em>new<\/em> pathlib module, you can creates a\npath object with some nice functions.<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"kn\">import<\/span> <span class=\"nn\">pathlib<\/span>\n<span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">path<\/span> <span class=\"o\">=<\/span> <span class=\"n\">pathlib<\/span><span class=\"o\">.<\/span><span class=\"n\">Path<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;path\/to\/my\/file&#39;<\/span><span class=\"p\">)<\/span>\n<span class=\"o\">&gt;&gt;&gt;<\/span> <span class=\"n\">path<\/span><span class=\"o\">.<\/span><span class=\"n\">exists<\/span><span class=\"p\">()<\/span>\n<span class=\"kc\">False<\/span>\n<\/pre><\/div>\n<p>The path object has more than just the function <em>exist()<\/em>. You can do everything\nsimilar to the os.path module and more.<\/p>\n<\/div>\n<div class=\"section\" id=\"example\">\n<h2>Example<\/h2>\n<p>This create the folder <em>.axju<\/em> in your home folder and the file <em>data.txt<\/em> with\nthe content <em>hello<\/em>.<\/p>\n<p>With <strong>pathlib<\/strong>:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kn\">from<\/span> <span class=\"nn\">pathlib<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Path<\/span>\n\n<span class=\"n\">data_file<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Path<\/span><span class=\"o\">.<\/span><span class=\"n\">home<\/span><span class=\"p\">()<\/span> <span class=\"o\">\/<\/span> <span class=\"s1\">&#39;.axju&#39;<\/span> <span class=\"o\">\/<\/span> <span class=\"s1\">&#39;data.txt&#39;<\/span>\n<span class=\"n\">data_file<\/span><span class=\"o\">.<\/span><span class=\"n\">parent<\/span><span class=\"o\">.<\/span><span class=\"n\">mkdir<\/span><span class=\"p\">(<\/span><span class=\"n\">parents<\/span><span class=\"o\">=<\/span><span class=\"kc\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">exist_ok<\/span><span class=\"o\">=<\/span><span class=\"kc\">True<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">with<\/span> <span class=\"n\">data_File<\/span><span class=\"o\">.<\/span><span class=\"n\">open<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;w&#39;<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">file<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">file<\/span><span class=\"o\">.<\/span><span class=\"n\">write<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;hello&#39;<\/span><span class=\"p\">)<\/span>\n<\/pre><\/div>\n<p>With <strong>os.path<\/strong>:<\/p>\n<div class=\"highlight\"><pre><span><\/span><span class=\"kn\">import<\/span> <span class=\"nn\">os<\/span>\n\n<span class=\"n\">home<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">path<\/span><span class=\"o\">.<\/span><span class=\"n\">expanduser<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;~&#39;<\/span><span class=\"p\">)<\/span>\n<span class=\"n\">home_axju_dir<\/span> <span class=\"o\">=<\/span> <span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">path<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"n\">home<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;.axju&#39;<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">if<\/span> <span class=\"ow\">not<\/span> <span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">path<\/span><span class=\"o\">.<\/span><span class=\"n\">exists<\/span><span class=\"p\">(<\/span><span class=\"n\">home_axju_dir<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">makedirs<\/span><span class=\"p\">(<\/span><span class=\"n\">home_axju_dir<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">with<\/span> <span class=\"nb\">open<\/span><span class=\"p\">(<\/span><span class=\"n\">os<\/span><span class=\"o\">.<\/span><span class=\"n\">path<\/span><span class=\"o\">.<\/span><span class=\"n\">join<\/span><span class=\"p\">(<\/span><span class=\"n\">home_axju_dir<\/span><span class=\"p\">,<\/span> <span class=\"s1\">&#39;data.txt&#39;<\/span><span class=\"p\">),<\/span> <span class=\"s1\">&#39;w&#39;<\/span><span class=\"p\">)<\/span> <span class=\"k\">as<\/span> <span class=\"n\">file<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">file<\/span><span class=\"o\">.<\/span><span class=\"n\">write<\/span><span class=\"p\">(<\/span><span class=\"s1\">&#39;hello&#39;<\/span><span class=\"p\">)<\/span>\n<\/pre><\/div>\n<\/div>\n","category":[{"@attributes":{"term":"python"}},{"@attributes":{"term":"python"}}]}]}