<?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: Tom Malkin</title>
    <description>The latest articles on DEV Community by Tom Malkin (@harlekuin).</description>
    <link>https://dev.to/harlekuin</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%2F70675%2F475bbf63-bdc4-4d44-87d0-84f58624cfb9.png</url>
      <title>DEV Community: Tom Malkin</title>
      <link>https://dev.to/harlekuin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harlekuin"/>
    <language>en</language>
    <item>
      <title>AutoDocument - Open-Source Mail Merge Alternative</title>
      <dc:creator>Tom Malkin</dc:creator>
      <pubDate>Mon, 12 Aug 2024 02:09:27 +0000</pubDate>
      <link>https://dev.to/harlekuin/autodocument-open-source-mail-merge-alternative-1o9f</link>
      <guid>https://dev.to/harlekuin/autodocument-open-source-mail-merge-alternative-1o9f</guid>
      <description>&lt;h2&gt;
  
  
  AutoDocument - Open-Source Mail Merge Alternative
&lt;/h2&gt;

&lt;p&gt;Hi there, this post is introducing &lt;a href="https://autodocument.app" rel="noopener noreferrer"&gt;AutoDocument&lt;/a&gt;, a free and open-source document generating web app that connects spreadsheets, databases and user forms into documents such as Microsoft Word and PDFs. It's based on fantastic open sources libraries like &lt;a href="https://github.com/elapouya/python-docx-template" rel="noopener noreferrer"&gt;python-docx-template&lt;/a&gt; and headless LibreOffice. &lt;/p&gt;

&lt;p&gt;MailMerge is a pain because it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only converts from Excel to Word&lt;/li&gt;
&lt;li&gt;Uses special field objects in the Word document&lt;/li&gt;
&lt;li&gt;Requires a Microsoft Office License&lt;/li&gt;
&lt;li&gt;Has limited templating options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AutoDocument is a free and easily installable web app that can setup reusable Workflows that convert data from a variety of sources including straight from databases and spreadsheets to several types of outputs, including Word and PDFs. It only uses text based fields such as &lt;code&gt;{{ myfield }}&lt;/code&gt; instead of special objects. It can deal with logical blocks of text and loops to populate flexible templates including lists and tables.&lt;/p&gt;

&lt;p&gt;Features&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create (optional) user forms to kick off a workflow and link to your users&lt;/li&gt;
&lt;li&gt;Load and save data, templates and output from windows and linux network mounts, as well as S3 and SharePoint libraries.&lt;/li&gt;
&lt;li&gt;Powerful templating based on jinja2 and python-docx-template with logic blocks (like if, while etc) as well as standard field substitution.&lt;/li&gt;
&lt;li&gt;Chain sources together like forms, spreadsheets and SQL queries to create clever workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Easily installed by running the container: &lt;code&gt;docker.io/tommalkin/autodocument:latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/TomMalkin/AutoDocument" rel="noopener noreferrer"&gt;https://github.com/TomMalkin/AutoDocument&lt;/a&gt;&lt;br&gt;
Documentation: &lt;a href="https://tommalkin.github.io/AutoDocument/" rel="noopener noreferrer"&gt;https://tommalkin.github.io/AutoDocument/&lt;/a&gt;&lt;br&gt;
Landing Page: &lt;a href="https://autodocument.app/" rel="noopener noreferrer"&gt;https://autodocument.app/&lt;/a&gt;&lt;br&gt;
Container: &lt;a href="https://hub.docker.com/r/tommalkin/autodocument" rel="noopener noreferrer"&gt;https://hub.docker.com/r/tommalkin/autodocument&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd appreciate it if you can try it out and give me some feedback!&lt;/p&gt;

</description>
      <category>python</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>SimQLe - very simple SQL in Python</title>
      <dc:creator>Tom Malkin</dc:creator>
      <pubDate>Sun, 16 Jun 2019 12:21:25 +0000</pubDate>
      <link>https://dev.to/harlekuin/simqle-very-simple-sql-in-python-23h1</link>
      <guid>https://dev.to/harlekuin/simqle-very-simple-sql-in-python-23h1</guid>
      <description>&lt;h1&gt;
  
  
  SimQLe
&lt;/h1&gt;

&lt;p&gt;Hi all,&lt;/p&gt;

&lt;p&gt;I found when creating various Python projects at work that require connections to SQL Databases, it wasn't easy to tick all the following boxes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy to read and write SQL integration in any project&lt;/li&gt;
&lt;li&gt;Manage multiple database connections simultaneously (including multiple types of SQL databases)&lt;/li&gt;
&lt;li&gt;Get robust SQL connections in quick scripts up and running ASAP&lt;/li&gt;
&lt;li&gt;Store connection strings, drivers etc nicely and consistently in secret .env variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;But most importantly&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make it dead easy to write integration tests with test database instances where the code of the project doesn't need to change! Plus doing so with best practice and where you can be 100% sure that across the board your project isn't touching production databases during tests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SimQLe was created to fix all these issues. It is based on the amazing SQLAlchemy library. SimQLe intends to be perfect when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't need an ORM, just SQL queries,&lt;/li&gt;
&lt;li&gt;You want a dead simple way to manage databases, and&lt;/li&gt;
&lt;li&gt;You want super easy, robust testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Basics
&lt;/h2&gt;

&lt;p&gt;Install it: &lt;code&gt;$ pip install simqle&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.connections.yaml&lt;/code&gt; file anywhere that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-sql-server-database&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql+pyodbc:///?odbc_connect=&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DRIVER={SQL Server};UID=&amp;lt;username&amp;gt;;PWD=&amp;lt;password&amp;gt;;SERVER=&amp;lt;my-server&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;url_escape&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;


&lt;span class="na"&gt;test-connections&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# the names of the test-connections should mirror the connections above.&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-sql-server-database&lt;/span&gt;
    &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mssql+pyodbc:///?odbc_connect=&lt;/span&gt;
    &lt;span class="na"&gt;connection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DRIVER={SQL Server};UID=&amp;lt;username&amp;gt;;PWD=&amp;lt;password&amp;gt;;SERVER=&amp;lt;my-test-server&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;url_escape&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Then write some python like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="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;simqle&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;recordset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;load_connections&lt;/span&gt;

&lt;span class="n"&gt;load_connections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"./.connections.yaml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"SELECT name, age FROM people WHERE category = :category"&lt;/span&gt;
&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"category"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recordset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;con_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"my-database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Then, when you're writing the tests, simply flip the &lt;code&gt;SIMQLE_TEST&lt;/code&gt; environment variable to &lt;code&gt;True&lt;/code&gt; before running the tests and the whole project will now use the connections defined in &lt;code&gt;test-connections&lt;/code&gt; instead. Note how the server in the test connection is different. Voila! Stress free tests, and the actual project is just as clean as ever.&lt;/p&gt;

&lt;p&gt;Make sure &lt;code&gt;.connections.yaml&lt;/code&gt; is in your .gitignore for secure connections when collaborating too.&lt;/p&gt;

&lt;p&gt;There's more it can do - but the above demonstrates how simple it can be. It has named parameters, engine exposure if you want to use them for pandas' fantastic read_sql, 100% coverage and is fully tested with every major open source SQL Database. Check out the Repo for more.&lt;/p&gt;

&lt;p&gt;Let me know if you have any ideas or questions! There's a few upgrades on the roadmap :)&lt;/p&gt;

&lt;p&gt;Github Repo: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Harlekuin"&gt;
        Harlekuin
      &lt;/a&gt; / &lt;a href="https://github.com/Harlekuin/SimQLe"&gt;
        SimQLe
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The simplest way to use SQL in Python
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
SimQLe&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;The simple way to SQL&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://travis-ci.org/Harlekuin/SimQLe" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/956227c5784948c61f1671f3b6e74a3844bf795c/687474703a2f2f696d672e736869656c64732e696f2f7472617669732f4861726c656b75696e2f53696d514c652f6d61737465722e7376673f7374796c653d666c6174" alt="build status"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/Harlekuin/SimQLe" rel="nofollow"&gt;&lt;img src="https://camo.githubusercontent.com/8340242006ba7fc20e0716c0b3c23878b084ffc7/68747470733a2f2f636f6465636f762e696f2f67682f4861726c656b75696e2f53696d514c652f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Perfect for no fuss SQL in your Python projects. Execute SQL and return simple
record sets with named parameters. Manage several connections, and switch
between production, development and testing modes.&lt;/p&gt;
&lt;p&gt;Documentation can be found &lt;a href="https://simqle.readthedocs.io/en/latest/" rel="nofollow"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Installation&lt;/h2&gt;
&lt;h3&gt;
Repository&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/Harlekuin/SimQLe"&gt;https://github.com/Harlekuin/SimQLe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or choose your poison:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$ pip install simqle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ poetry add simqle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$ pipenv install simqle&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SimQLe reads from a connections file in yaml format. See the
&lt;code&gt;.connections.yaml&lt;/code&gt; file section for more details.&lt;/p&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;h3&gt;
In Production&lt;/h3&gt;
&lt;p&gt;Get a result from the name of your connection, the SQL statement, and a dict
of parameters:&lt;/p&gt;
&lt;div class="highlight highlight-source-python"&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;simqle&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-v"&gt;ConnectionManager&lt;/span&gt;
&lt;span class="pl-c"&gt;# Intialise your connections&lt;/span&gt;
&lt;span class="pl-s1"&gt;cm&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-v"&gt;ConnectionManager&lt;/span&gt;(&lt;span class="pl-s"&gt;".connections.yaml"&lt;/span&gt;)
&lt;span class="pl-c"&gt;# Write some simple SQL&lt;/span&gt;
&lt;span class="pl-s1"&gt;sql&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"SELECT name, age FROM people WHERE category = :category"&lt;/span&gt;
&lt;span class="pl-s1"&gt;params&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {&lt;span class="pl-s"&gt;"category"&lt;/span&gt;: &lt;span class="pl-c1"&gt;5&lt;/span&gt;}
&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;cm&lt;/span&gt;.&lt;span class="pl-en"&gt;recordset&lt;/span&gt;(&lt;span class="pl-s1"&gt;con_name&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;"my-database"&lt;/span&gt;, &lt;span class="pl-s1"&gt;sql&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s1"&gt;sql&lt;/span&gt;, &lt;span class="pl-s1"&gt;params&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;/pre&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Harlekuin/SimQLe"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;



</description>
      <category>python</category>
      <category>sql</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
