Chris Padilla/Blog

My passion project! Posts spanning music, art, software, books, and more
You can follow by Newsletter or RSS! (What's RSS?) Full archive here.

    Landscape Gestures

    🏑

    Home on the range

    Playing with charcoal gestures!

    Generating Post Templates Programmatically with Python

    I'm extending my quick script from a previous post on Automating Image Uploads to Cloudinary with Python. I figured β€” why stop there! Instead of just automating the upload flow and getting the url copied to my clipboard, I could have it generate the whole markdown file for me!

    Form there, the steps that will be automated:

    • Verifying it's an art post (based on which folder I select to save the image to)
    • Creating a file with the post date in the filename (I usually put them together on Fridays, and share on Saturday)
    • Writing details from the command line, such as title, alt text, and post body.

    Here we go!

    Reorganizing

    First order of business is organizing the code. This was previously just a script, but now I'd like to encapsulate everything within a class.

    In my index.py, I'll setup the class:

    from dotenv import load_dotenv
    load_dotenv()
    
    import datetime
    import cloudinary
    import cloudinary.uploader
    import cloudinary.api
    import pyperclip
    
    class ImageHandler():
        """
        Upload Images to cloudinary. Generate Blog page if applicable
        """
        def __init__(self, test: bool = False):
            self.test = test
    
            config = cloudinary.config(secure=True)
            print("****1. Set up and configure the SDK:****\nCredentials: ", config.cloud_name, config.api_key, "\n")

    Beneath, I'll wrap the previous code in a method called "upload_image()"

    I'll still call the file directly to run the main script, so at the bottom of the file I'll add the code to do so:

    if __name__ == '__main__':
        ImageHandler().run()

    So, on run, I want to handle the upload to Cloudinary. From the result, I want to get the image url back, and I want to know if I should start generating an art post:

    def run(self):
        image_url, is_art_image = self.upload_image()
        print(is_art_image)
        if is_art_image:
            self.generate_blog_post(image_url=image_url)

    To make that happen, I'm adding a bit of logic to image_upload to check if I'm storing the image in my art folder:

    def upload_image(self):
    
        ... 
        
        options = [
            "/chrisdpadilla/blog/art",
            "/chrisdpadilla/blog/images",
            "/chrisdpadilla/albums",
        ]
    
        is_art_image = selected_number == 0
        
        ...
        
        selected_number = int(selected_number_input) - 1
        is_art_image = selected_number == 0
            
        ...
        
        return (res_url, is_art_image)

    That tuple will then return string and boolean in a neat little package.

    Now for the meat of it! I'll write out my generate_blog_post() method.

    Starting with date getting. Using datetime and timedelta, I'll be checking to see when the next Saturday will be (ART_TARGET_WEEKDAY is a constant set to 6 for Saturday):

    def generate_blog_post(self, image_url: str = '') -> bool:
        today = datetime.datetime.now()
    
        weekday = today.weekday()
        days_from_target = datetime.timedelta(days=ART_TARGET_WEEKDAY - weekday)
        target_date = today + days_from_target
        target_date_string = target_date.strftime('%Y-%m-%d')

    Sometimes, I do this a week out, so I'll add some back and forth incase I want to manually set the date:

        date_ok = input(f"{target_date_string} date ok? (Y/n): ")
        if "n" in date_ok:
            print("Set date:")
            target_date_string = input()
            print(f"New date: {target_date_string}")
            input("Press enter to continue ")

    From here, it's all command line inputs.

        
        title = input("Title: ")
        alt_text = input("Alt text: ")
        caption = input("Caption: ")

    And then I'll use a with statement to do my file writing. The benefit of using the with keyword here is that it will handle file closing automatically.

    
        md_body = SKETCHES_POST_TEMPLATE.format(title, target_date_string, alt_text, image_url, caption)
        with open(BLOG_POST_DIR + f"/sketches-{target_date_string}.md", "w") as f:
            f.write(md_body)
    
        return True

    ViolΓ ! Running through the command line now generates a little post! Lots of clicking and copy-and-pasting time saved! πŸ™Œ

    Angels We Have Heard on High

    Taeko Onuki

    Sunshower!

    Been listening to the City Pop gem Sunshower by Taeko Onuki

    New Album β€” Ice 🧊

    Brr!

    Music somewhere between ambient classical and winter lofi!

    Purchase on 🀘 Bandcamp and Listen on πŸ™‰ Spotify or any of your favorite streaming services!