written by Eric J. Ma on 2023-10-14 | tags: pre-commit pre-commit hook automation python python script software development data science dalle-3 til
In this blog post, I share my experience creating a custom pre-commit hook for resizing images within a repository. This hook automates the process of ensuring all logos meet a defined width, saving time and maintaining consistency. It uses Python and integrates with the pre-commit framework, running in an isolated environment to keep the main project clean. I also discuss the potential of distributing these hooks for wider use. Curious about how you can automate checks and streamline your development process with pre-commit hooks?
Today I learned how to make a pre-commit hook that lives locally within a repository. Pre-commit hooks are a powerful tool in any coder's arsenal -- whether they are a data scientist or software developer -- enabling us to automate certain checks before changes are committed to the repository. This ensures that every commit meets the defined standards and can save countless hours in code reviews.
The primary function of the pre-commit hook I made is to resize images, particularly logos, within the repository. I wanted this hook so I could avoid manually resizing blog banner images, which I've been creating using DALLE-3. Let's dive into a high-level overview of the script:
#!/usr/bin/env python3 """Resize images within the repository.""" from PIL import Image from pyprojroot import here def resize_image(image_path, base_width): with Image.open(image_path) as img: if img.size[0] > base_width: w_percent = base_width / float(img.size[0]) h_size = int(float(img.size[1]) * float(w_percent)) img = img.resize((base_width, h_size), Image.LANCZOS) img.save(image_path) return True return False def resize_logos_in_tree(root_dir, logo_name, max_width): resized_any = False for path in root_dir.rglob(logo_name): if resize_image(path, max_width): print(f"Resized: {path}") resized_any = True return resized_any if __name__ == "__main__": root_directory = here() logo_filename = "logo.webp" maximum_width = 600 if resize_logos_in_tree(root_directory, logo_filename, maximum_width): print("Some logos were resized. Commit rejected.") exit(1) else: print("All logos are of the maximum width. Commit accepted.") exit(0)
At its core, this script:
To understand how this script integrates with the pre-commit framework, let's break down the configuration for the pre-commit hook:
- repo: local hooks: - id: resize-logos name: Resize Logos entry: scripts/resize_images.py language: python language_version: python3 additional_dependencies: [pillow, pyprojroot] types: [png] files: logo\.webp$ pass_filenames: false
pillow
is for image processing and pyprojroot
helps in finding the root of the project.false
, meaning the script does not expect file names as command-line arguments.Now, how does this all work together? The magic of the pre-commit framework is that it creates an isolated Python environment specifically for the hook. This means the script doesn't run using the Python interpreter in your PATH. Instead, it uses a hidden, separate Python interpreter.
This might initially seem confusing or even redundant. However, it offers a significant advantage. By having a separate environment, there's no need to mix dependencies required by the hook with those of your main project. This separation ensures that the main project environment remains clean and free from unnecessary dependencies.
Harnessing the power of pre-commit hooks, especially custom ones tailored to specific project needs, is super empowering. They help maintain code and asset quality, automate checks, and streamline the development process.
Moving forward, I'd like to explore how to distribute these hooks, enabling other developers to benefit from them in their projects. The world of pre-commit hooks is vast, and there's always something new to learn and implement!
@article{
ericmjl-2023-how-images,
author = {Eric J. Ma},
title = {How I made a local pre-commit hook to resize images},
year = {2023},
month = {10},
day = {14},
howpublished = {\url{https://ericmjl.github.io}},
journal = {Eric J. Ma's Blog},
url = {https://ericmjl.github.io/blog/2023/10/14/how-i-made-a-local-pre-commit-hook-to-resize-images},
}
I send out a newsletter with tips and tools for data scientists. Come check it out at Substack.
If you would like to sponsor the coffee that goes into making my posts, please consider GitHub Sponsors!
Finally, I do free 30-minute GenAI strategy calls for teams that are looking to leverage GenAI for maximum impact. Consider booking a call on Calendly if you're interested!