<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Thuwarakesh Murallie</title>
    <description>The latest articles on DEV Community by Thuwarakesh Murallie (@thuwarakesh).</description>
    <link>https://dev.to/thuwarakesh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F704949%2F6b36d4ca-3f80-4692-a332-adeeb7dc1cfc.png</url>
      <title>DEV Community: Thuwarakesh Murallie</title>
      <link>https://dev.to/thuwarakesh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thuwarakesh"/>
    <language>en</language>
    <item>
      <title>How to Work With Large Pandas Dataframes and Limited Memory.</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Fri, 20 Jan 2023 02:36:48 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/how-to-work-with-large-pandas-dataframes-and-limited-memory-3p5</link>
      <guid>https://dev.to/thuwarakesh/how-to-work-with-large-pandas-dataframes-and-limited-memory-3p5</guid>
      <description>&lt;p&gt;Few Pandas users take advantage of this amazing tweak. &lt;/p&gt;

&lt;p&gt;The default configuration when you read a dataframe is suitable for smaller datasets. But for larger datasets, you'd soon need more memory. &lt;/p&gt;

&lt;p&gt;This post describes compressing your dataframes to fit in your memory without losing any information. Do this and tap into the full potential of your computer. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/a-little-pandas-hack-to-handle-large-datasets-with-limited-memory-6745140f473b?sk=9f87fec31134b3ff35ad0f51c3657104" rel="noopener noreferrer"&gt;A Little Pandas Hack to Handle Large Datasets with Limited Memory&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devmeme</category>
      <category>discuss</category>
      <category>productivity</category>
      <category>learning</category>
    </item>
    <item>
      <title>GitHub Actions + Black = Automatically Clean Python Code</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Tue, 17 Jan 2023 02:22:23 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/github-actions-black-automatically-clean-python-code-29k3</link>
      <guid>https://dev.to/thuwarakesh/github-actions-black-automatically-clean-python-code-29k3</guid>
      <description>&lt;p&gt;A codebase that is easy to understand and navigate allows programmers to work more efficiently and effectively. Thi sis why having a clean and well-formatted codebase is crucial for the success of programmers.  Yet, ensuring that every team member follows a common standard can be difficult, which is where GitHub Actions comes in.&lt;/p&gt;

&lt;p&gt;GitHub Actions is a powerful tool. And you can use it to automatically format code whenever changes are made to a repository. By configuring Black and other formatting libraries in GitHub Actions, you can ensure that your codebase is always consistent and easy to read. Additionally, if any formatting tasks fail, you can set up email notifications to alert you of the issue.&lt;/p&gt;

&lt;p&gt;This post provides a step-by-step guide on how to set up automated code formatting in GitHub Actions, so you never have to worry about poorly formatted code being committed by team members again. &lt;/p&gt;

&lt;p&gt;If you're a Python dev, I'm sure you'll use this on a daily basis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/black-with-git-hub-actions-4ffc5c61b5fe?sk=715088977804f6e316e2594d2dc345d7" rel="noopener noreferrer"&gt;Maintain Clean Python Code With Black and GitHub Actions&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Are No-Code Platforms a Threat to Developers?</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Sat, 19 Nov 2022 11:41:52 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/are-no-code-platforms-a-threat-to-developers-pdb</link>
      <guid>https://dev.to/thuwarakesh/are-no-code-platforms-a-threat-to-developers-pdb</guid>
      <description>&lt;p&gt;The world is simplified. The work of developers is to be.&lt;/p&gt;

&lt;p&gt;Ever since we started using machines, there has been programming. The algorithm for the Analytical Engine is considered the &lt;a href="https://www.hp.com/us-en/shop/tech-takes/computer-history-programming-languages" rel="noopener noreferrer"&gt;first computer programming language&lt;/a&gt;. The English mathematician &lt;a href="https://en.wikipedia.org/wiki/Ada_Lovelace" rel="noopener noreferrer"&gt;Ada Lovelace&lt;/a&gt; created it in 1883 for &lt;a href="https://en.wikipedia.org/wiki/Charles_Babbage" rel="noopener noreferrer"&gt;Charles Babbage&lt;/a&gt;'s mechanical &lt;a href="https://www.computerhope.com/jargon/g/general-purpose-computer.htm" rel="noopener noreferrer"&gt;general-purpose computer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After several evolutionary steps, modern programming languages such as &lt;a href="https://www.python.org/" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, &lt;a href="https://www.javascript.com/" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt;, and &lt;a href="https://www.java.com/en/" rel="noopener noreferrer"&gt;Java&lt;/a&gt; rose in popularity in the early nineties. These languages are &lt;a href="https://www.geeksforgeeks.org/difference-between-high-level-and-low-level-languages/" rel="noopener noreferrer"&gt;high-level programming languages&lt;/a&gt;. Meaning it's very close to our human languages, but computers can still understand them.&lt;/p&gt;

&lt;p&gt;And it never stopped there. The next leap in programming is visual programming/no-code development.&lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://www.the-analytics.club/become-a-data-scientist-or-data-engineer-without-coding-skills" rel="noopener noreferrer"&gt;&lt;em&gt;How to Become a Terrific Data Scientist (+Engineer) Without Coding&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visual programming lets users create graphical elements to build application logic. Several no-code online platforms offer this, and there's hope that this will be the primary mode of programming in the future.&lt;/p&gt;

&lt;p&gt;Today you can find visual programming tools for almost any need. You have &lt;a href="https://powerapps.microsoft.com/en-us/" rel="noopener noreferrer"&gt;Microsoft Power App&lt;/a&gt;s for general software development. If you need to develop data science apps, &lt;a href="https://www.knime.com/" rel="noopener noreferrer"&gt;KNIME&lt;/a&gt; is an excellent choice.&lt;/p&gt;

&lt;p&gt;Beyond visual programming, you have no-code options for famous use cases. For instance, using &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;terraform&lt;/a&gt;, you can create and manage an entire cloud architecture only with a configuration file. No-code involved.&lt;/p&gt;

&lt;p&gt;Yet, what do they mean to developers of the present and future?&lt;/p&gt;

&lt;p&gt;Will no-code platforms reduce the need for trained developers? Or will developers have a better tool in their toolkit? Let's find out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are no-code platforms?
&lt;/h2&gt;

&lt;p&gt;No-code platforms are a relatively new kind of software allowing users to create complex applications without coding knowledge.&lt;/p&gt;

&lt;p&gt;These platforms typically provide a visual drag-and-drop interface, making them easy to use even for those with no technical background. While no-code platforms were initially designed for simple applications, they have become increasingly influential in recent years and can now support sophisticated workflows and business processes.&lt;/p&gt;

&lt;p&gt;In many cases, no-code platforms can completely replace traditional coding frameworks, making them a popular choice for businesses that want to quickly develop and deploy new applications without incurring the cost and complexity of working with code.&lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://www.the-analytics.club/scalable-no-code-automl-solution-on-your-amazon-cloud" rel="noopener noreferrer"&gt;&lt;em&gt;Scalable, No-Code, AutoML Solution on Your Amazon Cloud&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When do no-code platforms do well over code-based development?
&lt;/h2&gt;

&lt;p&gt;No-code sure lets you build apps and websites without coding knowledge. Yet, there are still many instances where code-based development is the better option.&lt;/p&gt;

&lt;p&gt;As of writing this post, most no-code platforms are suitable for faster prototyping, yet not for production systems.&lt;/p&gt;

&lt;p&gt;When planning the app for the first time, it's essential to visualize your ideas as soon as possible. Of course, you can have some Figma wireframes. But the next step would be to put up a minimum viable product (MVP.)&lt;/p&gt;

&lt;p&gt;At this point, you still don't know if you're application has any potential in the future. You don't want to hire developers to get an MVP. It would only shoot up your initial investment.&lt;/p&gt;

&lt;p&gt;The best way to get users to test your idea is by creating an app using a no-code platform. You'd only be spending a few hours, if not days. Then your users have a working product at hand for testing.&lt;/p&gt;

&lt;p&gt;Some no-code platforms are great for production systems as well. For instance, you can use KNIME to build your pipelines faster when working on data science projects. But KNIME is capable of running production-grade applications as well.&lt;/p&gt;

&lt;p&gt;Therefore the critical factor to consider is the complexity of the project. A no-code platform can likely suffice if you're trying to build something straightforward, such as a basic attendance app. But, if you're looking to create something more complex, such as a custom web app, then code-based development will be necessary to give you the flexibility and control you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawbacks of no-code development
&lt;/h2&gt;

&lt;p&gt;Like anything, no-code development has its pros and cons. Here are five potential drawbacks to keep in mind:&lt;/p&gt;

&lt;p&gt;Lack of Flexibility: No-code development platforms can be inflexible, making it challenging to customize your project to your specific needs. Think about the switching cost. After developing so much, and at some point in the future, when you realize you can't create a new feature that all your competitors have, you have to spend a massive chunk of your budget switching to a different technology.&lt;/p&gt;

&lt;p&gt;Limited Functionality: While no-code development platforms have come a long way, they still offer limited functionality compared to traditional coding languages. You can get the basics for sure. You may even be able to connect it to your other systems. But you still have to wait for a very long time every time a new software concept sets the trend in the industry. That's because you can't develop them for yourself.&lt;/p&gt;

&lt;p&gt;Difficulty scaling: As your project grows, managing everything within a no-code development platform can become challenging. You may not be able to install extra servers and database instances as you'd do in a traditional development environment. And most no-code platforms charge per user. Thus when you scale, the cost becomes massive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Are no-code platforms a threat to programmers?
&lt;/h2&gt;

&lt;p&gt;By now, you'd have guessed that the answer is no. But no code development can replace programmers in the future.&lt;/p&gt;

&lt;p&gt;Even though no-code development platforms help a lot, they are not a direct substitute for more production-grade applications. You can create more scalable, efficient, and cost-effective applications with programming.&lt;/p&gt;

&lt;p&gt;But with the rate of technological growth, this would soon change. In the future, you could directly translate the diagrams from a business meeting to an app. And with minor tweaks, they could become production ready.&lt;/p&gt;

&lt;p&gt;Thus, it's primarily a question of what skillset developers should develop to stay ahead of the curve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills developers need to work with no-code platforms.
&lt;/h2&gt;

&lt;p&gt;No-code platforms have been gaining popularity in recent years, as they offer a way for non-technical users to create custom applications and solutions without writing code. However, working with no-code platforms still requires some technical skills. Here are five skills that developers need to work with no-code media:&lt;/p&gt;

&lt;p&gt;Ability to explain things visually: Programmers do not care much about diagrams. They care about them to understand the concepts but do not explain what we build. Business Analysts usually do this.&lt;/p&gt;

&lt;p&gt;Cloud computing experience: Many no-code platforms are cloud-based, so developers need to have some experience working with cloud services such as &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;Amazon Web Services (AWS)&lt;/a&gt; or &lt;a href="https://azure.microsoft.com/en-us/" rel="noopener noreferrer"&gt;Microsoft Azure&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Negotiation skills: This is another skill that developers long considered not relevant. But they do now. When diagrams become the code, the business team might not understand the challenges. Besides, these challenges are new to the developers too.&lt;/p&gt;

&lt;p&gt;These are not new requirements. Articulating skills and negotiation skills are just as crucial for any job. But they will be more significant as no-code development platforms take over the stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;No code platforms are a leap in the programming evolution. They are going to let everyone create software products with little idea-to-app time.\&lt;br&gt;
Yet, although the initial benefits are high, no-code solutions can be costly to scale up. In some instances, you may not be able to develop the feature you need.\&lt;br&gt;
But a code-based platform gives the flexibility to develop anything you want. Also, you don't have to wait till the no-code platform introduces the feature. You can set it for yourself.\&lt;br&gt;
Thus developers will be in the driving seat for a very long time. But what skills they need is going to be different. As a developer, you might need excellent skills to articulate ideas with diagrams and negotiate with business stakeholders.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>beginners</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Is Your Python For-loop Slow? Use NumPy Instead</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Wed, 28 Sep 2022 00:12:19 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/is-your-python-for-loop-slow-use-numpy-instead-1ba0</link>
      <guid>https://dev.to/thuwarakesh/is-your-python-for-loop-slow-use-numpy-instead-1ba0</guid>
      <description>&lt;p&gt;Speed is always a concern for developers — especially for data-savvy work.&lt;/p&gt;

&lt;p&gt;As developers, the easiest way to scale up things is using a for-loop. But there are drawbacks to using them for large numerical computations. &lt;/p&gt;

&lt;p&gt;This post compares how for-loops perform in such workloads with vectorized alternatives. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/numpy-vectorization-speed-ffdab5deb402?sk=c6f7809aafb6cb4155853ac5d155d775"&gt;Is Your Python For-loop Slow? Use NumPy Instead&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>5 Unusual Ways Bias Can Sneak into Your Models</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Sun, 18 Sep 2022 00:58:22 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/5-unusual-ways-bias-can-sneak-into-your-models-30kb</link>
      <guid>https://dev.to/thuwarakesh/5-unusual-ways-bias-can-sneak-into-your-models-30kb</guid>
      <description>&lt;p&gt;These "Generally Good Practices" have their downsides.&lt;/p&gt;

&lt;p&gt;We should be using more AI solutions by now. But there's this bias issue to consider!&lt;/p&gt;

&lt;p&gt;We've seen AI models perform differently for underrepresented groups. These issues have been debated heavily in recent years. In search of why bias arises, we found that there are more ways than a human trainer's intention could cause bias.&lt;/p&gt;

&lt;p&gt;Yet, when other people's lives and jobs are concerned, the innocence of a creator is not excused. Customer backlashes, public opinion, and badmouthing could harm your reputation, and it may be tough to recover from them.&lt;/p&gt;

&lt;p&gt;Thus it's critical to understand AI bias. You can't manage something you don't understand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/5-sources-of-bias-in-ai-ml-729acbec3215?sk=17e0674f35ef1c7aeda4a542ad90cd7a"&gt;Here are five situations where bias can sneak into your models.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>datascience</category>
      <category>career</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>When Your Machine Learning Model Performance Starts to Fade ...</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Tue, 13 Sep 2022 14:22:46 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/when-your-machine-learning-model-performance-starts-to-fade--2oai</link>
      <guid>https://dev.to/thuwarakesh/when-your-machine-learning-model-performance-starts-to-fade--2oai</guid>
      <description>&lt;p&gt;Would you raft with no paddles in a river no one had traveled before?&lt;/p&gt;

&lt;p&gt;Hoping everything will be okay after deploying an ML model is also like that. &lt;/p&gt;

&lt;p&gt;ML models in production degrade in performance over time. Finding them before they happen and making a course correction is vital. &lt;/p&gt;

&lt;p&gt;Data scientists often use these strategies to recover their failing models. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/3-tested-techniques-to-recover-your-failing-models-67c070fb591?sk=500c05bf55bd51486bea06faa8d06d15"&gt;3 Tested Techniques to Recover Your Failing Models&lt;/a&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>devops</category>
      <category>career</category>
    </item>
    <item>
      <title>Painless Task Scheduling Using Python</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Tue, 16 Aug 2022 02:15:42 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/painless-task-scheduling-using-python-l90</link>
      <guid>https://dev.to/thuwarakesh/painless-task-scheduling-using-python-l90</guid>
      <description>&lt;p&gt;Running tasks on a schedule is not a rare use case. Pretty much every programmer does it. &lt;/p&gt;

&lt;p&gt;The standard technique used for scheduling is using Cron jobs. I have no objection to using Cron and still think it's a stable way. &lt;/p&gt;

&lt;p&gt;But what if you want a scheduler all in Python? What if you also want it easier to configure?&lt;/p&gt;

&lt;p&gt;That's the focus of this post. &lt;/p&gt;

&lt;p&gt;Related: &lt;a href="https://www.the-analytics.club/the-prefect-way-to-automate-orchestrate-data-pipelines"&gt;&lt;em&gt;The Prefect Way to Automate &amp;amp; Orchestrate Data Pipelines&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling tasks in Python
&lt;/h2&gt;

&lt;p&gt;Task scheduling in Python is made easy with the python package called '&lt;a href="https://schedule.readthedocs.io/en/stable/"&gt;schedule&lt;/a&gt;.' You can install it from the PyPI repository.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;schedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you're using &lt;a href="https://www.the-analytics.club/virtualenv-alternative-for-python-dependency-management"&gt;poetry instead of virtualenv&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry add schedule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The schedule uses a familiar builder pattern. It lets you construct schedules almost as you'd speak in a natural language. That is, if you want to run a function (say &lt;code&gt;send_email&lt;/code&gt;) once every hour, you could do it like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;schedule.every().hour.do(send_email)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's very close to a normal conversation, isn't it? Here's a complete script to send emails in a schedule, but once a day instead of every hour.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;schedule&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# All your email sending logics goes here
&lt;/span&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sending email..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"14:45"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run_pending&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above code will call the send_email function at 2.45 PM per your system time. &lt;/p&gt;

&lt;p&gt;Besides the ease of scheduling, the package offers a range of other features. &lt;/p&gt;
&lt;h3&gt;
  
  
  Scheduling with a decorator
&lt;/h3&gt;

&lt;p&gt;I have a personal preference for using decorators whenever possible. It's more clean and elegant. &lt;/p&gt;

&lt;p&gt;The 'schedule' package supports decorators out of the box. Here's our example of sending emails, this time using decorators.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;schedule&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;run_pending&lt;/span&gt;

&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# All your email sending logics goes here
&lt;/span&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sending email..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;run_pending&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sleep&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the example above, you can also see that we've done two scheduled for the same task. The first one will call the function every 10 seconds. The second one will call it every 5 seconds. &lt;/p&gt;
&lt;h3&gt;
  
  
  Run scheduled tasks with parameters
&lt;/h3&gt;

&lt;p&gt;Scheduling alone is not very useful. We often want more control over the execution of the function. We do it by passing arguments.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"thuwarakesh@abc.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"default@mydomain.abc"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# All your email sending logics goes here
&lt;/span&gt;    &lt;span class="k"&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="s"&gt;"Sending email...: to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;As we see, our send email function takes an optional argument, email. When scheduling, we can pass in the parameters as keyword arguments. &lt;/p&gt;

&lt;p&gt;These are just a few examples of using the library in Python. Please refer to the &lt;a href="https://schedule.readthedocs.io/en/stable/examples.html"&gt;official documentation&lt;/a&gt; for more valuable examples. &lt;/p&gt;
&lt;h2&gt;
  
  
  Scheduling tasks with cron tab--- the conventional way.
&lt;/h2&gt;

&lt;p&gt;Crontab is the most popular technique for running scheduled tasks. It's famous for a couple of reasons. &lt;/p&gt;

&lt;p&gt;One it's provided by the OS. Crontab is for Linux. Even Windows users can use&lt;a href="https://www.howtogeek.com/746532/how-to-launch-cron-automatically-in-wsl-on-windows-10-and-11/"&gt; Crontab using WSL&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The other reason is that Crontab is independent of the tasks' programming language. You can also use the same technique to run a node js script. &lt;/p&gt;

&lt;p&gt;First, we need to modify our code to run on demand instead of on a schedule because Crontab will take care of the scheduling.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;argparse&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"default@mydomain.abc"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# All your email sending logics goes here
&lt;/span&gt;    &lt;span class="k"&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="s"&gt;"Sending email...: to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Email to send"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I've used the argparse module in the above version to &lt;a href="https://www.the-analytics.club/argparser-example-python-script"&gt;accept command line arguments&lt;/a&gt;. You can also use Typer to &lt;a href="https://www.the-analytics.club/python-cli-tutorial"&gt;create more advanced CLIs in Python&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We can run the above script in our terminal as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python send_mail.py &lt;span class="nt"&gt;-e&lt;/span&gt; thuwarakesh@abc.com
&lt;span class="c"&gt;# OR without any arguments&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;python send_email.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can start editing the Crontab with the following command. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;crontab -e&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The command prompt will ask you to choose an editor upon your first edit. I've chosen vim as it's comfortable for me. But you can choose anything. &lt;/p&gt;

&lt;p&gt;I've added the following line at the end of the file. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;45 14 * * * /&amp;lt;ENV_PATH&amp;gt;/env/bin/python /&amp;lt;PROJECT PATH&amp;gt;/send_email.py -e thuwarakesh@abc.com&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This configuration tells Crontab to run the &lt;code&gt;send_email.py&lt;/code&gt; script at 2.45PM every day. Save it and close the file. Your script should run as expected. &lt;/p&gt;

&lt;p&gt;If you're not clear about the crontab configurations, my best advice is to use &lt;a href="https://crontab.guru/"&gt;Crontab.guru&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Crontab or Python Schedule?
&lt;/h2&gt;

&lt;p&gt;Both tools are excellent for scheduling tasks. But depending on the circumstances, one works better than the other. &lt;/p&gt;

&lt;p&gt;The plus point of Python's schedule is its flexibility and friendliness. Anyone can understand the schedule just by reading it. You don't even have to refer to the documentation. &lt;/p&gt;

&lt;p&gt;Although crontab configurations are not that hard to understand, beginners will need a little effort to understand them. &lt;/p&gt;

&lt;p&gt;Everything is in one place, which makes the schedule library straightforward. In Crontab, you'd have to edit the configuration file outside your developing module. If someone else wants to use your application, you'd have to instruct them. &lt;/p&gt;

&lt;p&gt;Also, if I want to create a new schedule, All I have to do is to annotate the function with another. &lt;code&gt;@repeat&lt;/code&gt;. Also, in Crontab, you'd add another configuration line. But not as swift as you'd do in a Python script.&lt;/p&gt;

&lt;p&gt;These pros make Python's schedule library suitable for most use cases. But take a look at the &lt;a href="https://schedule.readthedocs.io/en/stable/#when-not-to-use-schedule"&gt;library's documentation page&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This library is designed to be a simple solution for simple scheduling problems. You should probably look somewhere else if you need to remember schedule between restarts, sub-second precision execution, multiple threads, time zones, workdays or holidays support. --- schedule library docs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Running tasks on a schedule is a frequent need in software development. I often find it useful to run the little productive hacks I do on the go. &lt;/p&gt;

&lt;p&gt;I've been using Crontab for several years, thinking that it's the only way to do the job. But the schedule Python library made it super simple. &lt;/p&gt;

&lt;p&gt;It may not be the perfect tool for every instance. But not everything we do daily needs more sophisticated techniques. &lt;/p&gt;

&lt;p&gt;Now, I've converted many such periodic executions to Python schedules. &lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Did you like what you read? &lt;a href="https://thuwarakesh.medium.com/subscribe"&gt;Consider subscribing to my email newsletter&lt;/a&gt; because I post more like this frequently.&lt;/p&gt;

&lt;p&gt;Thanks for reading, friend! Say Hi to me on &lt;a href="https://www.linkedin.com/in/thuwarakesh/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/Thuwarakesh"&gt;Twitter&lt;/a&gt;, and &lt;a href="https://thuwarakesh.medium.com/"&gt;Medium&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Create File System Triggers in Python</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Fri, 12 Aug 2022 04:46:30 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/how-to-create-file-system-triggers-in-python-1pck</link>
      <guid>https://dev.to/thuwarakesh/how-to-create-file-system-triggers-in-python-1pck</guid>
      <description>&lt;p&gt;Imagine you work with a client system where they upload files to an FTP folder. We’ve got to process the file as soon as it appears in the folder and push it to a database. &lt;/p&gt;

&lt;p&gt;A real-time dashboard is accessing the database. Therefore, we must update the database without any delays. &lt;br&gt;
You could run a periodic task and check for folder content. But let’s assume the quicker you update the database, the better for the user. The cost of the little delay when using a periodic task is high. Shorter periods might need more resources as your tasks run more often. &lt;/p&gt;

&lt;p&gt;We need to build a filesystem trigger to accomplish the task. &lt;/p&gt;
&lt;h2&gt;
  
  
  Monitor new file creations in a folder.
&lt;/h2&gt;

&lt;p&gt;We can use a Python script that actively listens to file system events in a folder. &lt;/p&gt;

&lt;p&gt;We can start by installing a Python package called Watchdog. It’s available through the PyPI repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;watchdog
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using &lt;a href="https://www.the-analytics.club/virtualenv-alternative-for-python-dependency-management"&gt;Poetry instead of Virtualenv&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry add watchdog.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s an example to start with. The following Python script will watch for file changes in the current directory. It’ll log all the changes when they happen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;watchdog.observers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Observer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;watchdog.events&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FileSystemEventHandler&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileCreateHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FileSystemEventHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&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="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Created: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

    &lt;span class="n"&gt;event_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FileCreateHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Create an observer.
&lt;/span&gt;    &lt;span class="n"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Observer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Attach the observer to the event handler.
&lt;/span&gt;    &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recursive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Start the observer.
&lt;/span&gt;    &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&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="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_alive&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&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;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part of the above code is the FileProcessor class. But before getting in there, we should create an observer object to attach an event handler. &lt;/p&gt;

&lt;p&gt;We can attach an event handler to the observer using the schedule method. In the example above, we’ve attached it to watch events in the current and all its downstream directories. &lt;/p&gt;

&lt;p&gt;If you run this code and create a new file in the current directory, we could see the Python script printing the event on the terminal. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cg8mVaxS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.the-analytics.club/documents/23/ezgif.com-gif-maker_1_n5H7KnB.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cg8mVaxS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.the-analytics.club/documents/23/ezgif.com-gif-maker_1_n5H7KnB.gif" alt="Watching filesystem changes in a Python script" width="600" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve used the current folder in the schedule method of the observer object. You could also use any path of your choice. You could also choose to get it from the command line argument. &lt;/p&gt;

&lt;p&gt;Here’s a modification to the same code that &lt;a href="https://www.the-analytics.club/argparser-example-python-script"&gt;converts our script into a CLI&lt;/a&gt;. Now you can pass the path to monitor using a command line argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;argparse&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Watchdog script to watch for new CSV files and load them into the database"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"Path to watch for new CSV files"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;

    &lt;span class="c1"&gt;# Create an observer.
&lt;/span&gt;    &lt;span class="n"&gt;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Observer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event_handler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recursive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now run your script like the following in your terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &amp;lt;YourScript&amp;gt;.py /somewhare/in/your/computer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my previous post, you can learn more about &lt;a href="https://www.the-analytics.club/python-cli-tutorial"&gt;creating a command line interface using Python&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Process file changes in the handler class
&lt;/h2&gt;

&lt;p&gt;In our example, we’ve created an event handler by subclassing the ‘FileSystemEventHandler’ class. All event handlers should be like this. &lt;/p&gt;

&lt;p&gt;The parent class has placeholders for several methods for file system events. We’ve used the ‘on_create’ method to handle all new file creations. Likewise, you can also use on_deleted, on_modified, on_moved, and on_any_event methods to handle other types of events. &lt;/p&gt;

&lt;p&gt;Let’s update the on_create to process the file and insert values into a database. Feel free to skip this section if it’s irrelevant to your use case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_engine&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;watchdog.events&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FileSystemEventHandler&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FileCreateHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FileSystemEventHandler&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&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="c1"&gt;# Create SQLAlchemy engine for postgres database using environment variables
&lt;/span&gt;        &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"DATABASE_URL"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Read the CSV data
&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="p"&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;src_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# Do the required transformations
&lt;/span&gt;            &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_datetime&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="s"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

            &lt;span class="c1"&gt;# Write the data to the database
&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;to_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;con&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;if_exists&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"append"&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="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code might look very familiar if you’ve worked with Sqlalchemy and Pandas. What’s worth noting is how we get the path of the newly created file. &lt;/p&gt;

&lt;p&gt;Each event trigger in the ‘FileSystemEventHandler’ class references the path in its event argument. We can access it with the src-path tag as shown in the code. &lt;/p&gt;

&lt;p&gt;If you run the code and let the Python script listen to the changes, it’ll also immediately push those changes to the database. &lt;/p&gt;

&lt;p&gt;Serve your app in the background.&lt;br&gt;
By now, you’d have noticed that our app runs on a live terminal. But it’s not wise to do this in production. Anything to the terminal session can impact the app. &lt;/p&gt;

&lt;p&gt;The best way to run such services in the background is through a system service. Windows users can use the tool &lt;a href="https://nssm.cc/"&gt;NSSM&lt;/a&gt; (Non-sucking Service Manager.) It’d be pretty straightforward if you skim through their documentation. &lt;/p&gt;

&lt;p&gt;But in this post, I’ll cover the Linux system's use of &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units"&gt;systemctl&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You can create a new system service by creating a file with the following content in ‘/etc/systemd/system’ folder. You can name it anything with an extension of ‘.service’&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description="Process Data"

[Service]
Restart=always
WorkingDirectory=&amp;lt;PATH_TO_PROJECT_DIRECTORY&amp;gt;
ExecStart=&amp;lt;PATH_TO_PYTHON_EXECUTABLE&amp;gt; &amp;lt;YOUR_SCRIPT&amp;gt;.py

[Install]
WantedBy=multi-user target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, you can run the following commands on the terminal to activate the service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# To make your new service available to systemctl utility.&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl daemon-reload

&lt;span class="c"&gt;# To start the service &lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl start &amp;lt;YOUR_SERVICE_FILE_NAME&amp;gt;.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will start the process. Now, as new files are being created on our FTP destination, this service will process and upload them to the database. And our real-time database will get fresh data without any delays. &lt;/p&gt;

&lt;p&gt;You can check if your service is running properly with the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status &amp;lt;YOUR_SERVICE_FILE_NAME&amp;gt;.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Processing file system change is rare these days as the world moves towards more robust integration between systems. But it doesn’t mean filesystem triggers have no usage. &lt;/p&gt;

&lt;p&gt;There are many instances where we need to monitor new file creation or modifications. Take, for example, log stream processing. You could use the technique described here to process a new log line and push it to a data warehouse. &lt;/p&gt;

&lt;p&gt;I’ve been using it for a long time now. And I don’t see the need for it to be reduced yet. &lt;/p&gt;




&lt;p&gt;Did you like what you read? &lt;a href="https://thuwarakesh.medium.com/subscribe"&gt;&lt;strong&gt;&lt;em&gt;Consider subscribing to my email newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;  because I post more like this frequently. &lt;/p&gt;

&lt;p&gt;Thanks for reading, friend! Say Hi to me on &lt;a href="https://www.linkedin.com/in/thuwarakesh/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/Thuwarakesh"&gt;Twitter&lt;/a&gt;, and &lt;a href="https://thuwarakesh.medium.com/"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>codenewbie</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How To Write Readable, Elegant Regex Patterns In Python</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Wed, 10 Aug 2022 16:30:00 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/how-to-write-readable-elegant-regex-patterns-in-python-5e42</link>
      <guid>https://dev.to/thuwarakesh/how-to-write-readable-elegant-regex-patterns-in-python-5e42</guid>
      <description>&lt;p&gt;Regex is, without a doubt, the most helpful text processing tool ever invented. It helps us find patterns rather than exact words or phrases in a text. And regex engines are noticeably faster too.&lt;/p&gt;

&lt;p&gt;Yet, the difficult part is to define a pattern. Experienced programmers may define it on the go. But most developers will have to spend time googling and reading through documentation.&lt;/p&gt;

&lt;p&gt;Regardless of experience, everyone finds reading a pattern others defined difficult.&lt;/p&gt;

&lt;p&gt;This is the problem PRegEx solves.&lt;/p&gt;

&lt;p&gt;PRegEx is a Python library that makes regex patterns more elegant and readable. It’s now one of my favorite libraries for &lt;a href="https://www.the-analytics.club/python-project-structure-best-practices"&gt;cleaner python code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can install it from the PyPI repository.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pregex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using &lt;a href="https://www.the-analytics.club/virtualenv-alternative-for-python-dependency-management"&gt;Poetry instead of Virtualenv&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry add pregex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start writing more readable regex.
&lt;/h2&gt;

&lt;p&gt;Here’s an example of grasping how cool PRegEx is.&lt;/p&gt;

&lt;p&gt;It’s widespread to need to extract (US) zip codes from addresses. It’s not difficult if the addresses are standardized. Otherwise, we need to use some clever techniques to extract them.&lt;/p&gt;

&lt;p&gt;United States zip codes are usually five-digit numbers. Also, some zipcodes may have an extension of four digits separated by a hyphen.&lt;/p&gt;

&lt;p&gt;For instance, 88310 is a postal code in New Mexico. Some prefer to use also the geographic segment with an extension like 88310–7241.&lt;/p&gt;

&lt;p&gt;Here’s the typical approach (using the re module) to find patterns of this kind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;re&lt;/span&gt;

&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="s"&gt;"\d{5}(-\d{4})?"&lt;/span&gt;

&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"730 S White Sands Blvd, Alamogordo, NM 88310, United States"&lt;/span&gt;

&lt;span class="n"&gt;zip_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zip_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 88310
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The steps may seem straightforward. However, if you’re to explain how you defined the pattern to a novice programmer, you’ll have to do an hour-long lecture.&lt;/p&gt;

&lt;p&gt;I’m not going to explain it either. Because we have PRegEx. Here’s the PRegEx version of it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.classes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnyDigit&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.quantifiers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Exactly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;

&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Exactly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnyDigit&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"-"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Exactly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnyDigit&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;address1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"730 S White Sands Blvd, Alamogordo, NM 88310, United States"&lt;/span&gt;
&lt;span class="n"&gt;address2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"730 S White Sands Blvd, Alamogordo, NM 88310-7421, United States"&lt;/span&gt;

&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# ['88310']
&lt;/span&gt;
&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# ['88310-7421']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this code is both simple to define and understand.&lt;/p&gt;

&lt;p&gt;The pattern has two segments. The first segment should have exactly five digits, and the second one is optional. Also, the second segment, if available, should have a hyphen and four numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understand the submodules to create more exciting regex patterns.
&lt;/h2&gt;

&lt;p&gt;Here we used a couple of submodules of the PRegEx library — classes and quantifiers. The ‘classes’ submodule determines what to match and the quantifier submodule help specifying how many repetitions to perform.&lt;/p&gt;

&lt;p&gt;You could use other classes such as AnyButDigit to match non-numeric values or AnyLowercaseLetter with lower case strings. To create more complex regex patterns, you could also use different quantifiers such as OneOrMore, AtLeast, AtMost, or Indefinite.&lt;/p&gt;

&lt;p&gt;Here’s another example with more exciting matches. We need to find out email addresses in a text. That’s simple. But we’re also interested in capturing the domains of email addresses in addition to matching the pattern.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.classes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnyButWhitespace&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.groups&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Capture&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.quantifiers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AtLeastAtMost&lt;/span&gt;


&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnyButWhitespace&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"@"&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Capture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnyButWhitespace&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;AtLeastAtMost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnyButWhitespace&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"""My names is Alice. I live in Wonderland. You can mail me: alice@wonderland.com. 
In case if I couldn't reply, please main my friend the White Rabbit: whiterabbit@wonderland.com.
But for more serious issues, you should main Tony Stark at tony@stark.org.
"""&lt;/span&gt;

&lt;span class="c1"&gt;# Get everything you captured. 
&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_captures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# [('wonderland.com',), ('wonderland.com',), ('stark.org',)]
&lt;/span&gt;
&lt;span class="c1"&gt;# Get all your matches. 
&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_matches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# ['alice@wonderland.com', 'whiterabbit@wonderland.com', 'tony@stark.org']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ve used the Capture class from the ‘groups’ submodule in the above example. It allows us to collect segments within a match so that you don’t have to do any post-processing to extract them.&lt;/p&gt;

&lt;p&gt;Another submodule you’d often need is the operator module. It helps you concatenate patterns or select either of a set of options.&lt;/p&gt;

&lt;p&gt;Here’s a slightly modified version of the same example above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.classes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnyButWhitespace&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.groups&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Capture&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.operators&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Either&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pregex.quantifiers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OneOrMore&lt;/span&gt;


&lt;span class="n"&gt;pattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnyButWhitespace&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"@"&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Capture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OneOrMore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AnyButWhitespace&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;Either&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".org"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"""My names is Alice. I live in Wonderland. You can mail me: alice@wonderland.com. 
In case if I couldn't reply, please main my friend the White Rabbit: whiterabbit@wonderland.com.
But for more serious issues, you should main Tony Stark at tony@stark.org.
Please don't message [thanos@wierdland.err](https://thuwarakesh.medium.com/subscribe)
"""&lt;/span&gt;

&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_captures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# [('wonderland.com',), ('wonderland.com',), ('stark.org',)]
&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, we’ve restricted the top-level domain to either ‘.com’ or ‘.org. We’ve used the ‘Either’ class from the operator submodule to build this pattern. As you can see, it didn’t match with &lt;a href="mailto:thanos@wierdland.err"&gt;thanos@wierdland.err&lt;/a&gt; as its top-level domain is ‘.err,’ not ‘.com’ or ‘.org.’&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Defining regex may not be a massive task for experienced developers. But even for them, reading and understanding a pattern created by someone else is difficult. For beginners, both can be daunting.&lt;/p&gt;

&lt;p&gt;Besides, regex is an excellent tool for text mining. Any developer or data scientist will almost certainly come across regex usage.&lt;/p&gt;

&lt;p&gt;If you’re a Python programmer, PRegEx has the complex parts covered.&lt;/p&gt;




&lt;p&gt;Did you like what you read? &lt;a href="https://thuwarakesh.medium.com/subscribe"&gt;&lt;strong&gt;&lt;em&gt;Consider subscribing to my email newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;  because I post more like this frequently. &lt;/p&gt;

&lt;p&gt;Thanks for reading, friend! Say Hi to me on &lt;a href="https://www.linkedin.com/in/thuwarakesh/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/Thuwarakesh"&gt;Twitter&lt;/a&gt;, and &lt;a href="https://thuwarakesh.medium.com/"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>regex</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Easily Build Command Line Tools in Python?</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Fri, 05 Aug 2022 04:15:00 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/how-to-easily-build-command-line-tools-in-python-60j</link>
      <guid>https://dev.to/thuwarakesh/how-to-easily-build-command-line-tools-in-python-60j</guid>
      <description>&lt;p&gt;It's so much easy to develop a command line tool than a &lt;a href="https://towardsdatascience.com/5-python-gui-frameworks-to-create-desktop-web-and-even-mobile-apps-c25f1bcfb561"&gt;graphical UI&lt;/a&gt;. But it's easier in Python now than it was before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.the-analytics.club/python-cli-tutorial"&gt;Typer&lt;/a&gt; is a handy tool that helps convert our ordinary functions into command line utilities.&lt;/p&gt;

&lt;p&gt;A common need in most CLIs is to accept arguments from the user. Typer makes it super easy to do this. Further, Typer also has the flexibility to style your output.&lt;/p&gt;

&lt;p&gt;All this happens in two magical lines of code!&lt;/p&gt;

&lt;p&gt;Here's a simple python function that accepts a name and says hello. Two lines of Typer code have changed it to a CLI.&lt;/p&gt;

&lt;p&gt;If you're not using Typer, you can &lt;a href="https://www.the-analytics.club/argparser-example-python-script"&gt;use the standard module, argparser to create CLIs&lt;/a&gt;. But, Typer is so much easier than argparser. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create your first command line tool in Python.
&lt;/h2&gt;

&lt;p&gt;Before you begin with the rest of the guide, please &lt;a href="https://pypi.org/project/typer/"&gt;install typer&lt;/a&gt; on your local computer or your virtual environment. The following code will help.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install typer[all]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import typer

def main(name: str):
   print(f"Hello {name}")

if __name__ == "__main__":
   typer.run(main)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Say you've named your Python script app.py. If you run the python script on your terminal with an argument, you'd see it printing hello to your input value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(env) $ python app.py thuwa
Hello thuwa

(env) $ python app.py
Usage: app.py [OPTIONS] NAME
Try 'app.py --help' for help.
╭─ Error ──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Missing argument 'NAME'.                                                                                             │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, you could also see it failing when you try to run the script without an argument. But try adjusting your code and give the name parameter a default value. This makes the command line argument 'name' an optional one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def main(name: str = "world"):
    print(f"Hello {name}")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(env) $ python app.py
Hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create multiple command line functions in the same Python script.
&lt;/h2&gt;

&lt;p&gt;Often you'd want to have more than one function on your Python script. In such cases, you can choose which parts appear as command line utilities.&lt;/p&gt;

&lt;p&gt;For instance, the following script has three Python functions. One is to say hi, and the other is to say bye. We also have a third function to tell 'Run Away.'&lt;/p&gt;

&lt;p&gt;We want to convert the first two into command line functions and leave the last one.&lt;/p&gt;

&lt;p&gt;The following script does it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import typer

app = typer.Typer()

@app.command()
def say_hi(name: str):
    print(f"Hello {name}")

@app.command()
def say_bye(name: str):
    print(f"Bye {name}!")

if __name__ == "__main__":
    app()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script may look a bit more complicated than the previous simple example. But it is not.&lt;/p&gt;

&lt;p&gt;In this example, we create a Typer app and manually add commands to it. We add commands by annotating functions with &lt;code&gt;@app.command&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the main app, we called our app itself.&lt;/p&gt;

&lt;p&gt;Now run the script with &lt;code&gt;--help&lt;/code&gt; at the end and see the beautiful help document printing on the screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(env) $ python app.py --help

 Usage: app.py [OPTIONS] COMMAND [ARGS]...

╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --install-completion          Install completion for the current shell.                                              │
│ --show-completion             Show completion for the current shell, to copy it or customize the installation.       │
│ --help                        Show this message and exit.                                                            │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ say-bye                                                                                                              │
│ say-hi                                                                                                               │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the help menu, you can see the two functions we've annotated with &lt;code&gt;@app.command&lt;/code&gt;. We can use these with arguments in our command line.&lt;/p&gt;

&lt;p&gt;We can also see that the runaway function is not a CLI, although it's there in the script. If we try to run this command, it'll fail as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env) $ python app.py say-hi thuwa
Hello thuwa
(env) $ python app.py say-bye thuwa
Bye thuwa!
(env) $ python app.py run-away thuwa
Usage: app.py [OPTIONS] COMMAND [ARGS]...
Try 'app.py --help' for help.
╭─ Error ──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ No such command 'run-away'.                                                                                          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running shell commands in your CLI.
&lt;/h2&gt;

&lt;p&gt;I've wanted to write a find and replace command. It should go inside every file in the current directory and replace values.&lt;/p&gt;

&lt;p&gt;You can do it in Linux using the following command.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;find ./ -type f -exec sed -i -e 's/&amp;lt;FIND VALUE&amp;gt;/&amp;lt;REPLACE VALUE&amp;gt;/g' {} \;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Yet, the above function is hard to memorize and reuse. Let's create a convenient Python wrapper around it.&lt;/p&gt;

&lt;p&gt;We can run this &lt;a href="https://www.the-analytics.club/python-shell-commands"&gt;shell command inside Python&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import typer
import subprocess

def replace(old: str, new: str):
    """Find and replace 'old' with 'new' in every file in the current directory"""

    command = [
        "find",
        "./",
        "-type",
        "f",
        "-exec",
        "sed",
        "-i",
        f"s/{old}/{new}/g",
        "{}",
        ";",
    ]

    subprocess.call(command)

if __name__ == "__main__":
    typer.run(replace)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may not be a very Pythonic way to find and replace values in a folder. But it explains well how to run shell commands inside your CLI wrapper.&lt;/p&gt;




&lt;p&gt;Did you like what you read? &lt;a href="https://thuwarakesh.medium.com/subscribe"&gt;&lt;strong&gt;&lt;em&gt;Consider subscribing to my email newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;  because I post more like this frequently. &lt;/p&gt;

&lt;p&gt;Thanks for reading, friend! Say Hi to me on &lt;a href="https://www.linkedin.com/in/thuwarakesh/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/Thuwarakesh"&gt;Twitter&lt;/a&gt;, and &lt;a href="https://thuwarakesh.medium.com/"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A Brief Guide To Manage Configurations Using TOML Files</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Thu, 04 Aug 2022 14:37:00 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/a-brief-guide-to-manage-configurations-using-toml-files-2k2l</link>
      <guid>https://dev.to/thuwarakesh/a-brief-guide-to-manage-configurations-using-toml-files-2k2l</guid>
      <description>&lt;p&gt;How'd you change the behavior of a software project based on a set of parameters?&lt;/p&gt;

&lt;p&gt;You could use environment variables. But what if you want complex structures in the parameters?&lt;/p&gt;

&lt;p&gt;Can you use JSON? Yes, you can. JSON files don't allow comments. How'd you describe your parameters to readers?&lt;/p&gt;

&lt;p&gt;The answer is to use a TOML configuration file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should we use a config file, and why TOML?
&lt;/h2&gt;

&lt;p&gt;Config files are great ways to extract the project parameters. When you share your code with others, they know exactly where to make changes to tweak the behavior of the software.&lt;/p&gt;

&lt;p&gt;For instance, say yours is a website codebase that supports several themes. Others who set up your code can go to the config file and change the theme variable to a different one. It's more convenient than going to the codebase and editing the theme in various files.&lt;/p&gt;

&lt;p&gt;But to let your users know what themes are available, you need to have comments on the config files. You can say your website supports 'dark', 'light,' 'pop,' and 'grayscale' themes. JSON files fall short, as they don't allow comments.&lt;/p&gt;

&lt;p&gt;It's a misconception that environment files are config files. They are not.&lt;/p&gt;

&lt;p&gt;While it's also possible to store values in the &lt;a href="https://www.ibm.com/docs/en/aix/7.2?topic=files-environment-file"&gt;environment file&lt;/a&gt;, its purpose is to hide secrets from other developers.&lt;/p&gt;

&lt;p&gt;Say you have database credentials and API keys. Publishing your code with these values to a public cloud like GitHub can be harmful. Hence we use env variables to separate them.&lt;/p&gt;

&lt;p&gt;Config files are to store values that you can happily share with other developers. The themes option we discussed is a good example.&lt;/p&gt;

&lt;p&gt;Why TOML?&lt;/p&gt;

&lt;p&gt;TOML is an excellent option because it's both super straightforward, and most popular platforms accept it. &lt;/p&gt;

&lt;p&gt;For instance, the popular headless CMS platform &lt;a href="https://docs.netlify.com/configure-builds/file-based-configuration"&gt;Netlify uses TOML files&lt;/a&gt; to upload build configurations. We can configure the node environment, the build command, the output directory, etc., in this config file. &lt;/p&gt;

&lt;p&gt;Another good example is the GitLab Runner. &lt;a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html"&gt;Gitlab runner&lt;/a&gt; is part of the Gitlab CI/CD pipeline. It allows you to run jobs in a pipeline during continuous deployment. How do you configure it? You use a TOML file. &lt;/p&gt;

&lt;p&gt;In a TOML file, you can tell the runner how many concurrent jobs to execute, the log level, listening port, and many other options. &lt;/p&gt;

&lt;p&gt;TOML also files also have syntax highlighting support from many code editors. For instance, on VSCode, I've installed the "Even Better TOML" extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--822jgN7h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.the-analytics.club/media/images/Untitled_design.width-800.jpg%3Fezimgfmt%3Drs:587x330/rscb1/ng:webp/ngcb1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--822jgN7h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.the-analytics.club/media/images/Untitled_design.width-800.jpg%3Fezimgfmt%3Drs:587x330/rscb1/ng:webp/ngcb1" alt="TOML syntax highlighting" width="587" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TOML file is a great feature of a &lt;a href="https://www.the-analytics.club/python-project-structure-best-practices"&gt;modern Python project structure&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a TOML file?
&lt;/h2&gt;

&lt;p&gt;TOML (Tom's Obvious Minimal Language) is a configuration file format that is easy to read and write. It's minimal, and even people with no programming experience can easily understand it.&lt;/p&gt;

&lt;p&gt;TOML supports many data structures, such as key-value pairs, arrays, and tables. Parser libraries can convert them to native data structures in different programming languages.&lt;/p&gt;

&lt;p&gt;Most mainstream programming languages can parse it. As of this post, over &lt;a href="https://github.com/toml-lang/toml/wiki"&gt;40 languages have TOML parsers&lt;/a&gt;. This list includes JavaScript, Java, C#, PHP, and C++.&lt;/p&gt;

&lt;p&gt;This post focuses on TOML file usage in Python.&lt;/p&gt;

&lt;p&gt;A TOML file can live anywhere in a project. The ideal location is the project's root folder because we want to edit the configuration for the project. If we only care about a module, we can move it to a subfolder.&lt;/p&gt;

&lt;p&gt;TOML files have an extension, .toml. Here's an example config file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# This is a TOML document&lt;/span&gt;

&lt;span class="py"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"TOML Example"&lt;/span&gt;

&lt;span class="nn"&gt;[owner]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Tom Preston-Werner"&lt;/span&gt;
&lt;span class="py"&gt;dob&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1979-05-27&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;07&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00-08&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;

&lt;span class="nn"&gt;[database]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;ports&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;8000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8002&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="py"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"delta"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"phi"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nn"&gt;[3.14]&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nn"&gt;temp_targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;cpu&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;79.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="py"&gt;case&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;72.0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nn"&gt;[servers]&lt;/span&gt;

&lt;span class="nn"&gt;[servers.alpha]&lt;/span&gt;
&lt;span class="py"&gt;ip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"10.0.0.1"&lt;/span&gt;
&lt;span class="py"&gt;role&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"frontend"&lt;/span&gt;

&lt;span class="nn"&gt;[servers.beta]&lt;/span&gt;
&lt;span class="py"&gt;ip&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"10.0.0.2"&lt;/span&gt;
&lt;span class="py"&gt;role&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"backend"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's a lot to learn from this example.&lt;/p&gt;

&lt;p&gt;First, the file starts with a comment. You can create a comment anywhere in the config file by adding a # sign.&lt;/p&gt;

&lt;p&gt;Next is value assignment. It's pretty straightforward, as you can see. You can name a key and assign a value to it using the = sign.&lt;/p&gt;

&lt;p&gt;The values can be of many types. In the example, the title is assigned to a string. But you can see the DOB is a DateTime. The Ports key is a list, data is a list of lists, and targets are another set of key-value pairs.&lt;/p&gt;

&lt;p&gt;An important aspect of TOML file is the headers([owners], [database], etc) . In TOML, these headers are called tables. It depicts a hashtable which is a collection of key-value pairs.&lt;/p&gt;

&lt;p&gt;Parser libraries will use this information to create high-level keys in their native types. More on this later.&lt;/p&gt;

&lt;p&gt;Tables can also be multi-level. As you can see in the above example, alpha and beta are two hashtables created inside the server hashtable.&lt;/p&gt;

&lt;p&gt;Python parser libraries will convert these into nested dictionaries.&lt;/p&gt;

&lt;p&gt;TOML supports many other data types that parser libraries convert to native varieties of the programming language.&lt;/p&gt;

&lt;p&gt;We're going to use a Python TOML parser library called tomli.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to read TOML files in Python.
&lt;/h2&gt;

&lt;p&gt;The upcoming &lt;a href="https://towardsdatascience.com/python-3-11-is-indeed-faster-than-3-10-1247531e771b"&gt;Python version, 3.11&lt;/a&gt;, has a standard library called tomlib. This module helps read TOML files from a string.&lt;/p&gt;

&lt;p&gt;Yet, for all other Python versions (3.6+), we can use an external package called &lt;a href="https://github.com/hukkin/tomli"&gt;tomli&lt;/a&gt;. We can install tomli from PyPI repository as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;tomli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we need to import the module. Thankfully, both the standard module in 3.11 and the external package follow the same API. Thus we can import them conditionally as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tomllib&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ModuleNotFoundError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tomli&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tomllib&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can convert any TOML string into Python native variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;toml_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"""
# This is a TOML document

title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00

[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }

[servers]

[servers.alpha]
ip = "10.0.0.1"
role = "frontend"

[servers.beta]
ip = "10.0.0.2"
role = "backend"
"""&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tomllib&lt;/span&gt;&lt;span class="p"&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;toml_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;
&lt;span class="c1"&gt;# {'title': 'TOML Example', 'owner': {'name': 'Tom Preston-Werner', 'dob': datetime.datetime(1979, 5, 27, 7, 32, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=57600)))}, 'database': {'enabled': True, 'ports': [8000, 8001, 8002], 'data': [['delta', 'phi'], [3.14]], 'temp_targets': {'cpu': 79.5, 'case': 72.0}}, 'servers': {'alpha': {'ip': '10.0.0.1', 'role': 'frontend'}, 'beta': {'ip': '10.0.0.2', 'role': 'backend'}}}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the converted example, we can see our hashtables (or the headers) are the top level-keys. Secondary headings are converted to nested dictionaries.&lt;/p&gt;

&lt;p&gt;We can also see the parser library did an amazing job converting TOML configurations to native data types.&lt;/p&gt;

&lt;p&gt;We can also read TOM files from a file. We need to open it as a binary file and load it with tomllib.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;tomli&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tomllib&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./config.toml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&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="n"&gt;tomllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="c1"&gt;# {'title': 'TOML Example', 'owner': {'name': 'Tom Preston-Werner', 'dob': datetime.datetime(1979, 5, 27, 7, 32, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=57600)))}, 'database': {'enabled': True, 'ports': [8000, 8001, 8002], 'data': [['delta', 'phi'], [3.14]], 'temp_targets': {'cpu': 79.5, 'case': 72.0}}, 'servers': {'alpha': {'ip': '10.0.0.1', 'role': 'frontend'}, 'beta': {'ip': '10.0.0.2', 'role': 'backend'}}}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why TOML over YAML?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://yaml.org/"&gt;YAML&lt;/a&gt; is another widely-used, feature-rich config file format. Both file formats have pretty straightforward syntax. Yet, the notable difference in the YAML file is the significance of whitespaces.&lt;/p&gt;

&lt;p&gt;In YAML, you specify a list by typing the list items in separate lines with an indentation. You can create nested lists with more indentation.&lt;/p&gt;

&lt;p&gt;This can confuse a non-technical reader.&lt;/p&gt;

&lt;p&gt;In TOML, however, whitespace plays no role. You create lists with a square bracket.&lt;/p&gt;

&lt;p&gt;If you think your config file users are somewhat technical, you can choose one based on other factors. For instance, you can think of the platform on which you will deploy your project. If it's Netlify or Gitlab, you can choose a TOML file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Abstracting config parameters out transforms a project from good to great. Whenever you need a new deployment, you change the configurations in one place, and your app responds.&lt;/p&gt;

&lt;p&gt;A configuration file is what you need to do this. This post introduced TOML files and why they are fantastic. You could also use the environment file, a JSON file, or any text document. But TOML files have significant advantages over these other formats.&lt;/p&gt;

&lt;p&gt;We've discussed using the Python library tomli to read from TOML files. Going forward, we might not need an external library to work with TOML. Python 3.11 ships with a standard module called tomllib.&lt;/p&gt;

&lt;p&gt;Lastly, we discussed how we compare TOML with YAML. YAML is also a popular library to store configurations. While YAML can be beneficial for complex configuration options, TOML is more beginner friendly.&lt;/p&gt;




&lt;p&gt;Did you like what you read? &lt;a href="https://thuwarakesh.medium.com/subscribe"&gt;&lt;strong&gt;&lt;em&gt;Consider subscribing to my email newsletter&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;  because I post more like this frequently. &lt;/p&gt;

&lt;p&gt;Thanks for reading, friend! Say Hi to me on &lt;a href="https://www.linkedin.com/in/thuwarakesh/"&gt;LinkedIn&lt;/a&gt;, &lt;a href="https://twitter.com/Thuwarakesh"&gt;Twitter&lt;/a&gt;, and &lt;a href="https://thuwarakesh.medium.com/"&gt;Medium&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Create Web UIs for Python APIs and ML Models</title>
      <dc:creator>Thuwarakesh Murallie</dc:creator>
      <pubDate>Fri, 01 Jul 2022 06:15:58 +0000</pubDate>
      <link>https://dev.to/thuwarakesh/how-to-create-web-uis-for-python-apis-and-ml-models-5999</link>
      <guid>https://dev.to/thuwarakesh/how-to-create-web-uis-for-python-apis-and-ml-models-5999</guid>
      <description>&lt;p&gt;An experienced data scientist would agree. Building Machine learning models are highly iterative. &lt;/p&gt;

&lt;p&gt;The critical challenge for a data scientist is to prototype the model as fast as possible. What they need is a quicker way to build apps around their work. &lt;/p&gt;

&lt;p&gt;Only then can they share their model with others for evaluation and collect feedback. &lt;/p&gt;

&lt;p&gt;Yet, building an app requires a lot of HTML, CSS, and JavaScript knowledge. Also, hosting them is a different challenge. &lt;/p&gt;

&lt;p&gt;But with tools like this, Data scientists can build apps at no time only using Python. They can also deploy the app on Hugginface spaces and share it with others. &lt;/p&gt;

&lt;p&gt;This article walks you through the steps you need to build web UI's around your ML models. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://towardsdatascience.com/python-web-apps-for-machine-learning-e29d075e6459?sk=8b0055c3b395066e6c1dfe957862b4f0"&gt;&lt;strong&gt;Create Web UIs for Python APIs and ML Models&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>machinelearning</category>
      <category>datascience</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
