diff --git a/content/blog/2011-12-21_python-progress-bar.rst b/content/blog/2011-12-21_python-progress-bar.rst index 2b2e4a5..2397a1b 100644 --- a/content/blog/2011-12-21_python-progress-bar.rst +++ b/content/blog/2011-12-21_python-progress-bar.rst @@ -17,7 +17,7 @@ newPythonProgressBar [deadlink] To use this progressbar, it is very easy. -.. code:: python +.. code-block:: python # To Setup from progress_bar import ProgressBar diff --git a/content/blog/2012-01-05_custom-django-urlfield.rst b/content/blog/2012-01-05_custom-django-urlfield.rst index cd8258b..a205995 100644 --- a/content/blog/2012-01-05_custom-django-urlfield.rst +++ b/content/blog/2012-01-05_custom-django-urlfield.rst @@ -21,12 +21,12 @@ This would be a little cleaner. this example would allow for http, https, ssh, spdy and mailto, anything else would error out. -.. code:: python +.. code-block:: python facebook_page = URLField(default_protocol="http", protocols=["https","ssh","spdy","mailto"]) The way I could improve this would be -.. code:: python +.. code-block:: python facebook_page = URLField(protocols=["https","https","ssh","spdy","mailto"]) diff --git a/content/blog/2012-01-13_you-can-un-expire-a-gpg-key.rst b/content/blog/2012-01-13_you-can-un-expire-a-gpg-key.rst index 72f6e1d..fd85873 100644 --- a/content/blog/2012-01-13_you-can-un-expire-a-gpg-key.rst +++ b/content/blog/2012-01-13_you-can-un-expire-a-gpg-key.rst @@ -13,14 +13,14 @@ This key had a sub key as well, so figuring out this was tricky. To start, you can list your gpg keys like so: -.. code:: console +.. code-block:: console $ gpg --list-keys This will list keys such as -.. code:: console +.. code-block:: console pub 4096R/01A53981 2011-11-09 [expires: 2016-11-07] uid Tyrel Anthony Souza (Five year key for email.) @@ -28,7 +28,7 @@ This will list keys such as To make this not expire, (same steps to change expiration date to another time), you must first edit the key -.. code:: console +.. code-block:: console $ gpg --edit-key 01A53981 @@ -38,7 +38,7 @@ You will then see a gpg prompt ``gpg>`` Type "expire" in and you will be prompted for how long to change it to -.. code:: console +.. code-block:: console Changing expiration time for the primary key. Please specify how long the key should be valid. diff --git a/content/blog/2012-03-08_some-bash-tips.rst b/content/blog/2012-03-08_some-bash-tips.rst index 7bf1fe7..a74a27d 100644 --- a/content/blog/2012-03-08_some-bash-tips.rst +++ b/content/blog/2012-03-08_some-bash-tips.rst @@ -14,7 +14,7 @@ I recently found a cool command in BASH that I hadn't previously known. ``C-o`` For example: -.. code:: console +.. code-block:: console $ touch a $ touch b diff --git a/content/blog/2012-11-07_cfengine3-install-on-centos-5-7.rst b/content/blog/2012-11-07_cfengine3-install-on-centos-5-7.rst index 165e6a4..aaaeb91 100644 --- a/content/blog/2012-11-07_cfengine3-install-on-centos-5-7.rst +++ b/content/blog/2012-11-07_cfengine3-install-on-centos-5-7.rst @@ -10,7 +10,7 @@ CFEngine3 Install on CentOS 5.7 | Today I was tasked with installing CFEngine3 on CentOS-5.7 (A little outdated). When installing CFEngine-3.3.1 I kept getting an error that I couldn't find libtokyocabinet.so.9. I had to set my prefix to /usr/ because the location that tokyocabinet was installing my libraries to was not being read by CFEngine's make script. | To do this (I am using tokyocabinet 1.4.47) -.. code:: console +.. code-block:: console wget http://fallabs.com/tokyocabinet/tokyocabinet-1.4.47.tar.gz tar -xzvf tokyocabinet-1.4.47.tar.gz @@ -23,7 +23,7 @@ Then I was able to ./configure && make && make install cfengine3 without any pro So my overall script looked something like this: -.. code:: console +.. code-block:: console wget http://fallabs.com/tokyocabinet/tokyocabinet-1.4.47.tar.gz tar -xzvf tokyocabinet-1.4.47.tar.gz @@ -32,7 +32,7 @@ So my overall script looked something like this: make sudo make install -.. code:: console +.. code-block:: console wget http://cfengine.com/source-code/download?file=cfengine-3.3.1.tar.gz tar -xzvf cfengine-3.3.1.tar.gz diff --git a/content/blog/2013-07-02_getting-started-in-python-part-1.rst b/content/blog/2013-07-02_getting-started-in-python-part-1.rst index 3b56943..e9f4601 100644 --- a/content/blog/2013-07-02_getting-started-in-python-part-1.rst +++ b/content/blog/2013-07-02_getting-started-in-python-part-1.rst @@ -35,7 +35,7 @@ If you notice I mentioned a current environment in my previous ``pip freeze`` ex Let's show an example of the first time use of ``virtualenv``: -.. code:: console +.. code-block:: console $ sudo pip install virtualenv # Only time you might need sudo, try without first. $ virtualenv myenv # Create the virtual environment @@ -51,7 +51,7 @@ After you create a virtual environment, you just run``source bin/activate`` and Once installed correctly, you can run the command ``mkvirtualenv envname`` to create a virtual environment. You can then run``workon envname`` from anywhere, and it will activate that environment. For example, you could be at``/var/www/vhosts/www.mysite.com/django/`` and run``workon envname`` and it would activate the environment from there. This isn't a required package (none of them are really…) as I went a couple years without using``virtualenvwrapper``, but it is very useful and now I use it every day. Some tips I use with my setup of``virtualenvwrapper`` is that I use the postactivate scripts to automatically try to change into the proper project directory of my environment. This also means I usually name my``virtualenv`` after my project name for easy memory. It makes no sense to have a project called "cash_register" but the``virtualenv`` be called "fez". This is how I change to the right project after activating my ``virtualenv``. This goes in ``$WORKON_HOME/postactivate`` -.. code:: bash +.. code-block:: bash #!/bin/bash # This hook is run after every virtualenv is activated. diff --git a/content/blog/2013-08-06_help-i-have-too-many-django-manytomany-queries-fixed.rst b/content/blog/2013-08-06_help-i-have-too-many-django-manytomany-queries-fixed.rst index bb2c9bf..52b8ab0 100644 --- a/content/blog/2013-08-06_help-i-have-too-many-django-manytomany-queries-fixed.rst +++ b/content/blog/2013-08-06_help-i-have-too-many-django-manytomany-queries-fixed.rst @@ -15,7 +15,7 @@ The solution, after a day and a half of research is to override the **formfield_ Our solution is to prefetch for any M2M that are related to the current Model. -.. code:: python +.. code-block:: python def formfield_for_manytomany(self, db_field, request, **kwargs): if db_field.__class__.__name__ == "ManyToManyField" and \ diff --git a/content/blog/2013-11-13_how-to-not-trigger-a-post_save-in-django-but-still-modify-data.rst b/content/blog/2013-11-13_how-to-not-trigger-a-post_save-in-django-but-still-modify-data.rst index 543aadc..33518d8 100644 --- a/content/blog/2013-11-13_how-to-not-trigger-a-post_save-in-django-but-still-modify-data.rst +++ b/content/blog/2013-11-13_how-to-not-trigger-a-post_save-in-django-but-still-modify-data.rst @@ -11,7 +11,7 @@ Recently I have been diving into using signals with Django, which of course are I am working on a website for work which in the most basicexplanation, is a task management site. Recently I have added in the ability to subscribe to tasks and get emails, I did this by connecting to the post_save signal. I only email out when a task is changed, not created (of course, no one would be subscribed to it). This worked flawlessly and "emails" out to anyone who is subscribed. I say that in quotes, because I haven't actually hooked it up to a real SMTP server, and only use -.. code:: shell +.. code-block:: shell python -m smtpd -n -c DebuggingServer localhost:1025 @@ -23,7 +23,7 @@ I tried a lot of different things, and was debating some that would be a bit mes You can do this by doing something like this: -.. code:: python +.. code-block:: python from app.models import ModelName diff --git a/content/blog/2015-01-09_ssh-agent-on-boot.rst b/content/blog/2015-01-09_ssh-agent-on-boot.rst index bce5b59..ca89595 100644 --- a/content/blog/2015-01-09_ssh-agent-on-boot.rst +++ b/content/blog/2015-01-09_ssh-agent-on-boot.rst @@ -9,7 +9,7 @@ SSH Agent on "boot" I had a friend complain that he had to keep adding his ssh key to his ssh-agent every time he rebooted. I have a really easy bit of shell code you can put into your .bashrc or your .zshrc file: -.. code:: bash +.. code-block:: bash SSHKEYFILE=/path/to/your/ssh/key/file ssh-add -l | grep -q $SSHKEYFILE diff --git a/content/blog/2022-01-09_garage-door-opener.rst b/content/blog/2022-01-09_garage-door-opener.rst index a936769..3547bc6 100644 --- a/content/blog/2022-01-09_garage-door-opener.rst +++ b/content/blog/2022-01-09_garage-door-opener.rst @@ -56,7 +56,7 @@ I added some markers to figure out what I needed to imitate in ESPHome, and saw This looks like this in yaml: -.. code:: yaml +.. code-block:: yaml switch: - platform: gpio @@ -78,7 +78,7 @@ I'm pretty sure I jumped and screamed with excitement when it opened! Once the door was opening and closing, I was able to add more yaml to set another binary sensor to show whether it was open or closed (from the reed sensor): -.. code:: yaml +.. code-block:: yaml binary_sensor: - platform: gpio @@ -90,7 +90,7 @@ Once the door was opening and closing, I was able to add more yaml to set anothe All together this is shown on my Home Assistant Lovelace dashboard using two cards, one that shows a closed door, and one with an open door (both actual pictures of the door!) with a button to open it. Once it opens or closes the other card switches into place, Home Assistant at least at the time didn't have good conditional cards like I wanted. -.. code:: yaml +.. code-block:: yaml type: conditional conditions: diff --git a/content/blog/2022-06-01_writing-an-epub-parser-part-1.rst b/content/blog/2022-06-01_writing-an-epub-parser-part-1.rst index 9c386fd..86fcb92 100644 --- a/content/blog/2022-06-01_writing-an-epub-parser-part-1.rst +++ b/content/blog/2022-06-01_writing-an-epub-parser-part-1.rst @@ -18,14 +18,14 @@ The tool I've chosen for reading EPUBs is the Python library `ebooklib >> from ebooklib import epub >>> print(book := epub.read_epub("TOG.epub") This returned me a ```` , seeing I had an EpubBook I ran a ``dir(book)`` and found the properties available to me -.. code:: python +.. code-block:: python ['add_author', 'add_item', 'add_metadata', 'add_prefix', 'bindings', 'direction', 'get_item_with_href', 'get_item_with_id', @@ -42,7 +42,7 @@ I will note, at this time I was thinking that this wasn't the direction I wanted Seeing I was on at least some track, I opened up PyCharm and made a new Project. First I setup a class called Epub, made a couple of functions for setting things up and ended up with -.. code:: python +.. code-block:: python class Epub: def __init__(self, book_path: str) -> None: @@ -52,7 +52,7 @@ Seeing I was on at least some track, I opened up PyCharm and made a new Project. I then setup a ``parse_chapters`` file, where I loop through the TOC. Here I went to the definition of ``Link`` and saw I was able to get a ``href`` and a ``title``, I decided my object for chapters would be a dictionary (I'll move to a DataClass later) with ``title`` and ``content``. I remembered from earlier I had a ``get_item_by_href`` so I stored the itext from the TOC's href: ``self.contents.get_item_with_href(link.href).get_content()``. This would later prove to be a bad decision when I opened "The Fold.epub" and realized that a TOC could have a tuple of ``Section`` and ``Link``, not just ``Links``. I ended up storing the item itself, and doing a double loop in the ``parse_chapters`` function to loop if it's a tuple. -.. code:: python +.. code-block:: python def parse_chapters(self) -> None: idx = 0 @@ -67,7 +67,7 @@ I then setup a ``parse_chapters`` file, where I loop through the TOC. Here I wen ``_parse_link`` simply makes that dictionary of ``title`` and ``item`` I mentioned earlier, with a new ``index`` as I introduced buttons in the DearPyGUI at this time as well. -.. code:: python +.. code-block:: python def _parse_link(self, idx, link) -> None: title = link.title @@ -81,7 +81,7 @@ That's really all there is to make an MVP of an EPUB parser. You can use ``Beaut In my implementation my Epub class keeps track of the currently selected chapter, so this loads from all chapters and sets the ``current_text`` variable. -.. code:: python +.. code-block:: python def load_view(self) -> None: item = self.chapters[self.current_index]['item'] diff --git a/content/blog/2022-10-13_scrollbar-colors.rst b/content/blog/2022-10-13_scrollbar-colors.rst index 719cf45..2432bcb 100644 --- a/content/blog/2022-10-13_scrollbar-colors.rst +++ b/content/blog/2022-10-13_scrollbar-colors.rst @@ -9,7 +9,7 @@ Scrollbar Colors Was talking to someone about CSS Nostalgia and "back in my day" when scrollbar colors came up. -.. code:: css +.. code-block:: css /* For Chromium based browsers */ ::-webkit-scrollbar { diff --git a/content/blog/2022-10-17_comparing-go-gorm-and-sqlx.rst b/content/blog/2022-10-17_comparing-go-gorm-and-sqlx.rst index 9bab31e..556403e 100644 --- a/content/blog/2022-10-17_comparing-go-gorm-and-sqlx.rst +++ b/content/blog/2022-10-17_comparing-go-gorm-and-sqlx.rst @@ -17,11 +17,11 @@ My first job out of college was a Python/Django company - and that directed my n Django, if you are unaware, is a MVC framework that ships with a really great ORM. You can do about 95% of your database queries automatically by using the ORM. -.. code:: python +.. code-block:: python entry, created = Entry.objects.get_or_create(headline="blah blah blah") -.. code:: python +.. code-block:: python q = Entry.objects.filter(headline__startswith="What") q = q.filter(pub_date__lte=datetime.date.today()) @@ -49,7 +49,7 @@ Full design disclosure: I followed a couple of blog posts in order to develop th In order to instantiate a model definition, it's pretty easy. What I did is make a new package called ``models`` and inside made a file for my Album. -.. code:: go +.. code-block:: go type Album struct { ID string `json:"id" gorm:"primary_key"` @@ -67,7 +67,7 @@ Each of the controller functions were bound to a ``gin.Context`` pointer, rather The ``FindAlbum`` controller was simple: -.. code:: go +.. code-block:: go func FindAlbum(c *gin.Context) { var album models.Album @@ -79,7 +79,7 @@ The ``FindAlbum`` controller was simple: Which will take in a ``/:id`` path parameter, and the GORM part of this is the third line there. -.. code:: go +.. code-block:: go models.DB.Where("id = ?", c.Param("id")).First(&album).Error @@ -90,7 +90,7 @@ Error handling is standard Go logic, ``if err != nil`` etc and then pass that in This was really easy to set up, and if you want to get a slice back you just use ``DB.Find`` instead, and bind to a slice of those structs. -.. code:: go +.. code-block:: go var albums []models.Album models.DB.Find(&albums) @@ -109,7 +109,7 @@ I'll only bother describing the ``models`` package here, as thats the SQLX part In the ``models/album.go`` file, there's your standard struct here, but this time its bound to ``db`` not ``json``, I didn't look too deep yet but I presume that also forces the columns to set the json name. -.. code:: go +.. code-block:: go type Album struct { ID int64 `db:"id"` @@ -120,7 +120,7 @@ In the ``models/album.go`` file, there's your standard struct here, but this tim An interface to make a service, and a receiver are made for applying the ``CreateAlbum`` form (in another package) which sets the form name and json name in it. -.. code:: go +.. code-block:: go func (a *Album) ApplyForm(form *forms.CreateAlbum) { a.ID = *form.ID @@ -135,7 +135,7 @@ Nested inside the ``models/sql/album.go`` file and package, is all of the Receiv I'll just comment the smallest one, as that gets my point across. Here is where the main part of GORM/SQLX differ - raw SQL shows up. -.. code:: go +.. code-block:: go func (s *AlbumService) GetAll() (*[]models2.Album, error) { q := `SELECT * FROM albums;` diff --git a/content/blog/2022-11-04_office-meeting-sensor.rst b/content/blog/2022-11-04_office-meeting-sensor.rst index d178b2d..edd3caf 100644 --- a/content/blog/2022-11-04_office-meeting-sensor.rst +++ b/content/blog/2022-11-04_office-meeting-sensor.rst @@ -41,7 +41,7 @@ For software, I installed the python packages for Pimoroni and Blinkt, which cam I then added a new service in systemd to control the mqtt server -.. code:: ini +.. code-block:: ini [Unit] Description=Meeting Indicator diff --git a/content/blog/2023-05-26_set-environment-variables-with-lastpass.rst b/content/blog/2023-05-26_set-environment-variables-with-lastpass.rst index 1d9974c..9c33775 100644 --- a/content/blog/2023-05-26_set-environment-variables-with-lastpass.rst +++ b/content/blog/2023-05-26_set-environment-variables-with-lastpass.rst @@ -14,7 +14,7 @@ Recently my coworker set something up that we need an environment variable set u * After that you can use ``lpass show`` and capture that in a variable to export your API key as an environment variable. -.. code:: bash +.. code-block:: bash lpass status if [ $? -ne 0 ]; then diff --git a/content/blog/2023-09-26_which-which-is-which.rst b/content/blog/2023-09-26_which-which-is-which.rst index 8e089de..aa09e6f 100644 --- a/content/blog/2023-09-26_which-which-is-which.rst +++ b/content/blog/2023-09-26_which-which-is-which.rst @@ -13,7 +13,7 @@ I was talking to a `friend `_ [citation needed] about updati I did this by showing the following output: -.. code:: shell +.. code-block:: shell $ which ls /usr/bin/ls @@ -34,7 +34,7 @@ It turns out that ZSH's ``which`` is equivalent to the ZSH shell built-in ``when After running ``/usr/bin/zsh`` and sourcing my aliases (I don't have a zshrc file anymore, I need to set that back up), I was able to settle my fears and prove to myself that I wasn't making things up. There is a which which shows you which aliases you have set up, which is default for ZSH. -.. code:: shell +.. code-block:: shell $ which ls ls: aliased to exa -lhFgxUm --git --time-style long-iso --group-directories-first diff --git a/content/blog/2023-10-03_rotate-a-matrix-in-python.rst b/content/blog/2023-10-03_rotate-a-matrix-in-python.rst new file mode 100644 index 0000000..0c5ae39 --- /dev/null +++ b/content/blog/2023-10-03_rotate-a-matrix-in-python.rst @@ -0,0 +1,93 @@ +Rotate a Matrix in Python +######################### +:author: tyrel +:category: Tech +:tags: python +:status: published + +I've been doing Advent of Code for a few years now, and every year I do it in my favorite language, Python. +One thing that comes up a lot, is rotating matrices. + +One way to do this, is to use Numpy, using ``np.rot90(mat)``, but not everyone wants to install Numpy just to do one small task. +I know I don't always. + +The way I always do it, that will support non-square matrixes, is to use zip. + +.. code-block:: python + + >>> matrix = [ + [1,2,3], + [4,5,6], + [7,8,9] + ] + >>> rotated = list(zip(*matrix[::-1])) + # And result is + [[7, 4, 1], + [8, 5, 2], + [9, 6, 3]] + +We can break this down bit by bit. + +This will copy the list, with a -1 step, resulting in a reverse order + +.. code-block:: python + + >>> matrix[::-1] + [[7,8,9], + [4,5,6], + [1,2,3]] + +Next we need to call zip in order to get the x-th item from each inner list, but first, we need to unpack it. If you'll notice, the unpacked version isn't wrapped with another list, which is what zip needs from us. + +.. code-block:: python + + # Too many lists + >>> print(matrix[::-1]) + [[7, 8, 9], [4, 5, 6], [1, 2, 3]] + + # Just right + >>> print(*matrix[::-1]) + [7, 8, 9] [4, 5, 6] [1, 2, 3] + +From there, we can pass this unpacked list of - in our case - three lists, to zip (and in Python 3 this returns a generator, so we need to call list again on it, or just use it) + +.. code-block:: python + + >>> # Again, we get the rotated matrix + >>> list(zip(*matrix[::-1])) + [[7, 4, 1], + [8, 5, 2], + [9, 6, 3]] + + +Notes +----- + +Small note: If you run this, you will actually get a list of tuples, so you can map those back to a list, if you need to update them for any reason. +I just wanted square brackets in my examples. + +.. code-block:: python + + # This is just messy looking, so I didn't mention it until now + >>> list(map(list, zip(*matrix[::-1]))) + + +As I mentioned, due to using ``zip`` this will work with non-square examples as well. + +.. code-block:: python + + >>> matrix = [ + ... [1,2,3,4,5,6,7,8,9], + ... [9,8,7,6,5,4,3,2,1], + ... ] + >>> print(list(zip(*matrix[::-1]))) + [(9, 1), + (8, 2), + (7, 3), + (6, 4), + (5, 5), + (4, 6), + (3, 7), + (2, 8), + (1, 9)] + diff --git a/pelicanconf.py b/pelicanconf.py index 77fec88..ef92e2c 100644 --- a/pelicanconf.py +++ b/pelicanconf.py @@ -40,7 +40,7 @@ FEED_ATOM = 'tyrel-dev.atom.xml' FEED_ALL_ATOM = 'tyrel-dev.all.xml' -PLUGINS = ["webassets"] +PLUGINS = ["webassets","syntax_highlighting"] DEFAULT_PAGINATION = True DISPLAY_CATEGORIES_ON_MENU = False