<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>sglavoie.com – Tag: Google Sheets</title><link>https://www.sglavoie.com/tags/google-sheets/</link><description>Posts and writings by Sébastien Lavoie. Customization setups and articles on productivity for developers who like minimalism.</description><language>en</language><atom:link href="https://www.sglavoie.com/tags/google-sheets/feed.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Sun, 19 Dec 2021 21:00:00 -0600</lastBuildDate><item><title>Using Google Sheets as a database to extract data converted to Markdown</title><link>https://www.sglavoie.com/posts/using-google-sheets-as-a-database-to-extract-data-converted-to-markdown/</link><description>Using Google Sheets API, this little tool reads a spreadsheet, extract relevant data and converts it into Markdown so it can be repurposed, in the example given in this article to generate an HTML output for this website with Pelican, a powerful static site generator.</description><content:encoded>&lt;hr&gt;
&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The purpose of this tool is to parse and convert the content of a Google Sheets spreadsheet to Markdown. In this specific case, I just wanted a simple script to reduce the friction in getting a valid output I could use to maintain a &lt;a href="https://www.sglavoie.com/posts/what-it-took-to-propel-a-career-in-tech-in-five-years/"&gt;&amp;ldquo;learning log&amp;rdquo; on my website&lt;/a&gt;. So that gives me a quick way to input data in a spreadsheet and then I can take the time whenever needed to update the learning progress as desired by reformatting any of the entries and optionally adding notes to them.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="general-software-requirements"&gt;General software requirements&lt;/h2&gt;
&lt;p&gt;This tool should:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Be able to read a private spreadsheet with a service account configured with the Google Sheets API.&lt;/li&gt;
&lt;li&gt;Convert rows from a Google Sheets spreadsheet into Markdown (see &lt;strong&gt;Input&lt;/strong&gt; and &lt;strong&gt;Output&lt;/strong&gt; sections below for details).&lt;/li&gt;
&lt;li&gt;Skip rendering rows that are missing a value for the &lt;code&gt;Title&lt;/code&gt; or &lt;code&gt;Date&lt;/code&gt; columns (it couldn&amp;rsquo;t be rendered in the correct place properly without this information).
&lt;ul&gt;
&lt;li&gt;Other columns are optional and the corresponding level of nesting will be skipped if no value was provided (e.g. a category &lt;code&gt;Articles&lt;/code&gt; may have an item with no sub-category and could be missing any of the other values except for &lt;code&gt;Title&lt;/code&gt; and &lt;code&gt;Date&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Separate entries by month by parsing the &lt;code&gt;Date&lt;/code&gt; column.
&lt;ul&gt;
&lt;li&gt;A command-line parameter should exist to specify a year from which the date should be extracted.&lt;/li&gt;
&lt;li&gt;The output should be in reverse chronological order (i.e. for a full year with entries for each month, December will appear at the top and January at the bottom).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Output a hierarchical format like the following: &lt;code&gt;Category &amp;gt; Sub-category &amp;gt; Title &amp;gt; Activity &amp;amp; notes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Group entries by category &lt;strong&gt;and&lt;/strong&gt; sub-category (e.g. if a category is named &lt;code&gt;Articles&lt;/code&gt; and there is a sub-category named &lt;code&gt;Python&lt;/code&gt;, then &lt;code&gt;Python&lt;/code&gt; must be nested under &lt;code&gt;Articles&lt;/code&gt; for the corresponding month).&lt;/li&gt;
&lt;li&gt;Sort on the &lt;code&gt;Date&lt;/code&gt; column before doing any parsing on other columns (rows in the spreadsheet &lt;em&gt;can&lt;/em&gt; be in non-chronological order).
&lt;ul&gt;
&lt;li&gt;Dates from a single year will be kept (either the year received as a parameter or the most recent year found).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Sort &lt;code&gt;Category&lt;/code&gt;, &lt;code&gt;Sub-category&lt;/code&gt; and &lt;code&gt;Title&lt;/code&gt; alphabetically (ascending order from top to bottom).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not&lt;/strong&gt; sort the &lt;code&gt;Activity&lt;/code&gt; column to preserve the order in which rows were added to the spreadsheet.&lt;/li&gt;
&lt;li&gt;Render links only if the &lt;code&gt;Link&lt;/code&gt; column is a valid URL.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not&lt;/strong&gt; validate the content of columns except for &lt;code&gt;Date&lt;/code&gt; and &lt;code&gt;Link&lt;/code&gt; (i.e. render the other columns as is).&lt;/li&gt;
&lt;li&gt;Display items with no category above those having a category. The same logic would be true for sub-categories.&lt;/li&gt;
&lt;li&gt;Format the output:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Date&lt;/code&gt; should become headers (&lt;code&gt;##&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Category&lt;/code&gt; should be &lt;strong&gt;bolded&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Sub-category&lt;/code&gt; should be &lt;em&gt;emphasized&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Title&lt;/code&gt; should become a &lt;a href="https://example.com"&gt;link&lt;/a&gt; if the &lt;code&gt;Link&lt;/code&gt; column contains a valid URL.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Activity&lt;/code&gt; should be nested under &lt;code&gt;Title&lt;/code&gt;, occupying a new line for each activity.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Notes&lt;/code&gt; should appear (&lt;em&gt;italicized and inside parentheses&lt;/em&gt;) next to the activity.
&lt;ul&gt;
&lt;li&gt;If there is a value for &lt;code&gt;Notes&lt;/code&gt; but no value for &lt;code&gt;Activity&lt;/code&gt;, the output would be next to the &lt;code&gt;Title&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="input"&gt;Input&lt;/h3&gt;
&lt;p&gt;A spreadsheet with the following columns (starting with &lt;strong&gt;Date&lt;/strong&gt;):&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;[additional info]&lt;/th&gt;
 &lt;th&gt;Date&lt;/th&gt;
 &lt;th&gt;Category&lt;/th&gt;
 &lt;th&gt;Sub-category&lt;/th&gt;
 &lt;th&gt;Title&lt;/th&gt;
 &lt;th&gt;Activity&lt;/th&gt;
 &lt;th&gt;Link&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;November&lt;/td&gt;
 &lt;td&gt;13/11/2021&lt;/td&gt;
 &lt;td&gt;Articles&lt;/td&gt;
 &lt;td&gt;Python&lt;/td&gt;
 &lt;td&gt;Python slots, slots, and object layout&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://www.youtube.com/watch?v=Iwf17zsDAnY"&gt;https://www.youtube.com/watch?v=Iwf17zsDAnY&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;understood that X does Y&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;November&lt;/td&gt;
 &lt;td&gt;14/11/2021&lt;/td&gt;
 &lt;td&gt;Books&lt;/td&gt;
 &lt;td&gt;Software engineering&lt;/td&gt;
 &lt;td&gt;The Pragmatic Programmer&lt;/td&gt;
 &lt;td&gt;ch. 1&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/"&gt;https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;note 1 here&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;November&lt;/td&gt;
 &lt;td&gt;15/11/2021&lt;/td&gt;
 &lt;td&gt;Books&lt;/td&gt;
 &lt;td&gt;Software engineering&lt;/td&gt;
 &lt;td&gt;The Pragmatic Programmer&lt;/td&gt;
 &lt;td&gt;ch. 2&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;note 2 here too&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;November&lt;/td&gt;
 &lt;td&gt;16/11/2021&lt;/td&gt;
 &lt;td&gt;Books&lt;/td&gt;
 &lt;td&gt;Software engineering&lt;/td&gt;
 &lt;td&gt;Clean Code&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;December&lt;/td&gt;
 &lt;td&gt;1/12/2021&lt;/td&gt;
 &lt;td&gt;Documentation&lt;/td&gt;
 &lt;td&gt;Python&lt;/td&gt;
 &lt;td&gt;The Python Tutorial&lt;/td&gt;
 &lt;td&gt;Sections 1-4&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://docs.python.org/3/tutorial/index.html"&gt;https://docs.python.org/3/tutorial/index.html&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;December&lt;/td&gt;
 &lt;td&gt;2/12/2021&lt;/td&gt;
 &lt;td&gt;Books&lt;/td&gt;
 &lt;td&gt;Software engineering&lt;/td&gt;
 &lt;td&gt;Clean Code&lt;/td&gt;
 &lt;td&gt;ch. 2-10&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Render available values&lt;/td&gt;
 &lt;td&gt;2/12/2021&lt;/td&gt;
 &lt;td&gt;Books&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Clean Coder&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;book note&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Render available values&lt;/td&gt;
 &lt;td&gt;2/12/2021&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Python/C API Reference Manual&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://docs.python.org/3/c-api/index.html"&gt;https://docs.python.org/3/c-api/index.html&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Title missing: skip rendering&lt;/td&gt;
 &lt;td&gt;3/12/2021&lt;/td&gt;
 &lt;td&gt;Articles&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Title missing: skip rendering&lt;/td&gt;
 &lt;td&gt;3/12/2021&lt;/td&gt;
 &lt;td&gt;Articles&lt;/td&gt;
 &lt;td&gt;Software engineering&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;ch. 3&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://docs.python.org/3/c-api/index.html"&gt;https://docs.python.org/3/c-api/index.html&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;note&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Date missing: skip rendering&lt;/td&gt;
 &lt;td&gt;&lt;/td&gt;
 &lt;td&gt;Articles&lt;/td&gt;
 &lt;td&gt;Python&lt;/td&gt;
 &lt;td&gt;Python slots, slots, and object layout&lt;/td&gt;
 &lt;td&gt;Section 2&lt;/td&gt;
 &lt;td&gt;&lt;a href="https://www.youtube.com/watch?v=Iwf17zsDAnY"&gt;https://www.youtube.com/watch?v=Iwf17zsDAnY&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;note not rendered&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="output"&gt;Output&lt;/h3&gt;
&lt;p&gt;A Markdown output to the terminal in the following format:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;markdown&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## December
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; [&lt;span class="nt"&gt;Python/C API Reference Manual&lt;/span&gt;](&lt;span class="na"&gt;https://docs.python.org/3/c-api/index.html&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; **Books**
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Clean Coder (_book note_)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; _Software engineering_
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Clean Code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; ch. 2-10
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; **Documentation**
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; _Python_
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; [&lt;span class="nt"&gt;The Python Tutorial&lt;/span&gt;](&lt;span class="na"&gt;https://docs.python.org/3/tutorial/index.html&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Sections 1-4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## November
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; **Articles**
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; _Python_
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; [&lt;span class="nt"&gt;Python slots, slots, and object layout&lt;/span&gt;](&lt;span class="na"&gt;https://www.youtube.com/watch?v=Iwf17zsDAnY&lt;/span&gt;) (_understood that X does Y_)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; **Books**
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; _Software engineering_
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; Clean Code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; [&lt;span class="nt"&gt;The Pragmatic Programmer&lt;/span&gt;](&lt;span class="na"&gt;https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;-&lt;/span&gt; ch. 1 (_note 1 here_)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - ch. 2 (_note 2 here too_)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;figure&gt;
 &lt;a href="https://www.sglavoie.com/images/posts/0028_google_sheets_as_database_output_markdown/input_output.png"&gt;
 &lt;img src="https://www.sglavoie.com/images/posts/0028_google_sheets_as_database_output_markdown/input_output.png" alt="Sample learning log input converted into markdown output" class="max-size-img-post" width="1915" height="941" loading="lazy" decoding="async"&gt;
 &lt;/a&gt;
 &lt;figcaption&gt;Input/Output example when using this tool.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="installing-this-tool"&gt;Installing this tool&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Tested only under Python 3.9.7&lt;/em&gt;, requires at least Python 3.7+.&lt;/p&gt;
&lt;h3 id="using-pip"&gt;Using &lt;code&gt;pip&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;[recommended] Activate a virtual environment.&lt;/li&gt;
&lt;li&gt;To install dependencies, run from this directory: &lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Then execute the script to run the tool: &lt;code&gt;python3 get_learning_logs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="using-pipenv"&gt;Using &lt;code&gt;pipenv&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Run from this directory: &lt;code&gt;pipenv install&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Activate the newly created virtual environment with &lt;code&gt;pipenv shell&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Then execute the script to run the tool: &lt;code&gt;python3 get_learning_logs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-to-use-this-tool"&gt;How to use this tool&lt;/h2&gt;
&lt;p&gt;You will need to create an environment file (default path: &lt;code&gt;~/.learning-logs&lt;/code&gt; or edit the path for &lt;code&gt;LEARNING_LOGS_ENV_PATH&lt;/code&gt; in &lt;code&gt;get_learning_logs.py&lt;/code&gt;). It should look as follows:&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;env&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-env" data-lang="env"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SERVICE_ACCOUNT_FILEPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/path/to/service_account_learning_logs.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;SPREADSHEET_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;SPREADSHEET_ID &lt;span class="c1"&gt;# Found in the URL of the document&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;WORKSHEET_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# First sheet is 0 by default, it comes after the URL parameter `gid`&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To set up this project, you will have to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable the Google Sheets API for your project (&lt;a href="https://support.google.com/googleapi/answer/6158841?hl=en%29"&gt;https://support.google.com/googleapi/answer/6158841?hl=en)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In the project, search for &amp;ldquo;service account&amp;rdquo; in the search bar and create new credentials.&lt;/li&gt;
&lt;li&gt;Download the credentials and put them at the path &lt;code&gt;SERVICE_ACCOUNT_FILEPATH&lt;/code&gt; referenced in the environment file.&lt;/li&gt;
&lt;li&gt;Create a spreadsheet with the following columns (not necessarily in that order): &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;Category&lt;/code&gt;, &lt;code&gt;Sub-category&lt;/code&gt;, &lt;code&gt;Title&lt;/code&gt;, &lt;code&gt;Activity&lt;/code&gt;, &lt;code&gt;Link&lt;/code&gt;, &lt;code&gt;Notes&lt;/code&gt;.
&lt;ul&gt;
&lt;li&gt;The column &lt;code&gt;Date&lt;/code&gt; Should match a date format: select all cells from that column, go to &lt;code&gt;Format &amp;gt; Number &amp;gt; Date&lt;/code&gt; to apply the expected format (&lt;code&gt;mm/dd/yyyy&lt;/code&gt;). You can then input a date (e.g. &lt;code&gt;11/1/2021&lt;/code&gt;) and you will see a calendar pop up when double-clicking on it. Dragging it down to a new cell will create a new date for the next day (in this example, &lt;code&gt;11/2/2021&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Get its &lt;code&gt;SPREADSHEET_ID&lt;/code&gt; (&lt;code&gt;https://docs.google.com/spreadsheets/d/SPREADSHEET_ID_HERE/edit#gid=0&lt;/code&gt;) to put it in the environment file.&lt;/li&gt;
&lt;li&gt;Get the &lt;code&gt;WORKSHEET_ID&lt;/code&gt; (the integer after &lt;code&gt;gid=&lt;/code&gt; in the URL of the document).&lt;/li&gt;
&lt;li&gt;From the spreadsheet document (or from the folder view in Google Drive), share with the email associated with the service account (e.g. &lt;code&gt;learning-logs-something@project-name-12345.iam.gserviceaccount.com&lt;/code&gt;). Read access (&amp;ldquo;Viewer&amp;rdquo; permission) is enough.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By now, the script is ready to be called. I just created an alias to execute it more easily by putting the following in &lt;code&gt;~/.bash_aliases&lt;/code&gt; (you will have to adapt the paths of course):&lt;/p&gt;
&lt;div class="code-block"&gt;
 &lt;div class="code-block__bar" data-pagefind-ignore&gt;
 &lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
 &lt;button class="code-block__wrap" type="button" aria-pressed="false" hidden&gt;Wrap&lt;/button&gt;
 
 &lt;/div&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;alias&lt;/span&gt; learning-logs&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;~/.local/share/virtualenvs/learning-logs-to-markdown-XJLvhmzn/bin/python3.9 \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; ~/dev/sglavoie/dev-helpers/learning-logs-to-markdown/get_learning_logs.py&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This will output the converted data from the spreadsheet to Markdown &lt;a href="#output"&gt;as shown above&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This little tool scratched an itch and will be helpful in making the process of updating the &lt;a href="https://www.sglavoie.com/posts/what-it-took-to-propel-a-career-in-tech-in-five-years/"&gt;learning progress&lt;/a&gt; of this website more straightforward, more convenient and less hands-on! You can find its source code &lt;a href="https://github.com/sglavoie/dev-helpers/tree/main/learning-logs-to-markdown"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;</content:encoded><dc:creator>Sébastien Lavoie</dc:creator><pubDate>Sun, 19 Dec 2021 21:00:00 -0600</pubDate><guid isPermaLink="false">https://www.sglavoie.com/posts/using-google-sheets-as-a-database-to-extract-data-converted-to-markdown/</guid><category>automation</category><category>google sheets</category><category>markdown</category><category>python</category><category>terminal</category></item></channel></rss>