diff --git a/.editorconfig b/.editorconfig index ac98278..1a83fe3 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,29 +1,24 @@ -# EditorConfig is awesome: https://EditorConfig.org +# https://EditorConfig.org -# Top-most EditorConfig file root = true -# Global settings (applicable to all files unless overridden) [*] -charset = utf-8 # Default character encoding -end_of_line = lf # Use LF for line endings (Unix-style) -indent_style = space # Use spaces for indentation -indent_size = 4 # Default indentation size -insert_final_newline = true # Make sure files end with a newline -trim_trailing_whitespace = true # Remove trailing whitespace +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true -[*.py] +[*.{py,pyi}] max_line_length = 100 -# Markdown files [*.md] -max_line_length = 120 +max_line_length = 150 trim_trailing_whitespace = false -# Bash scripts [*.sh] indent_size = 2 -# YAML files [*.{yml,yaml}] indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 38f567d..de9ef06 100644 --- a/.gitattributes +++ b/.gitattributes @@ -65,3 +65,4 @@ # Exclude files from language stats (GitHub Linguist) *.ipynb linguist-vendored +Makefile linguist-vendored diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..e68f584 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [ habedi ] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..db16dc5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,25 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: + +1. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Logs** +If applicable, add logs to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3b844d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discussions + url: https://github.com/habedi/template-python-library/discussions + about: Please ask and answer general questions here diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a49800b..5f66595 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,19 +2,21 @@ name: Build and Deploy Docs on: workflow_dispatch: + push: + branches: + - main + tags: + - "v*" permissions: - contents: read - pages: write - id-token: write + contents: write -# Only allow one deployment at a time running concurrency: - group: "pages" - cancel-in-progress: false + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - deploy: + publish-docs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} @@ -28,21 +30,7 @@ jobs: with: python-version: '3.11' - - name: Install Poetry - uses: snok/install-poetry@v1 - with: - virtualenvs-create: true - virtualenvs-in-project: true - - - name: Load cached venv - id: cached-poetry-dependencies - uses: actions/cache@v4 - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }} - - name: Install Dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' run: | make setup make install diff --git a/.github/workflows/lints.yml b/.github/workflows/lints.yml index 36bae0a..12918dd 100644 --- a/.github/workflows/lints.yml +++ b/.github/workflows/lints.yml @@ -2,21 +2,31 @@ name: Run Linter Checks on: workflow_dispatch: + pull_request: + branches: + - main + paths-ignore: + - '**.md' + - 'docs/**' push: - tags: - - 'v*' + branches: + - main permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - build: + lint: runs-on: ubuntu-latest strategy: matrix: # Define the Python versions check against - python-version: [ "3.10", "3.11", "3.12", "3.13" ] + python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - name: Checkout Repository diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d8a83a0..c793c26 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -9,14 +9,15 @@ on: permissions: contents: read -jobs: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true - # Run tests before publishing +jobs: call_tests: uses: ./.github/workflows/tests.yml - # Try to publish if only tests pass - publish_to_pypi: + publish-to-pypi: runs-on: ubuntu-latest needs: call_tests diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5f29f61..358a1eb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,21 +4,29 @@ on: workflow_dispatch: workflow_call: pull_request: + branches: + - main + paths-ignore: + - '**.md' + - 'docs/**' + push: branches: - main - develop + tags: + - "v*" permissions: contents: read jobs: - build: + test: runs-on: ubuntu-latest strategy: matrix: # Define the Python versions to test against - python-version: [ "3.10", "3.11", "3.12", "3.13" ] + python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ] steps: - name: Checkout Repository diff --git a/.gitignore b/.gitignore index fdf870e..42481a6 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,4 @@ site/ # Miscellaneous files and directories to ignore # Add any additional file patterns a directory names that should be ignored down here +.env diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ad9e202..ef5a8f7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,50 @@ +default_stages: [ pre-push ] +fail_fast: false +exclude: '(^external/|^docs/)' + repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: trailing-whitespace + args: [ --markdown-linebreak-ext=md ] - id: end-of-file-fixer + - id: mixed-line-ending + - id: check-merge-conflict + - id: check-added-large-files + - id: detect-private-key - id: check-yaml - id: check-toml - - id: check-added-large-files - - id: check-merge-conflict + - id: check-json + - id: check-docstring-first + - id: pretty-format-json + args: [ --autofix, --no-sort-keys ] + + - repo: local + hooks: + - id: format + name: Format Code + entry: make format + language: system + pass_filenames: false + stages: [ pre-commit ] + + - id: lint + name: Run Linter Checks + entry: make lint + language: system + pass_filenames: false + stages: [ pre-commit ] + + - id: typecheck + name: Run Typechecks + entry: make typecheck + language: system + pass_filenames: false + stages: [ pre-commit ] + + - id: test + name: Run Tests + entry: make test + language: system + pass_filenames: false diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index e0f169f..e19a328 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ -# Code of Conduct +## Code of Conduct We adhere to the [Python Software Foundation Code of Conduct](https://policies.python.org/python.org/code-of-conduct). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eae1e4e..8b9ddad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,25 @@ -# Contribution Guidelines +## Contribution Guidelines Thank you for considering contributing to this project! Contributions are always welcome and appreciated. -## How to Contribute +### How to Contribute Please check the [issue tracker](https://github.com/habedi/template-python-library/issues) to see if there is an issue you would like to work on or if it has already been resolved. -### Reporting Bugs +#### Reporting Bugs 1. Open an issue on the [issue tracker](https://github.com/habedi/template-python-library/issues). 2. Include information such as steps to reproduce the observed behavior and relevant logs or screenshots. -### Suggesting Features +#### Suggesting Features 1. Open an issue on the [issue tracker](https://github.com/habedi/template-python-library/issues). 2. Provide details about the feature, its purpose, and potential implementation ideas. -## Submitting Pull Requests +### Submitting Pull Requests - Make sure all tests pass before submitting a pull request. - Write a clear description of the changes you made and the reasons behind them. @@ -27,36 +27,36 @@ would like to work on or if it has already been resolved. > [!IMPORTANT] > It's assumed that by submitting a pull request, you agree to license your contributions under the project's license. -## Development Workflow +### Development Workflow -### Prerequisites +#### Prerequisites Install GNU Make if it's not already installed on your system. ```shell -# For Debian-based systems like Debian, Ubuntu, etc. +## For Debian-based systems like Debian, Ubuntu, etc. sudo apt-get install make ``` - Use the `make setup` command to install the development dependencies. - Use the `make install` command to install the Python dependencies. -### Code Style +#### Code Style - Use the `make format` command to format the code. -### Running Tests +#### Running Tests - Use the `make test` command to run the tests. -### Running Linter Checks +#### Running Linter Checks - Use the `make lint` command to run the linter checks. -### See Available Commands +#### See Available Commands - Run `make help` to see all available commands for managing different tasks. -## Code of Conduct +### Code of Conduct -We adhere to the [Python Software Foundation Code of Conduct](https://policies.python.org/python.org/code-of-conduct). +We adhere to the project's [Code of Conduct](CODE_OF_CONDUCT.md). diff --git a/LICENSE b/LICENSE index a2559ba..d899227 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Hassan Abedi +Copyright (c) 2026 Hassan Abedi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index ab070da..6dd12a3 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,13 @@ # Generic Makefile for Python projects +# Load environment variables from .env file +ifneq (,$(wildcard ./.env)) + include .env + export $(shell sed 's/=.*//' .env) +else + $(warning .env file not found. Environment variables not loaded.) +endif + # Variables PYTHON ?= python3 PIP ?= pip3 @@ -15,13 +23,13 @@ TMP_DIRS = site .DEFAULT_GOAL := help .PHONY: help -help: ## Show help for all targets - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ - awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' +help: ## Show help messages for all available targets + @grep -E '^[a-zA-Z_-]+:.*## .*$$' Makefile | \ + awk 'BEGIN {FS = ":.*## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' -# Setup & Installation +# Setup and Installation .PHONY: setup -setup: ## Install system dependencies and dependency manager (e.g., Poetry) +setup: ## Install system dependencies and dependency manager (default: Poetry) sudo apt-get update sudo apt-get install -y python3-pip $(PIP) install --upgrade pip @@ -29,9 +37,10 @@ setup: ## Install system dependencies and dependency manager (e.g., Poetry) .PHONY: install install: ## Install Python dependencies - $(DEP_MNGR) install --all-extras --no-interaction + $(DEP_MNGR) install --all-extras --no-interaction # For Poetry + #(DEP_MNGR) sync --all-extras # For uv -# Quality & Testing +# Quality and Testing .PHONY: test test: ## Run tests $(DEP_MNGR) run pytest @@ -48,12 +57,22 @@ format: ## Format code typecheck: ## Typecheck code $(DEP_MNGR) run mypy . +.PHONY: setup-hooks +setup-hooks: ## Install Git hooks (pre-commit and pre-push) + $(DEP_MNGR) run pre-commit install --hook-type pre-commit + $(DEP_MNGR) run pre-commit install --hook-type pre-push + $(DEP_MNGR) run pre-commit install-hooks + +.PHONY: test-hooks +test-hooks: ## Test Git hooks on all files + $(DEP_MNGR) run pre-commit run --all-files + # Documentation .PHONY: docs docs: ## Build documentation $(DEP_MNGR) run mkdocs build -# Build & Publish +# Build and Publish .PHONY: build build: ## Build distributions $(DEP_MNGR) build diff --git a/README.md b/README.md index f0aec2c..a1df963 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,9 @@ [![Code Coverage](https://img.shields.io/codecov/c/github/habedi/template-python-library?style=flat&label=coverage&labelColor=333333&logo=codecov&logoColor=white)](https://codecov.io/gh/habedi/template-python-library) [![Code Quality](https://img.shields.io/codefactor/grade/github/habedi/template-python-library?style=flat&label=code%20quality&labelColor=333333&logo=codefactor&logoColor=white)](https://www.codefactor.io/repository/github/habedi/template-python-library) [![PyPI Version](https://img.shields.io/pypi/v/template-python-library-placeholder.svg?style=flat&label=pypi&labelColor=333333&logo=pypi&logoColor=white&color=3775a9)](https://pypi.org/project/template-python-library-placeholder/) -[![Downloads](https://img.shields.io/pypi/dm/template-python-library-placeholder.svg?style=flat&label=downloads&labelColor=333333&logo=pypi&logoColor=white&color=cc8400)](https://pypi.org/project/template-python-library-placeholder/) [![Python Version](https://img.shields.io/badge/python-%3E=3.10-3776ab?style=flat&labelColor=333333&logo=python&logoColor=white)](https://github.com/habedi/template-python-library) [![Documentation](https://img.shields.io/badge/docs-latest-8ca0d7?style=flat&labelColor=333333&logo=read-the-docs&logoColor=white)](https://github.com/habedi/template-python-library/blob/main/docs) [![License](https://img.shields.io/badge/license-MIT-00acc1?style=flat&labelColor=333333&logo=open-source-initiative&logoColor=white)](https://github.com/habedi/template-python-library/blob/main/LICENSE) -[![Managed with Poetry](https://img.shields.io/badge/managed%20with-Poetry-60A5FA?style=flat&logo=poetry&labelColor=333333&logoColor=white)](https://python-poetry.org/) -[![Managed with uv](https://img.shields.io/badge/managed%20with-uv-000000?style=flat&logo=uv&labelColor=333333&logoColor=white)](https://astral.sh/uv) -[![Makefile](https://img.shields.io/badge/managed%20with-Makefile-000000?style=flat&logo=gnu&labelColor=333333&logoColor=white)](https://www.gnu.org/software/make/) --- diff --git a/env.example b/env.example new file mode 100644 index 0000000..9b97295 --- /dev/null +++ b/env.example @@ -0,0 +1 @@ +DEBUG_MODE=True diff --git a/library/__init__.py b/library/__init__.py index 2d3023f..8b73560 100644 --- a/library/__init__.py +++ b/library/__init__.py @@ -1,12 +1,13 @@ -import importlib import logging +from importlib.metadata import PackageNotFoundError, version from package import DummyClass _logger = logging.getLogger(__name__) + try: - __version__ = importlib.metadata.version("template-python-library") -except importlib.metadata.PackageNotFoundError: + __version__ = version("template-python-library") +except PackageNotFoundError: __version__ = "0.0.0-unknown" _logger.warning( "Could not determine package version using importlib.metadata. " diff --git a/pyproject.toml b/pyproject.toml index 5e30bef..b6238cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "template-python-library" -version = "0.1.0a1" +version = "0.1.0-alpha.1" description = "A template for developing Python libraries" readme = "README.md" license = { text = "MIT" } @@ -10,37 +10,46 @@ authors = [ maintainers = [ { name = "Hassan Abedi", email = "hassan.abedi.t@gmail.com" } ] -keywords = ["template", "python", "library"] +keywords = ["template", "python", "library", "package"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", + "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Software Development :: Libraries", - "Topic :: Software Development :: Libraries :: Python Modules" + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Artificial Intelligence" ] requires-python = ">=3.10,<4.0" -dependencies = [] +dependencies = [ + "python-dotenv (>=1.1.0,<2.0.0)" +] [project.optional-dependencies] dev = [ - "pytest>=8.0.1", - "pytest-cov>=6.0.0", - "pytest-mock>=3.14.0", - "pytest-asyncio (>=0.26.0,<0.27.0)", - "mypy>=1.11.1", - "ruff>=0.9.3", + "pytest (>=8.0.1,<10.0.0)", + "pytest-cov (>=6.0.0,<8.0.0)", + "pytest-mock (>=3.14.0,<4.0.0)", + "pytest-asyncio (>=1.1.0,<2.0.0)", + "mypy (>=1.11.1,<2.0.0)", + "ruff (>=0.9.3,<1.0.0)", "pre-commit (>=4.2.0,<5.0.0)", - "griffe (>=1.7.3,<2.0.0)", + "icecream (>=2.1.4,<3.0.0)", "mkdocs (>=1.6.1,<2.0.0)", + "mkdocs-material (>=9.6.12,<10.0.0)", "mkdocstrings-python (>=1.16.10,<2.0.0)", - "mkdocs-material (>=9.6.14,<10.0.0)", - "types-requests (>=2.32.0.20250515,<3.0.0.0)" + "pyyaml (>=6.0.1,<7.0.0)", + "rundoc (>=0.2.3,<0.3.0)", + "hypothesis (>=6.150.2,<7.0.0)", + "griffe (>=1.7.3,<2.0.0)", ] [project.urls] @@ -52,8 +61,8 @@ include = ["README.md"] packages = [{ include = "library" }] [build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +requires = ["hatchling>=1.20", "build>=1.0"] +build-backend = "hatchling.build" [tool.pytest.ini_options] pythonpath = ["library"] @@ -99,8 +108,7 @@ exclude = [ ".bzr", ".direnv", ".eggs", ".git", ".git-rewrite", ".hg", ".mypy_cache", ".nox", ".pants.d", ".pytype", ".ruff_cache", ".svn", ".tox", ".venv", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", - "venv", - "tests" + "venv", "tests" ] line-length = 100 indent-width = 4