<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Avil Page (Posts about python)</title><link>https://avilpage.com/</link><description></description><atom:link href="https://avilpage.com/tags/python.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Tue, 03 Feb 2026 03:33:53 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Python UV in 100 seconds</title><link>https://avilpage.com/2025/04/learn-python-uv-in-100-seconds.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;UV is a fast Python package manager that replaces tools like pip, pyenv, virtualenv, etc.&lt;/p&gt;
&lt;h4&gt;Install uv&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# On macOS and Linux.&lt;/span&gt;
curl&lt;span class="w"&gt; &lt;/span&gt;-LsSf&lt;span class="w"&gt; &lt;/span&gt;https://astral.sh/uv/install.sh&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sh
&lt;span class="c1"&gt;# On Windows.&lt;/span&gt;
powershell&lt;span class="w"&gt; &lt;/span&gt;-ExecutionPolicy&lt;span class="w"&gt; &lt;/span&gt;ByPass&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"irm https://astral.sh/uv/install.ps1 | iex"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Installing Python&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;uv&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;list

uv&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.13
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This makes it easy to install and manage multiple versions of Python on your system without needing of &lt;code&gt;pyenv&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Using UV with existing requirements.txt&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;uv&lt;span class="w"&gt; &lt;/span&gt;venv&lt;span class="w"&gt; &lt;/span&gt;--seed&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.13

&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;.venv/bin/activate

uv&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;requirements.txt
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is way faster than using any other tool to create virtual environments.&lt;/p&gt;
&lt;h4&gt;Managing virtual environments&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;uv&lt;span class="w"&gt; &lt;/span&gt;init&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.13&lt;span class="w"&gt; &lt;/span&gt;--name&lt;span class="w"&gt; &lt;/span&gt;demo

uv&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;pandas
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This creates a new virtual environment named &lt;code&gt;demo&lt;/code&gt; with Python 3.13 and adds the &lt;code&gt;pandas&lt;/code&gt; package to it.&lt;/p&gt;
&lt;h4&gt;Runs scripts with inline dependencies&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# /// script&lt;/span&gt;
&lt;span class="c1"&gt;# requires-python = "&amp;gt;=3.13"&lt;/span&gt;
&lt;span class="c1"&gt;# dependencies = [&lt;/span&gt;
&lt;span class="c1"&gt;#     "requests",&lt;/span&gt;
&lt;span class="c1"&gt;# ]&lt;/span&gt;
&lt;span class="c1"&gt;# ///&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;requests&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"https://avilpage.com"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;uv&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;script.py
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;uvx&lt;/h4&gt;
&lt;p&gt;Similar to &lt;code&gt;pipx&lt;/code&gt;, it can install and run Python applications in isolated environments.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;uv&lt;span class="w"&gt; &lt;/span&gt;tool&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;glances

uv&lt;span class="w"&gt; &lt;/span&gt;tool&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;glances

&lt;span class="c1"&gt;# shortcut&lt;/span&gt;
uvx&lt;span class="w"&gt; &lt;/span&gt;glances
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;UV speeds up Python development by providing a fast package manager, virtual environment management, and inline dependency management. It is a great alternative to traditional tools like pip, pyenv, and virtualenv.&lt;/p&gt;</description><category>python</category><category>uv</category><guid>https://avilpage.com/2025/04/learn-python-uv-in-100-seconds.html</guid><pubDate>Wed, 30 Apr 2025 17:46:24 GMT</pubDate></item><item><title>macOS - Log &amp; track historical CPU, RAM usage</title><link>https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-grafana.png"&gt;&lt;/p&gt;
&lt;p&gt;In macOS, we can use inbuilt &lt;code&gt;Activity Monitor&lt;/code&gt; or third party apps like &lt;code&gt;Stats&lt;/code&gt; to check the live CPU/RAM usage. But, we can't track the historical CPU &amp;amp; memory usage. &lt;code&gt;sar&lt;/code&gt;, &lt;code&gt;atop&lt;/code&gt; can track the historical CPU &amp;amp; memory usage. But, they are not available for macOS.&lt;/p&gt;
&lt;h4&gt;Netdata&lt;/h4&gt;
&lt;p&gt;Netdata&lt;sup id="fnref:Netdata"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:Netdata"&gt;1&lt;/a&gt;&lt;/sup&gt; is an open source observability tool that can monitor CPU, RAM, network, disk usage. It can also track the historical data. &lt;/p&gt;
&lt;p&gt;Unfortunately, it is not stable on macOS. I tried installing it on multiple macbooks, but it didn't work. I raised an issue&lt;sup id="fnref:netdata_issue"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:netdata_issue"&gt;2&lt;/a&gt;&lt;/sup&gt; on their GitHub repository and the team mentioned that macOS is a low priority for them.&lt;/p&gt;
&lt;h4&gt;Glances&lt;/h4&gt;
&lt;p&gt;Glances&lt;sup id="fnref:Glances"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:Glances"&gt;3&lt;/a&gt;&lt;/sup&gt; is a cross-platform monitoring tool that can monitor CPU, RAM, network, disk usage. It can also track the historical data.&lt;/p&gt;
&lt;p&gt;We can install it using Brew or pip.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;glances

$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;glances
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once it is installed, we can monitor the resource usage using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;glances
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-glances.png"&gt;&lt;/p&gt;
&lt;p&gt;Glances can log historical data to a file using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;glances&lt;span class="w"&gt; &lt;/span&gt;--export-csv&lt;span class="w"&gt; &lt;/span&gt;/tmp/glances.csv
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In addition to that, it can log data to services like influxdb, prometheus, etc.&lt;/p&gt;
&lt;p&gt;Let's install influxdb and export stats to it.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;influxdb
$&lt;span class="w"&gt; &lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;services&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;influxdb
$&lt;span class="w"&gt; &lt;/span&gt;influx&lt;span class="w"&gt; &lt;/span&gt;setup

$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;influxdb-client

$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;glances.conf
&lt;span class="o"&gt;[&lt;/span&gt;influxdb&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost
&lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8086&lt;/span&gt;
&lt;span class="nv"&gt;protocol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http
&lt;span class="nv"&gt;org&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;avilpage
&lt;span class="nv"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;glances
&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret_token

$&lt;span class="w"&gt; &lt;/span&gt;glances&lt;span class="w"&gt; &lt;/span&gt;--export-influxdb&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;glances.conf
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can view stats in the influxdb from Data Explorer web UI at &lt;a href="http://localhost:8086"&gt;http://localhost:8086&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-influxdb.png"&gt;&lt;/p&gt;
&lt;p&gt;Glances provides a prebuilt Grafana dashboard&lt;sup id="fnref:grafana_dashboard"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:grafana_dashboard"&gt;4&lt;/a&gt;&lt;/sup&gt; that we can import to visualize the stats. &lt;/p&gt;
&lt;p&gt;From Grafana -&amp;gt; Dashboard -&amp;gt; Import, we can import the dashboard using the above URL.&lt;/p&gt;
&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-grafana.png"&gt;&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;In addition to InfluxDB, Glances can export data to ~20 services. So far, it is the best tool to log, track and view historical CPU, RAM, network and disk usage in macOS. The same method works for Linux and Windows as well.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:Netdata"&gt;
&lt;p&gt;&lt;a href="https://github.com/netdata/netdata"&gt;https://github.com/netdata/netdata&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:Netdata" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:netdata_issue"&gt;
&lt;p&gt;&lt;a href="https://github.com/netdata/netdata/issues/16696"&gt;https://github.com/netdata/netdata/issues/16696&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:netdata_issue" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:Glances"&gt;
&lt;p&gt;&lt;a href="https://github.com/nicolargo/glances"&gt;https://github.com/niolargo/glances&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:Glances" title="Jump back to footnote 3 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:grafana_dashboard"&gt;
&lt;p&gt;&lt;a href="https://glances.readthedocs.io/en/latest/gw/influxdb.html#grafana"&gt;https://glances.readthedocs.io/en/latest/gw/influxdb.html#grafana&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:grafana_dashboard" title="Jump back to footnote 4 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>devops</category><category>macbook</category><category>python</category><guid>https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html</guid><pubDate>Fri, 31 May 2024 20:18:02 GMT</pubDate></item><item><title>Screen Time Alerts from Activity Watch</title><link>https://avilpage.com/2024/05/screen-time-alerts-from-activity-watch.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;h4&gt;Introduction&lt;/h4&gt;
&lt;div class="embed-responsive embed-responsive-16by9"&gt;
&lt;iframe class="embed-responsive-item" src="https://www.youtube.com/embed/41A0r2H-EXs" allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Activity Watch&lt;sup id="fnref:activity_watch"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/05/screen-time-alerts-from-activity-watch.html#fn:activity_watch"&gt;1&lt;/a&gt;&lt;/sup&gt; is a cross-platform open-source time-tracking tool that helps us to track time spent on applications and websites.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Activity Watch" src="https://avilpage.com/images/activity-watch-alerts.png"&gt;&lt;/p&gt;
&lt;p&gt;At the moment, Activity Watch doesn't have any feature to show screen time alerts. In this post, we will see how to show screen time alerts using Activity Watch.&lt;/p&gt;
&lt;h4&gt;Python Script&lt;/h4&gt;
&lt;p&gt;Activity Watch provides an API to interact with the Activity Watch server. We can use the API to get the screen time data and show alerts.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datetime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;requests&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_nonafk_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeperiods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"Content-type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"charset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"""afk_events = query_bucket(find_bucket('aw-watcher-afk_'));&lt;/span&gt;
&lt;span class="s2"&gt;window_events = query_bucket(find_bucket('aw-watcher-window_'));&lt;/span&gt;
&lt;span class="s2"&gt;window_events = filter_period_intersect(window_events, filter_keyvals(afk_events, 'status', ['not-afk']));&lt;/span&gt;
&lt;span class="s2"&gt;RETURN = merge_events_by_keys(window_events, ['app', 'title']);"""&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"timeperiods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;timeperiods&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;"http://localhost:5600/api/0/query/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;timeperiods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()])&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_nonafk_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeperiods&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;total_time_secs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;total_time_mins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;total_time_secs&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Total time: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total_time_mins&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; seconds"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;divmod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_time_mins&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"Screen Time: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; hours &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; minutes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# show mac notification&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;"osascript -e 'display notification &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; hours &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; minutes&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; with title &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Screen TIme&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This script&lt;sup id="fnref:github"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/05/screen-time-alerts-from-activity-watch.html#fn:github"&gt;2&lt;/a&gt;&lt;/sup&gt; will show the screen time alerts using the Activity Watch API. We can run this script using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;screen_time_alerts.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="Screen Time Alerts" src="https://avilpage.com/images/activity-watch-alerts2.png"&gt;&lt;/p&gt;
&lt;p&gt;We can set up a cron job to run this script every hour to show screen time alerts.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;crontab&lt;span class="w"&gt; &lt;/span&gt;-e
&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;screen_time_alerts.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can also modify the script to show alerts only when the screen time exceeds a certain limit.&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Since Actvity Watch is open-source and provides an API, we can extend its functionality to show screen time alerts. We can also use the API to create custom reports and dashboards.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:activity_watch"&gt;
&lt;p&gt;&lt;a href="https://activitywatch.net/"&gt;Activity Watch&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/05/screen-time-alerts-from-activity-watch.html#fnref:activity_watch" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:github"&gt;
&lt;p&gt;&lt;a href="https://github.com/ChillarAnand/avilpage.com/blob/master/scripts/activity_watch_alerts.py"&gt;Screen Time Alerts Script&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/05/screen-time-alerts-from-activity-watch.html#fnref:github" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>productivity</category><category>python</category><guid>https://avilpage.com/2024/05/screen-time-alerts-from-activity-watch.html</guid><pubDate>Wed, 01 May 2024 01:29:27 GMT</pubDate></item><item><title>Setup FTP server on Mac OS X</title><link>https://avilpage.com/2024/04/how-to-setup-ftp-server-on-mac-os.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;div class="embed-responsive embed-responsive-16by9"&gt;
&lt;iframe class="embed-responsive-item" src="https://www.youtube.com/embed/WmmB-6MXRYc" allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;On Linux &amp;amp; Mac OS X, Python comes pre-installed. On Windows, we can install it from Windows store or from &lt;a href="https://python.org"&gt;https://python.org&lt;/a&gt; website.&lt;/p&gt;
&lt;p&gt;We can verify the Python version using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;--version
Python&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.11.6
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can use the &lt;code&gt;pyftpdlib&lt;/code&gt; library to create an FTP server. We can install the library using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;pyftpdlib
&lt;span class="o"&gt;[&lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;:28:21&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;concurrency&lt;span class="w"&gt; &lt;/span&gt;model:&lt;span class="w"&gt; &lt;/span&gt;async
&lt;span class="o"&gt;[&lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;:28:21&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;masquerade&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;NAT&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;address:&lt;span class="w"&gt; &lt;/span&gt;None
&lt;span class="o"&gt;[&lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;:28:21&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;passive&lt;span class="w"&gt; &lt;/span&gt;ports:&lt;span class="w"&gt; &lt;/span&gt;None
&lt;span class="o"&gt;[&lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;:28:21&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;starting&lt;span class="w"&gt; &lt;/span&gt;FTP&lt;span class="w"&gt; &lt;/span&gt;server&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;:::2121,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;99951&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we can start the FTP server using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pyftpdlib
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It will start the FTP server on port 2121. We can connect to the FTP server using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;ftp&lt;span class="w"&gt; &lt;/span&gt;localhost&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2121&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><category>ftp</category><category>macbook</category><category>python</category><guid>https://avilpage.com/2024/04/how-to-setup-ftp-server-on-mac-os.html</guid><pubDate>Tue, 30 Apr 2024 18:04:14 GMT</pubDate></item><item><title>Cross Platform File Explorer in 50 lines of code</title><link>https://avilpage.com/2024/01/cross-platform-file-explorer-in-50-lines-of-code.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;In an earlier post, I wrote about why I need a &lt;a href="https://avilpage.com/2023/11/add-column-for-row-count-in-file-manager.html"&gt;"line count" column in file explorer&lt;/a&gt; and how I wrote a Lua script to see it in xplr file manager.&lt;/p&gt;
&lt;p&gt;xplr has only terminal interface. It is hard for non-developers to use it. I wanted a small team to use this feature so that it will save several hours of their time. So I decided to write a cross-platform GUI app.&lt;/p&gt;
&lt;h4&gt;GUI app&lt;/h4&gt;
&lt;p&gt;Since I am familiar with PySimpleGUI, I decided to write a simple file explorer using it. &lt;/p&gt;
&lt;p&gt;&lt;img alt="Cross Platform File Explorer" src="https://avilpage.com/images/lc_file_explorer.png"&gt;&lt;/p&gt;
&lt;p&gt;As seen in the above screenshot, the file explorer has a "Line Count" column. It is a simple Python script with ~50 lines of code. &lt;/p&gt;
&lt;p&gt;The project is open source and source code is available at &lt;a href="https://github.com/avilpage/lcfileexplorer"&gt;github.com/AvilPage/LCFileExplorer&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Cross Platform&lt;/h4&gt;
&lt;p&gt;A new user can't directly run this Python script on his machine unless Python is already installed. Even if Python is installed, he has to install the required packages and run it. This requires technical expertise.&lt;/p&gt;
&lt;p&gt;To make it easy for non-tech users to run this program, I decided to use &lt;a href="https://www.pyinstaller.org/"&gt;PyInstaller&lt;/a&gt; to create a single executable file for each platform.&lt;/p&gt;
&lt;p&gt;I created a GitHub action to build the executable files for Windows, Linux, and macOS. The action is triggered on every push to the master branch. This will generate &lt;code&gt;.exe&lt;/code&gt; file for Windows, &lt;code&gt;.AppImage&lt;/code&gt; file for Linux, and &lt;code&gt;.dmg&lt;/code&gt; file for macOS. The executable files are uploaded to the artifacts.&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;It is easy to create a cross-platform GUI app using Python and PySimpleGUI. It is also easy to distribute the apps built with Python using pyinstaller.&lt;/p&gt;</description><category>automation</category><category>python</category><guid>https://avilpage.com/2024/01/cross-platform-file-explorer-in-50-lines-of-code.html</guid><pubDate>Sat, 27 Jan 2024 12:29:05 GMT</pubDate></item><item><title>Running tests in parallel with pytest &amp; xdist</title><link>https://avilpage.com/2023/12/coverage-reports-with-pytest-xdist.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;When tests are taking too long to run, an easy way to speed them up is to run them in parallel.&lt;/p&gt;
&lt;p&gt;When using &lt;code&gt;pytest&lt;/code&gt; as test runner, &lt;code&gt;pytest-xdist&lt;/code&gt; &amp;amp; &lt;code&gt;pytest-parallel&lt;/code&gt; plugins makes it easy to run tests concurrently or in parallel.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pytest-parallel&lt;/code&gt; works better if tests are independent of each other. If tests are dependent on each other, &lt;code&gt;pytest-xdist&lt;/code&gt; is a better choice.&lt;/p&gt;
&lt;p&gt;If there are parameterised tests, pytest-xdist will fail as the order of the tests is not guaranteed.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;pytest&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;auto&lt;span class="w"&gt; &lt;/span&gt;tests/

Different&lt;span class="w"&gt; &lt;/span&gt;tests&lt;span class="w"&gt; &lt;/span&gt;were&lt;span class="w"&gt; &lt;/span&gt;collected&lt;span class="w"&gt; &lt;/span&gt;between&lt;span class="w"&gt; &lt;/span&gt;gw0&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;gw1.&lt;span class="w"&gt; &lt;/span&gt;The&lt;span class="w"&gt; &lt;/span&gt;difference&lt;span class="w"&gt; &lt;/span&gt;is:&lt;span class="w"&gt; &lt;/span&gt;...
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To fix this, we have to make sure that the parameterised tests are executed in the same order on all workers. It can be achieved by sorting the parameterised tests by their name.&lt;/p&gt;
&lt;p&gt;Alternatively, we can use &lt;code&gt;pytest-randomly&lt;/code&gt; plugin to order the tests.&lt;/p&gt;</description><category>python</category><category>testing</category><guid>https://avilpage.com/2023/12/coverage-reports-with-pytest-xdist.html</guid><pubDate>Sat, 30 Dec 2023 14:46:31 GMT</pubDate></item><item><title>Rearrange CSV columns alphabetically from CLI</title><link>https://avilpage.com/2023/08/rearrange-csv-columns-alphabetically-cli.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;We can use tools like KDiff3 to compare two CSV files. But, it is difficult to identify the diff when the columns are not in the same order.&lt;/p&gt;
&lt;p&gt;For example, look at the below output of 2 simple csv files.&lt;/p&gt;
&lt;p&gt;&lt;img alt="kdiff3-csv-compare" src="https://avilpage.com/images/kdiff3-csv-compare.png"&gt;&lt;/p&gt;
&lt;p&gt;Even though it highlights the diff, it is difficult to identify the diff because the columns are not in the same order. Here is the same diff after rearranging the columns alphabetically.&lt;/p&gt;
&lt;p&gt;&lt;img alt="kdiff3-csv-compare-sorted" src="https://avilpage.com/images/kdiff3-csv-compare-sorted.png"&gt;&lt;/p&gt;
&lt;p&gt;Now, it is easy to identify the diff.&lt;/p&gt;
&lt;h4&gt;Rearrange CSV columns alphabetically&lt;/h4&gt;
&lt;p&gt;We can write a simple python script using Pandas&lt;sup id="fnref:pandas"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/08/rearrange-csv-columns-alphabetically-cli.html#fn:pandas"&gt;1&lt;/a&gt;&lt;/sup&gt; as follows.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="ch"&gt;#! /usr/bin/env python3&lt;/span&gt;

&lt;span class="sd"&gt;"""&lt;/span&gt;
&lt;span class="sd"&gt;re-arrange columns in alphabetical order&lt;/span&gt;
&lt;span class="sd"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sys&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pandas&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pd&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;colsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;input_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;IndexError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;output_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input_file&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;colsort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'__main__'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can use this script as follows.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;python3&lt;span class="w"&gt; &lt;/span&gt;rearrange_csv_columns.py&lt;span class="w"&gt; &lt;/span&gt;input.csv&lt;span class="w"&gt; &lt;/span&gt;output.csv
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Instead of writing a script by ourselves, we can use &lt;code&gt;miller&lt;/code&gt;&lt;sup id="fnref:miller"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/08/rearrange-csv-columns-alphabetically-cli.html#fn:miller"&gt;2&lt;/a&gt;&lt;/sup&gt; tool. Miller can perform various operations on CSV files. We can use &lt;code&gt;sort-within-records&lt;/code&gt; to sort the columns.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;mlr&lt;span class="w"&gt; &lt;/span&gt;--csv&lt;span class="w"&gt; &lt;/span&gt;sort-within-records&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;input.csv&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.csv
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;We can use &lt;code&gt;miller&lt;/code&gt; to sort the columns in a CSV file. This will help us to identify the diff easily when comparing two CSV files.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:pandas"&gt;
&lt;p&gt;&lt;a href="https://pandas.pydata.org/"&gt;https://pandas.pydata.org/&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/08/rearrange-csv-columns-alphabetically-cli.html#fnref:pandas" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:miller"&gt;
&lt;p&gt;&lt;a href="https://github.com/johnkerl/miller"&gt;https://github.com/johnkerl/miller&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/08/rearrange-csv-columns-alphabetically-cli.html#fnref:miller" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>command-line</category><category>python</category><guid>https://avilpage.com/2023/08/rearrange-csv-columns-alphabetically-cli.html</guid><pubDate>Fri, 04 Aug 2023 01:49:54 GMT</pubDate></item><item><title>Train LLMs with Custom Dataset on Laptop</title><link>https://avilpage.com/2023/07/train-llm-custom-data-laptop.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;h4&gt;Problem Statement&lt;/h4&gt;
&lt;p&gt;I want to train a Large Language Model(LLM)&lt;sup id="fnref:LLM"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fn:LLM"&gt;1&lt;/a&gt;&lt;/sup&gt; with some private documents and query various details.&lt;/p&gt;
&lt;h4&gt;Journey&lt;/h4&gt;
&lt;p&gt;There are open-source available LLMs like Vicuna, LLaMa, etc which can be trained on custom data. However, training these models on custom data is not a trivial task.&lt;/p&gt;
&lt;p&gt;After trying out various methods, I ended up using privateGPT&lt;sup id="fnref:privateGPT"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fn:privateGPT"&gt;2&lt;/a&gt;&lt;/sup&gt; which is quite easy to train on custom documents. There is no need to format or clean up the data as privateGPT can directly consume documents in many formats like txt, html, epub, pdf, etc.&lt;/p&gt;
&lt;h4&gt;Training&lt;/h4&gt;
&lt;p&gt;First, let's clone the repo, install requirements.txt and download the default model.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/imartinez/privateGPT
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;privateGPT
$&lt;span class="w"&gt; &lt;/span&gt;pip3&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;requirements.txt
$&lt;span class="w"&gt; &lt;/span&gt;wget&lt;span class="w"&gt; &lt;/span&gt;https://gpt4all.io/models/ggml-gpt4all-j-v1.3-groovy.bin

$&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;example.env&lt;span class="w"&gt; &lt;/span&gt;.env
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;.env
&lt;span class="nv"&gt;MODEL_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;GPT4All
&lt;span class="nv"&gt;MODEL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ggml-gpt4all-j-v1.3-groovy.bin
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I have sourced all documents and kept them in a folder called &lt;code&gt;docs&lt;/code&gt;. Let's ingest(train) the data.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;~/docs/*&lt;span class="w"&gt; &lt;/span&gt;source_documents

$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;ingest.py
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will take a while depending on the number of documents we have. Once the ingestion is done, we can start querying the model.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;privateGPT.py
Enter&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;query:&lt;span class="w"&gt; &lt;/span&gt;Summarise&lt;span class="w"&gt; &lt;/span&gt;about&lt;span class="w"&gt; &lt;/span&gt;Gaaliveedu
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The default &lt;code&gt;GPT4All-J v1.3-groovy&lt;/code&gt;&lt;sup id="fnref:gpt4all"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fn:gpt4all"&gt;3&lt;/a&gt;&lt;/sup&gt; model doesn't provide good results. We can easily swap it with &lt;code&gt;LlamaCpp&lt;/code&gt;&lt;sup id="fnref:llama.cpp"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fn:llama.cpp"&gt;4&lt;/a&gt;&lt;/sup&gt;. Lets download the model and convert it.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://huggingface.co/openlm-research/open_llama_13b

$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/ggerganov/llama.cpp.git
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;llama.cpp
$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;convert.py&lt;span class="w"&gt; &lt;/span&gt;../open_llama_13b
Wrote&lt;span class="w"&gt; &lt;/span&gt;../open_llama_13b/ggml-model-f16.bin
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can now update the &lt;code&gt;.env&lt;/code&gt; file to use the new model and start querying again.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;.env
&lt;span class="nv"&gt;MODEL_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LlamaCpp
&lt;span class="nv"&gt;MODEL_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/to/ggml-model-f16.bin

$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;privateGPT.py
Enter&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;query:&lt;span class="w"&gt; &lt;/span&gt;Summarise&lt;span class="w"&gt; &lt;/span&gt;about&lt;span class="w"&gt; &lt;/span&gt;Gaaliveedu
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;This makes it easy to build domain-specific LLMs and use them for various tasks. I have used this to build a chatbot for my internal docs and it is working well.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:LLM"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Large_language_model"&gt;https://en.wikipedia.org/wiki/Large_language_model&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fnref:LLM" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:privateGPT"&gt;
&lt;p&gt;&lt;a href="https://github.com/imartinez/privateGPT"&gt;https://github.com/imartinez/privateGPT&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fnref:privateGPT" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:gpt4all"&gt;
&lt;p&gt;&lt;a href="https://github.com/nomic-ai/gpt4all"&gt;https://github.com/nomic-ai/gpt4all&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fnref:gpt4all" title="Jump back to footnote 3 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:llama.cpp"&gt;
&lt;p&gt;&lt;a href="https://github.com/ggerganov/llama.cpp"&gt;https://github.com/ggerganov/llama.cpp&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/07/train-llm-custom-data-laptop.html#fnref:llama.cpp" title="Jump back to footnote 4 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>artificial-intelligence</category><category>python</category><guid>https://avilpage.com/2023/07/train-llm-custom-data-laptop.html</guid><pubDate>Thu, 06 Jul 2023 23:06:42 GMT</pubDate></item><item><title>Remote Debug Docker Container with PyCharm</title><link>https://avilpage.com/2023/06/pycharm-debug-python-app-in-docker.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;h4&gt;Problem Statement&lt;/h4&gt;
&lt;p&gt;How to debug a Python application running inside a Docker container that is launched by a third-party process using PyCharm?&lt;/p&gt;
&lt;h4&gt;Solution&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Install the &lt;code&gt;pydevd-pycharm&lt;/code&gt; package in the Docker image.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'pydevd-pycharm~=222.4554.11'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Add the following lines to the Python script that you want to debug.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pydevd_pycharm&lt;/span&gt;
&lt;span class="n"&gt;pydevd_pycharm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;settrace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'host.docker.internal'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdoutToServer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stderrToServer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Create a new Python Remote Debug configuration in PyCharm with the following settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="PyCharm Remote Debug Configuration" src="https://avilpage.com/images/pycharm-docker-debug.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Run the Remote Debug configuration in PyCharm.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the Docker container with the following command or let a shell script or another package run the container.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;flask_web
$&lt;span class="w"&gt; &lt;/span&gt;docker&lt;span class="w"&gt; &lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;--rm&lt;span class="w"&gt; &lt;/span&gt;flask_web
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Explanation&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;pydevd-pycharm&lt;/code&gt; package is a Python debugger that can be used to debug a Python application running inside a Docker container. The &lt;code&gt;pydevd_pycharm.settrace()&lt;/code&gt; function is used to connect the debugger to the PyCharm IDE. The &lt;code&gt;host.docker.internal&lt;/code&gt; is the hostname of the host machine from inside the Docker container. The &lt;code&gt;port&lt;/code&gt; is the port number that is used to connect to the PyCharm IDE. The &lt;code&gt;stdoutToServer&lt;/code&gt; and &lt;code&gt;stderrToServer&lt;/code&gt; are used to redirect the standard output and standard error to the PyCharm IDE.&lt;/p&gt;
&lt;h4&gt;Gotchas&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;You might face the following error depending on the version of the &lt;code&gt;pydevd-pycharm&lt;/code&gt; package.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;Traceback&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;most&lt;span class="w"&gt; &lt;/span&gt;recent&lt;span class="w"&gt; &lt;/span&gt;call&lt;span class="w"&gt; &lt;/span&gt;last&lt;span class="o"&gt;)&lt;/span&gt;:
&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/lib/python3.10/site-packages/flask/cli.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;218&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;locate_app
&lt;span class="w"&gt;    &lt;/span&gt;__import__&lt;span class="o"&gt;(&lt;/span&gt;module_name&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/app/app.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;module&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;import&lt;span class="w"&gt; &lt;/span&gt;pydevd_pycharm
&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/lib/python3.10/site-packages/pydevd_pycharm.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;module&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;pydevd&lt;span class="w"&gt; &lt;/span&gt;import&lt;span class="w"&gt; &lt;/span&gt;settrace
&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/lib/python3.10/site-packages/pydevd.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;41&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;module&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;_pydevd_bundle&lt;span class="w"&gt; &lt;/span&gt;import&lt;span class="w"&gt; &lt;/span&gt;pydevd_utils
&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/lib/python3.10/site-packages/_pydevd_bundle/pydevd_utils.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;module&amp;gt;
&lt;span class="w"&gt;    &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;_pydevd_asyncio_util.pydevd_asyncio_utils&lt;span class="w"&gt; &lt;/span&gt;import&lt;span class="w"&gt; &lt;/span&gt;eval_async_expression_in_context
ModuleNotFoundError:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;module&lt;span class="w"&gt; &lt;/span&gt;named&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'_pydevd_asyncio_util'&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There seems to be an issue with all 223.*.* versions. The solution is to use the 222.*.* version.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You might face &lt;code&gt;ConnectionRefused&lt;/code&gt; error when running the docker container.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/lib/python3.10/site-packages/pydevd.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1758&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;_locked_settrace
&lt;span class="w"&gt;    &lt;/span&gt;debugger.connect&lt;span class="o"&gt;(&lt;/span&gt;host,&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Note: connect can raise error.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/lib/python3.10/site-packages/pydevd.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;660&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;connect
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;start_client&lt;span class="o"&gt;(&lt;/span&gt;host,&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/local/lib/python3.10/site-packages/_pydevd_bundle/pydevd_comm.py"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;463&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;start_client
&lt;span class="w"&gt;    &lt;/span&gt;s.connect&lt;span class="o"&gt;((&lt;/span&gt;host,&lt;span class="w"&gt; &lt;/span&gt;port&lt;span class="o"&gt;))&lt;/span&gt;
ConnectionRefusedError:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;Errno&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;111&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Connection&lt;span class="w"&gt; &lt;/span&gt;refused
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ensure that you have started the Remote Debug configuration in PyCharm before running the docker container.&lt;/p&gt;</description><category>debugging</category><category>docker</category><category>python</category><guid>https://avilpage.com/2023/06/pycharm-debug-python-app-in-docker.html</guid><pubDate>Sun, 11 Jun 2023 15:36:04 GMT</pubDate></item><item><title>Reducing System Load With ChatGPT</title><link>https://avilpage.com/2023/04/reduce-system-load-with-chatgpt.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;h4&gt;Problem Statement&lt;/h4&gt;
&lt;p&gt;I am using M1 Macbook Air for Python development purposes. Since M1 uses ARM architecture, many Python packages don't have wheels for ARM64/aarch64. confluent-kafka-python is one of them. &lt;/p&gt;
&lt;p&gt;I had to run AMD64 docker container to use confluent-kafka-python. Since it is a cross-architecture container, its CPU usage is too high and performance was too slow.  &lt;/p&gt;
&lt;h4&gt;Solution&lt;/h4&gt;
&lt;p&gt;To reduce system load, I decided to build aarch64 wheels for confluent-kafka-python. I looked at open issues on GitHub and asked maintainers how to build aarch64 wheels. There was no response&lt;sup id="fnref:librdkafka"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/04/reduce-system-load-with-chatgpt.html#fn:librdkafka"&gt;1&lt;/a&gt;&lt;/sup&gt; from them.&lt;/p&gt;
&lt;p&gt;As a workaround, I asked ChatGPT&lt;sup id="fnref:chatgpt"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2023/04/reduce-system-load-with-chatgpt.html#fn:chatgpt"&gt;2&lt;/a&gt;&lt;/sup&gt; on how to build confluent-kafka-python aarch64 wheels in a docker container.&lt;/p&gt;
&lt;p align="center"&gt;
&lt;img src="https://avilpage.com/images/chatgpt-reduce-system-load.png" alt="chatgpt-reduce-system-load"&gt;
&lt;/p&gt;

&lt;p&gt;This initial suggestion didn't work as &lt;code&gt;confluent-kafka-python&lt;/code&gt; depends on &lt;code&gt;librdkafka&lt;/code&gt; which is a C library. I had to build &lt;code&gt;librdkafka&lt;/code&gt; from source for aarch64 and then build &lt;code&gt;confluent-kafka-python&lt;/code&gt; from source.&lt;/p&gt;
&lt;p&gt;To build &lt;code&gt;librdkafka&lt;/code&gt; from the source, I again asked ChatGPT. After making minor changes to the snippet suggested by ChatGPT, I was able to build &lt;code&gt;librdkafka&lt;/code&gt; from the source for aarch64.&lt;/p&gt;
&lt;p&gt;Here is the final snippet:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ubuntu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;22.04&lt;/span&gt;

&lt;span class="n"&gt;ARG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DEBIAN_FRONTEND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;noninteractive&lt;/span&gt;

&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;postgresql&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;nano&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;less&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mime&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;openjdk&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;jre&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;headless&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;\
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;libpq&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tzdata&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;

&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setuptools&lt;/span&gt;

&lt;span class="n"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;confluentinc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;confluent&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;
&lt;span class="n"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;confluent&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;

&lt;span class="n"&gt;COPY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="n"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;configure&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;arch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;aarch64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;

&lt;span class="n"&gt;WORKDIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;confluent&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;
&lt;span class="n"&gt;RUN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;By running native containers, I was able to reduce the system load by ~50%. With ChatGPT, it is easy to build/tweak programs in languages &amp;amp; environments that we are not familiar with.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:librdkafka"&gt;
&lt;p&gt;&lt;a href="https://github.com/confluentinc/librdkafka/issues/3546#issuecomment-1340237177"&gt;https://github.com/confluentinc/librdkafka/3546&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/04/reduce-system-load-with-chatgpt.html#fnref:librdkafka" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:chatgpt"&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/ChatGPT"&gt;https://en.wikipedia.org/wiki/ChatGPT&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2023/04/reduce-system-load-with-chatgpt.html#fnref:chatgpt" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>artificial-intelligence</category><category>docker</category><category>macbook</category><category>python</category><guid>https://avilpage.com/2023/04/reduce-system-load-with-chatgpt.html</guid><pubDate>Sat, 01 Apr 2023 02:25:49 GMT</pubDate></item></channel></rss>