From 8398deaf3f9e3d0686271fc1b6e78256ada3780d Mon Sep 17 00:00:00 2001 From: f-PLT Date: Tue, 24 Mar 2026 13:21:31 -0400 Subject: [PATCH 1/6] Update with new version of makefile --- .make/.bumpversion.toml | 40 ++ .make/CHANGES_MAKEFILE.md | 94 ++++ .make/Makefile | 94 ++++ .make/README.md | 63 +++ .make/base.make | 527 ++++++------------- .make/conda.make | 362 +++++++++++++ .make/docs.make | 29 + .make/img/README.md | 3 + .make/img/install_targets.png | Bin 0 -> 27228 bytes .make/img/make_targets.png | Bin 0 -> 235419 bytes .make/img/versionning_targets.png | Bin 0 -> 13208 bytes .make/lint.make | 45 ++ .make/manager.make | 63 +++ .make/poetry.make | 415 +++++++++++++++ .make/scripts/auto_init_script.py | 846 ++++++++++++++++++++++++++++++ .make/test.make | 52 ++ .make/tests/test-script.sh | 340 ++++++++++++ .make/tests/test_environment.yml | 6 + .make/tests/verify_init.py | 275 ++++++++++ .make/uv.make | 258 +++++++++ Makefile | 24 +- Makefile.private.example | 35 +- Makefile.variables | 36 +- pyproject.toml | 2 +- 24 files changed, 3219 insertions(+), 390 deletions(-) create mode 100644 .make/.bumpversion.toml create mode 100644 .make/CHANGES_MAKEFILE.md create mode 100644 .make/Makefile create mode 100644 .make/README.md create mode 100644 .make/conda.make create mode 100644 .make/docs.make create mode 100644 .make/img/README.md create mode 100644 .make/img/install_targets.png create mode 100644 .make/img/make_targets.png create mode 100644 .make/img/versionning_targets.png create mode 100644 .make/lint.make create mode 100644 .make/manager.make create mode 100644 .make/poetry.make create mode 100644 .make/scripts/auto_init_script.py create mode 100644 .make/test.make create mode 100755 .make/tests/test-script.sh create mode 100644 .make/tests/test_environment.yml create mode 100644 .make/tests/verify_init.py create mode 100644 .make/uv.make diff --git a/.make/.bumpversion.toml b/.make/.bumpversion.toml new file mode 100644 index 0000000..77fa299 --- /dev/null +++ b/.make/.bumpversion.toml @@ -0,0 +1,40 @@ +[tool.bumpversion] +current_version = "1.3.0" +commit = true +message = "Makefile version {new_version} released." +tag = true +tag_name = "makefile-{new_version}" +parse = '(?P\d+)\.(?P\d+)\.(?P\d+) (?P.*)?' +serialize = [ + "{major}.{minor}.{patch}" +] + +[[tool.bumpversion.files]] +filename = "CHANGES_MAKEFILE.md" +search = ''' +## [Unreleased](https://github.com/RolnickLab/lab-advanced-template/tree/main) (latest) + +______________________________________________________________________ +''' +replace = ''' +## [Unreleased](https://github.com/RolnickLab/lab-advanced-template/tree/main) (latest) + +______________________________________________________________________ + + + +## [{new_version}](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-{new_version}) ({utcnow:%Y-%m-%d}) + +______________________________________________________________________ +''' + +[[tool.bumpversion.files]] +filename = "base.make" +search = 'MAKEFILE_VERSION := {current_version}' +replace = 'MAKEFILE_VERSION := {new_version}' + + +[[tool.bumpversion.files]] +filename = "Makefile" +search = 'MAKEFILE_VERSION := {current_version}' +replace = 'MAKEFILE_VERSION := {new_version}' diff --git a/.make/CHANGES_MAKEFILE.md b/.make/CHANGES_MAKEFILE.md new file mode 100644 index 0000000..bdb2c53 --- /dev/null +++ b/.make/CHANGES_MAKEFILE.md @@ -0,0 +1,94 @@ +# CHANGES.md + +## [Unreleased](https://github.com/RolnickLab/lab-advanced-template/tree/main) (latest) + +______________________________________________________________________ + + + +## [1.3.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-1.3.0) (2026-02-12) + +______________________________________________________________________ + +- Fix test targets +- Move `docs` and `lab` dependency groups as optional groups `[extras]` +- Remove upper bounds of dependencies +- Add `test-notebooks` target to facilitate running tests using notebooks through the `nbval` library +- Add `self-test` and `self-test-autoinit` targets to Makefile utils +- Add new test for auto-initialization script +- Add `mypy` and `autotyping` + +## [1.2.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-1.2.0) (2026-01-21) + +______________________________________________________________________ + +- Add auto-initialization script and corresponding makefile targets + +## [1.1.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-1.1.0) (2026-01-20) + +______________________________________________________________________ + +- Add MkDocs dependencies and skeleton structure for MkDocs pages +- Add `docs` makefile targets +- Refactor base package to `src/core` instead of `src/` and improve package structure to follow current python best practices +- Improve and fix bugs/typos from the conda, poetry and uv targets + +## [1.0.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-1.0.0) (2025-11-21) + +______________________________________________________________________ + +- BREAKING CHANGE - Make default version of project use `uv` + - Consists of a rework of the `pyproject.toml` file that no longer works with `poetry<2.0.0` +- Added `poetry python install` functionality to the makefike +- Refactored `conda` installation to use miniforge and micromamba instead of miniconda +- Improve determination of build tool and environment by makefile to make experience simpler +- Refactor target group enablement via `Makefile.variables` file instead of commenting + out lines in `Makefile` +- Add link checker to `pre-commit` +- Refactor tests to reduce duplication +- Remove target that installed `poetry` inside conda environment +- Update documentation and README.md +- Convert to Google docstring format + +## [0.7.1](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-0.7.1) (2025-09-17) + +______________________________________________________________________ + +## [0.7.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-0.7.0) (2025-09-10) + +______________________________________________________________________ + +- Add `mdformat` tool for markdown linting +- Modularize the Makefile structure, allowing to choose which tools are available +- Add tests for the Makefile + +## [0.6.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-0.6.0) (2025-05-29) + +______________________________________________________________________ + +- Improve venv support +- Add venv remove target +- Refactor `poetry-install-auto` to really be automatic +- Add `mamba-install` target as an alternative/complement to conda for local dev +- Add `autoflake`, `autopep8` and `ruff` targets +- Fix some typos that caused targets to fail + +## [0.5.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-0.5.0) (2025-03-11) + +______________________________________________________________________ + +- Add venv support +- Update and fix `poetry-install-auto` target + +## [0.4.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-0.4.0) (2024-10-30) + +______________________________________________________________________ + +- Add cyclomatic complexity check target + +## [0.3.0](https://github.com/RolnickLab/lab-advanced-template/tree/makefile-0.3.0) (2024-10-30) + +______________________________________________________________________ + +- Add utilities to track makefile versions +- Fix many of the targets relating to standalone `poetry` installation diff --git a/.make/Makefile b/.make/Makefile new file mode 100644 index 0000000..41bd9ae --- /dev/null +++ b/.make/Makefile @@ -0,0 +1,94 @@ +######################################################################################## +# +# DO NOT MODIFY!!! +# If necessary, override the corresponding variable and/or target, or create new ones +# in one of the following files, depending on the nature of the override : +# +# `Makefile.variables`, `Makefile.targets` or `Makefile.private`, +# +# The only valid reason to modify this file is to fix a bug or to add new +# files to include. +######################################################################################## +PROJECT_PATH := $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) +MAKEFILE_VERSION := 1.3.0 +BUMP_TOOL := bump-my-version +BUMP_CONFIG_FILE := $(PROJECT_PATH).bumpversion.toml +SHELL := /usr/bin/env bash + + +# Colors +_SECTION := \033[1m\033[34m +_TARGET := \033[36m +_NORMAL := \033[0m + +.DEFAULT_GOAL := help +## -- Informative targets ------------------------------------------------------------------------------------------- ## + +.PHONY: all +all: help + +# Auto documented help targets & sections from comments +# detects lines marked by double #, then applies the corresponding target/section markup +# target comments must be defined after their dependencies (if any) +# section comments must have at least a double dash (-) +# +# Original Reference: +# https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html +# Formats: +# https://misc.flogisoft.com/bash/tip_colors_and_formatting +# +# As well as influenced by it's implementation in the Weaver Project +# https://github.com/crim-ca/weaver/tree/master + +.PHONY: help +# note: use "\#\#" to escape results that would self-match in this target's search definition +help: ## print this help message (default) + @echo "" + @echo "Please use 'make ' where is one of below options." + @echo "" + @for makefile in $(MAKEFILE_LIST); do \ + grep -E '\#\#.*$$' "$(PROJECT_PATH)/$${makefile}" | \ + awk 'BEGIN {FS = "(:|\-\-\-)+.*\#\# "}; \ + /\--/ {printf "$(_SECTION)%s$(_NORMAL)\n", $$1;} \ + /:/ {printf " $(_TARGET)%-24s$(_NORMAL) %s\n", $$1, $$2} ' 2>/dev/null ; \ + done + +.PHONY: targets +targets: help + +.PHONY: version +version: ## display current version of makefile + @echo "version: $(MAKEFILE_VERSION)" + +## -- Makefile versioning targets --------------------------------------------------- ## + +# Use the "dry" target for a dry-run version bump, ex. +# make bump-major dry +BUMP_ARGS ?= --verbose +ifeq ($(filter dry, $(MAKECMDGOALS)), dry) + BUMP_ARGS := $(BUMP_ARGS) --dry-run --allow-dirty +endif + +.PHONY: dry +dry: ## Add the dry target for a preview of changes; ex. `make bump-major dry` + @-echo > /dev/null + +.PHONY: bump-major +bump-major: ## Bump makefile major version + $(BUMP_TOOL) bump $(BUMP_ARGS) major --config-file $(BUMP_CONFIG_FILE) + +.PHONY: bump-minor +bump-minor: ## Bump makefile minor version <0.X.0> + $(BUMP_TOOL) bump $(BUMP_ARGS) minor --config-file $(BUMP_CONFIG_FILE) + +.PHONY: bump-patch +bump-patch: ## Bump makefile patch version <0.0.X> + $(BUMP_TOOL) bump $(BUMP_ARGS) patch --config-file $(BUMP_CONFIG_FILE) + +.PHONY: self-test +self-test: ## Run Makefile tests + @(cd $(PROJECT_PATH)/tests/ && $(SHELL) test-script.sh lint) + +.PHONY: self-test-autoinit +self-test-autoinit: ## Run Makefile auto init script test + @(cd $(PROJECT_PATH)/tests/ && python3 verify_init.py) \ No newline at end of file diff --git a/.make/README.md b/.make/README.md new file mode 100644 index 0000000..47d80d8 --- /dev/null +++ b/.make/README.md @@ -0,0 +1,63 @@ +# Makefile documentation + +This folder contains the base makefile targets. + +The project uses a Makefile to automate most operations. If `make` is available on your +machine there's a good chance this will work. + +## The Makefiles + +The following Makefile files should not be modified, but can be consulted: + +- [Makefile](../Makefile) : Entrypoint of the makefile utilities. +- [base.make](base.make) : Shared utilities, project agnostic. +- [conda.make](conda.make) : Conda related targets. +- [lint.make](lint.make) : Linting and formatting related targets. +- [poetry.make](poetry.make) : Poetry related targets. +- [manager.make](manager.make) : Manages which group to include based on Makefile variables. +- [test.make](test.make) : Test related targets. +- [uv.make](uv.make) : UV related targets. + +The following Makefile files are project or user specific and can be modified by +project users: + +- [Makefile.variables](../Makefile.variables) : Shared project variables. + - In this file, you can activate or deactivate target groups, and configure + settings according to your project's needs. +- [Makefile.targets](../Makefile.targets) : Shared project targets. +- [Makefile.private](../Makefile.private.example) : User specific variables and targets. + - This file is ignored by git and should never be committed, as it can also contain + secrets. You can override project configurations for local requirements, as + well as personal preferences. + - You can create your own version locally by copying from + [Makefile.private.example](../Makefile.private.example) + +## Basic Information + +The different targets and their description can be examined by executing the command: + +![](img/make_targets.png) + +If there is a problem with the contents of these targets, please open an +issue [here](https://github.com/RolnickLab/lab-advanced-template/issues). + +If you know how to fix the problem, please also consider opening a pull request with +your proposed solution. + +You can always override the faulty targets located here by creating new targets +with the same names inside [Makefile.targets](../Makefile.targets). + +The Makefile and `bump-my-version` related files in this directory are to help with +change tracking for the makefile itself. If you are using this makefile as part of a +template in another repository, you won't have to interact with them. + +## Tests + +Makefile tests can be found in the [.make/tests/](tests) folder. Current tests are +essentially bash scripts to test the different makefile targets. + +These should only be run when modifying the makefiles inside the +[Template's repository](https://github.com/RolnickLab/lab-advanced-template). + +They should **never** be run in a project implemented from the template, as they could +cause side effects to your project. diff --git a/.make/base.make b/.make/base.make index 9342369..b92dd71 100644 --- a/.make/base.make +++ b/.make/base.make @@ -3,7 +3,7 @@ # If necessary, override the corresponding variable and/or target, or create new ones # in one of the following files, depending on the nature of the override : # -# Makefile.variables, Makefile.targets or Makefile.private`, +# Makefile.variables, Makefile.targets or Makefile.private, # # The only valid reason to modify this file is to fix a bug or to add new # files to include. @@ -11,12 +11,14 @@ # Please report bugs to francis.pelletier@mila.quebec ######################################################################################## +.DEFAULT_GOAL := help + # Basic variables PROJECT_PATH := $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) MAKEFILE_NAME := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) SHELL := /usr/bin/env bash BUMP_TOOL := bump-my-version -MAKEFILE_VERSION := 0.2.0 +MAKEFILE_VERSION := 1.3.0 DOCKER_COMPOSE ?= docker compose AUTO_INSTALL ?= @@ -24,15 +26,105 @@ AUTO_INSTALL ?= # CONDA_TOOL can be overridden in Makefile.private file CONDA_TOOL := conda CONDA_ENVIRONMENT ?= +CONDA_YES_OPTION ?= + +# Global Variables +PIPX_VENV_PATH := $$HOME/.pipx_venv + +# Default variables (if Makefile.variables is missing) +APP_VERSION := 0.0.0 +APPLICATION_NAME := core +PYTHON_VERSION := 3.12 +DEFAULT_INSTALL_ENV := uv +DEFAULT_BUILD_TOOL := uv +TARGET_GROUPS := lint,test +CONDA_ENVIRONMENT := core + +# Targets Colors +_ESC := $(shell printf '\033') +_SECTION := $(_ESC)[1m\033[34m +_TARGET := $(_ESC)[1m\033[36m +_CYAN := $(_ESC)[36m +_NORMAL := $(_ESC)[0m +_WARNING := $(_ESC)[1;39;41m + +WARNING := $(_WARNING) -- WARNING -- $(_NORMAL) + +# Project and Private variables and targets import to override variables for local +# This is to make sure, sometimes the Makefile includes don't work. +-include Makefile.variables +-include Makefile.private + +comma := , +contains = $(if $(filter $(1),$(subst $(comma), ,$(2))),true) +not_in = $(if $(filter $(1),$(subst $(comma), ,$(2))),,true) + +INSTALL_ENV_IS_VENV := $(call contains,venv,$(DEFAULT_INSTALL_ENV)) +INSTALL_ENV_IS_UV := $(call contains,uv,$(DEFAULT_INSTALL_ENV)) +INSTALL_ENV_IS_POETRY := $(call contains,poetry,$(DEFAULT_INSTALL_ENV)) +INSTALL_ENV_IS_CONDA := $(call contains,conda,$(DEFAULT_INSTALL_ENV)) + +BUILD_TOOL_IS_UV := $(call contains,uv,$(DEFAULT_BUILD_TOOL)) +BUILD_TOOL_IS_POETRY := $(call contains,poetry,$(DEFAULT_BUILD_TOOL)) + +CONDA_CONFLICT := $(and $(INSTALL_ENV_IS_CONDA),$(BUILD_TOOL_IS_UV)) +UV_CONFLICT := $(and $(INSTALL_ENV_IS_POETRY),$(BUILD_TOOL_IS_UV)) +POETRY_CONFLICT := $(and $(INSTALL_ENV_IS_UV),$(BUILD_TOOL_IS_POETRY)) +PLEASE_FIX_CONFLICT_MSG := Please fix the conflict in your [Makefile.variables] and/or [Makefile.private] file(s) + +IS_MAKEFILE_VARIABLES_MISSING := $(call not_in,Makefile.variables,$(MAKEFILE_LIST)) +PLEASE_FIX_MISSING_FILE := Please consider adding a [Makefile.variables] file to your project - See lab-advanced-template for more info + +check_configs = $(if $($(1)), \ + $(info ) \ + $(info $(WARNING) $(2)) \ + $(info $(PLEASE_FIX_CONFLICT_MSG)) \ + $(info ) \ +) + +check_files = $(if $($(1)), \ + $(info ) \ + $(info $(WARNING) $(2)) \ + $(info $(PLEASE_FIX_MISSING_FILE)) \ + $(info ) \ +) + +# Config Checks +# These run immediately when you type 'make' +$(call check_configs,CONDA_CONFLICT,'conda' environment is enabled while using 'uv') +$(call check_configs,UV_CONFLICT,'poetry' environment is enabled while using 'uv') +$(call check_configs,POETRY_CONFLICT,'uv' environment is enabled while using 'poetry') +$(call check_files,IS_MAKEFILE_VARIABLES_MISSING,The configuration file 'Makefile.variables' is missing - Using default values) + + +## -- Initialization targets ---------------------------------------------------------------------------------------- ## +.PHONY: project-init +project-init: ## Initialize the project from the template - Only run once! + @python3 $(PROJECT_PATH).make/scripts/auto_init_script.py + +.PHONY: project-init-dry-run +project-init-dry: ## Test run: no changes will be made - Initialize the project from the template + @python3 $(PROJECT_PATH).make/scripts/auto_init_script.py --dry -# Colors -_SECTION := \033[1m\033[34m -_TARGET := \033[36m -_NORMAL := \033[0m -.DEFAULT_GOAL := help ## -- Informative targets ------------------------------------------------------------------------------------------- ## +.PHONY: info +info: ## Get project configuration info + @echo "" + @echo -e "$(_BLUE)--- Configuration Status ---$(_NORMAL)" + @echo "" + @echo -e "$(_CYAN)Application Name$(_NORMAL) : $(APPLICATION_NAME)" + @echo -e "$(_CYAN)Application version$(_NORMAL) : $(APP_VERSION)" + @echo -e "$(_CYAN)Application Root$(_NORMAL) : [$(PROJECT_PATH)]" + @echo -e "$(_CYAN)Application package$(_NORMAL) : [$(PROJECT_PATH)src/$(APPLICATION_NAME)]" + @echo -e "$(_CYAN)Environment manager$(_NORMAL) : $(DEFAULT_INSTALL_ENV)" + @echo -e "$(_CYAN)Build tool$(_NORMAL) : $(DEFAULT_BUILD_TOOL)" + @echo -e "$(_CYAN)Python version$(_NORMAL) : $(PYTHON_VERSION)" + @echo -e "$(_CYAN)Active makefile targets$(_NORMAL) : [$(TARGET_GROUPS)]" + @echo -e "$(_CYAN)Makefile version$(_NORMAL) : $(MAKEFILE_VERSION)" + + .PHONY: all all: help @@ -67,310 +159,51 @@ targets: help .PHONY: version version: ## display current version - @echo "version: $(APP_VERSION)" - -## -- Conda targets ------------------------------------------------------------------------------------------------- ## - -.PHONY: conda-install -conda-install: ## Install Conda on your local machine - @echo "Looking for [$(CONDA_TOOL)]..."; \ - $(CONDA_TOOL) --version; \ - if [ $$? != "0" ]; then \ - echo " "; \ - echo "Your defined Conda tool [$(CONDA_TOOL)] has not been found."; \ - echo " "; \ - echo "If you know you already have [$(CONDA_TOOL)] or some other Conda tool installed,"; \ - echo "Check your [CONDA_TOOL] variable in the Makefile.private for typos."; \ - echo " "; \ - echo "If your conda tool has not been initiated through your .bashrc file,"; \ - echo "consider using the full path to its executable instead when"; \ - echo "defining your [CONDA_TOOL] variable"; \ - echo " "; \ - echo "If in doubt, don't install Conda and manually create and activate"; \ - echo "your own Python environment."; \ - echo " "; \ - echo -n "Would you like to install Miniconda ? [y/N]: "; \ + @echo -e "$(_CYAN)Application version$(_NORMAL) : $(APP_VERSION)" + @echo -e "$(_CYAN)Makefile version$(_NORMAL) : $(MAKEFILE_VERSION)" + +## -- Virtualenv targets -------------------------------------------------------------------------------------------- ## + +VENV_PATH := $(PROJECT_PATH).venv +VENV_ACTIVATE := $(VENV_PATH)/bin/activate + +.PHONY: venv-create +venv-create: ## Create a virtualenv '.venv' at the root of the project folder + @virtualenv $(VENV_PATH) + @make -s venv-activate + +.PHONY: venv-activate +venv-activate: ## Print out the shell command to activate the project's virtualenv. + @echo "source $(VENV_ACTIVATE)" + +.PHONY: venv-remove +venv-remove: ## Delete the virtualenv '.venv' at the root of the project folder. + @if [ -d $(VENV_PATH) ]; then \ + echo "Current venv folder is [$(VENV_PATH)]"; \ + if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to completely delete this virtual environment? [y/N]: "; \ read ans; \ - case $$ans in \ + fi; \ + case $$ans in \ [Yy]*) \ - echo "Fetching and installing miniconda"; \ - echo " "; \ - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh; \ - bash ~/miniconda.sh -b -p $${HOME}/.conda; \ - export PATH=$${HOME}/.conda/bin:$$PATH; \ - conda init; \ - /usr/bin/rm ~/miniconda.sh; \ + echo ""; \ + echo "Starting deletion process for [$(VENV_PATH)]"; \ + rm -rf $(VENV_PATH); \ + echo ""; \ + echo "-- Deletion complete --"; \ ;; \ *) \ - echo "Skipping installation."; \ + echo ""; \ + echo "Skipping virtual environment deletion."; \ echo " "; \ ;; \ esac; \ - else \ - echo "Conda tool [$(CONDA_TOOL)] has been found, skipping installation"; \ - fi; - -.PHONY: conda-create-env -conda-create-env: conda-install ## Create a local Conda environment based on `environment.yml` file - @$(CONDA_TOOL) env create -f environment.yml - -.PHONY: conda-env-info -conda-env-info: ## Print information about active Conda environment using - @$(CONDA_TOOL) info - -.PHONY: _conda-poetry-install -_conda-poetry-install: - $(CONDA_TOOL) run -n $(CONDA_ENVIRONMENT) $(CONDA_TOOL) install -c conda-forge poetry; \ - CURRENT_VERSION=$$(poetry --version | awk '{print $$NF}' | tr -d ')'); \ - REQUIRED_VERSION="1.6.0"; \ - if [ "$$(printf '%s\n' "$$REQUIRED_VERSION" "$$CURRENT_VERSION" | sort -V | head -n1)" != "$$REQUIRED_VERSION" ]; then \ - echo "Poetry installed version $$CURRENT_VERSION is less than minimal version $$REQUIRED_VERSION, fixing urllib3 version to prevent problems"; \ - poetry add "urllib3<2.0.0"; \ - fi; - -.PHONY:conda-poetry-install -conda-poetry-install: ## Install Poetry in currently active Conda environment. Will fail if Conda is not found - @poetry --version; \ - if [ $$? != "0" ]; then \ - echo "Poetry not found, proceeding to install Poetry..."; \ - echo "Looking for [$(CONDA_TOOL)]...";\ - $(CONDA_TOOL) --version; \ - if [ $$? != "0" ]; then \ - echo "$(CONDA_TOOL) not found; Poetry will not be installed"; \ - else \ - echo "Installing Poetry with Conda in [$(CONDA_ENVIRONMENT)] environment"; \ - make -s _conda-poetry-install; \ - fi; \ - fi; - -.PHONY: conda-poetry-uninstall -conda-poetry-uninstall: ## Uninstall Poetry located in currently active Conda environment - $(CONDA_TOOL) run -n $(CONDA_ENVIRONMENT) $(CONDA_TOOL) remove poetry - -.PHONY: conda-clean-env -conda-clean-env: ## Completely removes local project's Conda environment - $(CONDA_TOOL) env remove -n $(CONDA_ENVIRONMENT) - -## -- Poetry targets ------------------------------------------------------------------------------------------------ ## - -.PHONY: poetry-install-auto -poetry-install-auto: ## Install Poetry in activated Conda environment, or with pipx if Conda not found - @poetry --version; \ - if [ $$? != "0" ]; then \ - echo "Poetry not found, proceeding to install Poetry..."; \ - echo "Looking for [$(CONDA_TOOL)]...";\ - $(CONDA_TOOL) --version; \ - if [ $$? != "0" ]; then \ - echo "$(CONDA_TOOL) not found, trying with pipx"; \ - pipx --version; \ - if [ $$? != "0" ]; then \ - echo "pipx not found; installing pipx"; \ - pip install --user pipx; \ - pipx ensurepath; \ - fi; \ - pipx install poetry; \ - else \ - echo "Installing poetry with Conda"; \ - make -s _conda-poetry-install; \ - fi; \ - fi; - -.PHONY: poetry-install -poetry-install: ## Install standalone Poetry using pipx and create Poetry env. Will install pipx if not found - @echo "Looking for Poetry version...";\ - poetry --version; \ - if [ $$? != "0" ]; then \ - if [ "$(AUTO_INSTALL)" = "true" ]; then \ - ans="y";\ - else \ - echo "Looking for pipx version...";\ - pipx --version; \ - if [ $$? != "0" ]; then \ - echo""; \ - echo -e "\e[1;39;41m-- WARNING --\e[0m The following pip has been found and will be used to install pipx: "; \ - echo " -> "$$(which pip); \ - echo""; \ - echo "If you do not have write permission to that environment, you will need to either activate"; \ - echo "a different environment, or create a virtual one (ex. venv) to install pipx into it."; \ - echo "See documentation for more information."; \ - echo""; \ - echo "Alternatively, the [make poetry-install-venv] target can also be used"; \ - echo""; \ - echo -n "Would you like to install pipx and Poetry? [y/N]: "; \ - else \ - echo""; \ - echo -n "Would you like to install Poetry using pipx? [y/N]: "; \ - fi; \ - read ans; \ - fi; \ - case $$ans in \ - [Yy]*) \ - pipx --version; \ - if [ $$? != "0" ]; then \ - echo "pipx not found; installing pipx"; \ - pip install --user pipx || pip install pipx; \ - pipx ensurepath; \ - fi; \ - echo "Installing Poetry"; \ - pipx install poetry; \ - make -s poetry-create-env; \ - ;; \ - *) \ - echo "Skipping installation."; \ - echo " "; \ - ;; \ - esac; \ - fi; - -.PHONY: poetry-install-venv -poetry-install-venv: ## Install standalone Poetry and Poetry environment. Will install pipx in $HOME/.pipx_venv - @echo "Creating virtual environment using venv here : [$$HOME/.pipx_venv]" - @python3 -m venv $$HOME/.pipx_venv - @echo "Activating virtual environment [$$HOME/.pipx_venv]" - @source $$HOME/.pipx_venv/bin/activate - @pip3 install pipx - @make -s poetry-install - -.PHONY: poetry-env-info -poetry-env-info: ## Information about the currently active environment used by Poetry - @poetry env info - -.PHONY: poetry-create-env -poetry-create-env: ## Create a Poetry managed environment for the project (Outside of Conda environment). - @echo "Creating Poetry environment that will use Python $(PYTHON_VERSION)"; \ - poetry env use $(PYTHON_VERSION); \ - poetry env info - @echo"" - @echo "This environment can be accessed either by using the " - @echo "command, or activated with the command." - @echo"" - @echo "Use and for more information" - @echo"" - -.PHONY: poetry-remove-env -poetry-remove-env: ## Remove current project's Poetry managed environment. - @if [ "$(AUTO_INSTALL)" = "true" ]; then \ - ans_env="y";\ - env_path=$$(poetry env info -p); \ - env_name=$$(basename $$env_path); \ - else \ - echo""; \ - env_path=$$(poetry env info -p); \ - if [[ "$$env_path" != "" ]]; then \ - echo "The following environment has been found for this project: "; \ - env_name=$$(basename $$env_path); \ - echo""; \ - echo "Env name : $$env_name"; \ - echo "PATH : $$env_path"; \ - echo""; \ - echo "If the active environment listed above is a Conda environment,"; \ - echo "Choosing to delete it will have no effect; use the target "; \ - echo""; \ - echo -n "Would you like delete the environment listed above? [y/N]: "; \ - read ans_env; \ - else \ - env_name="None"; \ - env_path="None"; \ - fi; \ - fi; \ - if [[ $$env_name != "None" ]]; then \ - case $$ans_env in \ - [Yy]*) \ - poetry env remove $$env_name || echo "No environment was removed"; \ - ;; \ - *) \ - echo "No environment was found/provided - skipping environment deletion"; \ - ;;\ - esac; \ - fi; \ - -.PHONY: poetry-uninstall -poetry-uninstall: poetry-remove-env ## Uninstall pipx-installed Poetry and the created environment - @if [ "$(AUTO_INSTALL)" = "true" ]; then \ - ans="y";\ - else \ - echo""; \ - echo -n "Would you like to uninstall pipx-installed Poetry? [y/N]: "; \ - read ans; \ - fi; \ - case $$ans in \ - [Yy]*) \ - pipx uninstall poetry; \ - ;; \ - *) \ - echo "Skipping uninstallation."; \ - echo " "; \ - ;; \ - esac; \ - -.PHONY: poetry-uninstall-pipx -poetry-uninstall-pipx: poetry-remove-env ## Uninstall pipx-installed Poetry, the created Poetry environment and pipx - @if [ "$(AUTO_INSTALL)" = "true" ]; then \ - ans="y";\ - else \ - echo""; \ - echo -n "Would you like to uninstall pipx-installed Poetry and pipx? [y/N]: "; \ - read ans; \ - fi; \ - case $$ans in \ - [Yy]*) \ - pipx uninstall poetry; \ - pip uninstall -y pipx; \ - ;; \ - *) \ - echo "Skipping uninstallation."; \ - echo " "; \ - ;; \ - esac; \ - -.PHONY: poetry-uninstall-venv -poetry-uninstall-venv: ## Uninstall pipx-installed Poetry, the created Poetry environment, pipx and $HOME/.pipx_venv - @python3 -m venv $$HOME/.pipx_venv - @source $$HOME/.pipx_venv/bin/activate - @make -s poetry-uninstall-pipx - @if [ "$(AUTO_INSTALL)" = "true" ]; then \ - ans="y";\ - else \ - echo""; \ - echo -n "Would you like to remove the virtual environment located here : [$$HOME/.pipx_venv] ? [y/N]: "; \ - read ans; \ - fi; \ - case $$ans in \ - [Yy]*) \ - rm -r $$HOME/.pipx_venv; \ - ;; \ - *) \ - echo "Skipping [$$HOME/.pipx_venv] virtual environment removal."; \ - echo ""; \ - ;; \ - esac; \ - -## -- Install targets (All install targets will install Poetry if not found using `make poetry-install-auto`)-------- ## - -.PHONY: install -install: install-precommit ## Install the application package, developer dependencies and pre-commit hook - -.PHONY: install-precommit -install-precommit: install-dev## Install the pre-commit hooks (also installs developer dependencies) - @if [ -f .git/hooks/pre-commit ]; then \ - echo "Pre-commit hook found"; \ - else \ - echo "Pre-commit hook not found, proceeding to configure it"; \ - poetry run pre-commit install; \ - fi; - -.PHONY: install-dev -install-dev: poetry-install-auto ## Install the application along with developer dependencies - @poetry install --with dev - -.PHONY: install-with-lab -install-with-lab: poetry-install-auto ## Install the application and it's dev dependencies, including Jupyter Lab - @poetry install --with dev --with lab - - -.PHONY: install-package -install-package: poetry-install-auto ## Install the application package only - @poetry install + else \ + echo "Venv [$(VENV_PATH)] does not exist, nothing to do"; \ + fi; ## -- Versioning targets -------------------------------------------------------------------------------------------- ## @@ -381,83 +214,39 @@ ifeq ($(filter dry, $(MAKECMDGOALS)), dry) BUMP_ARGS := $(BUMP_ARGS) --dry-run --allow-dirty endif +.PHONY: dry +dry: ## Add the dry target for a preview of changes; ex. 'make bump-major dry' + @-echo > /dev/null + .PHONY: bump-major bump-major: ## Bump application major version - $(BUMP_TOOL) $(BUMP_ARGS) bump major + @$(ENV_COMMAND_TOOL) $(BUMP_TOOL) bump $(BUMP_ARGS) major .PHONY: bump-minor bump-minor: ## Bump application minor version <0.X.0> - $(BUMP_TOOL) $(BUMP_ARGS) bump minor + @$(ENV_COMMAND_TOOL) $(BUMP_TOOL) bump $(BUMP_ARGS) minor .PHONY: bump-patch bump-patch: ## Bump application patch version <0.0.X> - $(BUMP_TOOL) $(BUMP_ARGS) bump patch - -## -- Docker targets ------------------------------------------------------------------------------------------------ ## - -## -- Apptainer/Singularity targets --------------------------------------------------------------------------------- ## + @$(ENV_COMMAND_TOOL) $(BUMP_TOOL) bump $(BUMP_ARGS) patch -## -- Linting targets ----------------------------------------------------------------------------------------------- ## -.PHONY: check-lint -check-lint: ## Check code linting (black, isort, flake8, docformatter and pylint) - poetry run nox -s check -.PHONY: check-pylint -check-pylint: ## Check code linting with pylint - poetry run nox -s pylint -.PHONY: fix-lint -fix-lint: ## Fix code linting (black, isort, flynt, docformatter) - poetry run nox -s fix +## -- General Install Targets ---------------------------------------------------------------------------------------- ## -.PHONY: precommit -precommit: ## Run Pre-commit on all files manually - poetry run nox -s precommit - - -## -- Tests targets ------------------------------------------------------------------------------------------------- ## - -.PHONY: test -test: ## Run all tests - poetry run nox -s test - -TEST_ARGS ?= -MARKER_TEST_ARGS = -m "$(TEST_ARGS)" -SPECIFIC_TEST_ARGS = -k "$(TEST_ARGS)" -CUSTOM_TEST_ARGS = "$(TEST_ARGS)" +.PHONY: install +install: install-dev install-precommit ## Install the application package, developer dependencies and pre-commit hook -.PHONY: test-marker -test-marker: ## Run tests using pytest markers. Ex. make test-marker TEST_ARGS="" - @if [ -n "$(TEST_ARGS)" ]; then \ - poetry run nox -s test_custom -- -- $(MARKER_TEST_ARGS); \ - else \ - echo "" ; \ - echo 'ERROR : Variable TEST_ARGS has not been set, please rerun the command like so :' ; \ - echo "" ; \ - echo ' make test-marker TEST_ARGS=""' ; \ - echo "" ; \ - fi -.PHONY: test-specific -test-specific: ## Run specific tests using the -k option. Ex. make test-specific TEST_ARGS="" - @if [ -n "$(TEST_ARGS)" ]; then \ - poetry run nox -s test_custom -- -- $(SPECIFIC_TEST_ARGS); \ - else \ - echo "" ; \ - echo 'ERROR : Variable TEST_ARGS has not been set, please rerun the command like so :' ; \ - echo "" ; \ - echo ' make test-specific TEST_ARGS=""' ; \ - echo "" ; \ - fi - -.PHONY: test-custom -test-custom: ## Run tests with custom args. Ex. make test-custom TEST_ARGS="-m 'not offline'" - @if [ -n "$(TEST_ARGS)" ]; then \ - poetry run nox -s test_custom -- -- $(CUSTOM_TEST_ARGS); \ +.PHONY: install-precommit +install-precommit: ## Install the pre-commit hook (need to run one of the install targets first) + @if [ -f .git/hooks/pre-commit ]; then \ + echo "Pre-commit hook found"; \ else \ - echo "" ; \ - echo 'ERROR : Variable TEST_ARGS has not been set, please rerun the command like so :' ; \ - echo "" ; \ - echo ' make test-custom TEST_ARGS=""' ; \ - echo "" ; \ - fi \ No newline at end of file + echo "Pre-commit hook not found, proceeding to configure it"; \ + $(ENV_COMMAND_TOOL) pre-commit install; \ + fi; + +.PHONY: uninstall-precommit +uninstall-precommit: ## Uninstall the pre-commit hook + @$(ENV_COMMAND_TOOL) pre-commit uninstall diff --git a/.make/conda.make b/.make/conda.make new file mode 100644 index 0000000..7471c25 --- /dev/null +++ b/.make/conda.make @@ -0,0 +1,362 @@ +-include Makefile.variables +-include Makefile.private + +## -- Conda targets ------------------------------------------------------------------------------------------------- ## + +CONDA_ENVIRONMENT_FILE := environment.yml +SLURM_ENV_VAR_PRESENT := env | grep -q "SLURM" + +CONDA_ENV_TOOL := $(shell command -v $(CONDA_TOOL) 2> /dev/null) +LOCAL_CONDA_TOOL_PATH := $(shell echo $$HOME/.local/bin/$(CONDA_TOOL)) +ifeq ($(CONDA_ENV_TOOL),) + CONDA_ENV_TOOL := $(LOCAL_CONDA_TOOL_PATH) +endif + +.PHONY: conda-install +conda-install: ## General target to install conda like tool - Uses 'CONDA_TOOL' makefile variable + @echo "### Checking if [$(CONDA_ENV_TOOL)] is installed ..."; \ + $(CONDA_ENV_TOOL) --version; \ + if [ $$? != "0" ]; then \ + echo " "; \ + echo "Your defined Conda tool [$(CONDA_TOOL)] has not been found."; \ + echo " "; \ + echo "If [$(CONDA_TOOL)] or some other Conda tool installed is supposed to already be installed"; \ + echo "on your system, check your [CONDA_TOOL] variable in the Makefile.private for typos."; \ + echo ""; \ + echo "If you already have some version of conda installed, it might not have"; \ + echo "been properly activated (which can also be on purpose when on a compute cluster)."; \ + echo "Consider reloading your shell before you try again."; \ + echo ""; \ + echo "If in doubt, don't install Conda and manually - create and activate"; \ + echo "your own Python environment some other way."; \ + echo ""; \ + echo "This script provides 2 option:"; \ + echo ""; \ + echo " * You can install 'conda' and 'mamba' through Miniforge3 (https://github.com/conda-forge/miniforge)"; \ + echo " which is recommended if you need both 'conda' and 'mamba' - Also strongly recommended if you use"; \ + echo " Pycharm, as 'micromamba' sometimes is not properly recognized by Pycharm."; \ + echo ""; \ + echo " * Or you can install 'micromamba' (which will also be available as 'mamba' in your shell)"; \ + echo " from the Micromamba project (https://mamba.readthedocs.io/en/latest/index.html)."; \ + echo " This is the ultra-lightweight solution."; \ + echo ""; \ + echo -n "Would you like to install one of the tools mentioned above? [y/N]: "; \ + read ans; \ + case $$ans in \ + [Yy]*) \ + echo ""; \ + echo -n "Would you like to install miniforge or micromamba? [miniforge/micromamba/none]: "; \ + read conda_provider; \ + case $$conda_provider in \ + "miniforge" | "mini" | "forge" ) \ + echo ""; \ + make -s _miniforge-install;\ + ;; \ + "micromamba" | "micro" | "mamba" ) \ + echo ""; \ + make -s mamba-install; \ + ;; \ + "None" | "none" | "no" | "n" ) \ + echo ""; \ + echo "Exiting process"; \ + ;; \ + *) \ + echo ""; \ + echo "Input is not conform, process is stopping - please try again"; \ + esac; \ + ;; \ + *) \ + echo ""; \ + echo "Terminating installation process."; \ + echo ""; \ + ;; \ + esac; \ + else \ + echo "Conda tool [$(CONDA_TOOL)] has been found, skipping installation"; \ + fi; + +.PHONY: _is_local_bin_on_path +_is_local_bin_on_path: + @echo "" + @echo "### Verifying if [$$HOME/.local/bin] is in PATH" + @if echo $$PATH | tr ':' '\n' | grep -Fxq "$$HOME/.local/bin"; then \ + echo "";\ + echo "[$$HOME/.local/bin] found in PATH variable - skipping";\ + echo "";\ + else \ + echo "";\ + echo "[$$HOME/.local/bin] NOT found in PATH variable"; \ + echo "";\ + echo "Adding 'export PATH="\$$HOME/.local/bin:\$$PATH"' to your .bashrc file"; \ + echo 'export PATH="$$HOME/.local/bin:$$PATH"' >> $$HOME/.bashrc; \ + echo "";\ + echo -e "$(WARNING) Consider reloading your shell after this.";\ + echo "";\ + fi; + +.PHONY: _installer-miniforge +_installer-miniforge: + @make -s _is_local_bin_on_path + @wget "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$$(uname)-$$(uname -m).sh" + @bash Miniforge3-$$(uname)-$$(uname -m).sh -b -p $$HOME/.miniforge3 + @echo "" + @echo "Adding [conda] and [mamba] to your '\$$HOME/.local/bin' directory" + @mkdir -p $$HOME/.local/bin + @ln -s $$HOME/.miniforge3/condabin/conda $$HOME/.local/bin/conda + @ln -s $$HOME/.miniforge3/condabin/mamba $$HOME/.local/bin/mamba + @/usr/bin/rm Miniforge3-$$(uname)-$$(uname -m).sh + @echo "" + @echo "Please configure the [CONDA_TOOL] variable in your 'Makefile.private file to" + @echo "either 'CONDA_TOOL := conda' or 'CONDA_TOOL := mamba', depending on which one " + @echo "you prefer to use" + @echo "" + @echo "Consider reloading your shell after this so you can have access to the tool" + @echo "" + +.PHONY: _installer-mamba +_installer-mamba: + @make -s _is_local_bin_on_path + @wget -qO- https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba + @echo "Adding [mamba] to your '\$$HOME/.local/bin' directory" + @mkdir -p $$HOME/.local/bin + @mv bin/micromamba $$HOME/.local/bin/mamba + @rm -rf bin/ + @echo "" + @echo "Please configure the [CONDA_TOOL] variable in your 'Makefile.private file to" + @echo "'CONDA_TOOL := mamba' for micromamba to be used by the makefile." + @echo "" + @echo "Consider reloading your shell after this so you can have access to the tool" + @echo "" + +.PHONY: _slurm-warming +_slurm-warming: + @echo "" + @echo "#" + @echo "#" + @echo "#" + @echo "" + @echo -e "$(WARNING)SLURM Environment variables have been found!!!" + @echo "" + @echo "#" + @echo "#" + @echo "#" + @echo "" + @echo "This indicates you might be on a compute cluster" + @echo "" + @echo "It is NOT advisable to execute this command if you are on a Compute Cluster (ie. Mila/DRAC)," + @echo "as they either have modules available (Mila), or even prohibit the installation " + @echo "and use of Conda (DRAC) based environments." + @echo "" + @echo "Please do not install Conda or similar tools on one the clusters of the" + @echo "Digital Research Alliance of Canada" + @echo "" + @echo "Only proceed if you know what you are doing!!!" + @echo "" + +.PHONY: _miniforge-install +_miniforge-install: + @echo "### Verifying for SLURM environment variable ..." + @if $(SLURM_ENV_VAR_PRESENT) ; then \ + make -s _slurm-warming; \ + echo -n "Are you sure you want to install Miniforge ? [y/N]: "; \ + read ans_slurm; \ + case $$ans_slurm in \ + [Yy]*) \ + echo ""; \ + echo "Installing Miniforge3 - without initializing it."; \ + make -s _installer-miniforge; \ + ;; \ + *) \ + echo ""; \ + echo "Terminating installation process."; \ + echo ""; \ + echo "Please activate the required cluster anaconda module or use another way "; \ + echo "to manage your environment before continuing."; \ + echo ""; \ + ;; \ + esac; \ + else \ + echo ""; \ + echo "Installing and initializing Miniforge"; \ + echo ""; \ + make -s _installer-miniforge; \ + $$HOME/.local/bin/mamba shell init --shell bash --root-prefix=$$HOME/.mamba; \ + echo ""; \ + echo "Installation process is complete."; \ + echo ""; \ + echo "Only 'mamba' has been initialized. Having 'conda' initialized forces activation the the base environment"; \ + echo "and can cause conflicts and/or unpredictable behavior with some environments - especially compute clusters."; \ + echo ""; \ + echo "To manually initialized, conda use the following command:"; \ + echo ""; \ + echo "$HOME/.local/bin/conda init"; \ + echo ""; \ + fi; \ + +.PHONY: _mamba-install +_mamba-install: + @echo "### Verifying for SLURM environment variable ..." + @if $(SLURM_ENV_VAR_PRESENT) ; then \ + make -s _slurm-warming; \ + echo -n "Are you sure you want to install Micromamba ? [y/N]: "; \ + read ans_slurm; \ + case $$ans_slurm in \ + [Yy]*) \ + echo ""; \ + echo "Installing Micromamba - without initializing it."; \ + make -s _installer-mamba; \ + ;; \ + *) \ + echo ""; \ + echo "Terminating installation process."; \ + echo ""; \ + echo "Please activate the required cluster anaconda module or use another way "; \ + echo "to manage your environment before continuing."; \ + echo " "; \ + ;; \ + esac; \ + else \ + echo ""; \ + echo "Installing and initializing Micromamba "; \ + echo ""; \ + make -s _installer-mamba; \ + $$HOME/.local/bin/mamba shell init -s bash $$HOME/.micromamba; \ + fi; \ + +.PHONY: miniforge-install +miniforge-install: ## Install conda and mamba from Miniforge3. (Full functionality for local development) + @echo "#"; \ + echo "# Miniforge Install process"; \ + echo "#"; \ + echo ""; \ + echo "### Verifying that [conda] is not already installed ..."; \ + conda --version; \ + if [ $$? != "0" ]; then \ + echo ""; \ + echo ""; \ + echo "[conda] has not been found."; \ + echo " "; \ + echo "If [conda] is already supposed to be installed on this system, it might not have"; \ + echo "been properly configured, and/or has not been initialized (which can also be on purpose when "; \ + echo "on a compute cluster). Consider reloading your shell before you try again."; \ + echo ""; \ + echo "If in doubt, don't install Miniforge. Instead, manually create and activate"; \ + echo "your Python environment some other way."; \ + echo ""; \ + echo "### Verifying that [mamba] is not already installed ..."; \ + mamba --version; \ + if [ $$? = "0" ]; then \ + echo -e "$(WARNING)[mamba] has been found - Installing miniforge is probably redundant"; \ + fi; \ + echo ""; \ + echo "### Verifying that [micromamba] is not already installed ..."; \ + micromamba --version; \ + if [ $$? = "0" ]; then \ + echo -e "$(WARNING)[micromamba] has been found - Installing miniforge is probably redundant"; \ + fi; \ + echo ""; \ + echo -n "Would you like to install and initialize Miniforge ? [y/N]: "; \ + read ans; \ + case $$ans in \ + [Yy]*) \ + echo ""; \ + make -s _miniforge-install; \ + ;; \ + *) \ + echo ""; \ + echo "Terminating installation process."; \ + echo ""; \ + ;; \ + esac; \ + else \ + echo "Conda tool [conda] has been found, skipping installation"; \ + fi; + +.PHONY: mamba-install +mamba-install: ## Install Micromamba as 'mamba'. (Minimalistic install for env management) + @echo "#"; \ + echo "# Micromamba Install process"; \ + echo "#"; \ + echo ""; \ + echo "### Verifying that [mamba] is not installed ..."; \ + mamba --version; \ + if [ $$? != "0" ]; then \ + echo ""; \ + echo "### Verifying that [micromamba] is not already installed ..."; \ + micromamba --version; \ + if [ $$? != "0" ]; then \ + echo ""; \ + echo "[mamba] and [micromamba] have not been found."; \ + echo ""; \ + echo "If [mamba] and/or [micromamba] are already supposed to be installed on this system,"; \ + echo "they might not have been properly configured, and/or have not been initialized"; \ + echo "(which can also be on purpose when on a compute cluster). Consider reloading your"; \ + echo "shell before you try again."; \ + echo ""; \ + echo "If in doubt, don't install Micromamba. Instead, manually create and activate"; \ + echo "your Python environment some other way."; \ + echo ""; \ + echo "### Verifying that [conda] is not already installed ..."; \ + conda --version; \ + if [ $$? = "0" ]; then \ + echo -e "$(WARNING)[conda] has been found - Only install micromamba if you really need it"; \ + fi; \ + echo ""; \ + echo -n "Would you like to install and initialize [micromamba] ? [y/N]: "; \ + read ans; \ + case $$ans in \ + [Yy]*) \ + echo ""; \ + make -s _mamba-install; \ + ;; \ + *) \ + echo ""; \ + echo "Terminating installation process."; \ + echo ""; \ + ;; \ + esac; \ + else \ + echo "[micromamba] has been found, skipping installation"; \ + fi; \ + else \ + echo "[mamba] has been found, skipping installation"; \ + fi; \ + + +.PHONY: conda-create-env +conda-create-env: conda-install ## Create a local Conda environment based on 'environment.yml' file + @if [ ! -f $(CONDA_ENVIRONMENT_FILE) ]; then \ + $(CONDA_ENV_TOOL) create $(CONDA_YES_OPTION) python=$(PYTHON_VERSION) -c conda-forge -n $(CONDA_ENVIRONMENT); \ + echo "Generating '$(ENV_FILE)' file..."; \ + if [ -f $(CONDA_ENVIRONMENT_FILE) ]; then \ + echo "Warning: $(CONDA_ENVIRONMENT_FILE) already exists. Overwriting..."; \ + fi; \ + ( \ + echo "name: $(CONDA_ENVIRONMENT)"; \ + echo "channels:"; \ + echo " - conda-forge"; \ + echo "dependencies:"; \ + echo -n " - python=$(PYTHON_VERSION)"; \ + ) > $(CONDA_ENVIRONMENT_FILE); \ + echo ""; \ + echo "#"; \ + echo "Done. File content:"; \ + cat $(CONDA_ENVIRONMENT_FILE); \ + echo ""; \ + echo "#"; \ + echo ""; \ + else \ + $(CONDA_ENV_TOOL) env create $(CONDA_YES_OPTION) -f $(CONDA_ENVIRONMENT_FILE); \ + fi; + +.PHONY: conda-env-info +conda-env-info: ## Print information about active Conda environment using + @$(CONDA_ENV_TOOL) info + +.PHONY: conda-activate +conda-activate: ## Print the shell command to activate the project's Conda env. + @echo "$(CONDA_ENV_TOOL) activate $(CONDA_ENVIRONMENT)" + +.PHONY: conda-clean-env +conda-clean-env: ## Completely removes local project's Conda environment + $(CONDA_ENV_TOOL) env remove $(CONDA_YES_OPTION) -n $(CONDA_ENVIRONMENT) diff --git a/.make/docs.make b/.make/docs.make new file mode 100644 index 0000000..c1c5804 --- /dev/null +++ b/.make/docs.make @@ -0,0 +1,29 @@ +## -- Docs targets -------------------------------------------------------------------------------------------------- ## +.PHONY: preview-docs +preview-docs: install-docs ## Preview the documentation site locally + @$(ENV_COMMAND_TOOL) mkdocs serve -a 0.0.0.0:7000 + + +.PHONY: build-docs +build-docs: install-docs ## Build the documentation files locally + @$(ENV_COMMAND_TOOL) mkdocs build + +.PHONY: deploy-docs +deploy-docs: install-docs ## Publish and deploy the documentation to the live Github page + @echo ""; \ + echo -e "\e[1;39;41m-- WARNING --\e[0m This command will deploy all current changes to the live Github page - Making it publicly available"; \ + echo ""; \ + echo -n "Would you like to deploys the docs? [Y/n]: "; \ + read ans; \ + case $$ans in \ + [Yy]*) \ + echo ""; \ + $(ENV_COMMAND_TOOL) mkdocs gh-deploy; \ + echo ""; \ + ;; \ + *) \ + echo ""; \ + echo "Skipping publication to Github Pages."; \ + echo " "; \ + ;; \ + esac; \ diff --git a/.make/img/README.md b/.make/img/README.md new file mode 100644 index 0000000..94f7956 --- /dev/null +++ b/.make/img/README.md @@ -0,0 +1,3 @@ +# Images + +This folder is for images used in the different Markdown documents. diff --git a/.make/img/install_targets.png b/.make/img/install_targets.png new file mode 100644 index 0000000000000000000000000000000000000000..433ae45c168b3be014d8d49f9f1da783c27c18a6 GIT binary patch literal 27228 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

|WmdlkCWUXb4*W2%NhtIc5Yv zOACh~MBu|IcMS8dA!m{Ka$+#Vzkmdg% z4xqwKCm$4Kef~SZTe>YX+a;nX`c>8N;~i!&U5DOGvlpq9+E}kDZ9!r7~j0G z)VTt|AQp-}V2Gvk)Gb;P6uQZ)@mD9&6p&*=1ya0Veo)Gp?2Mv+>!!r=V&B4*{$j!r znWTCphFNYoXo^~Upt!)jw2K>S_m+0%(F`^uSV~eQ^QjCvh&<97pv%D3B(ij?$u_Eu zPg9+q34{jqcU_%?5zBVGc9922E1+_-H%pS$ib+fSrj4EFtY8W$iwe8I3)V}Y$o8Dk zMWB%3@Y}#$Wp5W<$siY+bSSi<3QO2-5e!#-Sg(3IP+^7~lzSV!9*_tQuhDAU0MN8a4^-vSgGI%77c@|Co^YjSRt|J!>FtL6?QWgIeNnyn* zYy}o^wVB7((I|bD+WJt1a|Eo@O9?{N<_8(zHKV z#UPKaWkK#^gj~!xlu!~K7V#dwuQ{^`ISOH4&`1i@t(+{T?mnH5q&cAC;M^_-#qQ&J zD~YqeC$>&CmHQmuZ_;Yk%20i0rm*rC#US!Q8M?Gb@9=oNmdoLygR=mBcyp(;zaC!v zAw|d(UAWI8HBv(wGx}@SeQEQ8-)lx=R%%wTBG`FL?qu@^cG}NS@0cuK&D8^_>t!LV zSv!T$aR_@Y!A_=MEi*;gnyj6Ql9A`wL(oGCUT)A*FagLqD{7e;SIfM0hhJwh;Pbx5 z@JIEtVL4!>C7GP=vkM13vhp$;Qr>g&?=M$F3ZTMgz&I%2;3W`rVDItX<%KpS^+mZ3 zFPcSgR2oZ;u3FQA;?&KLM<`9U$74^lWgzRg%*}nK{^x=s@=z=l&?hzWm8F1_3ZU#Y zTA=PT&!{NpgF_^M*5*w}iINi&csad5Y>H^VO*?)kKUK(ycZYp^=NtLbi+oF%*53`I z_j#910!W>4zfw8`=*iAY(uZ#h7-foYX0LMMd#bG~b>NK^otG;Yj^O;>m?XNs5Z?}$ za04fP>Q%&YvMvkn{t&W%+2Oh~OGdTv2z@u^8_E%ZE{%c$^v`kp8s2;xxX(B0kP5zG zIuoTY&5gh;ZAA?e`Z-pTci9Bs~B+#1og3^W?#l{em;Au)buSO*+qBPy_Y)V2QabWAIx z`H8L1)e9G#Dl&NNt*zeXhx}EM5tn-ZiG8{@Zc7xI6SkX80^ay*Xy*QRlx*LM0fb?T zbxdh>YKUI*6wQjN2MqhA=YK9L!uZelTM0P%_E-Fc%02T`*V0`w?-r172kH|j^tWu) z9#`To#32S-mZI<~upio0I(LSM7-EMemud6Qo#{#c3gYRaP^Wm?B&t|@_zx^bYg_(9 zRBcww^68v~ZZNIxv=%lR{=~R7=+SF2wqpch@qA|G$6+tQKmXH}lz71o05+whY%(js z_u2@Y{s-J*agEJpn(um`T6x5zY}rt=`^#Y|OegI#4cUsBml*@EScuiD~P`Jda z9ndd)Et=r&>$ijqy&m$K%=^Q_TL(Z5Aq)k6Ms7?0<;L~`=bJi3mh)!Y81C>Cc!1(F zLGYHn$W?|ZL+756ZH#9z&GlDyI{1n&f+KbwZ|9p-Yv_#>H?Ey$2N&5@>i5p*oX7F0 z4#i2^1N%53T+B2`NzYeNJ&sokGq8}nMGQ8oM->5o)U1KgknU>@xM^+ZBLOWT3 z!iV-;%X!CFB}XdJmWpK^Ii&g~0@Ln+t#jm|!PE$pdmuCR{<2n~l^ zo`w*jAVB96(pC#p*tAlRdd?I8V&X#F2WsXMTV1&swa?0bn*Kt153_mPb1bFv z=Ih?1o^}D53?PG@x~AD2cv~m4JTa{ws=Rla-BX)>8%FQh&Y&sNM)4d&#_MRY^OBC{SkQe=1cD@Q}Y#o_o|Ks zPLZ@n@>5?wNP}G%QL+G+tA_@wpM@5lR^V%h-pkzHa@e+l2Gl#v?fVEWo@PzcnRS)x zUxn8cy@xYF&+(@(ITG1zF27UV*&q5|AoAl0MMn4XMvlc#e)xSEL=FyhZR_xUE7{6> zg*~!ev^~Qc7xM!07dDFBa0L$Y-F-|K>P+}(^`4WgBcYS--No)M2O3152&CXAi30R> zW!7{v`z;}A2Hj=~Xl#s*(@RV!*FhPS-v~Q0qlxY)AFeHAIi?a3$eV)0a@M* zeGkYS=FI{v`$Dnbyw>I+eGD>q!R3|19iS}P7giHuh}`v6GWS~_F|mJ#q8i3E3kuhD zy8Ct8HIOpSnoo1?^NuM5eI98wZ;{FjBm!B3_Q zmDaLy*C$QHb8h?^vA$x!E}TF6;}u+3su8IDcWHtc0*F~z8a9FDk>7LQZ*~muJQ(*? z9rAV3&2(D9Pv3s@2)L&s=PJ-4d|$Z`Q+W^=U+Hs^4@I96gZNHfZeDh$`l2^2n;nbl z$uHb5#^4&4K^_Km5_@ufB9T@L#H{IZ_wytepNi{6E6q=!f8=I6bX}^ijm>{ntJ7Ee z@$23l6_b0(n2}zvJi6_4O@*m7Crj)fETkgAMTnt0*BtPeo@HACPp?#S!iBAR9lIZtaYocO^+2%w3y@8Xi z*Y5W5e}gI`##Mkj&|DYgLG@@)a8al__mQ}5c0>tZ;#FLk1p09V7B-I!AvZg$*zQTp zb}iyS^Fz<#OctBoKx`2)g`8qcfxvA*M{cM-9h>Vk*QObDk)LQ4_#u#4$_Vt_T=WA8GMtNzz@@f-DQV;*3&xV$A{bmW+746uad#E75AIXv26EFL6u^r`;B> z-W+`&TcUZp;t4@~C>8O3H4pwjs7Vf#AU>Gt$jYxua)CQBjnl*Yd9XYT8ZrawzCnvM z(o)cM1NzV`6`lJkEm|hdRteUZM}I&uiMl0+(aCZo+ka`w2D)|MFi%)Mn5ks-M642N za|(Ij>ifo;e=!pPj?6KU0m7wT-o$3LyNuI9n!>F9vm}w8iWcxvoC_Z}C%(FuBA}yYgr^|TFhsRK=IcLQfDc*g z;BCcC*CJ($&ZP`#7y%Gx_@U=OA@S$X~G=& zaDJ;`0wpsSweYx#(!VzDuDQ*_4JV-+-@o=$IGw!RL1teON&f!{Jxc#m=&8c4+R}cv zb4`}PG-8#jpl1VeLVtlK>H4UV%r)c^Tb2B7ZSMe`kIE7Y7O7ga^67X}&4~s}C?e3{ z*~xFEO(fD7#7cg~iB(ZME-MWZ+rW{dVcU|oKl=#u07A$}2-SBCI3FQ}wonBq`fA^5{*<8my;Ydx^N&|v z$2dN2K&7vt&9?szl+A{KV&5H|@D+YLw6*H_hLqZ(MqS=al>h0+Zf{x$5p69aUa@J>~6k(;AN! zRMPQ93AM4C1X2d}Z@-2OR6EX_Yn*-*#c43@wQV-lq)9YqO4r)aL*Z}7K+kkyR9$me z?2y7Ks7rm|MQo)G(0<^q1Vw%)A>?yp+UU`;f5je4Oe7hg#X{Czv*ieLSR=bhpISJ_!dMfJ6P zUqz)v5T#Q(q)QNH1Oe$ziJ_aJq+=8irMo+%LqIx4Kzitu8tE8eq!}1yUi{thKJUBk z`+4qXt^LnA>pEwh-uwFO@AW+BOm~2u7qzKDwEvJ zXKuYoN?VBKhRL<5=LJpr<52aAd8v=l6QJE>m*0LJN%V@ir5zrRs1n=9J#lBzmZ9u6 zpt_ey?hi>a#A4C?x$?=ZMTsDis~`9qt-^lbSQg}{bjJ*(RURGo5_NKthBUS>q*5p*sbN^PqppR-d1>c~i&p z`B=L+;a5_xYQGRw!_%w_G>#V=Z2R@tNLQ}Ik-F1%&j^*OzO%{!RP?w)mTDTLyjL8H z2XZA=Z-2`Ga1b}-q%kp&nVjy+CT#=acirDYA4Q3FhX6)(en%K95w7GH@2y?U-$b2EICuN++Mz2(8$Kf?_y)Z0h-R$) zHe>Uu9|LI4A05nyH&zc(u~3gv?b^$7WsYI{hl<*-Bmxf zYFfgZ=)X0wcHY2Oyf^Fr-kPazYKs2v(rS2b?LR_;U3(r!TK+S1HH@9S|DXHmCPGRW z&<;N@kk^!`O!aBLA`3_3bw?`~_vaa<3l{TrPDUGG8@vjeK(6ZgNT7)nfcdY3HYQZE z(m7F%>ASDf5XoD`0vR1^PVLSo#o!9n?&d7F1AORrJwkT9Sei_T1FLgRSxQKYEn;K) z0r~8WNy6>A$D8z)ak-+4?DsT}#??98ib>2|AZFmEv60JrggvQfF)R`bvzdjZ!?MH^ z(}j>$X3Mt|>JgIq%1c@+KBW}>=hj-wF|`!_a7W1|C$P5D)TPGJzVuP{*6?zS`a|ml zbx7}ijElIA>-8z$6e|7>Wy4QRjAf;){3QO6q$H5~0IODw-P7CwVtp|})oDfRtZCpd z>8p_qK1}$WPw6?Qm#t1(P1CZ(d?$m-wS2W^fJq?wtyVxz2A0pk66=|aR$5NGfPk!X z;L@@5xzTS=F81SFUrP=kVrAXk#}r4Knhp@?3m#+aLOp%E=n0o!B}newFWCbb%kS6< zpupRTP0z+&fGF^(hqXD{3&JatMISo^A6lRZxl zrxXuO8c@)RZGDnZ-ZDbI7_#y$NySlqzFS4zCJ!#m_)K|hNwi2M&LlvU8&(XQ=4_g|X0@vhipV zaNWOMDY1jOt{ux#@`W-AH{7q$_TT9^otN%+NkNH_^dX`b2#$!fvsru~%bcfnCD{$ zX3MQ68`Fq)q52yvUXXm-gy<;XDOG{&IA*=M(=VPihd zo}`-+1GitL)td1(JtXK=u3|#&=mD0$eDoj^?k#-(Yr5KJ(nSaSoxgJn?k}gd8vlY_ zfJ31`(wW2-h#apfqN`$H$2>#f41blSS=1;|tEj~As8l+th#$n>x5 zfOao-TZCti`#RcyvU5X(o(d6tx3neG_n6p-(}ApQV=kBTeAIU6%gO~pH|s@bNHk5t zbE68HK9_c^>NMP$WQt;ReYQ*L&@IJ7lr>%*0Q|HZ9*)_~N4L#)l1hYyvU*U_feX3( z8E`9ZO?kv3&N8Whw|3NM)#$dZbC=wu03-YkxfK|`k7}EPw&1lL7yYB?jxtSCX7Xb+ z`bIFeuB|36(G=8kXnA%D{sr-FLi(Z8DS^D(?B`b>9q%8u{0QnnsXnyr8w*lGI`jQr z$(Mim)Zu{7cN)UXS0(j+$`#wf0BxA_A*FB5)La!U_ec;o7KsuNVK^STOgw;m7%2_B ze+?pt*gnK&C~TF(YgyHCSOV7QH(JDX(PK4YT9UIq7`J6;#+o6ySJd(wVA$!yF6iL{ zc%{*6t!i7fapO_=NadqMAD;#12l(-v>Ts{Y3yRRu=?@hBT+5=+k#UG(>8mX_2Us#j zzIb9-?PP(aQc3;SIbX5aG*!WQGSlko&5c3fEL56w+fjV-ORj?~ML8A5&N4CsEui&) z8+CMyw+Ea_vi_6StNI1J+#w;o3me> zk>pAA{T5nrj=Lqsa<5*Bn11HUYlFp_U$NZ!5cW;tGVm(_pCg0-nK{P=IS@<)ez-Ja zk9Wk%GL(s(-6I@i$dtn_pQ()@qovutm%K}^cwDA&$$uP9wnUTLH{>j5rzIv2_Y^bV zMgE@La-vQm0b^o6EJ;2~gI%-gAh9%1mH65ygYMxe0>ch>nhz2?84=pJzs)a}uBc3o zsUSWWJhDd0Ey>QPdxs^4C{+PEf8_zmo{Nkt@3EiMn7Sjmm8M=nEIV-`Np2rQ6Is3@ zASw+@@|arm%TX`0j*pxWqV}~9W9K{X1SOU4F2&b^PlM#p*V#NeBtskhn8bV9f*02* z0g0Q{Ujy70WT>=uM3#HM0SMa=` z!PNL;2CMegbRaY;rtz|*`pwMFg)23uTmg51O)JtQ4DC^h_kjZ|K)Z4Zurpr?38X9djN*JqN$=8LN1s08N#BrD7+VuY(0kv8}!Zf9?O2M zGU2yk9GIpAeG2n^D>>avS_pt|wn1n9_Qz?iE!wh>(i3*VlbSF)l*cjv1?P)D4%3DdkMZSJDivs~WOp=Xb2Bx$A!;$dy7qXUW3_Tblyj_vi*aSj5d+^EkS@aw;)x z`zTJg2SteTpvx5yLTMikJ`YpxxW6$aRgo|`&iD;ne5Wf;-qcTmj4O{kE?!qIz>b7e z?p;Jr+3E~)a8TeL2N&o1H+E#)(vg-)@2*BBkScHWt%R$wyKFhL=SXBxBYNH^tgxhl zijFi?)@@sCgdcD#xqUihW6plZlZqBrx>lTWHr(+kW_rK?66H=-I>Lrhz)!Sfs%1+~ zYkp@}d`<0ZKY}Vrf>jb6>`_I?46n_VE^*vb%i?-I%^d|14;|<7Vpr)4E41YV_YuVI&u^HfP9W@t}P)W^i|J3!VPnuUzmrzsry;WnIXnM8rQMx1p zTtUIc_m)U&^Sz4vgIVHcS_T^seBv5;a7NUhJ8>aU4j;jo2M=FJjt4cRQ9{AJeD_F6 z@BX;b%4~$EjmE}@QpXbbfpQ1gcADqYB3xL-8uG$G>)AryJ z(Jk!a+7&p_8`*=OpYncsnZA{_WNw4e6ZhV@we2ACcGR7vBWkdtTZ1IhGXL0fzqgjk zufn_lM{8K5U*b+9`{Z-`CvqNalaxPk$=LC)0)(W!gg$zw_jPG=d}2@u(VuGcbb%;Acd2ZGnkvd_n?eH4jUE{4NNuG8DyXh>}`nubUzj0QXGTI#T4CqtYs<}bl zQ>;)z3e4T6-KwJsF(e58WzFjEV$aZJvaw&RQ~3BtA14c)FlIb$gfL@jExeda)$XY0 z-GLdcF}-59P#U%kMV30JYu@4_x^448Po5}?^*!^Ac{(!n-s!MA-o6o;?g(9R2%7Yy zQ%qUZU2!9gs4Q&oTZb9?WiWru<#aqPfQ5X1PDU3Zgs5}GB$hNIANH?4GH00F@^Bo`jJ|0s5}U5 zVUQvfie`U_G>EWy`2BK>_>-h|WT?tM9guC#;Y5bmEoF6v< zu0b1&DvQwOc+Rgbk>w>)3%7(p&{mNvoS`@YkMT;#Vq$7Z%$o6PE}Oqyf(6y*HWt{! z2|6Z+s8-0o%EzK@edoQ%?wsS1jTkB(!9lh?yJt`$aN~7E!T5BAbjpUZS|2RQJ1eGK zap0(T!U{je+`yI9o_+thL?E`zE+cBv!DqPcPR3rm_x17tq&2Ksu?kKoo3hC(a^5Ti zh+ec^!k!LU(hlW}G_S5E$v!CNJ$2d0pyQ%1WiXB=KJTk3S@Y0*KYVD5uC-XdT;5~I z9$h|jw4>&zVk7A-$SWHm{5eVw^%FnSq7(_Z`*inp>2JF4pD;mj&Ig+-we`&q4SE_( z`a(d7&ArHbUkT62`Rzc%NMkyNuK_nMPW>B3Hm+?VX<^R?cqVAD zu>ZBRYn3vTsF0hWwKtgUre+LWD||f)i~MY+L>~}Q|G0acrQspa5VFDx_tQNZ}roQN7W zfWf4ya`*+(oobPEFr#Y?s|wPzq3EH#;A7fe}d}uSgJD5$C* z)xBO4I9aQpL%`mLZ4WtOtP^VkH$;;DGFzwxKBXyatOiR<=ihNOd32VzIh|Ji!;~ zLRXUdn+PuCcFoMjUmyv zBg-l(VlzR}!Avwwe2{eWe1gqgBZH=jFEj9)$8td34Y&np3+C+NVfOu>In#((k3b7{ z0ain5tpVXF%LFh5bV*4bP6l3-Zd!eIGFxu)iZvD&O@-*wlx~ev(Ck31=%GG=Pj!D> zi5qA*V@|{NU8v>g4szN0Z9gvBmSYh*3_#ggG%lqUMg%+L*q?K(aLwEIF>`%R=&;3t zAEOe*kb0WA&*09l8N&1>=h^2*sodv65o5mz%B8O|8>Fye?(WCbjeO0i)_fyf{f6>e zoecp;f!4>#mLb>MUg*39Z3CM8+O^qCDBHC{F87u{xPx@r=4pWl}}&0I9PH(duAfx)>xu&$_p z4hd?X3U2O#>Uqn?3lH&SjEXK6i}xCIlZAypZExQoCm-44!si7ErW?yi+^{P7&0tsN z$Ll>pPHvJXM|ZLuO>OqWE6z#p<;iTGEsjt%1k_v-7WxSAJ3x3;9P&l7Q2gb&cV zix9G`c)+`BL;n?XAtuE(NdG~^NJ1;5Z+vwA!M#Fha&Fv?|H-|?ByT)-{uv7PxhbOi zJ6Q{6T>4%8$6$xq;mPM7Ka)#W{~OXrlcN$V-6UwO0t)y{QycWRy^if(j)|wBOX-2h z1#y->B@}Dht7LV5(AVRAStyjoWf_eqx0O=#%5s?^9@UnuTzF{~f;w^>i#@ucFJwA4 zDInG{MVN(p)$<1oI!X%8W=1-aCc~m@>izVo_IHM=9m9==5L1MxbtJSPk1kd#sskxP z-_{G|6zvxP_^rComWqK6yaL=grgARDH5K`ez)GpqKE-LHvD4Y}H_8n$$@KP~maL=S zXuD?Yix!Nd{9fPp{v2DC1(zF}fmQDJ4F6HMFQMYas|2p@{hUyLMwN>!oKN86ErVQb;KKL0=7d zmK&kCcm?EGhA9OGQgK*tIuN~IE%ic(p)|Oax&-bxSd>;?QQ$x&7T?NsizOuNPH`aS z=v1q^w&!{M*t5GAx{~lxCw1A?X2Q#NcQPKA^bCHO76pk%k1WfXeCO{DLA&KFceQ%9 z4V2x$;+g@)XK#FPYoF?|EGx=wc{^QPII8I)F4TRZQpt&0_@&WnRfe}p({m3O_E?5I z<8Z?GExU}tbWb8u-^i^@R0Xt}6K_-7MZCuOQD)*+3;tg+s$aSP9iuY79K0>!E#!hR z=a#FoNJU=?ZLXkHsAg#(9T6V=-e25ak=iOqs1&o zgWI^ZF9arl(Frbbpu%fQCSYpaBa!VAw9hwby_yyI&MBX(S<`hzpPyj)4~wOvid(KT z{C(2_Fm8l;!CDa3gB>b=t^Ds%k$ay#ul%3Kxq0R7YHzJl(};`E35awr&NqwN<1;kg z{-o}4hbVr<K{7rq+uH{TdL=ldUw#X?jmt)hTYp?ryjx2JKqyr4uuTDAzt4HS$R@5EJ z;Rfe)dS$rQgeeJ-W5Y{`ev}nuE`@H>Sm88xdM5<+V#SZrx*oZ?^yGzr(WvQ}wMW&t zECJY^wC>EmT~}!TywGA#*g+X;@oho45`e>@LK&VjS10E(s-CIbVo5VmF;)A9nZwkF z&$m!{$2$+rwTYBxf4rvsZD=N3ha)fz^_}1#THSK9kx96WrV!bh`Q^mh$KFGfNC{62 z+b;vACs*0Rkd~igqd~<32J+8VH|;-EnzlsC(7jddEyKCs4>-7vszyZtB_W{%Mh`sb zL4Cm&QF)zx11#tYS7keds#J<42c zC*@KNQ27ie*^-o?cX)HOZi7W^p!fbA%i$*PyXiN&i4FdSWGX5fJXxiCUT|0JDi!@l zOvd4c$;eYGd)&H(pZ4b;0sje~(JPN;-)TD{Yz1BTSX7*8hP#-O$vu^NXR&^<@p8}4 z@Nh9Z*rnm|0P{tK>inGwzSy1xnk$&5!qpt9@sd`{#97-a-uR(-!uyf@ko5<*#T#@u zM<9H-+KWd0*a~d}-IpWm{Dr}j1FmmtpLZ$=A5Bh`Y20pj7gfo%_9`Tf{q9va?v(LKREh%bq_h@zu{#x_lttUk(w?J-vdloGez_8Pz@!*I9Cy z*aKgYz3okn5C;~Qvo1#viR&Xt;o%*cI~lWkSc#ibCcv!Y^LBeWbMIau|G~F1!RY)G zj!dAz@WGvr;XK@T`$yQ!`r7ns))E^=~Ex%F9i6Tr$c{oPY!opJ^;pB>UsG zFq}s1u2vRD(KH_Wb4Jl1leu`S7L!dn_WS{fHx-A-XHp~alV`nfH-d;tlcOq9Rc&cK zUevTw=Jixjw=_4TNZn)FE$X*+gnyMhf4x_Wr_kqK(p+PVzak%W-?9Rg+wibrw}MU-V8Q_D-!Y%NP7Qzp$5>jhKh#uO6)8R~gD0ZmZl z6LXhe#7nV(7NAz=F=sBJg-$PeqkB3JX=N?-B=nFRqvxm6V=iT?a#|Jm=%caF?N5$G zCh_$w$=`{!74ODfQ`PR+A7l!~T_e=YPR`;tX!@njiAn-SjL;%g)I=XJ$GMy4i@JDA z%sRrhtb-6pHc`nUgq^c~U;oL6Vokz27EqmmfcA=;L^<2jCTeWTPs*@+`Uzf>F@;m- zxe>*K996}9hI%ixrTjK)tI$+PhB=hI6SyaxFQ{iv3b0fgAU;)czI{=wLJe~Q@%5V$ z6o$nzvRvblb%sz*z=`XOHv6M7-nvH>o5$BHl5B9nkj1L5qQGROWCNN%LtUV&$)$LI zYeAmTGrPLG13To(Q%G350YULbSIP4iPamk>VIj<5>VoD5NKnTG`j79}Ixhqb4<;1l z4Zr)m>*4z5rSSIEg{i6PE1bF~FJGncEs(7Vae1p22aWUZwOhZmgSO~3J%J?-Z%v<}>;UwvASz4I4ak?cU&Cs4HFt5|94$1g@9H;t ztLUgT(nZ4V^94DFPAsKLp{mUJ!$Nd5?f@O#vuaxZPele_40t%|LRp&7@QujLoSV5l z&lLEh_o;UW$SWhFicS1N=sRlP%R@=J(ar`{de4-GFYLAx(NB}zYkFgjVqD(I4ETn%W;cw5i&R07T)D!%Dl}{9{(Y6^CW3wzZoIT1{0BD@dL-UMg<89(#rIl)}6nB0hM^>~v>6 zAhr%@B8gD^Gk9M`wBD2t0iN&}so0wh$4i94a#iniWc`fADAfd{*4+Qs5*GIvgZ~ID z%(9E|luzL;zKClN-AtOd8jr;DM+VC5x3;*a3b!lqBmsWk)s+^U6>8fJ{I>E0Y92uJ zb`c}qHB}OSJpV+;;rA#y2hdhm?Q_KXBXPIG|CXT;xCh%)b0{_uRQBucDnoYOuCy+J z$P})Y@6(pkxA3!jL_!CQj=fGgRVeTecBS6)XsPb*FIPrV+dex}?cyDDW8$+BKT^|V zPdb3BGwCY>tsz6dtVAnc_zteANOeT=*fQ8m)C7ezF|A6rhHb-D^YgbzK;Q^-&F*@% zUwGnBmX%gS1#g?f=Um|T6z3kp_FrVheuD}N;-rvsa*!BM_-4{TA@h)`L!)MMr;m8I z#SFl0Y7!Nzr;4eibCR?>u(4<@J9B*UCbYNW?^Ys4@w`HRO4jnh#1_V;auFGA)3pda`lMkf(s@qz&i?);H7cs*wml*|!w z>8QAT@@SRtU^P7TpyxFYJGV6sqO-yO_fTylnyPV(5s1zC7@Qq|o*~IGexAAR;>_41 zi_!5XK)}_^rEU@6JeKEgwLbEw$L9O9LBrPT4<3{pXNTJEZ%1vf%={6Dgz_p!K%L7? zjdT@Xg&gwOg;tcJG}Rh7E5ap%K2J4NOY1+0V-d!3L_9voKiKh?MMB?rACrgjmZLN! z{z@;0$hL0OKwS+8CJ1R=LEZqV(z!Iuv@xl35Nf?CmJ<+?=b~*1G>CYd5(JGyZ2vAM7e}V~z7C?63CUt6tRq fA2hInz4L8=o0Qwm&H3ifPq!51)MTq=%!2<9R49(| literal 0 HcmV?d00001 diff --git a/.make/img/make_targets.png b/.make/img/make_targets.png new file mode 100644 index 0000000000000000000000000000000000000000..ee7160fabcf56f5259bda0e58b1e49841739ca81 GIT binary patch literal 235419 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 z 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 literal 0 HcmV?d00001 diff --git a/.make/img/versionning_targets.png b/.make/img/versionning_targets.png new file mode 100644 index 0000000000000000000000000000000000000000..d2b2a95a1fcd4af40e75445bdbb44b43de445a9b GIT binary patch literal 13208 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∓T;?<{s#k2N7))}o#$GBdLo3PAi|)4XSjS)6;+ zK5huKLy%hbY7svUy7CRQsKVg|7pjA8K)Bd$aFm-;)mGM3A6IhRi6fhAaO*_}l(t)B zYB6lXc^9gFr$Xx}T*f27@qiW4xh+Te8lsdi>=UYBbpopJ32LM5M6CO$w`e?Pd4&%9 zaw;@BxL+0F>qHAmoq=Bj0EJ*cpvr?NzkSZlVehU8oL1^`jZ#kTa|*HJap8-1N4ZK` z7{V=(C<`5+aWuJ!TPEQVlgFFSI@Qr(@tkezcZipX&2H~MT;{Thka>4HIh9WSUSNO7 z>A%Ol5mH{A|M`Gf6CRLse zsmAXraU@p;cier+oJz9QqA0E5F0fntO8z>e8UwFe10W(~G(iNm4SaNZ_5viAVvOhA4!C>f1pr3cC8;bi>;KuqVW9>Ode?g zTX}p`9aNsQ?e3+pXs4V4mkgPjUI?Vrro8>J#izgADk~1S2U~Zz&H{H%&KHR(7iXo& zFu<352CrcF)%!f2{-7K9ox!YEbfGs2KrkOnH@ zeLAl5*a9xV4S>!Dn{44Vw|3*X)25rhXc_pcf)Wrd=%magIZEv`IGiLjJ-n{hNU-!T z+T-YnU}tj#ZmO6%r7t|Cog3A`}v!)u!1 z8{42*?>`;9=K)P5XPH7ps(8_f zA$7rm+$`!L#n%HP|X#I%vAr?2ik4SE~b7L z?b}ka=d`WVf9KvjAUB4)nfa?0!j8B&UhjqH<|4ajy%oJAA_FuAKw)`hnn5d|e@ly? zzi9D(_=p#p{cm7owGzO>m$1Wp2<1bt1ns;%R@_$U#&bv*t?4e0EZwC{@E;e_W}&b1 zRlVfYbF*uYzTQJ^s{AIcigp|yz<*S(eE(r6dAaJ6$jJK{d|R=5QmZC?>lpd)2P#3b zIQk>6o9nTG(a)R%_Vj@nDiHeDIlL;8>*!Otuwm?u2;Hl~5sb!ejoJ$87 z?A?KX!M(As;50s`N-BQKqQObdC$2Lg3&PDmqt}&w+ScL^Z-1lTyr-IR5Y#qz9>OPV z>^vt1Fj#gX#$O=x``Iq!x~vj>sK%rS!5>cbChMeE85uq$In_gdFCpB;J_0Bo2ojBM{NPc3`Cjhe zfKNg%>gT|#GE~3Y#UV6v4VYF@Kwlx4m?HzAN<|{*&l>8%yie{4R=Nj{qNsScrd0OI zo#TOWJAgfvl)(UZw;X4$yxQ%*iG-5~6^$o%Xh;KNE-iI*A@P|3F>)U_12SNHxvSOU zv^KgaZD4G)r_$%45%);tDX#c{#t^_yo4376$j63q!nQk$-{@e7^BnI`VVa7@c7x!z z2|>$V!(2lIaWQKF;gag9{bC>={>OGaZ5FGE%YshRw9=^e3^)?{zj7k#z%~6pgNPd> zub+w$%FA(HKG_sWqQ19Q=)>*?9^_Ps3c&clJ-^Ff*K5Ly9BCCbHiJ$iLVnrL(n z9u}QaTZ|D>LK=@zRe%>ajP^(A_D!{rsk}qh{hS1BgW-x%dG8EAu4`e-^t^`5`8U%L(E9`|Ziz;CFzNfHO` zqZ#REEj1iN8ioJ}Wg)asI?m4fWc1pGyP3)XO-*JH``WdrD^->;rM9t9l#{LF72;gS zXm{Ndms4twz5|M{@Mpi1TO=p>r=HT$a(&ZB^y^puuD}AoRlo zzaLSM&pVI}?mdnEpU4=2{|6ZhWa9e3nk!_78`OBEaLr0Jc2u)tk+C8KTKuygyAWI8 zIa+0Lrw>c`;{{ew{br-`KR<0)B+L9^NzVuXHFt;>D^J?~_t#2(F#W&W@=DS6uGsSQ V&+M+GzHxKvmfjuR${S8`{|$e8*dG7@ literal 0 HcmV?d00001 diff --git a/.make/lint.make b/.make/lint.make new file mode 100644 index 0000000..d83a6f0 --- /dev/null +++ b/.make/lint.make @@ -0,0 +1,45 @@ +## -- Linting targets ----------------------------------------------------------------------------------------------- ## + +.PHONY: precommit +precommit: ## Run Pre-commit on all files manually (Only lint target that works without dev dependencies) + @$(ENV_COMMAND_TOOL) pre-commit run --all-files + +.PHONY: check-lint +check-lint: ## Check code linting (black, isort, flake8, docformatter and pylint) + @$(ENV_COMMAND_TOOL) nox -s check + +.PHONY: check-complexity +check-complexity: ## Check code cyclomatic complexity with Flake8-McCabe + @$(ENV_COMMAND_TOOL) nox -s complexity + +.PHONY: fix-lint +fix-lint: ## Fix code linting (autoflake, autopep8, black, isort, flynt, docformatter) + @$(ENV_COMMAND_TOOL) nox -s fix + +.PHONY: autotyping +autotyping: ## Add basic types using autotyping + @$(ENV_COMMAND_TOOL) nox -s autotyping + +.PHONY: mypy +mypy: ## Check code with mypy + @$(ENV_COMMAND_TOOL) nox -s mypy + +.PHONY: pylint +pylint: ## Check code with pylint + @$(ENV_COMMAND_TOOL) nox -s pylint + +.PHONY: markdown-lint +markdown-lint: ## Fix markdown linting using mdformat + @$(ENV_COMMAND_TOOL) nox -s mdformat + +.PHONY: ruff +ruff: ## Run the ruff linter + @$(ENV_COMMAND_TOOL) nox -s ruff-lint + +.PHONY: ruff-fix +ruff-fix: ## Run the ruff linter and fix automatically fixable errors + @$(ENV_COMMAND_TOOL) nox -s ruff-fix + +.PHONY: ruff-format +ruff-format: ## Run the ruff code formatter + @$(ENV_COMMAND_TOOL) nox -s ruff-format diff --git a/.make/manager.make b/.make/manager.make new file mode 100644 index 0000000..ad9ed1f --- /dev/null +++ b/.make/manager.make @@ -0,0 +1,63 @@ +######################################################################################## +# +# MODIFY WITH CARE!!! +# If necessary, override the corresponding variable and/or target, or create new ones +# in one of the following files, depending on the nature of the override : +# +# `Makefile.variables`, `Makefile.targets` or `Makefile.private`, +# +# The only valid reason to modify this file is to fix a bug or to add/remove +# files to include. +# +# REMEMBER!!! +# This is a project level config, any changes here will affect all other users +# +######################################################################################## +# +# Necessary make files +# +include .make/base.make +-include Makefile.variables + +# +# Optional makefiles targets +# + +# Env related +ifneq (,$(INSTALL_ENV_IS_CONDA)) + include .make/conda.make +endif + +# Build tool related +ifneq (,$(BUILD_TOOL_IS_UV)) + include .make/uv.make +endif + +ifneq (,$(BUILD_TOOL_IS_POETRY)) + include .make/poetry.make +endif + +## Linting targets +ifneq (,$(findstring lint,$(TARGET_GROUPS))) + include .make/lint.make +endif + +## Test related targets +ifneq (,$(findstring test,$(TARGET_GROUPS))) + include .make/test.make +endif + +## Docs related targets +ifneq (,$(findstring docs,$(TARGET_GROUPS))) + include .make/docs.make +endif + +# +# Project related makefiles +# +## Custom targets and variables +-include Makefile.targets + +## Private variables and targets import to override variables for local +-include Makefile.private + diff --git a/.make/poetry.make b/.make/poetry.make new file mode 100644 index 0000000..71f6fe2 --- /dev/null +++ b/.make/poetry.make @@ -0,0 +1,415 @@ +# Project and Private variables and targets import to override variables for local +# This is to make sure, sometimes the Makefile includes don't work. +-include Makefile.variables +-include Makefile.private + +POETRY_COMMAND_WITH_PROJECT_ENV := $(shell command -v poetry 2> /dev/null) +LOCAL_POETRY_PATH := $(shell echo $$HOME/.local/bin/poetry) + +ifeq ($(POETRY_COMMAND_WITH_PROJECT_ENV),) + POETRY_COMMAND_WITH_PROJECT_ENV := $(LOCAL_POETRY_PATH) +endif + +ifeq ($(DEFAULT_INSTALL_ENV),venv) +POETRY_COMMAND_WITH_PROJECT_ENV := source $(VENV_ACTIVATE) && $(POETRY_COMMAND_WITH_PROJECT_ENV) +else ifeq ($(DEFAULT_INSTALL_ENV),poetry) +POETRY_COMMAND_WITH_PROJECT_ENV := $(POETRY_COMMAND_WITH_PROJECT_ENV) +else ifeq ($(DEFAULT_INSTALL_ENV),conda) +POETRY_COMMAND_WITH_PROJECT_ENV := $(CONDA_ENV_TOOL) run -n $(CONDA_ENVIRONMENT) $(POETRY_COMMAND_WITH_PROJECT_ENV) +endif + +# Do not rename these unless you also rename across all other make files in .make/ +ENV_COMMAND_TOOL := $(POETRY_COMMAND_WITH_PROJECT_ENV) run +ENV_INSTALL_TOOL := $(POETRY_COMMAND_WITH_PROJECT_ENV) install + + +## -- Poetry targets ------------------------------------------------------------------------------------------------ ## + +.PHONY: poetry-install-auto +poetry-install-auto: ## Install Poetry automatically via pipx + @echo "Looking for Poetry version..."; \ + $(POETRY_COMMAND_WITH_PROJECT_ENV) --version; \ + if [ $$? != "0" ]; then \ + echo "Poetry not found, proceeding to install Poetry..."; \ + make AUTO_INSTALL=true -s poetry-install-venv; \ + else \ + echo "$$output"; \ + version=$$(echo "$$output" | sed -n 's/.*version \([0-9.]*\).*/\1/p'); \ + if [ -n "$$version" ]; then \ + is_lower=$$(echo "$$version" | awk -F. '{ if ($$1 < 2 || ($$1 == 2 && $$2 < 2) || ($$1 == 2 && $$2 == 2 && $$3 < 1)) print "yes" }'); \ + if [ "$$is_lower" = "yes" ]; then \ + echo ""; \ + echo -e "$(WARNING) Poetry version $$version is lower than 2.2.1. Some features might not work as expected."; \ + echo ""; \ + fi; \ + fi; \ + fi; + +.PHONY: _pipx_install_poetry +_pipx_install_poetry: + @output="$$(pip install --disable-pip-version-check poetry --dry-run)"; \ + if echo "$$output" | grep -q computecanada ; then \ + echo ""; \ + echo -e "$(WARNING)Compute Canada (DRAC) environment detected: Installing Poetry < 2.0.0"; \ + echo "Some features will not be available - like 'poetry python install' which allows poetry"; \ + echo "to manage python versions automatically. Consider loading the appropriate python module"; \ + echo ""; \ + echo "This will also require the 'pyproject.toml' file to use the classic poetry format."; \ + echo ""; \ + echo "Consider loading the appropriate python module before installing this package with 'make install'"; \ + echo "or switching to 'uv'."; \ + echo ""; \ + pipx install 'poetry<2.0.0' ; \ + else \ + pipx install poetry ; \ + fi; + + +.PHONY: poetry-install +poetry-install: ## Install Poetry interactively. + @echo "Looking for Poetry version...";\ + $(POETRY_COMMAND_WITH_PROJECT_ENV) --version; \ + if [ $$? != "0" ]; then \ + if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo "Poetry not found..."; \ + echo "Looking for pipx version...";\ + pipx_found=0; \ + pipx --version; \ + if [ $$? != "0" ]; then \ + pipx_found=1; \ + echo "pipx not found..."; \ + echo ""; \ + echo -n "Would you like to install pipx and Poetry? [y/N]: "; \ + else \ + echo ""; \ + echo -n "Would you like to install Poetry using pipx? [y/N]: "; \ + fi; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + if [ $$pipx_found == "1" ]; then \ + echo ""; \ + echo -e "$(WARNING)The following pip has been found and will be used to install pipx: "; \ + echo " -> "$$(which pip); \ + echo ""; \ + echo "If you do not have write permission to that environment, using it to install pipx will fail."; \ + echo "If this is the case, you should install pipx using a virtual one."; \ + echo ""; \ + echo "See documentation for more information."; \ + echo ""; \ + echo -n "Would you like to use the local available pip above, or create virtual environment to install pipx? [local/virtual]: "; \ + read ans_how; \ + case $$ans_how in \ + "LOCAL" | "Local" |"local") \ + make -s poetry-install-local; \ + ;; \ + "VIRTUAL" | "Virtual" | "virtual") \ + make -s poetry-install-venv; \ + ;; \ + *) \ + echo ""; \ + echo -e "$(WARNING)Option $$ans_how not found, exiting process."; \ + echo ""; \ + exit 1; \ + esac; \ + else \ + echo "Installing Poetry"; \ + make -s _pipx_install_poetry; \ + fi; \ + ;; \ + *) \ + echo "Skipping installation."; \ + echo " "; \ + ;; \ + esac; \ + fi; + + +.PHONY: poetry-install-venv +poetry-install-venv: ## Install standalone Poetry. Will install pipx in $HOME/.pipx_venv + @$(POETRY_COMMAND_WITH_PROJECT_ENV) --version; \ + if [ $$? != "0" ]; then \ + echo "Looking for pipx version..."; \ + pipx --version; \ + if [ $$? != "0" ]; then \ + echo "Looking for previously installed pipx environment..."; \ + source $(PIPX_VENV_PATH)/bin/activate && pipx --version; \ + if [ $$? != "0" ]; then \ + echo "Creating virtual environment using venv here : [$(PIPX_VENV_PATH)]"; \ + python3 -m venv $(PIPX_VENV_PATH); \ + echo "Activating virtual environment [$(PIPX_VENV_PATH)]"; \ + source $(PIPX_VENV_PATH)/bin/activate; \ + pip3 install pipx; \ + pipx ensurepath; \ + source $(PIPX_VENV_PATH)/bin/activate && make -s _pipx_install_poetry ; \ + else \ + echo "Pipx found!"; \ + source $(PIPX_VENV_PATH)/bin/activate && make -s _pipx_install_poetry ; \ + fi; \ + else \ + make -s _pipx_install_poetry ; \ + fi;\ + else \ + echo "Poetry is already installed - skipping"; \ + fi; + +.PHONY: poetry-install-local +poetry-install-local: ## Install standalone Poetry. Will install pipx with locally available pip. + @$(POETRY_COMMAND_WITH_PROJECT_ENV) --version; \ + if [ $$? != "0" ]; then \ + echo "Looking for pipx version..."; \ + pipx --version; \ + if [ $$? != "0" ]; then \ + echo "pipx not found; installing pipx"; \ + pip3 install pipx; \ + pipx ensurepath; \ + fi;\ + echo "Installing Poetry"; \ + make -s _pipx_install_poetry; \ + else \ + echo "Poetry is already installed - skipping"; \ + fi; + +.PHONY: poetry-env-info +poetry-env-info: ## Information about the currently active environment used by Poetry + @$(POETRY_COMMAND_WITH_PROJECT_ENV) env info + +.PHONY: poetry-env-set-local +poetry-env-set-local: ## Configure poetry to create env locally for this project. + @$(POETRY_COMMAND_WITH_PROJECT_ENV) config virtualenvs.in-project true --local + +.PHONY: poetry-create-env +poetry-create-env: ## Create a Poetry managed environment for the project (Outside of Conda environment). + @echo "Searching for python version $(PYTHON_VERSION) ..." + @available_python=$$($(POETRY_COMMAND_WITH_PROJECT_ENV) python list); \ + if ! echo "$$available_python" | grep -qF "$(PYTHON_VERSION)"; then \ + echo "Python version $(PYTHON_VERSION) not found ..."; \ + $(POETRY_COMMAND_WITH_PROJECT_ENV) python install "$(PYTHON_VERSION)"; \ + fi; + @if [ $(DEFAULT_INSTALL_ENV) != "conda" ]; then \ + echo "Creating Poetry environment using Python $(PYTHON_VERSION)"; \ + $(POETRY_COMMAND_WITH_PROJECT_ENV) env use $(PYTHON_VERSION); \ + $(POETRY_COMMAND_WITH_PROJECT_ENV) env info; \ + echo ""; \ + echo "This environment can be accessed either by using the "; \ + echo "command, or activated with the command."; \ + echo ""; \ + echo "Use and for more information"; \ + echo ""; \ + else \ + echo "Using project's conda environment"; \ + fi; + +.PHONY: poetry-activate +poetry-activate: ## Print the shell command to activate the project's poetry env. + @$(POETRY_COMMAND_WITH_PROJECT_ENV) env activate + +.PHONY: poetry-remove-env +poetry-remove-env: ## Remove current project's Poetry managed environment. + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans_env="y";\ + env_path=$$($(POETRY_COMMAND_WITH_PROJECT_ENV) env info -p); \ + env_name=$$(basename $$env_path); \ + else \ + echo ""; \ + echo "Looking for poetry environments..."; \ + env_path=$$($(POETRY_COMMAND_WITH_PROJECT_ENV) env info -p); \ + if [[ "$$env_path" != "" ]]; then \ + echo "The following environment has been found for this project: "; \ + env_name=$$(basename $$env_path); \ + echo ""; \ + echo "Env name : $$env_name"; \ + echo "PATH : $$env_path"; \ + echo ""; \ + echo "If the active environment listed above is a Conda environment,"; \ + echo "Choosing to delete it will have no effect; use the target "; \ + echo ""; \ + echo ""; \ + echo "If the active environment listed above is a venv environment,"; \ + echo "Choosing to delete it will have no effect; use the bash command $ rm -rf "; \ + echo "or 'make venv-remove'"; \ + echo ""; \ + echo -n "Would you like delete the environment listed above? [y/N]: "; \ + read ans_env; \ + else \ + env_name="None"; \ + env_path="None"; \ + fi; \ + fi; \ + if [[ $$env_name != "None" ]]; then \ + case $$ans_env in \ + [Yy]*) \ + $(POETRY_COMMAND_WITH_PROJECT_ENV) env remove $$env_name || echo "No environment was removed"; \ + ;; \ + *) \ + echo "No environment was found/provided - skipping environment deletion"; \ + ;;\ + esac; \ + else \ + echo "No environments were found... skipping environment deletion"; \ + fi; \ + +.PHONY: poetry-uninstall +poetry-uninstall: poetry-remove-env ## Uninstall pipx-installed Poetry and the created environment + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to uninstall pipx-installed Poetry? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + pipx --version ; \ + if [ $$? != "0" ]; then \ + echo "" ; \ + echo "Pipx not found globally, trying with $(PIPX_VENV_PATH) env" ;\ + echo "" ; \ + source $(PIPX_VENV_PATH)/bin/activate && pipx uninstall poetry ; \ + else \ + pipx uninstall poetry ; \ + fi; \ + ;; \ + *) \ + echo "Skipping uninstallation."; \ + echo " "; \ + ;; \ + esac; \ + +.PHONY: poetry-uninstall-pipx +poetry-uninstall-pipx: poetry-remove-env ## Uninstall pipx-installed Poetry, the created Poetry environment and pipx + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to uninstall pipx-installed Poetry and pipx? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + pipx --version ; \ + if [ $$? != "0" ]; then \ + echo "" ; \ + echo "Pipx not found globally, trying with $(PIPX_VENV_PATH) env" ;\ + echo "" ; \ + source $(PIPX_VENV_PATH)/bin/activate && pipx uninstall poetry && pip uninstall -y pipx; \ + else \ + pipx uninstall poetry ; \ + pip uninstall -y pipx ;\ + fi; \ + ;; \ + *) \ + echo "Skipping uninstallation."; \ + echo " "; \ + ;; \ + esac; \ + +.PHONY: poetry-uninstall-venv +poetry-uninstall-venv: poetry-remove-env ## Uninstall pipx-installed Poetry, the created Poetry environment, pipx and $HOME/.pipx_venv + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to uninstall pipx-installed Poetry and pipx? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + (source $(PIPX_VENV_PATH)/bin/activate && pipx uninstall poetry); \ + (source $(PIPX_VENV_PATH)/bin/activate && pip uninstall -y pipx); \ + ;; \ + *) \ + echo "Skipping uninstallation."; \ + echo " "; \ + ;; \ + esac; \ + + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to remove the virtual environment located here : [$(PIPX_VENV_PATH)] ? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + rm -r $(PIPX_VENV_PATH); \ + ;; \ + *) \ + echo "Skipping [$(PIPX_VENV_PATH)] virtual environment removal."; \ + echo ""; \ + ;; \ + esac; \ + +## -- Specific install targets (All install targets will install Poetry if the tool is not found) --------------------## + +.PHONY: _check-env +_check-env: + @if ! [ $(DEFAULT_INSTALL_ENV) ]; then \ + echo -e "$(WARNING)No installation environment have been defined." ; \ + echo "" ; \ + echo "[DEFAULT_INSTALL_ENV] is not defined - Poetry will use the currently activated environment." ; \ + echo "If there is no currently active environment (ie. conda or venv)," ; \ + echo "Poetry will create and manage it's own environment." ; \ + elif [ $(DEFAULT_INSTALL_ENV) = "venv" ]; then \ + if [ ! -f $(VENV_ACTIVATE) ]; then \ + make -s venv-create ;\ + fi; \ + elif [ $(DEFAULT_INSTALL_ENV) = "conda" ]; then \ + if ! $(CONDA_ENV_TOOL) env list | grep -q $(CONDA_ENVIRONMENT) ; then \ + make -s conda-create-env ; \ + fi; \ + fi; + +.PHONY: _remind-env-activate +_remind-env-activate: + @echo "" + @echo "Activate your environment using the following command:" + @echo "" + @if ! [ $(DEFAULT_INSTALL_ENV) ] || [ $(DEFAULT_INSTALL_ENV) = "poetry" ]; then \ + make -s poetry-activate ; \ + echo "" ; \ + echo "You can also use the eval bash command : eval \$$(make poetry-activate)"; \ + echo "" ; \ + echo "The environment can also be used through the 'poetry run ' command."; \ + echo "" ; \ + echo " Ex: poetry run python "; \ + elif [ $(DEFAULT_INSTALL_ENV) = "venv" ]; then \ + make -s venv-activate ; \ + echo "" ; \ + echo "You can also use the eval bash command : eval \$$(make venv-activate)"; \ + elif [ $(DEFAULT_INSTALL_ENV) = "conda" ]; then \ + make -s conda-activate ; \ + echo "" ; \ + echo "You can also use the eval bash command : eval \$$(make conda-activate)"; \ + fi; + @echo "" + +.PHONY: install-dev +install-dev: poetry-install-auto _check-env poetry-create-env ## Install the application along with developer dependencies + @$(ENV_INSTALL_TOOL) --with dev + @make -s _remind-env-activate + +.PHONY: install-all +install-all: poetry-install-auto _check-env poetry-create-env ## Install the application and all it's dependency groups + @$(ENV_INSTALL_TOOL) --with dev --all-extras + @make -s _remind-env-activate + +.PHONY: install-jupyter +install-jupyter: poetry-install-auto _check-env ## Install the application and it's dev dependencies, including Jupyter Lab + @$(ENV_INSTALL_TOOL) --with dev --extras lab + @make -s _remind-env-activate + + +.PHONY: install-docs +install-docs: poetry-install-auto _check-env poetry-create-env ## Install docs related dependencies + @$(ENV_INSTALL_TOOL) --with dev --extras docs + @make -s _remind-env-activate + +.PHONY: install-package +install-package: poetry-install-auto _check-env poetry-create-env ## Install the application package only + @$(ENV_INSTALL_TOOL) --only-root + @make -s _remind-env-activate diff --git a/.make/scripts/auto_init_script.py b/.make/scripts/auto_init_script.py new file mode 100644 index 0000000..8cc317d --- /dev/null +++ b/.make/scripts/auto_init_script.py @@ -0,0 +1,846 @@ +#!/usr/bin/env python3 +""" +Initialization Script for Lab Advanced Template. + +This script customizes the project based on user input and removes template-specific placeholders. +It handles: +- User input via CLI flags or interactive prompts. +- Automatic detection of repository URL. +- Variable replacement in configuration files. +- Directory renaming and import updates. +- Configuration updates in Makefile.variables. +- README customization. +- Link check configuration. +""" + +import argparse +import json +import re +import shutil +import subprocess +from argparse import Namespace +from pathlib import Path +from typing import Any, Dict, List, Optional + +try: + from typing import LiteralString +except ImportError: + # Workaround for python<3.11 + LiteralString = str + +# --- Constants --- +PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent + +# Placeholders (These will be updated by the script itself after the first run) +PLACEHOLDER_PACKAGE_NAME = "core" +PLACEHOLDER_IMPORT_NAME = "my_awesome_project" +PLACEHOLDER_PROJECT_NAME = "My Awesome Project" +PLACEHOLDER_README_PROJECT_NAME = "\\" +PLACEHOLDER_DESCRIPTION_TOML = "" +PLACEHOLDER_DESCRIPTION_README = "[Provide a brief, one-sentence description of your project here.]" +PLACEHOLDER_PYTHON_VERSION = "3.12" +PLACEHOLDER_REPO_URL = "REPOSITORY_URL" +PLACEHOLDER_AUTHOR = "Author" +PLACEHOLDER_EMAIL = "author@example.com" + +DEFAULT_PYTHON_VERSION = "3.12" +VALID_PYTHON_VERSIONS = ["3.11", "3.12", "3.13", "3.14"] +DEFAULT_INSTALL_ENV = "uv" +DEFAULT_BUILD_TOOL = "uv" +VALID_INSTALL_ENVS = ["uv", "poetry", "conda", "venv"] +VALID_BUILD_TOOLS = ["uv", "poetry"] + +# Files to modify +PYPROJECT_TOML = PROJECT_ROOT / "pyproject.toml" +MAKEFILE_VARIABLES = PROJECT_ROOT / "Makefile.variables" +README_MD = PROJECT_ROOT / "README.md" +CHANGES_MD = PROJECT_ROOT / "CHANGES.md" +MARKDOWN_LINK_CHECK = PROJECT_ROOT / ".markdown-link-check.json" +INIT_MARKER_FILE = PROJECT_ROOT / ".make" / ".init_completed" + +# Useful string variables +UV = "uv" +POETRY = "poetry" +CONDA = "conda" + + +# --- Helper Functions --- + + +def run_command(command: List[str], cwd: Path = PROJECT_ROOT, capture_output: bool = True) -> Optional[str]: + """ + Runs a shell command and returns the output. + + Args: + command: A list of strings representing the command to run. + cwd: The working directory for the command. Defaults to PROJECT_ROOT. + capture_output: Whether to capture stdout/stderr. Defaults to True. + + Returns: + The stripped stdout string if successful, or None if the command fails. + """ + try: + result = subprocess.run(args=command, cwd=cwd, capture_output=capture_output, text=True, check=True) + return result.stdout.strip() + except subprocess.CalledProcessError: + print(f"Error running command {' '.join(command)}") + return None + + +def get_git_remote_url() -> Optional[str]: + """ + Detects the git remote origin URL and converts it to HTTPS format. + + Returns: + The HTTPS URL of the git remote, or None if not found. + """ + url = run_command(command=["git", "remote", "get-url", "origin"]) + if not url: + return None + + # Convert SSH to HTTPS + # git@github.com:User/Repo.git -> https://github.com/User/Repo + if url.startswith("git@"): + url = url.replace(":", "/").replace("git@", "https://") + + if url.endswith(".git"): + url = url[:-4] + + return url + + +def prompt_user(prompt: str, default: Optional[str] = None, choices: Optional[List[str]] = None) -> Optional[str]: + """ + Prompts the user for input, with optional default and validation. + + Args: + prompt: The text to display to the user. + default: The default value to return if the user enters nothing. + choices: A list of valid choices. If provided, input is validated against this list. + + Returns: + The user's input or the default value. + """ + while True: + prompt_text = f"{prompt}" + if default: + prompt_text += f" - [{default}]" + if choices: + prompt_text += f" - Available choices: ({', '.join(choices)})" + prompt_text += ": " + + value = input(prompt_text).strip() + + if not value and default: + return default + + if not value and not default: + print("Value is required.") + continue + + if choices and value not in choices: + print(f"Invalid choice. Must be one of: {', '.join(choices)}") + continue + + return value + + +def replace_in_file(filepath: Path, replacements: Dict[str, str], dry_run: bool = False) -> None: + """ + Replaces text in a file based on a dictionary of replacements. + + Args: + filepath: Path to the file to modify. + replacements: A dictionary where keys are strings to find and values are replacements. + dry_run: If True, prints what would happen without modifying the file. + """ + if not filepath.exists(): + print(f"Warning: File not found: {filepath}") + return + + content = filepath.read_text(encoding="utf-8") + + new_content = content + for search, replace in replacements.items(): + new_content = new_content.replace(search, replace) + + if content != new_content: + if dry_run: + print(f"[Dry Run] Would update {filepath}") + else: + filepath.write_text(data=new_content) + print(f"Updated {filepath}") + + +def update_makefile_variables( + filepath: Path, + install_env: str, + build_tool: str, + python_version: str, + app_name: str, + conda_env: Optional[str], + conda_tool: Optional[str], + dry_run: bool, +) -> None: + """ + Updates specific variables in Makefile.variables. + + Args: + filepath: Path to the Makefile.variables file. + install_env: The installation environment (e.g., 'uv', 'poetry', 'conda'). + build_tool: The build tool (e.g., 'uv', 'poetry'). + python_version: The Python version string. + app_name: The application name. + conda_env: The conda environment name (optional). + conda_tool: The conda tool name (optional). + dry_run: If True, prints changes without writing to file. + """ + if not filepath.exists(): + print(f"Warning: File not found: {filepath}") + return + + updates = { + "DEFAULT_INSTALL_ENV :=": install_env, + "DEFAULT_BUILD_TOOL :=": build_tool, + "PYTHON_VERSION :=": python_version, + "APPLICATION_NAME :=": app_name, + } + + if not conda_env: + conda_env = app_name + updates["CONDA_ENVIRONMENT :="] = conda_env + if conda_tool: + updates["CONDA_TOOL :="] = conda_tool + + lines = filepath.read_text(encoding="utf-8").splitlines(keepends=True) + + new_lines = [] + for line in lines: + matched_key = next((key for key in updates if line.startswith(key)), None) + if matched_key: + new_lines.append(f"{matched_key} {updates[matched_key]}\n") + else: + new_lines.append(line) + + if dry_run: + print(f"[Dry Run] Would update {filepath} with configuration settings.") + else: + filepath.write_text(data="".join(new_lines), encoding="utf-8") + print(f"Updated {filepath}") + + +def comment_block(match: re.Match[str]) -> LiteralString: + """Utility function to help comment out sections of the pyproject.toml file, depending on the build tool + selected.""" + block = match.group(0) + lines = block.splitlines() + new_lines = [] + for line in lines: + if line.strip() == "": + new_lines.append(line) + elif line.startswith("# "): + new_lines.append(line) + else: + new_lines.append(f"# {line}") + return "\n".join(new_lines) + + +def uncomment_block(match: re.Match[str]) -> LiteralString: + """Utility function to help un-comment sections of the pyproject.toml file, depending on the build tool selected.""" + block = match.group(0) + lines = block.splitlines() + new_lines = [] + for line in lines: + if line.startswith("# "): + new_lines.append(line[2:]) + elif line.startswith("#"): + new_lines.append(line[1:]) + else: + new_lines.append(line) + return "\n".join(new_lines) + + +def update_pyproject_toml( + filepath: Path, + package_name: str, + description: str, + author: str, + email: str, + python_version: str, + repo_url: Optional[str], + build_tool: str, + dry_run: bool, +) -> None: + """ + Updates pyproject.toml with project metadata. + + Args: + filepath: Path to pyproject.toml. + package_name: The new package name. + description: Project description. + author: Author name. + email: Author email. + python_version: Python version string. + repo_url: Repository URL. + build_tool: The build tool to use ('uv' or 'poetry'). + dry_run: If True, prints changes without writing to file. + """ + if not filepath.exists(): + print(f"Warning: File not found: {filepath}") + return + + content = filepath.read_text(encoding="utf-8") + + # Basic replacements + # Note: Using regex for more robust replacement where simple string replace might be ambiguous + + # Update name = "core" -> name = "package_name" + # We look for name = "core" specifically in the [project] section usually at the top + content = re.sub( + pattern=f'name = "{PLACEHOLDER_PACKAGE_NAME}"', repl=f'name = "{package_name}"', string=content, count=1 + ) + + # Update description + content = re.sub( + pattern=f'description = "{PLACEHOLDER_DESCRIPTION_TOML}"', + repl=f'description = "{description}"', + string=content, + count=1, + ) + + # Update authors + # authors = [{ name = "Francis Pelletier", email = "fplt.softwaredeveloper@gmail.com" }] + new_authors = f'authors = [{{ name = "{author}", email = "{email}" }}]' + content = re.sub(pattern=r"authors = \[.*]", repl=new_authors, string=content, count=1) + + # Update python version + # requires-python = ">=3.12,<3.13" + # We assume the user provides "3.12", we want ">=3.12,<3.13" logic or just update the base + # For simplicity, let's try to construct the range if it matches X.Y format + match = re.match(pattern=r"(\d+)\.(\d+)", string=python_version) + if match: + major, minor = map(int, match.groups()) + next_minor = minor + 1 + new_requires = f'requires-python = ">={major}.{minor},<{major}.{next_minor}"' + content = re.sub(pattern=r'requires-python = ".*"', repl=new_requires, string=content, count=1) + + # Update tool.hatch.build.targets.wheel packages + # packages = ["src/core"] + content = content.replace(f'packages = ["src/{PLACEHOLDER_PACKAGE_NAME}"]', f'packages = ["src/{package_name}"]') + + # Update tool.poetry packages + # packages = [ + # { include = "core", from = "src" } + # ] + content = content.replace(f'include = "{PLACEHOLDER_PACKAGE_NAME}"', f'include = "{package_name}"') + + # Toggle Build Systems + # Hatchling Block Pattern + hatchling_pattern = ( + r"(?:# )?\[build-system\]\n" + r"(?:# )?requires = \[\"hatchling\"\]\n" + r"(?:# )?build-backend = \"hatchling\.build\"\n" + r"\n" + r"(?:# )?\[tool\.hatch\.build\.targets\.wheel\]\n" + r"(?:# )?packages = \[\"src/[^\"]+\"\]" + ) + + # Poetry Block Pattern + poetry_pattern = ( + r"(?:# )?\[build-system\]\n" + r"(?:# )?requires = \[\"poetry-core\"\]\n" + r"(?:# )?build-backend = \"poetry\.core\.masonry\.api\"\n" + r"\n" + r"(?:# )?\[tool\.poetry\]\n" + r"(?:# )?packages = \[\n" + r"(?:# )? \{ include = \"[^\"]+\", from = \"src\" \}\n" + r"(?:# )?\]" + ) + + if build_tool == "uv": + # Enable Hatchling, Disable Poetry + content = re.sub(pattern=hatchling_pattern, repl=uncomment_block, string=content, flags=re.MULTILINE) + content = re.sub(pattern=poetry_pattern, repl=comment_block, string=content, flags=re.MULTILINE) + elif build_tool == "poetry": + # Disable Hatchling, Enable Poetry + content = re.sub(pattern=hatchling_pattern, repl=comment_block, string=content, flags=re.MULTILINE) + content = re.sub(pattern=poetry_pattern, repl=uncomment_block, string=content, flags=re.MULTILINE) + + # Update bumpversion files + if repo_url: + content = content.replace(PLACEHOLDER_REPO_URL, repo_url) + + # Update black target-version + new_target_version = f'target-version = ["py{python_version.replace(".", "")}"]' + content = re.sub(pattern=r"target-version = .*", repl=new_target_version, string=content, count=1) + + # Update mypy target-version + new_target_version = f'python_version = "{python_version}"' + content = re.sub(pattern=r"python_version = .+", repl=new_target_version, string=content, count=1) + + if dry_run: + print(f"[Dry Run] Would update {filepath} with project metadata.") + else: + filepath.write_text(data=content, encoding="utf-8") + print(f"Updated {filepath}") + + +def rename_package_directory(package_name: str, dry_run: bool) -> None: + """ + Renames src/core to src/ and updates imports. + + Args: + package_name: The new name for the package directory. + dry_run: If True, prints changes without moving files or updating imports. + """ + src_previous = PROJECT_ROOT / "src" / PLACEHOLDER_PACKAGE_NAME + src_new = PROJECT_ROOT / "src" / package_name + + if not src_previous.exists(): + print(f"Warning: {src_previous} does not exist. Skipping rename.") + return + + if dry_run: + print(f"[Dry Run] Would rename {src_previous} to {src_new}") + else: + shutil.move(src=src_previous, dst=src_new) + print(f"Renamed {src_previous} to {src_new}") + + # Update imports in all .py files + # We need to walk through the project and replace "from my_awesome_project" with "from package_name" + # and "import my_awesome_project" with "import package_name" + + # Directories to skip + skip_dirs = {".git", ".venv", "__pycache__", ".nox", ".idea"} + + for file_path in PROJECT_ROOT.rglob("*.py"): + # Check if any part of the path is in skip_dirs + if any(part in skip_dirs for part in file_path.parts): + continue + + # Skip this script itself to avoid self-modification during this step + if file_path.resolve() == Path(__file__).resolve(): + continue + + content = file_path.read_text(encoding="utf-8") + + # Simple replacements for imports + # This is a basic heuristic and might need refinement for complex cases + new_content = content.replace(f"from {PLACEHOLDER_IMPORT_NAME}", f"from {package_name}") + new_content = new_content.replace(f"import {PLACEHOLDER_IMPORT_NAME}", f"import {package_name}") + + if content != new_content: + if dry_run: + print(f"[Dry Run] Would update imports in {file_path}") + else: + file_path.write_text(data=new_content, encoding="utf-8") + print(f"Updated imports in {file_path}") + + +def search_string(content: str, pattern: str) -> re.Match[str] | None: + result = re.search(pattern=pattern, string=content) + return result + + +def open_close_detail_sections(content: str, install_env: str) -> str: + """ + Helper utility to handle changing the opened and closed detail sections. + + Args: + content: The content to modify. + install_env: The installation environment used. + + Returns: + The modified content. + """ + # Patterns to capture the details block. + # Group 1: The opening tag (

or
) + # Group 2: The content (summary ... /details) including trailing newlines + + uv_pattern = r"()(\nStack: uv [\s\S]*?
\n*)" + poetry_pattern = r"()( Stack: Poetry[\s\S]*?
\n*)" + conda_pattern = ( + r"()( Stack: Poetry \+ Conda[\s\S]*?\n*)" + ) + + patterns = { + UV: uv_pattern, + POETRY: poetry_pattern, + CONDA: conda_pattern, + } + + working_content = content + + for env, pattern in patterns.items(): + if env == install_env: + # Ensure Open + replacement = r"
\2" + else: + # Ensure Closed + replacement = r"
\2" + + working_content = re.sub(pattern=pattern, repl=replacement, string=working_content) + + return working_content + + +def update_readme( + readme_path: Path, project_name: str, description: str, install_env: str, python_version: str, dry_run: bool +) -> None: + """ + Updates README.md content. + + Args: + readme_path: Path to README.md. + project_name: The project name. + description: The project description. + install_env: The installation environment used. + python_version: The Python version used. + dry_run: If True, prints changes without writing to file. + """ + if not readme_path.exists(): + return + + content = readme_path.read_text(encoding="utf-8") + + # Replace Title and Description + content = re.sub( + pattern=f"# {re.escape(PLACEHOLDER_README_PROJECT_NAME)}", repl=f"# {project_name}", string=content + ) + content = re.sub(pattern=re.escape(PLACEHOLDER_DESCRIPTION_README), repl=description, string=content) + + # Remove Template Initialization Section + # We look for the section start and end + start_marker = "## šŸš€ Template Initialization" + end_marker = "## šŸ Python Version" + + start_idx = content.find(start_marker) + end_idx = content.find(end_marker) + + if start_idx != -1 and end_idx != -1: + # Keep the end marker section + content = content[:start_idx] + content[end_idx:] + + # Update Python Version section text + content = re.sub( + pattern=f"This project uses \\*\\*Python {re.escape(PLACEHOLDER_PYTHON_VERSION)}\\*\\*", + repl=f"This project uses **Python {python_version}**", + string=content, + ) + + # Dynamic Content Removal based on stack + content = open_close_detail_sections(content=content, install_env=install_env) + + if dry_run: + print(f"[Dry Run] Would update {readme_path}") + else: + readme_path.write_text(data=content, encoding="utf-8") + print(f"Updated {readme_path}") + + +def update_link_check(filepath: Path, repo_url: Optional[str], dry_run: bool) -> None: + """ + Adds repository URL to .markdown-link-check.json ignore patterns. + + Args: + filepath: Path to .markdown-link-check.json. + repo_url: The repository URL to add to ignore patterns. + dry_run: If True, prints changes without writing to file. + """ + if not repo_url or not filepath.exists(): + return + + try: + data = json.loads(filepath.read_text(encoding="utf-8")) + except json.JSONDecodeError: + print(f"Error reading {filepath}") + return + + # Check if already exists + patterns = data.get("ignorePatterns", []) + if not any(p.get("pattern") == repo_url for p in patterns): + patterns.append({"pattern": repo_url}) + data["ignorePatterns"] = patterns + + # Also replace REPOSITORY_URL placeholder if present + new_patterns = [] + for p in patterns: + if p.get("pattern") == f"{PLACEHOLDER_REPO_URL}/tree/main": + new_patterns.append({"pattern": f"{repo_url}/tree/main"}) + else: + new_patterns.append(p) + data["ignorePatterns"] = new_patterns + + if dry_run: + print(f"[Dry Run] Would update {filepath} with repo URL.") + else: + filepath.write_text(data=json.dumps(obj=data, indent=2), encoding="utf-8") + print(f"Updated {filepath}") + + +def update_self(script_path: Path, replacements: Dict[str, str], dry_run: bool) -> None: + """Updates the script's own constants to match the new project state.""" + if not script_path.exists(): + return + + content = script_path.read_text(encoding="utf-8") + + for key, value in replacements.items(): + # Look for KEY = "..." or KEY = '...' + # We use json.dumps to generate a safe string representation (e.g. "value") + # and replace the existing assignment. + # We assume the constants are defined at the top level. + + # Regex explanation: + # ^: Start of line + # {key}: The constant name + # \s*=\s*: Assignment operator with optional whitespace + # .*$: Match the rest of the line (the value) + + new_line = f"{key} = {json.dumps(value)}" + content = re.sub(pattern=rf"^{key}\s*=\s*.*$", repl=new_line, string=content, flags=re.MULTILINE) + + if dry_run: + print(f"[Dry Run] Would update {script_path} constants.") + else: + script_path.write_text(data=content, encoding="utf-8") + print(f"Updated {script_path} constants for future runs.") + + +def self_update_for_next_run_of_script( + args: Namespace, + author: str | Any, + description: str | Any, + email: str | Any, + package_name: str | Any, + project_name: str | Any, + python_version: str | Any, + repo_url: str | None, +) -> None: + self_replacements = { + "PLACEHOLDER_PACKAGE_NAME": package_name, + "PLACEHOLDER_IMPORT_NAME": package_name, + "PLACEHOLDER_PROJECT_NAME": project_name, + "PLACEHOLDER_README_PROJECT_NAME": project_name, + "PLACEHOLDER_DESCRIPTION_TOML": description, + "PLACEHOLDER_PYTHON_VERSION": python_version, + "DEFAULT_PYTHON_VERSION": python_version, + "PLACEHOLDER_AUTHOR": author, + "PLACEHOLDER_EMAIL": email, + } + + if repo_url: + self_replacements["PLACEHOLDER_REPO_URL"] = repo_url + + update_self(script_path=Path(__file__), replacements=self_replacements, dry_run=args.dry_run) + + +def gather_build_and_env_fields(args: Namespace, package_name: str | Any) -> tuple[Any, Any, Any, Any]: + install_env = args.install_env + if not install_env: + install_env = prompt_user(prompt="Install Environment", default=DEFAULT_INSTALL_ENV, choices=VALID_INSTALL_ENVS) + + # Adjust build tool choices based on install env + available_build_tools = VALID_BUILD_TOOLS + if install_env == "conda" and "uv" in available_build_tools: + # Logic from plan: If conda is selected remove uv from the choices of build-tools + # and add explanation that only poetry is available when using conda + print( + "Note: When using Conda for environment management, 'poetry' is the only supported build tool in this " + "template." + ) + available_build_tools = ["poetry"] + if install_env == "uv" and "poetry" in available_build_tools: + # Logic from plan: If conda is selected remove uv from the choices of build-tools + # and add explanation that only poetry is available when using conda + print("Note: When using UV for environment management, 'uv' is the only supported build tool in this template.") + available_build_tools = ["uv"] + if install_env == "poetry" and "uv" in available_build_tools: + # Logic from plan: If conda is selected remove uv from the choices of build-tools + # and add explanation that only poetry is available when using conda + print( + "Note: When using Poetry for environment management, 'poetry' is the only supported build tool in this " + "template." + ) + available_build_tools = ["poetry"] + + build_tool = args.build_tool + if not build_tool: + default_bt = "poetry" if install_env in ["conda", "poetry"] else DEFAULT_BUILD_TOOL + build_tool = prompt_user(prompt="Build Tool", default=default_bt, choices=available_build_tools) + + # Validate build_tool with install_env + if install_env == "conda" and build_tool == "uv": + print("Warning: 'uv' build tool is not supported with 'conda' environment in this template.") + print("Switching build tool to 'poetry'.") + build_tool = "poetry" + + conda_env_name = None + conda_tool = None + if install_env == "conda": + conda_env_name = args.conda_env_name or prompt_user(prompt="Conda Environment Name", default=f"{package_name}") + conda_tool = args.conda_tool or prompt_user(prompt="Conda Tool", default="mamba", choices=["mamba", "conda"]) + return build_tool, conda_env_name, conda_tool, install_env + + +def gather_metadata_fields(args: Namespace) -> tuple[str | Any, str | Any, str | Any, str | Any, str | Any, str | Any]: + project_name = args.project_name or prompt_user(prompt="Project Name", default=PLACEHOLDER_PROJECT_NAME) + package_name_args = [ + "Package Name (snake_case)", + PLACEHOLDER_IMPORT_NAME.lower().replace(" ", "_").replace("-", "_"), + ] + if project_name != PLACEHOLDER_PROJECT_NAME and project_name: + package_name_args = ["Package Name (snake_case)", project_name.lower().replace(" ", "_").replace("-", "_")] + package_name = args.package_name or prompt_user(prompt=package_name_args[0], default=package_name_args[1]) + description = args.description or prompt_user(prompt="Project Description", default=PLACEHOLDER_DESCRIPTION_TOML) + author = args.author or prompt_user(prompt="Author Name", default=PLACEHOLDER_AUTHOR) + email = args.email or prompt_user(prompt="Author Email", default=PLACEHOLDER_EMAIL) + python_version = args.python_version or prompt_user( + prompt="Python Version", default=DEFAULT_PYTHON_VERSION, choices=VALID_PYTHON_VERSIONS + ) + return author, description, email, package_name, project_name, python_version + + +def generate_args_and_parser() -> Namespace: + parser = argparse.ArgumentParser(description="Initialize the project from the template.") + + # Project Metadata + parser.add_argument("--project-name", help="Name of the project") + parser.add_argument("--package-name", help="Python package name (snake_case)") + parser.add_argument("--description", help="Brief project description") + parser.add_argument("--author", help="Author's name") + parser.add_argument("--email", help="Author's email") + + # Technical Configuration + parser.add_argument("--python-version", choices=VALID_PYTHON_VERSIONS, help="Target Python version") + parser.add_argument("--install-env", choices=VALID_INSTALL_ENVS, help="Tool for virtual environment management") + parser.add_argument("--build-tool", choices=VALID_BUILD_TOOLS, help="Tool for dependency/build management") + + # Conda Specifics + parser.add_argument("--conda-env-name", help="Name of the conda environment") + parser.add_argument("--conda-tool", choices=["mamba", "conda"], help="Tool to use (mamba or conda)") + + # Flags + parser.add_argument("--dry-run", action="store_true", help="Preview changes without writing to disk") + + args = parser.parse_args() + return args + + +# --- Main Execution --- + + +def main() -> None: + """ + Main execution function for the initialization script. + + Parses arguments, gathers user input, and triggers file updates. + """ + args = generate_args_and_parser() + + if INIT_MARKER_FILE.exists() and not args.dry_run: + print("\nāš ļø WARNING: It looks like this project has already been initialized.") + print(f"Marker file exists: {INIT_MARKER_FILE}") + print("Re-running this script might overwrite your changes or cause unexpected behavior.") + + should_continue = prompt_user(prompt="Do you want to continue anyway?", default="no", choices=["yes", "no"]) + if should_continue != "yes": + print("Aborting initialization.") + return + + print("šŸš€ Starting Project Initialization...") + + # 1. Gather Inputs + author, description, email, package_name, project_name, python_version = gather_metadata_fields(args=args) + + build_tool, conda_env_name, conda_tool, install_env = gather_build_and_env_fields( + args=args, package_name=package_name + ) + + # 2. Automatic Repo Detection + repo_url = get_git_remote_url() + if repo_url: + print(f"Detected Repository URL: {repo_url}") + else: + print("Could not detect repository URL. Placeholders will remain.") + + # 3. Execution + print("\nApplying changes...") + + # Update Makefile.variables + update_makefile_variables( + filepath=MAKEFILE_VARIABLES, + install_env=install_env, + build_tool=build_tool, + python_version=python_version, + app_name=package_name, + conda_env=conda_env_name, + conda_tool=conda_tool, + dry_run=args.dry_run, + ) + + # Update pyproject.toml + update_pyproject_toml( + filepath=PYPROJECT_TOML, + package_name=package_name, + description=description, + author=author, + email=email, + python_version=python_version, + repo_url=repo_url, + build_tool=build_tool, + dry_run=args.dry_run, + ) + + # Rename Directory and Update Imports + if package_name != PLACEHOLDER_PACKAGE_NAME: + rename_package_directory(package_name=package_name, dry_run=args.dry_run) + + # Update README.md + update_readme( + readme_path=README_MD, + project_name=project_name, + description=description, + install_env=install_env, + python_version=python_version, + dry_run=args.dry_run, + ) + + # Update CHANGES.md + replace_in_file( + filepath=CHANGES_MD, + replacements={ + PLACEHOLDER_PROJECT_NAME: project_name, + PLACEHOLDER_README_PROJECT_NAME: project_name, + PLACEHOLDER_AUTHOR: author, + PLACEHOLDER_REPO_URL: repo_url if repo_url else PLACEHOLDER_REPO_URL, + }, + dry_run=args.dry_run, + ) + + # Update .markdown-link-check.json + update_link_check(filepath=MARKDOWN_LINK_CHECK, repo_url=repo_url, dry_run=args.dry_run) + + # 4. Update self (the script itself) to prepare for next run + self_update_for_next_run_of_script( + args=args, + author=author, + description=description, + email=email, + package_name=package_name, + project_name=project_name, + python_version=python_version, + repo_url=repo_url, + ) + + print("\nāœ… Initialization Complete!") + if args.dry_run: + print("(This was a dry run. No files were modified.)") + else: + INIT_MARKER_FILE.touch() + print("\nšŸ” Please review the changes and commit them.") + print("\nšŸ“¦ You can now process to installing the package using the 'make install' command.") + + +if __name__ == "__main__": + main() diff --git a/.make/test.make b/.make/test.make new file mode 100644 index 0000000..bc22e9c --- /dev/null +++ b/.make/test.make @@ -0,0 +1,52 @@ +## -- Tests targets ------------------------------------------------------------------------------------------------- ## + +.PHONY: test +test: ## Run all tests + @$(ENV_COMMAND_TOOL) nox -s test + +TEST_ARGS ?= +MARKER_TEST_ARGS = -m "$(TEST_ARGS)" +SPECIFIC_TEST_ARGS = -k "$(TEST_ARGS)" +CUSTOM_TEST_ARGS = "$(TEST_ARGS)" + + +.PHONY: test-marker +test-marker: ## Run tests using pytest markers. Ex. make test-marker TEST_ARGS="" + @if [ -n "$(TEST_ARGS)" ]; then \ + $(ENV_COMMAND_TOOL) nox -s test_custom -- $(MARKER_TEST_ARGS); \ + else \ + echo "" ; \ + echo 'ERROR : Variable TEST_ARGS has not been set, please rerun the command like so :' ; \ + echo "" ; \ + echo ' make test-marker TEST_ARGS=""' ; \ + echo "" ; \ + fi + +.PHONY: test-specific +test-specific: ## Run specific tests using the -k option. Ex. make test-specific TEST_ARGS="" + @if [ -n "$(TEST_ARGS)" ]; then \ + $(ENV_COMMAND_TOOL) nox -s test_custom -- $(SPECIFIC_TEST_ARGS); \ + else \ + echo "" ; \ + echo 'ERROR : Variable TEST_ARGS has not been set, please rerun the command like so :' ; \ + echo "" ; \ + echo ' make test-specific TEST_ARGS=""' ; \ + echo "" ; \ + fi + +.PHONY: test-custom +test-custom: ## Run tests with custom args. Ex. make test-custom TEST_ARGS="-m 'not offline'" + @if [ -n "$(TEST_ARGS)" ]; then \ + $(ENV_COMMAND_TOOL) nox -s test_custom -- $(CUSTOM_TEST_ARGS); \ + else \ + echo "" ; \ + echo 'ERROR : Variable TEST_ARGS has not been set, please rerun the command like so :' ; \ + echo "" ; \ + echo ' make test-custom TEST_ARGS=""' ; \ + echo "" ; \ + fi + + +.PHONY: test-notebooks +test-notebooks: ## Execute test notebooks using pytest and nbval + @$(ENV_COMMAND_TOOL) nox -s test_nb \ No newline at end of file diff --git a/.make/tests/test-script.sh b/.make/tests/test-script.sh new file mode 100755 index 0000000..d207398 --- /dev/null +++ b/.make/tests/test-script.sh @@ -0,0 +1,340 @@ +#!/usr/bin/env bash + +# Set strict mode: exit on error, use unbound variables, fail on pipe errors +set -euo pipefail + +# --- 1. Project Path Determination --- + +SCRIPT_PATH="$(readlink -f "$0")" + +# Get the directory of the script, its parent, and the project root +SCRIPT_DIR="$(dirname "$SCRIPT_PATH")" +MAKE_DIR="$(dirname "$SCRIPT_DIR")" +PROJECT_DIR="$(dirname "$MAKE_DIR")" + +# --- 2. Shared Configuration Variables --- + +TEST_CONDA_ENV="lab-advanced-template-testing" +TEST_VENV_PATH="$PROJECT_DIR/.testvenv" +PIPX_TEST_ENV="$PROJECT_DIR/.testvenvpipx" + +# Reusable Makefile argument strings +BASE_MAKEFILE_ARGS="-f $PROJECT_DIR/.make/base.make" +LINT_MAKEFILE_ARGS="-f $PROJECT_DIR/.make/lint.make" +CONDA_MAKEFILE_ARGS="-f $PROJECT_DIR/.make/conda.make" +POETRY_MAKEFILE_ARGS="-f $PROJECT_DIR/.make/poetry.make" +UV_MAKEFILE_ARGS="-f $PROJECT_DIR/.make/uv.make" + +# Overrides for different configurations (now more focused) +MAKEFILE_CONDA_OVERRIDE="$BASE_MAKEFILE_ARGS $CONDA_MAKEFILE_ARGS $LINT_MAKEFILE_ARGS" +MAKEFILE_POETRY_OVERRIDE="$BASE_MAKEFILE_ARGS $CONDA_MAKEFILE_ARGS $POETRY_MAKEFILE_ARGS $LINT_MAKEFILE_ARGS" +MAKEFILE_UV_OVERRIDE="$BASE_MAKEFILE_ARGS $UV_MAKEFILE_ARGS $LINT_MAKEFILE_ARGS" + +# Tool-specific arguments +POETRY_ARGS="DEFAULT_INSTALL_ENV=poetry DEFAULT_BUILD_TOOL=poetry VENV_PATH=$PROJECT_DIR/.venv" +UV_ARGS="DEFAULT_INSTALL_ENV=uv DEFAULT_BUILD_TOOL=uv" +POETRY_CONDA_ARGS="DEFAULT_INSTALL_ENV=conda DEFAULT_BUILT_TOOL=poetry CONDA_ENVIRONMENT=$TEST_CONDA_ENV" + +# --- 3. Core Helper Functions --- + +# Helper function to print section headers +print_header() { + echo "" + echo "###" + echo "### $1" + echo "###" + echo "" +} + +# Generic function to execute a make target with arguments +# Usage: make_test "Target Name" "MAKEFILE_ARGS" "CUSTOM_VARS" "make_target" +make_test() { + local target_name="$1" + local makefile_args="$2" + local custom_vars="$3" + local make_target="$4" + + echo "### Running 'make $make_target' ($target_name): ###" + echo "" + + # Use command grouping (subshell) to ensure 'cd' doesn't affect the main script's environment + ( + cd "$PROJECT_DIR" && \ + make $makefile_args $custom_vars $make_target + ) +} + +# Generic function to run a sequence of tests +# Usage: run_test_suite "Suite Description" "MAKEFILE_ARGS" "CUSTOM_VARS" "TARGET_LIST" +run_test_suite() { + local suite_description="$1" + local makefile_args="$2" + local custom_vars="$3" + # Shift arguments to treat all subsequent args as the target list + shift 3 + local targets=("$@") + + print_header "Test Suite: $suite_description" + + for target in "${targets[@]}"; do + make_test "$suite_description" "$makefile_args" "$custom_vars" "$target" + done +} + + +# --- 4. Setup and Cleanup Functions --- + +test_cleanup() { + print_header "Cleaning potential test environments" + rm -rf "$PROJECT_DIR/.venv" "$TEST_VENV_PATH" "$PIPX_TEST_ENV" "$PROJECT_DIR/poetry.lock" "$PROJECT_DIR/uv.lock" +} + +# --- 5. Specific Test Functions --- + +base() { + print_header "Test base targets" + + # Simple targets without special environment setup + make_test "Base Targets" "" "" "targets" + make_test "Base Targets" "" "" "version" + + # Test venv creation and removal with a temporary path + run_test_suite \ + "Test temporary venv creation/removal" \ + "$MAKEFILE_POETRY_OVERRIDE" \ + "$POETRY_CONDA_ARGS VENV_PATH='$TEST_VENV_PATH'" \ + "venv-create" \ + "venv-remove AUTO_INSTALL=true" + + # Test versioning (bump targets) within a Conda environment managed by Poetry + local version_targets=( + "conda-create-env CONDA_ENVIRONMENT_FILE='$SCRIPT_DIR/test_environment.yml' CONDA_YES_OPTION='-y'" + "conda-env-info" + "conda-activate" + "install AUTO_INSTALL=true" + "bump-major dry" + "bump-minor dry" + "bump-patch dry" + "conda-clean-env AUTO_INSTALL=true CONDA_YES_OPTION='-y'" + ) + run_test_suite \ + "Test version bump targets (Poetry/Conda)" \ + "$MAKEFILE_POETRY_OVERRIDE" \ + "$POETRY_CONDA_ARGS" \ + "${version_targets[@]}" +} + +conda() { + local conda_targets=( + "conda-create-env CONDA_ENVIRONMENT_FILE='$SCRIPT_DIR/test_environment.yml' CONDA_YES_OPTION='-y'" + "conda-env-info" + "conda-activate" + "conda-clean-env AUTO_INSTALL=true CONDA_YES_OPTION='-y'" + ) + run_test_suite \ + "Test core conda environment targets" \ + "$MAKEFILE_CONDA_OVERRIDE" \ + "$POETRY_CONDA_ARGS" \ + "${conda_targets[@]}" +} + +# The 'lint' function is the most complex due to the matrix of combinations. +lint() { + # Combination 1: Poetry (Default Venv Path) + local poetry_venv_lint_targets=( + "poetry-create-env" "install" "check-lint" "pylint" "check-complexity" + "fix-lint" "precommit" "ruff" "ruff-fix" "ruff-format" + "poetry-remove-env AUTO_INSTALL=true" "venv-remove AUTO_INSTALL=true" + ) + run_test_suite \ + "Lint targets for Poetry (default venv)" \ + "$MAKEFILE_POETRY_OVERRIDE" \ + "$POETRY_ARGS" \ + "${poetry_venv_lint_targets[@]}" + + # Combination 2: Poetry (Conda-managed) + local poetry_conda_lint_targets=( + "conda-create-env CONDA_ENVIRONMENT_FILE='$SCRIPT_DIR/test_environment.yml' CONDA_YES_OPTION='-y'" + "install" "check-lint" "pylint" "check-complexity" + "fix-lint" "precommit" "ruff" "ruff-fix" "ruff-format" + "conda-clean-env AUTO_INSTALL=true CONDA_YES_OPTION='-y'" + ) + run_test_suite \ + "Lint targets for Poetry (Conda-managed)" \ + "$MAKEFILE_POETRY_OVERRIDE" \ + "$POETRY_CONDA_ARGS" \ + "${poetry_conda_lint_targets[@]}" + + # Combination 3: uv (Default Venv Path) + local uv_lint_targets=( + "uv-create-env" "install" "check-lint" "pylint" "check-complexity" + "fix-lint" "precommit" "ruff" "ruff-fix" "ruff-format" + "uv-remove-env AUTO_INSTALL=true" + ) + run_test_suite \ + "Lint targets for uv" \ + "$MAKEFILE_UV_OVERRIDE" \ + "$UV_ARGS" \ + "${uv_lint_targets[@]}" +} + +poetry() { + # Test 1: Poetry managed environment + local poetry_targets=( + "poetry-create-env" "install" "poetry-remove-env AUTO_INSTALL=true" "venv-remove AUTO_INSTALL=true" + ) + run_test_suite \ + "Poetry managed environment (poetry/venv)" \ + "$MAKEFILE_POETRY_OVERRIDE" \ + "$POETRY_ARGS" \ + "${poetry_targets[@]}" + + # Test 2: Conda managed environment + local conda_targets=( + "conda-create-env CONDA_ENVIRONMENT_FILE='$SCRIPT_DIR/test_environment.yml' CONDA_YES_OPTION='-y'" + "install" "conda-clean-env AUTO_INSTALL=true" + ) + run_test_suite \ + "Poetry managed environment (Conda)" \ + "$MAKEFILE_POETRY_OVERRIDE" \ + "$POETRY_CONDA_ARGS" \ + "${conda_targets[@]}" +} + +poetry-pipx(){ + local pipx_poetry_targets=( + "poetry-install-venv PIPX_VENV_PATH='$PIPX_TEST_ENV'" + "poetry-uninstall-venv PIPX_VENV_PATH='$PIPX_TEST_ENV' AUTO_INSTALL=true" + "poetry-install-venv" # Test default pipx path + ) + run_test_suite \ + "Test pipx Poetry targets" \ + "$MAKEFILE_POETRY_OVERRIDE" \ + "$POETRY_ARGS" \ + "${pipx_poetry_targets[@]}" +} + +uv(){ + local uv_targets=( + "uv-create-env" + "install AUTO_INSTALL=true" + "uv-remove-env AUTO_INSTALL=true" + ) + # Cleanup is done outside the suite for the specific cleanup step (rm -rf pyproject.toml.uv.backup) + run_test_suite \ + "Test uv managed installs and migration" \ + "$MAKEFILE_UV_OVERRIDE" \ + "$UV_ARGS" \ + "${uv_targets[@]}" +} + +uv-pipx(){ + local uv_pipx_targets=( + "uv-install-venv PIPX_VENV_PATH='$PIPX_TEST_ENV'" + "uv-uninstall-venv PIPX_VENV_PATH='$PIPX_TEST_ENV' AUTO_INSTALL=true" + ) + run_test_suite \ + "Test pipx uv targets" \ + "$MAKEFILE_UV_OVERRIDE" \ + "$UV_ARGS" \ + "${uv_pipx_targets[@]}" +} + +# --- 6. Execution Control Functions --- + +all() { + base + conda + lint + poetry + uv +} + +list () { + echo + echo "!!! Do not run this script outside of the 'lab-advanced-template' repository." + echo "This script exists only to test the makefiles for integrity when adding or" + echo "modifying targets !!!" + echo + echo " List of available tests:" + echo + echo " - base : Test 'base' targets" + echo " - conda : Test 'conda' targets" + echo " - lint : Test 'linting' targets (Poetry/Conda/uv matrix)" + echo " - poetry : Test 'poetry' targets (venv/Conda matrix)" + echo " - poetry-pipx : Test 'poetry' targets related to pipx" + echo " - uv : Test 'uv' targets" + echo " - uv-pipx : Test 'uv' targets related to pipx" + + echo + echo " Full test suite" + echo + echo " - all : Run most tests, except '*-pipx'" + echo + +} + +check_and_run_cleanup() { + echo "" + echo "🚨 WARNING: Executing cleanup will **permanently remove environments** (e.g., .venv, conda) and **lock files** (e.g., poetry.lock, requirements.lock)." + read -r -p "Are you sure you want to continue with the cleanup? (y/n): " confirm_cleanup + + if [[ "$confirm_cleanup" =~ ^[Yy]$ ]]; then + test_cleanup + echo "Cleanup complete!" + else + echo "Cleanup aborted by user. Skipping environment removal." + fi +} + +# --- 7. Main Script Execution --- + +if [[ "$#" -eq 0 ]]; then + list + exit 0 +else + check_and_run_cleanup +fi + +for var in "$@" +do + # Use a case statement to map arguments to function calls + case "$var" in + "list") + list + ;; + "base") + base + ;; + "conda") + conda + ;; + "lint") + lint + ;; + "poetry") + poetry + ;; + "poetry-pipx") + poetry-pipx + ;; + "uv") + uv + ;; + "uv-pipx") + uv-pipx + ;; + "all") + all + ;; + *) + echo "* * * * * * * * * * * * * * * * * * * * * * * * * " + echo "* ""$var"" is not a valid input " + echo "* Use the list command to see available inputs" + echo "* * * * * * * * * * * * * * * * * * * * * * * * *" + echo "" + list + exit 1 + esac +done +test_cleanup diff --git a/.make/tests/test_environment.yml b/.make/tests/test_environment.yml new file mode 100644 index 0000000..bf1a448 --- /dev/null +++ b/.make/tests/test_environment.yml @@ -0,0 +1,6 @@ +name: lab-advanced-template-testing +channels: + - conda-forge +dependencies: + - python=3.12 + diff --git a/.make/tests/verify_init.py b/.make/tests/verify_init.py new file mode 100644 index 0000000..e798ca3 --- /dev/null +++ b/.make/tests/verify_init.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python3 +import importlib.util +import io +import shutil +import subprocess +import sys +import tempfile +import unittest +from contextlib import redirect_stdout +from pathlib import Path + +PROJECT_ROOT_ACTUAL = Path(__file__).resolve().parent.parent.parent +SCRIPT_REL_PATH = Path(".make/scripts/auto_init_script.py") +MAKE_FOLDER = ".make" + + +class TestAutoInit(unittest.TestCase): + @staticmethod + def _setup_test_env(temp_dir_path): + """Copies essential project files to the temp directory.""" + temp_root = Path(temp_dir_path) + + items_to_copy = [ + "pyproject.toml", + "Makefile.variables", + "README.md", + ".markdown-link-check.json", + MAKE_FOLDER, + "src", + "CHANGES.md", + ] + + for item in items_to_copy: + src = PROJECT_ROOT_ACTUAL / item + dst = temp_root / item + if src.is_dir(): + shutil.copytree(src, dst, dirs_exist_ok=True) + elif src.exists(): + shutil.copy2(src, dst) + + # Create a dummy python file to test import replacement + # We use 'my_awesome_project' as the import because that's what PLACEHOLDER_IMPORT_NAME is in the script + dummy_file = temp_root / "src" / "dummy_script.py" + dummy_file.write_text( + "import my_awesome_project\nfrom my_awesome_project.utils import create_logger\n", encoding="utf-8" + ) + + # Initialize dummy git repo to test git detection + try: + subprocess.run(["git", "init"], cwd=temp_root, check=True, capture_output=True) + subprocess.run( + [ + "git", + "remote", + "add", + "origin", + "https://githubbogusexample.com/testuser/testrepo.git", + ], + cwd=temp_root, + check=True, + capture_output=True, + ) + except (subprocess.CalledProcessError, FileNotFoundError): + print("Warning: Failed to initialize git repo in temp dir. Git tests might fail.") + + return temp_root + + @staticmethod + def _load_module_from_path(name, path): + """Loads a module dynamically from a file path.""" + spec = importlib.util.spec_from_file_location(name, path) + if spec is None or spec.loader is None: + raise ImportError(f"Could not load script from {path}") + module = importlib.util.module_from_spec(spec) + sys.modules[name] = module + spec.loader.exec_module(module) + return module + + def _verify_markdown_link_check(self, temp_root: Path): + link_check = (temp_root / ".markdown-link-check.json").read_text() + self.assertIn("https://githubbogusexample.com/testuser/testrepo", link_check) + + def _verify_self_update(self, python_version, script_path: Path, test_package_name: str): + script_content = script_path.read_text() + self.assertIn(f'PLACEHOLDER_PACKAGE_NAME = "{test_package_name}"', script_content) + self.assertIn( + 'PLACEHOLDER_REPO_URL = "https://githubbogusexample.com/testuser/testrepo"', + script_content, + ) + self.assertIn(f'PLACEHOLDER_PYTHON_VERSION = "{python_version}"', script_content) + + def _verify_package_imports(self, temp_root: Path, test_package_name: str): + dummy_file_after = temp_root / "src" / "dummy_script.py" + dummy_content = dummy_file_after.read_text() + self.assertIn(f"import {test_package_name}", dummy_content) + self.assertIn(f"from {test_package_name}.utils import create_logger", dummy_content) + + def _verify_changes(self, temp_root: Path): + changes = (temp_root / "CHANGES.md").read_text() + self.assertIn("https://githubbogusexample.com/testuser/testrepo", changes) + + def _verify_readme(self, python_version, temp_root: Path, test_project_name: str): + readme = (temp_root / "README.md").read_text() + self.assertIn(f"# {test_project_name}", readme) + self.assertNotIn("## šŸš€ Template Initialization", readme) + self.assertIn(f"This project uses **Python {python_version}**", readme) + + def _verify_makefile_variables(self, build_tool, install_env: str, python_version, temp_root: Path): + makefile_vars = (temp_root / "Makefile.variables").read_text() + self.assertIn(f"DEFAULT_INSTALL_ENV := {install_env}", makefile_vars) + + expected_build_tool = build_tool + if install_env == "conda" and build_tool == "uv": + expected_build_tool = "poetry" + self.assertIn(f"DEFAULT_BUILD_TOOL := {expected_build_tool}", makefile_vars) + self.assertIn(f"PYTHON_VERSION := {python_version}", makefile_vars) + + def _verify_pyprojecttoml( + self, build_tool, install_env: str, python_version, temp_root: Path, test_package_name: str + ): + pyproject = (temp_root / "pyproject.toml").read_text() + self.assertIn(f'name = "{test_package_name}"', pyproject) + self.assertIn("https://githubbogusexample.com/testuser/testrepo", pyproject) + + # Build System Assertions + if build_tool == "uv" and install_env != "conda": + self.assertRegex(pyproject, r'(?m)^build-backend = "hatchling\.build"') + self.assertNotRegex(pyproject, r'(?m)^build-backend = "poetry\.core\.masonry\.api"') + elif build_tool == "poetry" or install_env == "conda": + self.assertRegex(pyproject, r'(?m)^build-backend = "poetry\.core\.masonry\.api"') + self.assertNotRegex(pyproject, r'(?m)^build-backend = "hatchling\.build"') + + # Python Version Assertion + major, minor = python_version.split(".") + next_minor = int(minor) + 1 + expected_requires = f'requires-python = ">={major}.{minor},<{major}.{next_minor}"' + self.assertIn(expected_requires, pyproject) + + expected_python_target = f'target-version = ["py{major}{minor}"]' + self.assertIn(expected_python_target, pyproject) + + expected_python_version = f'python_version = "{major}.{minor}"' + self.assertIn(expected_python_version, pyproject) + + def _verify_directory_structure(self, temp_root: Path, test_package_name: str): + expected_src = temp_root / "src" / test_package_name + self.assertTrue(expected_src.exists(), f"Source directory {expected_src} should exist") + self.assertFalse( + (temp_root / "src" / "core").exists(), + "Old source directory 'core' should be gone", + ) + + def run_init_scenario(self, install_env, build_tool, python_version, dry_run=False): + """Runs a single initialization scenario in a fresh temporary directory.""" + + with tempfile.TemporaryDirectory() as temp_dir: + temp_root = self._setup_test_env(temp_dir) + script_path = temp_root / SCRIPT_REL_PATH + + module_name = ( + f"auto_init_{install_env}_{build_tool}_{python_version.replace('.', '')}_{'dry' if dry_run else 'full'}" + ) + + script_module = self._load_module_from_path(module_name, script_path) + + # Mock sys.argv + test_package_name = f"test_pkg_{install_env}_{build_tool}" + test_project_name = "Test Project" + args = [ + str(script_path), + "--project-name", + test_project_name, + "--package-name", + test_package_name, + "--description", + "Test Description", + "--author", + "Test Author", + "--email", + "test@example.com", + "--python-version", + python_version, + "--install-env", + install_env, + ] + + if install_env == "conda": + args.extend(["--conda-env-name", "test-conda-env", "--conda-tool", "mamba"]) + + args.extend(["--build-tool", build_tool]) + + if dry_run: + args.append("--dry-run") + + original_argv = sys.argv + sys.argv = args + + f = io.StringIO() + try: + with redirect_stdout(f): + script_module.main() + except SystemExit as e: + if e.code != 0: + self.fail(f"Script exited with code {e.code}. Output:\n{f.getvalue()}") + except Exception as e: + self.fail(f"Script crashed: {e}. Output:\n{f.getvalue()}") + finally: + sys.argv = original_argv + + # --- Assertions --- + if dry_run: + # In dry run, 'core' should still exist + self.assertTrue((temp_root / "src" / "core").exists()) + self.assertFalse((temp_root / "src" / test_package_name).exists()) + self.assertFalse((temp_root / MAKE_FOLDER / ".init_completed").exists()) + return + + # 1. Check Directory Structure + self._verify_directory_structure(temp_root, test_package_name) + + # 2. Check pyproject.toml + self._verify_pyprojecttoml(build_tool, install_env, python_version, temp_root, test_package_name) + + # 3. Check Makefile.variables + self._verify_makefile_variables(build_tool, install_env, python_version, temp_root) + + # 4. Check README.md + self._verify_readme(python_version, temp_root, test_project_name) + + # 5. Check CHANGES.md - Relaxed assertion + self._verify_changes(temp_root) + + # 6. Check Import Updates + self._verify_package_imports(temp_root, test_package_name) + + # 7. Check Marker File + self.assertTrue( + (temp_root / MAKE_FOLDER / ".init_completed").exists(), + "Init marker should exist", + ) + + # 8. Check Script Self-Update + self._verify_self_update(python_version, script_path, test_package_name) + + # 9. Check .markdown-link-check.json + self._verify_markdown_link_check(temp_root) + + def test_matrix(self): + """Iterate through all valid combinations.""" + combinations = [ + ("uv", "uv", "3.12"), + ("poetry", "poetry", "3.13"), + ("conda", "poetry", "3.12"), + ("venv", "uv", "3.12"), + ] + print("") # Spacing + for install_env, build_tool, py_ver in combinations: + with self.subTest(install_env=install_env, build_tool=build_tool, python_version=py_ver): + print( + f"Testing combination: Env={install_env}, Build={build_tool}, Py={py_ver} ...", + end="", + flush=True, + ) + self.run_init_scenario(install_env, build_tool, py_ver) + print(" OK") + + def test_dry_run(self): + """Tests that dry-run does not modify files.""" + print("Testing Dry Run ...", end="", flush=True) + self.run_init_scenario("uv", "uv", "3.12", dry_run=True) + print(" OK") + + +if __name__ == "__main__": + unittest.main() diff --git a/.make/uv.make b/.make/uv.make new file mode 100644 index 0000000..2afb118 --- /dev/null +++ b/.make/uv.make @@ -0,0 +1,258 @@ +# Project and Private variables and targets import to override variables for local +# This is to make sure, sometimes the Makefile includes don't work. + +## -- UV targets ------------------------------------------------------------------------------------------------ ## +ENV_TOOL := $(shell command -v uv 2> /dev/null) +LOCAL_UV_PATH := $(shell echo $$HOME/.local/bin/uv) +ifeq ($(ENV_TOOL),) + ENV_TOOL := $(LOCAL_UV_PATH) +endif +# Do not rename these unless you also rename across all other make files in .make/ +ENV_COMMAND_TOOL := $(ENV_TOOL) run +ENV_INSTALL_TOOL := $(ENV_TOOL) sync -p $(PYTHON_VERSION) + +.PHONY: uv-install-auto +uv-install-auto: + @$(ENV_TOOL) --version; \ + if [ $$? != "0" ]; then \ + make -s uv-install-venv; \ + fi; + +.PHONY: uv-install +uv-install: ## Install uv interactively. + @echo "Looking for uv version...";\ + $(ENV_TOOL) --version; \ + if [ $$? != "0" ]; then \ + if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo "uv not found..."; \ + echo "Looking for pipx version...";\ + pipx_found=0; \ + pipx --version; \ + if [ $$? != "0" ]; then \ + pipx_found=1; \ + echo "pipx not found..."; \ + echo ""; \ + echo -n "Would you like to install pipx and uv? [y/N]: "; \ + else \ + echo ""; \ + echo -n "Would you like to install uv using pipx? [y/N]: "; \ + fi; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + if [ $$pipx_found == "1" ]; then \ + echo ""; \ + echo -e "$(WARNING)The following pip has been found and will be used to install pipx: "; \ + echo " -> "$$(which pip); \ + echo ""; \ + echo "If you do not have write permission to that environment, using it to install pipx will fail."; \ + echo "If this is the case, you should install pipx using a virtual one."; \ + echo ""; \ + echo "See documentation for more information."; \ + echo ""; \ + echo -n "Would you like to use the local available pip above, or create virtual environment to install pipx? [local/virtual]: "; \ + read ans_how; \ + case $$ans_how in \ + "LOCAL" | "Local" |"local") \ + make -s uv-install-local; \ + ;; \ + "VIRTUAL" | "Virtual" | "virtual") \ + make -s uv-install-venv; \ + ;; \ + *) \ + echo ""; \ + echo -e "$(WARNING)Option $$ans_how not found, exiting process."; \ + echo ""; \ + exit 1; \ + esac; \ + else \ + echo "Installing uv"; \ + make -s _pipx_install_uv; \ + fi; \ + ;; \ + *) \ + echo "Skipping installation."; \ + echo " "; \ + ;; \ + esac; \ + fi; + +.PHONY: _pipx_install_uv +_pipx_install_uv: + @pipx install uv + + + +.PHONY: uv-install-venv +uv-install-venv: ## Install standalone uv. Will install pipx in $HOME/.pipx_venv + @pipx --version; \ + if [ $$? != "0" ]; then \ + echo "Creating virtual environment using venv here : [$(PIPX_VENV_PATH)]"; \ + virtualenv $(PIPX_VENV_PATH); \ + echo "Activating virtual environment [$(PIPX_VENV_PATH)]"; \ + source $(PIPX_VENV_PATH)/bin/activate; \ + pip3 install pipx; \ + pipx ensurepath; \ + source $(PIPX_VENV_PATH)/bin/activate && make -s _pipx_install_uv; \ + else \ + make -s _pipx_install_uv; \ + fi; + +.PHONY: uv-install-local +uv-install-local: ## Install standalone uv. Will install pipx with locally available pip. + @pipx --version; \ + if [ $$? != "0" ]; then \ + echo "pipx not found; installing pipx"; \ + pip3 install pipx; \ + pipx ensurepath; \ + fi; + @echo "Installing UV" + @make -s _pipx_install_uv + +.PHONY: uv-create-env +uv-create-env: ## Create a virtual environment for uv, using the project's python version. + @$(ENV_TOOL) python install $(PYTHON_VERSION) + @$(ENV_TOOL) venv --python $(PYTHON_VERSION) + +.PHONY: uv-activate +uv-activate: ## Print out the shell command to activate the project's uv environment. + @make -s venv-activate + +.PHONY: uv-remove-env +uv-remove-env: ## Remove current project's uv managed environment. + @make -s venv-remove + +.PHONY: uv-uninstall +uv-uninstall: uv-remove-env ## Uninstall pipx-installed uv and the created environment + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to uninstall pipx-installed uv? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + pipx --version ; \ + if [ $$? != "0" ]; then \ + echo "" ; \ + echo "Pipx not found globally, trying with $(PIPX_VENV_PATH) env" ;\ + echo "" ; \ + source $(PIPX_VENV_PATH)/bin/activate && pipx uninstall uv ; \ + else \ + pipx uninstall uv ; \ + fi; \ + ;; \ + *) \ + echo "Skipping uninstallation."; \ + echo " "; \ + ;; \ + esac; \ + +.PHONY: uv-uninstall-pipx +uv-uninstall-pipx: uv-remove-env ## Uninstall pipx-installed uv, the created uv environment and pipx + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to uninstall pipx-installed uv and pipx? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + pipx --version ; \ + if [ $$? != "0" ]; then \ + echo "" ; \ + echo "Pipx not found globally, trying with $(PIPX_VENV_PATH) env" ;\ + echo "" ; \ + source $(PIPX_VENV_PATH)/bin/activate && pipx uninstall uv && pip uninstall -y pipx; \ + else \ + pipx uninstall uv ; \ + pip uninstall -y pipx ;\ + fi; \ + ;; \ + *) \ + echo "Skipping uninstallation."; \ + echo " "; \ + ;; \ + esac; \ + +.PHONY: uv-uninstall-venv +uv-uninstall-venv: uv-remove-env ## Uninstall pipx-installed uv, the created uv environment, pipx and $HOME/.pipx_venv + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to uninstall pipx-installed uv and pipx? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + (source $(PIPX_VENV_PATH)/bin/activate && pipx uninstall uv); \ + (source $(PIPX_VENV_PATH)/bin/activate && pip uninstall -y pipx); \ + ;; \ + *) \ + echo "Skipping uninstallation."; \ + echo " "; \ + ;; \ + esac; \ + + @if [ "$(AUTO_INSTALL)" = "true" ]; then \ + ans="y";\ + else \ + echo ""; \ + echo -n "Would you like to remove the virtual environment located here : [$(PIPX_VENV_PATH)] ? [y/N]: "; \ + read ans; \ + fi; \ + case $$ans in \ + [Yy]*) \ + rm -r $(PIPX_VENV_PATH); \ + ;; \ + *) \ + echo "Skipping [$(PIPX_VENV_PATH)] virtual environment removal."; \ + echo ""; \ + ;; \ + esac; \ + +## -- Specific install targets (All install targets will install uv if the tool is not found using) ----------------- ## +.PHONY: _remind-env-activate +_remind-env-activate: + @echo "" + @echo "Activate your environment using the following command:" + @echo "" + @make -s uv-activate + @echo "" + @echo "or use the eval bash command : eval \$$(make uv-activate)" + @echo "" + @echo "You can also use the following command line to interact with the environment directly" + @echo "" + @echo " $$ uv run " + @echo "" + +.PHONY: install-dev +install-dev: uv-install-auto ## Install the application along with developer dependencies + @$(ENV_INSTALL_TOOL) --group dev --all-packages + @make -s _remind-env-activate + +.PHONY: install-all +install-all: uv-install-auto ## Install the application and all it's dependency groups + @$(ENV_INSTALL_TOOL) --all-extras --all-packages + @make -s _remind-env-activate + +.PHONY: install-jupyterlab +install-jupyterlab: uv-install-auto ## Install Jupyter Lab dependencies + @$(ENV_INSTALL_TOOL) --extra lab --all-packages + @make -s _remind-env-activate + +.PHONY: install-docs +install-docs: uv-install-auto ## Install docs related dependencies (mkdocs) + @$(ENV_INSTALL_TOOL) --extra docs --all-packages + @make -s _remind-env-activate + +.PHONY: install-package +install-package: uv-install-auto ## Install the application package only + @$(ENV_INSTALL_TOOL) --no-dev --all-packages + @make -s _remind-env-activate diff --git a/Makefile b/Makefile index 323195b..db6c1c5 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,19 @@ +######################################################################################## # -# DO NOT MODIFY!!! +# MODIFY WITH CARE!!! # If necessary, override the corresponding variable and/or target, or create new ones # in one of the following files, depending on the nature of the override : # -# Makefile.variables, Makefile.targets or Makefile.private, +# `Makefile.variables`, `Makefile.targets` or `Makefile.private`, # -# The only valid reason to modify this file is to fix a bug or to add new +# The only valid reason to modify this file is to fix a bug or to add/remove # files to include. # -# Please report bugs to francis.pelletier@mila.quebec - -# Include base makefile -include .make/base.make -# Include custom targets and variables --include Makefile.targets --include Makefile.variables -# Private variables and targets import to override variables for local --include Makefile.private +# REMEMBER!!! +# This is a project level config, any changes here will affect all other users +# +######################################################################################## +# +# Necessary make files +# +include .make/manager.make diff --git a/Makefile.private.example b/Makefile.private.example index be83cd0..48f4db1 100644 --- a/Makefile.private.example +++ b/Makefile.private.example @@ -16,13 +16,34 @@ ## Private variables -# If you use a different Conda tool, say `micromamba`, or if you use a different alias -# CONDA_TOOL := -DOCKER_COMPOSE := docker compose - -# Some targets use this variable. A 'false' value will ask user to confirm some steps. -# a 'true' value will automatically install/remove without asking beforehand. +# Most, but not all install/remove targets use this variable. A 'false' value will ask +# users to confirm some steps. A 'true' value will automatically install/remove without +# asking beforehand. AUTO_INSTALL := false -## -- Private targets ------------------------------------------------------------------------------------------------## +# The default environment to use. The choices are as follow: [venv, uv, poetry, conda] +# Here, we are talking about the virtual environment management - not dependencies. +# +# venv creates a standard virtual environment via the available 'virtualenv' +# uv creates a virtual environment via 'uv venv -p $(PYTHON_VERSION)' +# poetry creates a virtual environment via 'poetry env use $(PYTHON_VERSION) +# conda create a virtual environment via '$(CONDA_TOOL) env create -f environment.yml' +# +# This overrides the value found in 'Makefile.variables' +DEFAULT_INSTALL_ENV := uv + +# The default build tool to use. The choices are as follows: [uv, poetry] +# This value should also reflect the choice above - DO NOT choose 'poetry' or 'conda' for +# DEFAULT_INSTALL_ENV and then use 'uv' as the build tool +# +# This is the project's default. +DEFAULT_BUILD_TOOL := uv + +# This variable is to enable the '-y' flag when newer version of conda is available. +# The default Mila conda module does not allow this flag; leave blanks or commented out +# CONDA_YES_OPTION := -y +# If you use a different Conda tool, say `mamba`, or if you use a different alias +# CONDA_TOOL := + +DOCKER_COMPOSE := docker compose diff --git a/Makefile.variables b/Makefile.variables index 3602cb6..445f16e 100644 --- a/Makefile.variables +++ b/Makefile.variables @@ -1,6 +1,40 @@ # This file is for custom makefile variable at the project level. # They are meant to be share by the whole project team. +# +# Project Core variables +# +APP_VERSION := 0.0.0 + +# APPLICATION_NAME must be aligned with the name of the folder containing your package APPLICATION_NAME := climateset -CONDA_ENVIRONMENT := climateset + PYTHON_VERSION := 3.11 + +# This is the default install environment for the project. +# Here, we are talking about the virtual environment management - not dependencies. +# +# venv creates a standard virtual environment via the available 'virtualenv' +# uv creates a virtual environment via 'uv venv -p $(PYTHON_VERSION)' +# poetry creates a virtual environment via 'poetry env use $(PYTHON_VERSION)' +# conda create a virtual environment via '$(CONDA_TOOL) env create -f environment.yml' +# +# The default environment is uv. The choices are as follows: [venv, uv, poetry, conda] +DEFAULT_INSTALL_ENV := conda + +# This is the project's default build tool. +# This value should also reflect the choice above - DO NOT choose 'poetry' for +# DEFAULT_INSTALL_ENV and then use 'uv' as the build tool +# +# The default build tool is uv. The choices are as follows: [uv, poetry] +DEFAULT_BUILD_TOOL := poetry + +# Makefile target groups +# Below, you can chose what target groups are available. Full list: [lint,test,docs] +TARGET_GROUPS := lint,test,docs + +# +# Conda related variables +# +CONDA_ENVIRONMENT := climateset +CONDA_TOOL := mamba diff --git a/pyproject.toml b/pyproject.toml index 66f0c2f..8503b54 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,7 +77,7 @@ search = 'version = "{current_version}"' replace = 'version = "{new_version}"' [[tool.bumpversion.files]] -filename = "Makefile" +filename = "Makefile.variables" search = "APP_VERSION := {current_version}" replace = "APP_VERSION := {new_version}" From dd9c54d7a3aa22f22f69d4b5e3750784e46dd8ef Mon Sep 17 00:00:00 2001 From: f-PLT Date: Tue, 24 Mar 2026 13:22:11 -0400 Subject: [PATCH 2/6] Refactor ENV_SETUP.md to take advantage of new makefile --- ENV_SETUP.md | 325 ++++++--------------------------------------------- 1 file changed, 34 insertions(+), 291 deletions(-) diff --git a/ENV_SETUP.md b/ENV_SETUP.md index d45f13b..74fb0f0 100644 --- a/ENV_SETUP.md +++ b/ENV_SETUP.md @@ -1,311 +1,54 @@ -# ClimatesetExtension +# Environment Setup Guide -## Tools and Makefile structure - -The project uses a Makefile to automate most operations. If make is available on your -machine there's a good chance this will work. - -The following Makefile files should not be modified, but can be consulted: - -* [Makefile](Makefile) : Orchestration of the different files -* [base.make](.make/base.make) : Shared utilities, project agnostic. - -The following Makefile files are project or user specific: - -* [Makefile.variables](Makefile.variables) : Shared project variables. -* [Makefile.targets](Makefile.targets) : Shared project targets. -* [Makefile.private](Makefile.private.example) : User specific variables and targets. - -### Basic Information - -The different targets and their description can be examined by executing the command -`make targets` - -Ex. - -![](img/make_targets.png) +This guide covers the necessary steps to configure your environment for the ClimatesetExtension project. ## Requirements -This project has only been tested in a Linux (Debian based) environment and assumes -some basic tools for development are already installed. - -It also requires that minimally `Python`, `pip` and `venv` are available on your system. - -This project assumes environment management will be done with `Conda` or directly through -`Poetry`. - -* [Poetry](https://python-poetry.org/docs/basic-usage/) -* [Conda](https://conda.io/projects/conda/en/latest/user-guide/getting-started.html) - -While it is possible to manage the environment with, for example, pyenv or virtualenv, -those specific use cases are not supported by the Makefile and require users to set up -their own environments beforehand. - -For detailed information about `Poetry` and `Conda`: - -If you want to use something else than `Conda` or `Poetry` to manage environment isolation, -it is recommended to follow -[Poetry's guidelines on managing environments](https://python-poetry.org/docs/managing-environments/) - -Poetry is not included in the [environment.yml](environment.yml), due to some possible problems -in compute cluster environments, but will be installed automatically if needed -by most `install` targets. - -Currently, the project runs on Python version 3.10. - -## Environment management choices - -Environment management can become quite complicated. Using Conda allows a certain -ease of management since the Poetry installation is contained inside the created Conda -environment. - -However, some computing environments do not permit the use of Conda (like certain SLURM -clusters). This is why the `pipx` option for Poetry is also enabled in this project. - -**Unless you really know what you are doing, it is not recommended to install Poetry -as a standalone tool (with pipx) while also using Conda environments.** - -There are 2 recommended ways to manage `Poetry` if it is not already configured on -your system. Using `Conda`, or installing `Poetry` as a standalone tool using `pipx` - -It is not recommended to install `Poetry` in the same environment that will be managed -by `Poetry` in order to minimize dependency conflicts. - -### Note about Pipx installation - -If you want to install `Poetry` using `pipx`, and pipx is not already -installed on your system, it will be installed using `pip`. - -Write access to that environment is required (use `which pip` to learn which -environment is active if not sure). - -Particularly on remote compute clusters (SLURM), default system `pip` will probably not -allow users to install packages. One way around it is to create a generic virtual -environment using `venv` like so (preferably in your $HOME). It can be done manually using the -following commands: - -Ex. -``` -python -m venv $HOME/.venv -source $HOME/.venv/bin/activate -pip install pipx -pipx ensurepath -pipx install poetry -deactivate -``` - -This virtual environment can be deactivated afterward, as Poetry will still be -available to the user. - -There are also targets in the [Poetry section](#using-poetry) that handle this use case. - -## Using Conda - -If you need or want to install Conda: -``` -make conda-install -``` - -To create the conda environment: -``` -make conda-create-env -``` - -To remove the conda environment: -``` -make conda-clean-env -``` - -To install `Poetry` using `Conda` (after conda environment as been created: - -``` -make conda-poetry-install -``` - -To remove poetry from the Conda environment: - -``` -make conda-poetry-uninstall -``` - -Make sure to activate the conda environment before moving on the -[install targets](#install-targets). - -## Using Poetry - -The following target will first try to install `Poetry` in the active `Conda` -environment; if it can't find `Conda`, it will proceed to install via `pipx` - -``` -make poetry-install-auto -``` - -The following target will allow environment management directly with a standalone -`Poetry` installation through `pipx`. It will also create a virtual environment managed -by `Poetry` that uses Python 3.10. - -``` -make poetry-install -``` - -If the compute environment requires `pipx` to be installed in a virtual environment: - -``` -make poetry-install-venv -``` - -If you already have Poetry installed and configured, or want to recreate it later, -an environment for the project can also be created using: - -``` -make poetry-create-env -``` - -and removed using: - -``` -make poetry-remove-env -``` - -Information about the currently active environment used by `Poetry`, -whether `Conda` or `Poetry`, can be seen using: - -``` -make poetry-env-info -``` - -To remove `Poetry` that was installed with `pipx` (be sure to execute this command in -the environment where pipx is installed): - -``` -make poetry-uninstall -``` - -To uninstall both `Poetry` and `pipx` (again, be sure to execute this command in -the environment where pipx is installed): - -``` -make poetry-uninstall -``` - -If `Poetry` and `pipx` were installed using the `make poetry-install-venv`, they can be -removed, including the virtual environment, using: - -``` -make poetry-uninstall-venv -``` - -**Important note!** - -If you have an active `Conda` environment and install `Poetry` using `pipx`, -you will have to use `poetry run python ` instead of -`python `, (which is normal when using Poetry) as -Conda's active environment will define the available default `python` executable. - - -## Installing the python package and it's dependencies - -**All `install` targets will first check if `Poetry` is available and try to install -it with the `make poetry-install-auto` target.** - -To install the package, development dependencies and CLI tools (if available): -``` -make install -``` - -To install only the package, without development tools: -``` -make install-package -``` - -## First time user quick setup - -### Conda -The easiest and quickest way to get up and running with Conda. - -Create Conda environment (will check for Conda and install it if not found): -``` -make conda-create-env -``` - -Activate Conda environment (substitute with your if something else -than `conda`: - -``` -conda activate climateset -``` - -Install package: - -``` -make install -``` - -### Poetry - -The easiest and quickest way to get up and running with Poetry. - -Install pipx and Poetry and activate project environment : - -``` -make poetry-install -``` -_can be replaced by `make poetry-install-venv` if needed_ - -If Poetry is already available, the environment can be created using: +This project is configured to use `Miniforge` or `Micromamba` for environment isolation and non-Python dependencies, while using [Poetry](https://python-poetry.org/) as the primary build tool for managing Python packages. You can choose which one to install using the `make conda-install` command. -``` -make poetry-create-env -``` +The project is configured to use the `mamba` tool instead of `conda` or `micromamba`. See [Makefile.private.example](Makefile.private.example) if you require something other than `mamba` locally. -Install package: +## Makefile Automation -``` -make install -``` +The project relies on a `Makefile` to automate common tasks, including environment management, package installation, linting, testing, and documentation generation. -## Basic automations +For a comprehensive list of targets and detailed explanations of the Makefile structure, please consult the [Makefile Documentation](.make/README.md). -To run linting checks with `flake8`, `pylint`, `black` and `isort`: -``` -make check-lint -``` +You can discover all available commands and view your current project configuration directly in your terminal: -To fix linting with `black`, `flynt` and `isort`: -``` -make fix-lint -``` +```bash +# List all available Makefile targets +make targets -To run a `pre-commit` check before actually committing: -``` -make precommit +# View current project configuration (Python version, active target groups, etc.) +make info ``` -To run tests: -``` -make test -``` - - -## Data - -## Experiment tracking - -Nothing is set up for now, but since Weights and Bias is accessible to MILA and DRAC, it -will probably be the way to go. - - -## Training +## Quick Setup -## Contributing to this repository +Follow these steps to initialize the environment using the configured Conda and Poetry toolchain. -See [Contributing guidelines](CONTRIBUTING.md) +1. **Create the Conda environment**: + This step handles non-Python dependencies and isolates the environment. + ```bash + make conda-create-env + ``` +2. **Activate the environment**: + ```bash + eval $(make conda-activate) + ``` +3. **Install the Python package and development tools via Poetry**: + This target will automatically verify Poetry is available and use it to install the package dependencies. + ```bash + make install + ``` +## Experiment Tracking -### Configurations -Configurations are in the [configs/](configs) folder. +Weights and Biases (WandB) is the planned solution for experiment tracking, as it is natively accessible on MILA and DRAC clusters. +## Additional Resources -### Tests +- **Configurations**: Review the [configs/](configs) directory for YAML configurations. +- **Contributing**: Refer to the [Contribution Guidelines](CONTRIBUTING.md) for repository standards. From 03d27abe85be5132bd35c4ebacf5bf70ccf50368 Mon Sep 17 00:00:00 2001 From: f-PLT Date: Tue, 24 Mar 2026 13:24:42 -0400 Subject: [PATCH 3/6] Update Noxfile --- noxfile.py | 107 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/noxfile.py b/noxfile.py index 42460cb..23c23cb 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,7 +1,10 @@ +import re from pathlib import Path import nox +ARG_RE = re.compile(r"^[a-zA-Z0-9_.\-:=/\s\"'()\[\]]+$") # e.g. "-k", "--maxfail=1", "tests/foo.py" + nox.options.reuse_existing_virtualenvs = True # Reuse virtual environments nox.options.sessions = ["precommit"] @@ -18,32 +21,35 @@ def get_paths(session): package_path / "climateset", package_path / "scripts", ], + "root": [package_path], } # # Sessions # - - @nox.session() def pylint(session): paths = get_paths(session) - session.run("poetry", "run", "pylint", *paths["module"], external=True) + session.run("pylint", *paths["module"], external=True) @nox.session() def flake8(session): paths = get_paths(session) - session.run("poetry", "run", "flake8", *paths["all"], external=True) + session.run("flake8", *paths["all"], external=True) + + +@nox.session() +def complexity(session): + paths = get_paths(session) + session.run("flake8", "--max-complexity", "7", *paths["all"], external=True) @nox.session() def docformatter(session): paths = get_paths(session) session.run( - "poetry", - "run", "docformatter", "--config", f"{paths['all'][0].parent}/pyproject.toml", @@ -55,31 +61,30 @@ def docformatter(session): @nox.session() def check(session): paths = get_paths(session) - session.run("poetry", "run", "black", "--check", *paths["all"], external=True) - session.run("poetry", "run", "isort", *paths["all"], "--check", external=True) - session.run("poetry", "run", "flynt", *paths["all"], external=True) + session.run("black", "--check", *paths["all"], external=True) + session.run("isort", *paths["all"], "--check", external=True) + session.run("flynt", *paths["all"], external=True) + session.run("mypy", *paths["root"], external=True) session.run( - "poetry", - "run", "docformatter", "--config", f"{paths['all'][0].parent}/pyproject.toml", *paths["all"], external=True, ) - session.run("poetry", "run", "flake8", *paths["all"], external=True) - session.run("poetry", "run", "pylint", *paths["module"], external=True) + session.run("flake8", *paths["all"], external=True) + session.run("pylint", *paths["module"], external=True) @nox.session() def fix(session): paths = get_paths(session) - session.run("poetry", "run", "black", *paths["all"], external=True) - session.run("poetry", "run", "isort", *paths["all"], external=True) - session.run("poetry", "run", "flynt", *paths["all"], external=True) + session.run("autoflake", "-v", *paths["all"], external=True) + session.run("autopep8", *paths["all"], external=True) + session.run("black", *paths["all"], external=True) + session.run("isort", *paths["all"], external=True) + session.run("flynt", *paths["all"], external=True) session.run( - "poetry", - "run", "docformatter", "--in-place", "--config", @@ -91,44 +96,94 @@ def fix(session): @nox.session() def precommit(session): - session.run("poetry", "run", "pre-commit", "run", "--all-files", external=True) + session.run("pre-commit", "run", "--all-files", external=True) + + +@nox.session() +def autoflake(session): + paths = get_paths(session) + session.run("autoflake", "-v", *paths["all"], external=True) + + +@nox.session() +def autopep(session): + paths = get_paths(session) + session.run("autopep8", *paths["all"], external=True) @nox.session() def black(session): paths = get_paths(session) - session.run("poetry", "run", "black", "--check", *paths["all"], external=True) + session.run("black", "--check", *paths["all"], external=True) @nox.session() def isort(session): paths = get_paths(session) - session.run("poetry", "run", "isort", *paths["all"], "--check", external=True) + session.run("isort", *paths["all"], "--check", external=True) @nox.session() def flynt(session): paths = get_paths(session) - session.run("poetry", "run", "flynt", *paths["all"], external=True) + session.run("flynt", *paths["all"], external=True) + + +@nox.session() +def mypy(session): + paths = get_paths(session) + (session.run("mypy", *paths["root"], external=True)) + + +@nox.session() +def autotyping(session): + paths = get_paths(session) + session.run("autotyping", "--aggressive", *paths["all"], external=True) + + +@nox.session() +def mdformat(session): + paths = get_paths(session) + session.run("mdformat", *paths["root"], external=True) + + +@nox.session(name="ruff-lint") +def ruff_lint(session): + paths = get_paths(session) + session.run("ruff", "check", *paths["all"], external=True) + + +@nox.session(name="ruff-fix") +def ruff_fix(session): + paths = get_paths(session) + session.run("ruff", "check", "--fix", *paths["all"], external=True) + + +@nox.session(name="ruff-format") +def ruff_format(session): + paths = get_paths(session) + session.run("ruff", "format", *paths["all"], external=True) @nox.session() def test(session): - session.run("poetry", "run", "pytest", external=True) + session.run("pytest", external=True) @nox.session() def test_custom(session): + for a in session.posargs: + if not ARG_RE.match(a): + session.error(f"unsafe pytest argument detected: {a!r}") + session.run( - "poetry", "run", "pytest", external=True, *session.posargs + "python", "-m", "pytest", external=True, *session.posargs ) # Pass additional arguments directly to pytest @nox.session() def test_nb(session): session.run( - "poetry", - "run", "pytest", "--nbval", "tests/test_notebooks/", From 9f2a980a6e01a27e8853f57a832300c1563db9d9 Mon Sep 17 00:00:00 2001 From: f-PLT Date: Tue, 24 Mar 2026 14:17:02 -0400 Subject: [PATCH 4/6] Update CI --- .github/workflows/lint.yml | 20 +++++++++++++++++--- .github/workflows/precommit.yml | 18 ++++++++++++++++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 55cd09f..bd5d691 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,6 +1,6 @@ name: Lint -on: [pull_request, push] +on: [pull_request] concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -26,6 +26,20 @@ jobs: activate-environment: climateset use-mamba: true + - name: Install Poetry + run: | + make install-poetry-venv + + - name: Cache Poetry virtualenv and dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cache/pypoetry + ~/.cache/pip + key: poetry-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} + restore-keys: | + poetry-${{ runner.os }}- + - name: Get Date id: get-date run: echo "today=$(/bin/date -u '+%Y%m%d')" >> $GITHUB_OUTPUT @@ -51,8 +65,8 @@ jobs: - name: Install dependencies run: | - make CONDA_TOOL=mamba install + make install-dev - name: Run linting checks run: | - make check-pylint + make pylint diff --git a/.github/workflows/precommit.yml b/.github/workflows/precommit.yml index 8b6a139..e0bc14e 100644 --- a/.github/workflows/precommit.yml +++ b/.github/workflows/precommit.yml @@ -1,6 +1,6 @@ name: Pre-commit -on: [pull_request, push] +on: [pull_request] concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -26,6 +26,20 @@ jobs: activate-environment: climateset use-mamba: true + - name: Install Poetry + run: | + make install-poetry-venv + + - name: Cache Poetry virtualenv and dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cache/pypoetry + ~/.cache/pip + key: poetry-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} + restore-keys: | + poetry-${{ runner.os }}- + - name: Get Date id: get-date run: echo "today=$(/bin/date -u '+%Y%m%d')" >> $GITHUB_OUTPUT @@ -51,7 +65,7 @@ jobs: - name: Install dependencies run: | - make CONDA_TOOL=mamba install + make install-dev - name: Run Pre-commit checks run: | From bf89e8886f676c57175065fac34e1995378586b6 Mon Sep 17 00:00:00 2001 From: f-PLT Date: Tue, 24 Mar 2026 14:22:21 -0400 Subject: [PATCH 5/6] Update CI - fix poetry install --- .github/workflows/lint.yml | 2 +- .github/workflows/precommit.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index bd5d691..c58e168 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -28,7 +28,7 @@ jobs: - name: Install Poetry run: | - make install-poetry-venv + make poetry-install-venv - name: Cache Poetry virtualenv and dependencies uses: actions/cache@v4 diff --git a/.github/workflows/precommit.yml b/.github/workflows/precommit.yml index e0bc14e..5fa14e5 100644 --- a/.github/workflows/precommit.yml +++ b/.github/workflows/precommit.yml @@ -28,7 +28,7 @@ jobs: - name: Install Poetry run: | - make install-poetry-venv + make poetry-install-venv - name: Cache Poetry virtualenv and dependencies uses: actions/cache@v4 From 44ff0b107d2fc0d50613eea771c3ff1edafb6005 Mon Sep 17 00:00:00 2001 From: f-PLT Date: Tue, 24 Mar 2026 14:31:33 -0400 Subject: [PATCH 6/6] Update Makefile.private.example to refect project defaults --- Makefile.private.example | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.private.example b/Makefile.private.example index 48f4db1..361c869 100644 --- a/Makefile.private.example +++ b/Makefile.private.example @@ -30,20 +30,20 @@ AUTO_INSTALL := false # conda create a virtual environment via '$(CONDA_TOOL) env create -f environment.yml' # # This overrides the value found in 'Makefile.variables' -DEFAULT_INSTALL_ENV := uv +DEFAULT_INSTALL_ENV := conda # The default build tool to use. The choices are as follows: [uv, poetry] # This value should also reflect the choice above - DO NOT choose 'poetry' or 'conda' for # DEFAULT_INSTALL_ENV and then use 'uv' as the build tool # # This is the project's default. -DEFAULT_BUILD_TOOL := uv +DEFAULT_BUILD_TOOL := poetry # This variable is to enable the '-y' flag when newer version of conda is available. # The default Mila conda module does not allow this flag; leave blanks or commented out # CONDA_YES_OPTION := -y # If you use a different Conda tool, say `mamba`, or if you use a different alias -# CONDA_TOOL := +CONDA_TOOL := mamba DOCKER_COMPOSE := docker compose