Skip to content

Expand your project structure from atoms of code to galactic dimensions. 🌌

License

Notifications You must be signed in to change notification settings

manoelpqueiroz/galactipy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

❗ This is a mirror repository to galactipy, which is currently being developed on GitLab. Feel free to fork it and take a look at CONTRIBUTING.md to know how to contribute to the project!

Galactipy

Python support Repository Releases Licence Cookiecutter template

Project type Contributions Welcome Open issues Merge Requests

Poetry Pre-commit Editorconfig Code style: Ruff Docstrings: numpydoc

Semantic versions GitLab Pipelines Coverage

Expand your project structure from atoms of code to galactic dimensions. 🌌

TL;DR

cookiecutter gl:galactipy/galactipy --checkout v0.11.0

All you need is the latest version of cookiecutter! πŸ˜‰

πŸš€ Features

In this cookiecutter πŸͺ template we combine state-of-the-art libraries and best development practices for Python.

Development features

Deployment features

  • Issue and Merge Request templates for easy integration with GitLab and GitHub;
  • Predefined CI/CD build workflow for GitLab CI and Github Actions;
  • Automatic package uploads to PyPI test and production repositories;
  • Everything is already set up for security checks, codestyle checks, code formatting, testing, linting, docker builds etc. with invoke. More details in Invoke Usage;
  • Dockerfile for your package, with CI/CD workflows to publish your image to a container registry.

GitLab vs. GitHub features

You are free to choose whichever platform works best for you and your project. The original template by TezRomacH was created originally with GitHub in mind, which prompted the creation of a similarly fully-featured template for GitLab users as well.

However, not everything that is available for GitHub users is available to GitLab users, and vice-versa. Please mind the differences between both options.

Below is a comparison between the features available in this package depending on which platform you choose to host your project:

Feature GitLab GitHub Observations
Issue templates βœ… βœ… Both options feature automatic labels, but GitHub has an extra configuration to prevent the creation of empty issues.
Merge/pull requests templates βœ… βœ…
Project conditions checks βœ… βœ… A basic workflow to install the package and run tests, check codestyle and safety.
Publication to TestPyPI βœ… βœ… For GitHub, the workflow uses the official PyPI Publish action, while GitLab CI uses the PyPI API.
Publication to PyPI βœ… βœ… For GitHub, trusted publishing is used with the PyPI Publish action, while GitLab CI uses the PyPI API.
Image publication βœ… βœ… For GitHub, images are pushed to Docker Hub, while GitLab CI pushes images to the repository's Container Registry by default (and can be reconfigured).
Snapshot images βœ… ❌ For GitLab, the Docker CI/CD component is used and allows for pushing snapshot images for testing when a Merge Request is open.
Dockerfile linting βœ… ❌ The Docker GitLab CI/CD component includes a job for linting the Dockerfile with Hadolint.
Image vulnerability analysis βœ… ❌ The Docker GitLab CI/CD component uses Trivy to scan the image for vulnerabilities.
SBOM files βœ… ❌ The Docker GitLab CI/CD component generates a bill of materials with CycloneDX.
Stale issues βœ… βœ… GitLab rules are more flexible, marking stale issues only for those not opened by project members.
Greetings workflow ❌ βœ… GitHub provides workflows to automatically reply to issues and merge requests with the First Interaction action.
Dependabot ❌ βœ… Dependabot is a feature now incorporated into GitHub Security. See here how to enable it.
Release drafter ❌ βœ… Release Drafter is a custom workflow available on GitHub Marketplace. You may see the list of labels in release-drafter.yml. Works perfectly with Semantic Versions specification.
Changelog configuration βœ… ❌ GitLab provides automatic changelog updates through their API. You may modify the template in changelog_config.yml.
CI control over pushed tags βœ… ⚠️ GitLab provides full control for tags pushed to the repository using regex, while GitHub Actions is more restricted in how it filters workflows to run, and can only apply these filters at the top level, limiting workflow customization.

Open source community features

  • Ready-to-use Merge Request templates and several Issue templates;
  • Files such as: LICENCE, CONTRIBUTING.md, CODE_OF_CONDUCT.md, and SECURITY.md are generated automatically;
  • Loads of predefined badges to make your project stand out: project info, contributions, development practices, development tools and QA status; you can either keep them, remove as you wish or be welcome to add even more;
  • Workflows to mark and close abandoned issues after a period of inactivity for both GitLab with Triage Policies and GitHub with Stale Bot;
  • Semantic Versions specification with Changelog entries or Release Drafter.

🀯 How to use it

Installation

To begin using the template consider updating cookiecutter.

pip install -U cookiecutter

then go to a directory where you want to create your project and run:

cookiecutter gl:galactipy/galactipy --checkout v0.11.0

Input variables

Cookiecutter will ask you to fill some variables in order to generate the files with everything you need already set up.

The input variables, with their default values, are as follows:

Parameter Default value Description
project_name Python Project A suitable name by which people will refer to, you are free to name it however you wish to.
repo_name based on project_name Name of the repository to develop the project on. Check the availability of possible names before creating the project.
package_name based on project_name PyPI-compliant Python package name. Check the availability of possible names before creating the project.
project_description based on project_name A brief description of your project.
author Manoel Pereira de Queiroz Name of the author or organisation. Used to generate LICENCE and to specify ownership in pyproject.toml.
scm_platform GitLab One of GitLab and GitHub. Depending on the choice you will have different features to work with.
scm_username manoelpqueiroz GitHub or GitLab username for hosting. Also used to set up README.md, pyproject.toml and template files for either platform.
email based on scm_username Email for CODE_OF_CONDUCT.md, SECURITY.md files and to specify the ownership of the project in pyproject.toml.
licence MIT One of MIT, BSD-3, GNU GPL v3.0, GNU AGLP v3.0, GNU LGPL v3.0, Mozilla Public License 2.0 and Apache Software License 2.0, or Not open source.
minimal_python_version 3.9 Minimal Python version. All versions since 3.9 are available to choose. It is used for builds, pipelines and formatters.
use_ruff True πŸ”Ί Option to use ruff as the code formatter, along with a pre-commit hook.
line_length 88 The max length per line, dismiss if use_ruff is not used. NOTE: This value must be between 50 and 300.
docstring_style numpy One of numpy, pep257 or google, dismiss if use_ruff is not used. You can choose other to disable checks on your docstrings.
docstring_length based on line_lenght The max length for docstrings, dismiss if use_ruff is not used. NOTE: This value must be between 50 and 300 and lower of equal to line_lenght.
use_bdd True πŸ”Ί Option to use behaviour-driven development for managing tests.
create_cli True πŸ”Ί Option to create a simple CLI application with Typer and Rich libraries.
create_docker True πŸ”Ί Option to create a Dockerfile to build an image for your project.

✳️ Input variables marked with πŸ”Ί are boolean variables, you can dismiss those by typing either 0, false, f, no, n or off.

All input values will be saved in the cookiecutter-config-file.yml file so that you won't lose them. πŸ˜‰

Demo

$ cookiecutter gl:galactipy/galactipy
  [1/17] Project name (Python Project): A Decent Python Project
  [2/17] Project slug (a-decent-python-project): a-different-slug
  [3/17] Package name (a_decent_python_project): a_viable_package
  [4/17] Short description of the project (Awesome `a-different-slug` is a Python cli/package created with
https://gitlab.com/galactipy/galactipy): Let's try a cool description
  [5/17] Author or Organisation (The Galactipy Contributors):
  [6/17] In which platform would you like to host your code?
    1 - GitLab
    2 - GitHub
    Choose from [1/2] (1): 2
  [7/17] Platform username (galactipy): myuniqueusername
  [8/17] e-Mail ([email protected]): [email protected]
  [9/17] Which licence would you like to use for your project?
    1 - MIT Licence
    2 - 3-Clause BSD
    3 - GNU GPL v3.0
    4 - GNU AGPL v3.0
    5 - GNU LGPL v3.0
    6 - Mozilla Public License 2.0
    7 - Apache Software License 2.0
    8 - Not open source
    Choose from [1/2/3/4/5/6/7/8] (1): 4
  [10/17] Minimal Python version
    1 - 3.9
    2 - 3.10
    3 - 3.11
    4 - 3.12
    5 - 3.13
    Choose from [1/2/3/4/5] (1): 3
  [11/17] Use Ruff for linting and formatting? [y/n] (y): yes
  [12/17] Maximum line length (88):
  [13/17] Which docstring style would you like to use?
    1 - numpy
    2 - google
    3 - pep257
    4 - other
    Choose from [1/2/3/4] (1): 4
  [14/17] Docstring maximum line length (88):
  [15/17] Use behaviour-driven development for testing? [y/n] (y): 1
  [16/17] Would you like to create your project with CLI implementation? [y/n] (y): on
  [17/17] Containerize your application with Docker? [y/n] (y): no

Your project A Decent Python Project is created.

1) Now you can start working on it:

    $ cd a-different-slug && git init

2) If you don't have Poetry installed run:

    $ invoke poetry-download

3) Initialize poetry and install pre-commit hooks:

    $ invoke install
    $ invoke pre-commit-install

4) Run codestyle:

    $ invoke codestyle

5) Upload initial code to GitHub:

    $ git add .
    $ git commit -m ":tada: Initial commit"
    $ git remote add origin https://github.com/myuniqueusername/a-different-slug.git
    $ git push -u origin master

More details

Your project will contain README.md file with instructions for development, deployment etc. You can read the project README.md template before.

Initial set up

Initialize poetry

By running invoke install

After you create a project, it will appear in your directory, and will display a message about how to initialize the project.

Initialize pre-commit

By running invoke pre-commit-install. Make sure to set up git first via git init.

Package example

Want to know more about Poetry? Check its documentation.

Details about Poetry

Poetry's commands are very intuitive and easy to learn, like:

  • poetry add numpy@latest
  • poetry run pytest
  • poetry publish --build

etc.

CLI example

If you set create_cli to True the template comes with a cute little CLI application example. It utilises Typer and Rich for CLI input validation and beautiful formatting in the terminal.

After installation via invoke install (preferred) or poetry install you can try to play with the example:

poetry run <repo_name> --help
poetry run <repo_name> --name Manoel

Building and releasing your package

In order to release a new version of the application, a few steps are needed.

Make sure you have a PyPI account and generate an API token, you can then register it in your repository with

invoke pypi-config <API_token>

Then, you're all good to build and publish your package in one go!

invoke publish

You should also push a tag to GitLab or GitHub and create a Release for your application on the platform to ensure users can check the latest version contents.

Of course, you can also rely solely on the CI tools provided by Galactipy to handle building, publishing and releasing automatically, with minimal configuration required! πŸ₯³

If you have generated your project with the Docker option enabled, pushing a tag to your repository will also set up the automated workflows to build and publish your image to a container registry.

Invoke usage

invoke contains a lot of functions for faster development.

1. Download or remove Poetry

To download and install Poetry as a standalone application run:

invoke poetry-download

To uninstall

invoke poetry-remove

Alternatively, you can install it via your package manager (preferred) or any method provided by the documentation.

2. Install all dependencies and pre-commit hooks

Install requirements with

invoke install

And then add Poetry plugins to make development easier with

invoke poetry-plugins

Pre-commit hooks could be installed after git init via

invoke pre-commit-install

3. Codestyle

Automatic formatting uses ruff, and can be run with

invoke codestyle

# or use synonym
invoke format

For formatting checks only, without rewriting files:

invoke codestyle --check

Aside from the formatter, you can also use ruff to lint project files with several preconfigured rules defined in pyproject.toml:

invoke check-linter

4. Code security

invoke check-safety

This command launches Poetry integrity checks as well as identifies security issues with Safety and Bandit.

Update all dev libraries to the latest version using one command:

invoke update-dev-deps

5. Type checks

Run mypy static type checker with

invoke mypy

6. Tests

Run pytest with all essential parameters predefined with

invoke test

7. All code-related checks

Of course there is a command to rule run all checks in one:

invoke sweep

The same as:

invoke test check-linter codestyle mypy check-safety

8. Docker

Build your Docker image with the latest tag preconfigured with

invoke docker-build

Remove the Docker image with

invoke docker-remove

More information about Docker here.

9. Cleanup

Delete pycache files:

invoke pycache-remove

Remove package build:

invoke build-remove

Delete .DS_STORE files:

invoke dsstore-remove

Remove .mypycache:

invoke mypycache-remove

Or to remove all above run:

invoke cleanup

Applying BDD to Your Project

Behaviour-driven development is a software development paradigm in which domain language is used to describe the behaviour of the code. It sprang up from test-driven development.

Think of it as a way to use natural language to describe what we want the code to do in order to work on it with more clarity of end-goals and reduce bugs.

In order to apply BDD, however, a crucial perspective must change: tests should be described and written before the code itself. This is to make sure that the application's behaviour (what it should do and what it should not do) are made very clear from the beginning.

If you choose to use BDD for your project, a features directory will be created under tests and pytest-bdd will be added as a dependency. You should place .feature files inside this folder to specify them and describe scenarios using the Gherkin language:

# tests/features/divide.feature
Feature: Divide numbers
  Scenario: Full division
    When I ask the calculator to divide "21" by "7"
    Then the screen should return "3" as an integer

  Scenario: Division by zero
    When I ask the calculator to divide any number by "0"
    Then the screen should return an error message

You would then use pytest-bdd to wrap each scenario referred in the feature file as a step by step validation:

from mypackage import divide
from pytest_bdd import scenario, when, then

@scenario("divide.feature", "Full Division")
def test_full_division():
    pass

@when("I ask the calculator to divide \"21\" by \"7\"")
def divide_21_7():
    calculation = divide(21, 7)

    return calculation

@then("The screen should return \"3\" as an integer")
def return_integer():
    assert calculation.display == "3"


@scenario("divide.feature", "Division by Zero")
def test_zero_division():
    pass

@when("I ask the calculator to divide any number by \"0\"")
def divide_by_zero():
    calculation = divide(15, 0)

    return calculation

@then("The screen should return an error message")
def return_integer():
    assert calculation.display == "Error"

Then you can simply use pytest as you normally would to run the test suite and check the results.

For more information on behaviour-driven development and more advanced cases, please check out the Cucumber documentation.

🎯 What's next

Well, that's up to you. πŸ’ͺ

For further setting up your project:

  • Look for files and sections marked with UPDATEME, these should be updated according to the needs and characteristics of your project;

    • If you use VS Code, install the Todo Tree extension to easily locate and jump to these marks, they are already configured in the settings.json file;
  • Make sure to create your desired Issue labels on your platform before you start tracking them so it ensures you will be able to filter them from the get-go;

  • Make changes to your CI configurations to better suit your needs.

  • In order to reduce user prompts and keep things effective, the template generates files with a few assumptions:

    • It assumes your main git branch is master. If you wish to use another branch name for development, be aware of changes you will have to make in the Issue and Merge Request templates and README.md file so links won't break when you push them to your repo;
    • It generates a PyPI badge assuming you will be able to publish your project under repo_name, change it otherwise;
    • It generates a Docker badge assuming you also use scm_username for Docker Hub and you will push your image under repo_name, change it otherwise;

If you want to put your project on steroids, here are a few Python tools which can help you depending on what you want to achieve with your application:

  • Typer is great for creating CLI applications. If you chose to generate a CLI example during the Cookiecutter setup, Typer will already be among your dependencies;
  • Rich makes it easy to add beautiful formatting in the terminal. If you chose to generate a CLI example during the Cookiecutter setup, Rich will already be among your dependencies;
  • tqdm is a fast, extensible progress bar for Python and CLI;
  • Python Prompt Toolkit allows you to create more advanced terminal applications, such as a text editor or even your own shell;
  • orjson, an ultra fast JSON parsing library;
  • Pydantic is data validation and settings management using Python type hinting;
  • Returns makes you function's output meaningful, typed, and safe;
  • Loguru makes logging (stupidly) simple;
  • IceCream is a little library for sweet and creamy debugging;
  • Hydra is a framework for elegantly configuring complex applications;
  • FastAPI is a type-driven asynchronous web framework.

For taking development and exposition of your project to the next level:

  • Try out some more badges, not only it looks good, but it also helps people better understand some intricate details on how your project works:
    • You can look at dynamic badges available at Shields.io;
    • There is a myriad of standardised static badges at Simple Badges;
    • awesome-badges provides a lot of useful resources to help you deal with badges;
  • Add your project to OpenSSF Best Practices and OSSRank indexes. If you have greater ambitions for your project and/or expects it to scale at some point, it's worth considering adding it to these trackers;
    • There are already badges for those set up in your README.md file, just waiting for you to update their URLs with your project's index in both services; πŸ˜€
  • Setup a code coverage service for your tests, popular options include:
  • Setup a sponsorship page and allow users and organisations who appreciate your project to help raise for its development (and add a badge in the process! 😎). Popular platforms are:
    • Liberapay;
    • Open Collective;
    • Ko-fi;
    • If you host on GitHub, you can set a Sponsors account directly integrated into the platform;
    • Of course, you can also set any kind of gateway you wish, what works best for you and your project!

And here are a few articles which may help you:

πŸ“ˆ Galactipy Releases

You can see the list of available releases on the GitLab Releases page.

We follow Semantic Versions specification.

We use GitLab Changelog entries to track changes. You can categorise commits and Merge Requests made to this project using git trailers in your commit messages.

List of trailers and corresponding categories

Git trailer Category in CHANGELOG
enhancement, feature πŸš€ Features
bug, refactoring, bugfix, fix πŸ”§ Fixes & Refactoring
build, ci, testing πŸ“¦ Build System & CI/CD
breaking πŸ’₯ Breaking Changes
hooks, project-config βš™οΈ Internals
template-config :construction_site: Template Internals
documentation πŸ“ Documentation
dependencies ⬆️ Dependencies updates

🏞️ Roadmap

We aim to continue developing the template, following the bleeding edge new tools and best practices to improve the Python development experience, with the goal of turning Galactipy into the go-to reference for starting new projects, while giving users flexibility in how they wish to set up their repositories.

While we don't have a detailed roadmap for the project, our anticipated developments branch out in three categories.

Features Previewed in python-package-template

Galactipy was born out of python-package-template, developed by Roman Tezikov at GitHub. Roman's template was at the time the best template for Python projects for its feature richness which included the pre-configured CI workflows and makefile aliases that helped developers with day-to-day operations.

While the original project is now archived, there were some features Roman intended to develop and we wish to carry on for Galactipy:

Mirror GitHub features for GitLab

As the project started on GitHub, features like Dependabot, Release Drafter and stale issue were already set up, but require more research and complexity to implement on GitLab.

We would like Galactipy to have nearly equal functionality between GitHub and GitLab as possible, a considerable effort must be put just to ensure feature parity between the two.

Quality-of-life Features

We also wish to implement features completely new to the template, especially aiming at streamlining development process so less time is lost setting up a new project and apply software development best practices with available tools for the Python ecosystem:

  • Option to choose between test coverage or full code analysis, with providers for each yet to be selected;
  • Documentation upload to GitLab Pages and GitHub Pages;
  • Update GitHub Actions with the latest popular and useful workflows from the marketplace;
  • Add pre-commit hooks for finer control of the development cycle;
  • Implement SAST for improving security of your projects.

πŸ›‘οΈ Licence

Licence

This project is licenced under the terms of the MIT licence. See LICENCE for more details.

:sports_medal: Acknowledgements

Firstly, there is no way this template would exist without the previous phenomenal work by Roman Tezikov and his fully-featured python-package-template. If there is anyone more deserving of a 🌟 and acknowledgement, it's him! Please give a shoutout and support if possible.

The original template was inspired by several articles that might be helpful if you are starting out managing projects:

And also there are some projects which can be studied as references in project management and template design:

Additionally, we would like to thank the teams of the following projects for aiding us during our research and implementation of best practices and tools for Python development:

Give them your ⭐, these resources are amazing! πŸ˜‰

Galactipy Bot avatar created by Smashicons.

πŸ“ƒ Citation

@misc{galactipy,
  author = {Manoel Pereira de Queiroz},
  title = {Galactipy Python Package Project Generator},
  year = {2023, 2024},
  publisher = {GitLab},
  journal = {GitLab repository},
  howpublished = {\url{https://gitlab.com/galactipy/galactipy}}
}

Add the badge Expand your project structure from atoms of code to galactic dimensions. to your project! It would be really appreciated to spread the word of this template.

Here is the Markdown source for it:

[![Expand your project structure from atoms of code to galactic dimensions.](https://img.shields.io/badge/made%20with-galactipy%20%F0%9F%8C%8C-179287?style=for-the-badge&labelColor=193A3E)](https://kutt.it/7fYqQl)