diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..69dcd2b --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,11 @@ +name: Lint +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + - run: pip install -r requirements/common.txt + - run: ruff check --output-format=github . diff --git a/.gitignore b/.gitignore index 094e0c2..430a47c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ __pycache__/ *.py[cod] *$py.class +.ruff_cache/ # Distribution / packaging .Python diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 9119374..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,49 +0,0 @@ -default_stages: [commit] -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 - hooks: - - id: check-executables-have-shebangs - stages: [push] - - id: check-merge-conflict - - id: check-shebang-scripts-are-executable - stages: [push] - - id: check-toml - stages: [push] - exclude: "{{ cookiecutter.project_slug }}/pyproject.toml" - - id: check-yaml - stages: [push] - exclude: "{{ cookiecutter.project_slug }}/.pre-commit-config.yaml" - - id: end-of-file-fixer - stages: [push] - - id: trailing-whitespace - stages: [push] -- repo: local - hooks: - - id: black - name: Running black from local poetry env - entry: poetry run black . - # Black does not work with language as python - language: system - types: - - python - - id: flake8 - name: Running flake8 from local poetry env - entry: poetry run flake8 . - language: system - pass_filenames: false - files: ".*.py" - exclude: "{{ cookiecutter.project_slug }}" - - id: isort - name: Running isort from local poetry env - entry: poetry run isort . - language: system - files: ".*.py" - exclude: "{{ cookiecutter.project_slug }}" - - id: lizard - name: Running lizard from local poetry env - entry: poetry run lizard - # Max 7 arguments allowed, show only warnings, sort by CCN, exclude .venv - args: ["--CCN", "8", "-a", "7", "-w", "-s", "cyclomatic_complexity", "-x", ".\\.venv\\*"] - language: system - files: ".*.py" diff --git a/README.md b/README.md index f5b1f8b..157aa01 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,24 @@ # Cookiecutter Python Package -A [Cookiecutter](https://github.com/cookiecutter/cookiecutter) template for a Python package with Poetry as the dependency manager. +A [Cookiecutter](https://github.com/cookiecutter/cookiecutter) blank template for a project. **NOTE:** Only Python 3.8+ is supported. --- ## Features -- Hooks: Pre-commit -- Formatters and Linters: Black, Flake8, Flake8-bugbear, Isort, and Lizard +- Package manager: pip +- Formatters and Linters: Ruff - Testing Frameworks (Optional): Pytest, Coverage, and CovDefaults ## Usage -- Since this template uses Poetry as the dependancy manager, install poetry from `https://python-poetry.org/docs/#installation` - -- Install the `cookiecutter` library. - - ```python - pip install cookiecutter - ``` - OR - ```python - python -m pip install cookiecutter - ``` - -- Run the command: - ```python - cookiecutter https://github.com/gurashish1singh/cookiecutter-python.git - ``` - OR - ```python - python -m cookiecutter https://github.com/gurashish1singh/cookiecutter-python.git - ``` +- bash setup.sh + - This template uses post-project generation hooks to: - Initialize a git repository (with default branch as main), IF the working directory is not already a git repository. **NOTE**: You will have to create a repositry on remote if it doesn't already exist before running the cookiecutter command. - - Create a Poetry virtualenv - - Install all dependencies - - Install the pre-commit and pre-push hooks + - Create a python virtual environment and activate it + - Install ruff + - Include an initial lint github workflow diff --git a/cookiecutter.json b/cookiecutter.json index d5f3787..74bf396 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -5,7 +5,7 @@ "project_name": "Boilerplate Template", "github_repo_name": "{{ cookiecutter.project_name.lower().replace(' ', '-') }}", "project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '_').replace('-', '_') }}", - "project_short_description": "Minimal python cookiecutter template with Poetry as the dependency manager and Black, Isort, Flake8, Flake8-bugbear as the linters.", + "project_short_description": "Minimal python cookiecutter template with pip as the package manager and Ruff as the linting tool.", "version": "1.0.0", - "pytest": ["y", "n"] + "pytest": ["n", "y"] } diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index b24304e..6962c5c 100755 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -1,13 +1,25 @@ -#!/usr/bin/env python from __future__ import annotations +import os +import pathlib import shlex import subprocess import sys +import venv from pathlib import Path ERROR_MSG = "Error occured while running command" PRETTY_LINES = "*" * 80 +PROJECT_NAME = "{{ cookiecutter.project_slug }}" +# TODO: Can allow user to pass it in through cookiecutter.json +VENV_NAME = ".venv" +VIRTUAL_ENV = "VIRTUAL_ENV" + +SUBPROCESS_PARAMS = { + "stdout": subprocess.PIPE, + "stderr": subprocess.PIPE, + "check": True, +} def main() -> int: @@ -19,7 +31,12 @@ def main() -> int: if return_code_one == 0: return_code_two = setup_environment() - return 0 or return_code_one or return_code_two + + if return_code_two == 0: + return_code_three = _rename_pyproject_toml_file() + print(f"New project {PROJECT_NAME!r} is setup.") + + return 0 or return_code_one or return_code_two or return_code_three def initialize_git() -> int: @@ -30,14 +47,14 @@ def initialize_git() -> int: ), "init_git": ( shlex.split("git init"), - "Initializing an empty git repository locally. You will have to create a repo " + "Initializing an empty git repository locally. You will have to create a repository " "on remote.\n", ), } for cmds, message in COMMANDS_AND_MESSAGE.values(): print(message) try: - subprocess.run(cmds, check=True) + subprocess.run(cmds, **SUBPROCESS_PARAMS) except subprocess.CalledProcessError as e: print(ERROR_MSG, e) return e.returncode @@ -46,26 +63,87 @@ def initialize_git() -> int: def setup_environment() -> int: + return_code = 0 + try: + # Always create a new environment in the project dir + python_venv_path = _create_new_environment() + system_type, python_executable_path, python_activate_script_path = _get_python_paths(venv_path=python_venv_path) + _activate_environment(system_type, python_activate_script_path) + except Exception: + return_code = -1 + return_code = _install_requirements(python_executable_path) + return 0 or return_code - COMMANDS_AND_MESSAGE = { - "install_poetry": ( - shlex.split("poetry install"), - f"\n{PRETTY_LINES}\nInstalling poetry virtual environment", - ), - "install_pre_commit": ( - shlex.split( - "poetry run pre-commit install --hook-type pre-commit --hook-type pre-push" - ), - f"\n{PRETTY_LINES}\nInstalling pre-commit hooks", - ), - } - for cmds, message in COMMANDS_AND_MESSAGE.values(): - print(message) - try: - subprocess.run(cmds, check=True) - except subprocess.CalledProcessError as e: - print(ERROR_MSG, e) - return e.returncode + +def _create_new_environment() -> str: + parent_dir = pathlib.Path(os.getcwd()).parent.resolve() + project_name = PROJECT_NAME.strip() + python_venv_path = str(parent_dir / project_name / VENV_NAME) + + print(PRETTY_LINES) + print(f"Attempting to create a new virtual env at {python_venv_path}") + try: + venv.create(env_dir=python_venv_path, with_pip=True) + except Exception: + print("An unexpected error has occured") + raise + + print(f"Successfully created virtualenv at: {python_venv_path!r}") + return python_venv_path + + +def _get_python_paths(venv_path: str) -> tuple[str, str, str]: + sys_type = sys.platform + if sys_type == "win32": + python_executable_path = pathlib.Path(venv_path, "Scripts", "python.exe") + activate_script_path = pathlib.Path(venv_path, "Scripts", "activate") + elif sys_type in ("darwin", "linux", "linux2"): + python_executable_path = pathlib.Path(venv_path, "bin", "python") + activate_script_path = pathlib.Path(venv_path, "bin", "activate") + else: + raise OSError(f"Unsupported platform: {sys_type!r}") + return sys_type, str(python_executable_path), str(activate_script_path) + + +def _activate_environment(system_type: str, activate_script_path: str) -> None: + if system_type == "win32": + subprocess.call(["cmd.exe", "c", activate_script_path]) + elif system_type in ("darwin", "linux", "linux2"): + subprocess.call(f"source {activate_script_path}", shell=True) + + print("Successfully activated virtualenv.") + print(f"\n{PRETTY_LINES}") + + +def _install_requirements(python_executable_path: str) -> int: + print("Installing all dependencies from the requirements.txt file.\n") + try: + subprocess.run( + [python_executable_path, "-m", "pip", "install", "-r", "requirements.txt"], + **SUBPROCESS_PARAMS, + ) + if "{{ cookiecutter.project_slug }}": + subprocess.run( + [python_executable_path, "-m", "pip", "install", "-r", "dev-requirements.txt"], + **SUBPROCESS_PARAMS, + ) + except subprocess.CalledProcessError as e: + print(ERROR_MSG, e) + return e.returncode + + print(PRETTY_LINES) + return 0 + + +def _rename_pyproject_toml_file() -> int: + try: + os.rename( + "template-pyproject.toml", + "pyproject.toml", + ) + except subprocess.CalledProcessError as e: + print(ERROR_MSG, e) + return e.returncode return 0 diff --git a/poetry.lock b/poetry.lock deleted file mode 100644 index 80f9b29..0000000 --- a/poetry.lock +++ /dev/null @@ -1,425 +0,0 @@ -[[package]] -name = "attrs" -version = "22.1.0" -description = "Classes Without Boilerplate" -category = "dev" -optional = false -python-versions = ">=3.5" - -[package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] - -[[package]] -name = "black" -version = "22.10.0" -description = "The uncompromising code formatter." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "cfgv" -version = "3.3.1" -description = "Validate configuration and produce human readable error messages." -category = "dev" -optional = false -python-versions = ">=3.6.1" - -[[package]] -name = "click" -version = "8.1.3" -description = "Composable command line interface toolkit" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -category = "dev" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" - -[[package]] -name = "distlib" -version = "0.3.6" -description = "Distribution utilities" -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "filelock" -version = "3.8.0" -description = "A platform independent file lock." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2022.6.21)", "sphinx (>=5.1.1)", "sphinx-autodoc-typehints (>=1.19.1)"] -testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pytest-cov (>=3)", "pytest-timeout (>=2.1)"] - -[[package]] -name = "flake8" -version = "5.0.4" -description = "the modular source code checker: pep8 pyflakes and co" -category = "dev" -optional = false -python-versions = ">=3.6.1" - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.9.0,<2.10.0" -pyflakes = ">=2.5.0,<2.6.0" - -[[package]] -name = "flake8-bugbear" -version = "22.10.27" -description = "A plugin for flake8 finding likely bugs and design problems in your program. Contains warnings that don't belong in pyflakes and pycodestyle." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -attrs = ">=19.2.0" -flake8 = ">=3.0.0" - -[package.extras] -dev = ["coverage", "hypothesis", "hypothesmith (>=0.2)", "pre-commit", "tox"] - -[[package]] -name = "identify" -version = "2.5.8" -description = "File identification library for Python" -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -license = ["ukkonen"] - -[[package]] -name = "isort" -version = "5.10.1" -description = "A Python utility / library to sort Python imports." -category = "dev" -optional = false -python-versions = ">=3.6.1,<4.0" - -[package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -plugins = ["setuptools"] -requirements_deprecated_finder = ["pip-api", "pipreqs"] - -[[package]] -name = "lizard" -version = "1.17.10" -description = "A code analyzer without caring the C/C++ header files. It works with Java, C/C++, JavaScript, Python, Ruby, Swift, Objective C. Metrics includes cyclomatic complexity number etc." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "mypy-extensions" -version = "0.4.3" -description = "Experimental type system extensions for programs checked with the mypy typechecker." -category = "dev" -optional = false -python-versions = "*" - -[[package]] -name = "nodeenv" -version = "1.7.0" -description = "Node.js virtual environment builder" -category = "dev" -optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" - -[[package]] -name = "pathspec" -version = "0.10.1" -description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "platformdirs" -version = "2.5.2" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] - -[[package]] -name = "pre-commit" -version = "2.20.0" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -toml = "*" -virtualenv = ">=20.0.8" - -[[package]] -name = "pycodestyle" -version = "2.9.1" -description = "Python style guide checker" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "pyflakes" -version = "2.5.0" -description = "passive checker of Python programs" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "pyyaml" -version = "6.0" -description = "YAML parser and emitter for Python" -category = "dev" -optional = false -python-versions = ">=3.6" - -[[package]] -name = "toml" -version = "0.10.2" -description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" -optional = false -python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" - -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "typing-extensions" -version = "4.4.0" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" -optional = false -python-versions = ">=3.7" - -[[package]] -name = "virtualenv" -version = "20.16.6" -description = "Virtual Python Environment builder" -category = "dev" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<3" - -[package.extras] -docs = ["proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-argparse (>=0.3.2)", "sphinx-rtd-theme (>=1)", "towncrier (>=22.8)"] -testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=21.3)", "pytest (>=7.0.1)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.6.1)", "pytest-randomly (>=3.10.3)", "pytest-timeout (>=2.1)"] - -[metadata] -lock-version = "1.1" -python-versions = "^3.8" -content-hash = "61a88eda11b838d253a8851cb309bfd0e75fb0a7beafbedc2ba3e74504a63f70" - -[metadata.files] -attrs = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] -black = [ - {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"}, - {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"}, - {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"}, - {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"}, - {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"}, - {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"}, - {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"}, - {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"}, - {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"}, - {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"}, - {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"}, - {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"}, - {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"}, - {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"}, - {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"}, - {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"}, - {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"}, - {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"}, - {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"}, - {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"}, - {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"}, -] -cfgv = [ - {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, - {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, -] -click = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, -] -colorama = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] -distlib = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, -] -filelock = [ - {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"}, - {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"}, -] -flake8 = [ - {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, - {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, -] -flake8-bugbear = [ - {file = "flake8-bugbear-22.10.27.tar.gz", hash = "sha256:a6708608965c9e0de5fff13904fed82e0ba21ac929fe4896459226a797e11cd5"}, - {file = "flake8_bugbear-22.10.27-py3-none-any.whl", hash = "sha256:6ad0ab754507319060695e2f2be80e6d8977cfcea082293089a9226276bd825d"}, -] -identify = [ - {file = "identify-2.5.8-py2.py3-none-any.whl", hash = "sha256:48b7925fe122720088aeb7a6c34f17b27e706b72c61070f27fe3789094233440"}, - {file = "identify-2.5.8.tar.gz", hash = "sha256:7a214a10313b9489a0d61467db2856ae8d0b8306fc923e03a9effa53d8aedc58"}, -] -isort = [ - {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, - {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, -] -lizard = [ - {file = "lizard-1.17.10-py2.py3-none-any.whl", hash = "sha256:686748cc003de54d3e37f84b6cbbdd975be41a2094f0a779cb7fef65e70fc53e"}, - {file = "lizard-1.17.10.tar.gz", hash = "sha256:62d78acd64724be28b5f4aa27a630dfa4b4afbd1596d1f25d5ad1c1a3a075adc"}, -] -mccabe = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] -mypy-extensions = [ - {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, - {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, -] -nodeenv = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, -] -pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, -] -platformdirs = [ - {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, - {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, -] -pre-commit = [ - {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"}, - {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"}, -] -pycodestyle = [ - {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, - {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, -] -pyflakes = [ - {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, - {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, -] -pyyaml = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, -] -toml = [ - {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, - {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, -] -tomli = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] -typing-extensions = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, -] -virtualenv = [ - {file = "virtualenv-20.16.6-py3-none-any.whl", hash = "sha256:186ca84254abcbde98180fd17092f9628c5fe742273c02724972a1d8a2035108"}, - {file = "virtualenv-20.16.6.tar.gz", hash = "sha256:530b850b523c6449406dfba859d6345e48ef19b8439606c5d74d7d3c9e14d76e"}, -] diff --git a/pyproject.toml b/pyproject.toml index caad638..f0bbb16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,25 +1,3 @@ -[tool.poetry] -name = "cookiecutter-python" -version = "0.1.0" -description = "A Python Cookiecutter template with Poetry as a dependency manager" -authors = ["Gurashish Singh "] -readme = "README.md" -license = "MIT" - -[tool.poetry.dependencies] -python = "^3.8" - -[tool.poetry.dev-dependencies] -flake8 = "^5" -isort = "^5.5" -black = "^22.9" -pre-commit = "^2.20" -flake8-bugbear = "^22" -lizard = "^1.17" - -[tool.black] -line-length = 100 - [tool.isort] add_imports = ["from __future__ import annotations"] force_grid_wrap = 2 @@ -27,6 +5,32 @@ multi_line_output = 3 include_trailing_comma = true quiet = true -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +[tool.ruff] +line-length = 120 + +# Exclude TOML file from ruff check as it contains jinja syntax that fails toml parser +exclude = [ + "*/pyproject.toml", + "*/.venv" +] + +[tool.ruff.lint] +# Copied from docs +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default +# I -> isort. +# flake8-bugbear (`B`) +select = ["E4", "E7", "E9", "F", "I", "B"] +# BOO8 - https://docs.astral.sh/ruff/rules/function-call-in-default-argument/ (mostly ignoring for pydantic) +ignore = ["B008"] + +# Avoid trying to fix flake8-bugbear (`B`) violations. +unfixable = ["B"] + +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" diff --git a/requirements/common.txt b/requirements/common.txt new file mode 100644 index 0000000..ddedb93 --- /dev/null +++ b/requirements/common.txt @@ -0,0 +1 @@ +ruff==0.12.0 diff --git a/requirements/requirements.txt b/requirements/requirements.txt new file mode 100644 index 0000000..1428aab --- /dev/null +++ b/requirements/requirements.txt @@ -0,0 +1,23 @@ +-r common.txt +arrow==1.3.0 +binaryornot==0.4.4 +certifi==2025.6.15 +chardet==5.2.0 +charset-normalizer==3.4.2 +click==8.2.1 +cookiecutter==2.6.0 +idna==3.10 +Jinja2==3.1.6 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +mdurl==0.1.2 +Pygments==2.19.1 +python-dateutil==2.9.0.post0 +python-slugify==8.0.4 +PyYAML==6.0.2 +requests==2.32.4 +rich==14.0.0 +six==1.17.0 +text-unidecode==1.3 +types-python-dateutil==2.9.0.20250516 +urllib3==2.5.0 diff --git a/setup/__init__.py b/setup/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/setup/setup.py b/setup/setup.py new file mode 100644 index 0000000..9c9a92d --- /dev/null +++ b/setup/setup.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +import os +import pathlib +import subprocess +import sys +import venv + +ERROR_MSG = "Error occured while running command" +PRETTY_LINES = "*" * 80 +VENV_NAME = ".venv" +VIRTUAL_ENV = "VIRTUAL_ENV" + +SUBPROCESS_PARAMS = { + "stdout": subprocess.PIPE, + "stderr": subprocess.PIPE, + "check": True, +} + + +def main() -> int: + return_code_one = setup_environment() + return 0 or return_code_one + + +def setup_environment() -> int: + return_code = 0 + try: + # Always create a new environment in the project dir + python_venv_path = _create_new_environment() + system_type, python_executable_path, python_activate_script_path = _get_python_paths(venv_path=python_venv_path) + _activate_environment(system_type, python_activate_script_path) + except Exception: + return_code = -1 + return_code = _install_requirements(python_executable_path) + return 0 or return_code + + +def _create_new_environment() -> str: + parent_dir = pathlib.Path(os.getcwd()) + python_venv_path = str(parent_dir / VENV_NAME) + + print(PRETTY_LINES) + print(f"Attempting to create a new virtual env at {python_venv_path}") + try: + venv.create(env_dir=python_venv_path, with_pip=True) + except Exception: + print("An unexpected error has occured") + raise + + print(f"Successfully created virtualenv at: {python_venv_path!r}") + return python_venv_path + + +def _get_python_paths(venv_path: str) -> tuple[str, str, str]: + sys_type = sys.platform + if sys_type == "win32": + python_executable_path = pathlib.Path(venv_path, "Scripts", "python.exe") + activate_script_path = pathlib.Path(venv_path, "Scripts", "activate") + elif sys_type in ("darwin", "linux", "linux2"): + python_executable_path = pathlib.Path(venv_path, "bin", "python") + activate_script_path = pathlib.Path(venv_path, "bin", "activate") + else: + raise OSError(f"Unsupported platform: {sys_type!r}") + return sys_type, str(python_executable_path), str(activate_script_path) + + +def _activate_environment(system_type: str, activate_script_path: str) -> None: + if system_type == "win32": + subprocess.call(["cmd.exe", "c", activate_script_path]) + elif system_type in ("darwin", "linux", "linux2"): + subprocess.call(f"source {activate_script_path}", shell=True) + + print("Successfully activated virtualenv.") + print(f"\n{PRETTY_LINES}") + + +def _install_requirements(python_executable_path: str) -> int: + print("Installing all dependencies from the requirements.txt file.\n") + try: + subprocess.run( + [python_executable_path, "-m", "pip", "install", "-r", "requirements.txt"], + **SUBPROCESS_PARAMS, + ) + if "{{ cookiecutter.project_slug }}": + subprocess.run( + [python_executable_path, "-m", "pip", "install", "-r", "dev-requirements.txt"], + **SUBPROCESS_PARAMS, + ) + except subprocess.CalledProcessError as e: + print(ERROR_MSG, e) + return e.returncode + + print(PRETTY_LINES) + return 0 + + +if __name__ == "__main__": + main() diff --git a/setup/setup.sh b/setup/setup.sh new file mode 100644 index 0000000..e41d49d --- /dev/null +++ b/setup/setup.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eou pipefail + +python setup/setup.py diff --git a/{{ cookiecutter.project_slug }}/.github/workflows/lint.yaml b/{{ cookiecutter.project_slug }}/.github/workflows/lint.yaml new file mode 100644 index 0000000..0c4fa3b --- /dev/null +++ b/{{ cookiecutter.project_slug }}/.github/workflows/lint.yaml @@ -0,0 +1,11 @@ +name: Lint +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + - run: pip install -r requirements.txt + - run: ruff check --output-format=github . diff --git a/{{ cookiecutter.project_slug }}/.gitignore b/{{ cookiecutter.project_slug }}/.gitignore index 094e0c2..430a47c 100644 --- a/{{ cookiecutter.project_slug }}/.gitignore +++ b/{{ cookiecutter.project_slug }}/.gitignore @@ -2,6 +2,7 @@ __pycache__/ *.py[cod] *$py.class +.ruff_cache/ # Distribution / packaging .Python diff --git a/{{ cookiecutter.project_slug }}/.pre-commit-config.yaml b/{{ cookiecutter.project_slug }}/.pre-commit-config.yaml deleted file mode 100755 index 9edd10e..0000000 --- a/{{ cookiecutter.project_slug }}/.pre-commit-config.yaml +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -default_stages: [commit] -repos: -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 - hooks: - - id: check-executables-have-shebangs - stages: [push] - - id: check-merge-conflict - - id: check-shebang-scripts-are-executable - stages: [push] - - id: check-toml - stages: [push] - - id: check-yaml - stages: [push] - - id: end-of-file-fixer - stages: [push] - - id: trailing-whitespace - stages: [push] -- repo: local - hooks: - - id: black - name: Running black from local poetry env - entry: poetry run black . - # Black does not work with language as python - language: system - types: - - python - - id: flake8 - name: Running flake8 from local poetry env - entry: poetry run flake8 . - language: system - pass_filenames: false - files: ".*.py" - - id: isort - name: Running isort from local poetry env - entry: poetry run isort . - language: system - files: ".*.py" - - id: lizard - name: Running lizard from local poetry env - entry: poetry run lizard - # Max 7 arguments allowed, show only warnings, sort by CCN, exclude .venv - args: ["--CCN", "8", "-a", "7", "-w", "-s", "cyclomatic_complexity", "-x", ".\\.venv\\*"] - language: python diff --git a/{{ cookiecutter.project_slug }}/README.md b/{{ cookiecutter.project_slug }}/README.md index b1a2f6f..11052b2 100644 --- a/{{ cookiecutter.project_slug }}/README.md +++ b/{{ cookiecutter.project_slug }}/README.md @@ -1,7 +1,3 @@ # {{ cookiecutter.project_name }} - -The **pyproject.toml** file contains project dependencies and can be updated to add more dependencies at any stage of the project by running `poetry add `. -Minimum Python version supported is 3.8. - -The **.pre-commit-config.yaml** contains all the formatter and linters that runs before committing and before pushing changes. + diff --git a/{{ cookiecutter.project_slug }}/dev-requirements.txt b/{{ cookiecutter.project_slug }}/dev-requirements.txt new file mode 100644 index 0000000..7cc02ff --- /dev/null +++ b/{{ cookiecutter.project_slug }}/dev-requirements.txt @@ -0,0 +1,6 @@ +-r requirements.txt +{% if cookiecutter.pytest == "y" -%} +pytest>=7.4.4,<8.0 +covdefaults>=2.3.0,<3.0 +coverage>=7.4.4,<8.0 +{%- endif %} diff --git a/{{ cookiecutter.project_slug }}/requirements.txt b/{{ cookiecutter.project_slug }}/requirements.txt new file mode 100644 index 0000000..ddedb93 --- /dev/null +++ b/{{ cookiecutter.project_slug }}/requirements.txt @@ -0,0 +1 @@ +ruff==0.12.0 diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/template-pyproject.toml similarity index 56% rename from {{ cookiecutter.project_slug }}/pyproject.toml rename to {{ cookiecutter.project_slug }}/template-pyproject.toml index 9b5db57..edcbddf 100644 --- a/{{ cookiecutter.project_slug }}/pyproject.toml +++ b/{{ cookiecutter.project_slug }}/template-pyproject.toml @@ -1,31 +1,11 @@ -[tool.poetry] +[project] name = "{{ cookiecutter.project_name }}" version = "{{ cookiecutter.version }}" description = "{{ cookiecutter.project_short_description }}" authors = ["{{ cookiecutter.full_name }} <{{ cookiecutter.email }}>"] readme = "README.md" license = "MIT" - -[tool.poetry.dependencies] -python = "^3.8" -PyYAML = "^6" -python-json-logger = "^2" - -[tool.poetry.dev-dependencies] -flake8 = "^5" -isort = "^5.5" -black = "^22.9" -pre-commit = "^2.20" -flake8-bugbear = "^22" -lizard = "^1.17" -{% if cookiecutter.pytest == "y" -%} -pytest = "^7.1" -covdefaults = "^2" -coverage = "^6.5" -{%- endif %} - -[tool.black] -line-length = 100 +requires-python = ">=3.10" [tool.isort] add_imports = ["from __future__ import annotations"] @@ -34,6 +14,30 @@ multi_line_output = 3 include_trailing_comma = true quiet = true +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +# Copied from docs +# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. +# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or +# McCabe complexity (`C901`) by default +# I -> isort. +# flake8-bugbear (`B`) +select = ["E4", "E7", "E9", "F", "I", "B"] +# BOO8 - https://docs.astral.sh/ruff/rules/function-call-in-default-argument/ (mostly ignoring for pydantic) +ignore = ["B008"] + +# Avoid trying to fix flake8-bugbear (`B`) violations. +unfixable = ["B"] + +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + {% if cookiecutter.pytest == "y" -%} [tool.coverage.run] plugins = ["covdefaults"] @@ -61,8 +65,5 @@ exclude_lines = [ "if 0:", "if __name__ == .__main__.:", ] -{%- endif %} -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +{% endif %}