Volpe's Blog

My points of view, travels and code

Programming

on Programming

Blogging like a nerd: Cloudflare Pages is all you need

Blogging like a nerd: Cloudflare Pages is all you need

It took me 9 years to come back to blogging, and I used maintaining the old WordPress setup as an excuse the whole time. Turns out the fix was free. The previous version was a WordPress running on a VPS on Digital Ocean. I could have, in theory, just start writing there and hitting post. But the WordPress version was getting more outdated every day and the plugins I was using were also getting deprecated, so I’d have to migrate. The blog was down every couple of years because of issues in the VPS.

Beyond the operational headaches, there were deeper problems too. One of the key features I wanted to support was multi-language, and getting that out of the box is not supported by WordPress by default. Switching the plugin would mean having to make sure the URLs are kept the same and migrate all the data to the new one. Plus, I needed to make sure it ran, and that I didn’t get hacked, as WordPress has gotten many times. The setup with the VPS would have to be maintained, and I set that up when I was just getting started with software, so I’d probably have to rebuild it from scratch. In case one of my posts was a hit, I’d probably go down or with heavily degraded performance. There are also serious concerns everyone should have about WordPress (the Matt meltdown).

Alternatives to self-hosting

Of course, one-click WordPress-hostings exist, but that’d mean I need to pay money monthly and also risk it becoming expensive overnight if one post gets significant traffic. Migrating to them would also not be trivial if I wanted my old blog to have the same setup, and more importantly, the URLs. I could also host in something like Substack or similar platforms, but that’d mean I don’t really have full control of my website. I don’t have anything against Substack, I even own some shares of it, but I would rather have full control of my little internet corner, where I can write anything I want and not get banned or demonetized. I don’t want to have any external incentive influence what I write.

I also thought about using AI to create a custom blog code for me and host it in something like Vercel, but that felt like more of a passion project rather than something that’d make my life easier.

Continue reading →
on Programming, Python

Py2exe + Django is a bad idea.

A client asked me to build a program to track and store their production record. He didn’t want a web app and it had to run on Windows. Well, I first thought ”Most of the stack I use is multiplatform and I have Py2exe to do the dirty job”. I was wrong.

I chose to use the Django ORM to store the information and a sqlite as a backend, so I didn’t have to set up anything client-side. It was the most logical solution because as I concern the Django ORM + some South is a kick-ass. It turned out that it is very hard to tell Py2exe to package everything Django needs to work.

After a bit of try-error workflow I got a couple of windows being able to store some data. Now, it was time to think about the schema migrations, as the client ask for further and more advanced features in the future.

After hours of trying to get all of this in a .exe file, I got nothing better than a “Unknown command: syncdb” from Django’s manage.py. I could only find this article talking about it and it is from 2008(!), which made it more frustrating.

I ended up calling SQLAlchemy for help!

it made me remember why I like the “web platform” so much, because I use the stack I want, and I only switch if something is faster, cheaper or has a better documentation, no only because my clients use it. Sadly, you can’t change your client’s stack. Unless you are Steve Jobs.

Continue reading →
on Programming, PyGTK, Python, Twisted

Twisted + PyGTK

A few weeks ago I started getting interested in Twisted and asynchronous programming. I really liked the way that Twisted handles events and callbacks.

I’ve been working on a program with a graphical interface built in PyGTK that uses threads for every single task and I wondered if I could have this program running in just one thread asynchronously. It’s really simple to implement twisted code in a PyGTK application since both are event-based and Twisted has a native API to do so.

Let’s build a simple PyGTK example:

import gtk

class Gui:
    def __init__(self):
        self.window = gtk.Window()
        self.window.set_default_size(200,200)
        self.window.set_title("Simple PyGTK program")

        self.vbox = gtk.VBox()

        self.button = gtk.Button("I'm a button!")
        self.label = gtk.Label("Nothing here")

        self.vbox.pack_start(self.button)
        self.vbox.pack_start(self.label)

        self.window.add(self.vbox)

        self.button.connect("clicked", self.on_clicked)
        self.window.connect("destroy", lambda x: gtk.main_quit())
        self.window.show_all()
        self.window.show()

    def on_clicked(self, widget):
       self.label.set_text("You clicked the button!")

if __name__ == "__main__":
    app = Gui()
    #starts the GTK loop
    gtk.main()

So, this example is using the Gtk loop. Twisted applications use the Twisted reactor, and we need the Twisted reactor to “understand” Gtk signals. This is what you have to do:

from twisted.internet import gtk2reactor # for gtk-2.0
gtk2reactor.install()

#Your code
#...

from twisted.internet import reactor
#this starts the reactor
reactor.run()

Now we can re-implement our first example and it would look like this:

import gtk
from twisted.internet import gtk2reactor # for gtk-2.0
gtk2reactor.install() #this installs the gtk reactor
#NOTE: This have to be at top always, before importing the reactor

class Gui:
    def __init__(self):
        self.window = gtk.Window()
        self.window.set_default_size(200,200)
        self.window.set_title("Simple PyGTK program")

        self.vbox = gtk.VBox()

        self.button = gtk.Button("I'm a button!")
        self.label = gtk.Label("Nothing here")

        self.vbox.pack_start(self.button)
        self.vbox.pack_start(self.label)

        self.window.add(self.vbox)

        self.button.connect("clicked", self.on_clicked)
        self.window.connect("destroy", lambda x: gtk.main_quit())
        self.window.show_all()
        self.window.show()

    def on_clicked(self, widget):
       self.label.set_text("You clicked the button!")

if __name__ == "__main__":
    app = Gui()
    #No Gtk anymore!
    #gtk.main()
    from twisted.internet import reactor
    #let's start the loop
    reactor.run()

Now you can enjoy the Twisted power in your graphical apps, here is a (very)simple example using Twisted-way callbacks.

import gtk
import time
from twisted.internet import gtk2reactor # for gtk-2.0
gtk2reactor.install() #this installs the gtk reactor
#NOTE: This have to be at top always, before starting the reactor

class Gui:
    def __init__(self):
        self.window = gtk.Window()
        self.window.set_default_size(200,200)
        self.window.set_title("Simple PyGTK program")

        self.vbox = gtk.VBox()

        self.button = gtk.Button("I'm a button!")

        self.time = time.time()

        self.label = gtk.Label("0")

        self.vbox.pack_start(self.button)
        self.vbox.pack_start(self.label)

        self.window.add(self.vbox)

        self.button.connect("clicked", self.on_clicked)
        self.window.connect("destroy", lambda x: gtk.main_quit())
        self.window.show_all()
        self.window.show()
        self.time = time.time()

    def on_clicked(self, widget=None):
        self.label_text = time.time() - self.time
        self.label.set_text("%.2fs" % self.label_text)
        #Twisted will call the self.on_clicked function every 100ms
        reactor.callLater(.1, self.on_clicked)

if __name__ == "__main__":
    app = Gui()
    #No Gtk anymore!
    #gtk.main()
    from twisted.internet import reactor
    #let's start the loop
    reactor.run()

Twisted also has APIS for others toolkits such as Tkinter, wxPython, Win32(Windows) and PyUI. For more information you can visit the official documentation.

Continue reading →