diff --git a/cookiecutter.json b/cookiecutter.json index 349add2..1e5f69f 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -9,6 +9,10 @@ "Github", "None" ], + "linting_base": [ + "stable", + "ruff" + ], "jupytext": [ "No", "Yes" diff --git a/hooks/post_gen_project.py b/hooks/post_gen_project.py index 37a1eda..ac85573 100644 --- a/hooks/post_gen_project.py +++ b/hooks/post_gen_project.py @@ -29,6 +29,10 @@ REMOVE_PATHS.extend(["notebooks/example.py"]) {% endif %} +{% if cookiecutter.linting_base == "ruff" %} +REMOVE_PATHS.extend([".flake8"]) +{% endif %} + print("Cleaning files... 🌀") for path in REMOVE_PATHS: path = Path(path) diff --git a/{{ cookiecutter.repo_name }}/.pre-commit-config.yaml b/{{ cookiecutter.repo_name }}/.pre-commit-config.yaml index 5cefa17..5e508e3 100644 --- a/{{ cookiecutter.repo_name }}/.pre-commit-config.yaml +++ b/{{ cookiecutter.repo_name }}/.pre-commit-config.yaml @@ -12,17 +12,32 @@ repos: - id: check-json - id: check-yaml + {%- if cookiecutter.linting_base == "ruff" %} + + # Checks Python source files for errors, sorts imports alphabetically and cleans unused imports. + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: v0.1.5 + hooks: + - id: ruff + types_or: [ python, pyi, {%- if cookiecutter.jupytext == "No" %}jupyter{%- endif -%} ] + exclude: (/test_|tests/|docs/|notebooks/) + - id: ruff-format + types_or: [ python, pyi, {%- if cookiecutter.jupytext == "No" %}jupyter{%- endif -%} ] + exclude: (docs/) + {%- endif -%} + + {%- if cookiecutter.linting_base == "stable" %} # PEP 8 compliant opinionated formatter. - repo: https://github.com/psf/black rev: 23.10.1 hooks: - id: black - exclude: (docs/|notebooks/){% if cookiecutter.jupytext == "No" %} + exclude: (docs/|notebooks/){% endif %}{% if cookiecutter.jupytext == "No" and cookiecutter.linting_base == "stable" %} - id: black-jupyter files: \.ipynb$ {%- endif -%} - {% if cookiecutter.jupytext == "Yes" %} + {%- if cookiecutter.jupytext == "Yes" %} # Save .ipynb to .py:percent format - repo: https://github.com/mwouts/jupytext @@ -35,14 +50,6 @@ repos: - black==23.10.1 {%- endif %} - # Cleaning unused imports. - - repo: https://github.com/hadialqattan/pycln - rev: v2.3.0 - hooks: - - id: pycln - args: ["-a"] - exclude: (docs/|notebooks/) - # Modernizes python code and upgrade syntax for newer versions of the language - repo: https://github.com/asottile/pyupgrade rev: v3.15.0 @@ -50,17 +57,14 @@ repos: - id: pyupgrade args: [--py38-plus] - # Used to have proper type annotations for library code. - - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.6.1 + {%- if cookiecutter.linting_base == "stable" %} + # Cleaning unused imports. + - repo: https://github.com/hadialqattan/pycln + rev: v2.3.0 hooks: - - id: mypy - args: [] - # You can add additional plugins for mypy below - # such as types-python-dateutil - additional_dependencies: [] - exclude: (/test_|setup.py|/tests/|docs/) - + - id: pycln + args: ["-a"] + exclude: (docs/|notebooks/) # Sort imports alphabetically, and automatically separated into sections and by type. - repo: https://github.com/timothycrosley/isort rev: 5.12.0 @@ -79,23 +83,31 @@ repos: language: python types: [python] args: [--config, .flake8] - exclude: (docs/) + exclude: (docs/|notebooks/) # Enforces a coding standard, looks for code smells, and can make suggestions about how the code could be refactored. - repo: https://github.com/pycqa/pylint rev: v3.0.1 hooks: - id: pylint - exclude: (/test_|tests/|docs/) - # # You can add additional plugins for pylint here, - # here is an example for pydantic, remember to enable it in pyproject.toml - # additional_dependencies: - # - 'pylint_pydantic' - # args: - # # pylint can have issue with python libraries based on C - # # if it fails to find some objects likely you need to add them - # # here: - # ["--extension-pkg-whitelist=pydantic"] + exclude: (/test_|tests/|docs/|notebooks/) + additional_dependencies: + - 'pylint_pydantic' + args: + # pylint can have issue with python libraries based on C + # if it fails to find some objects likely you need to add them + # here: + ["--extension-pkg-whitelist=pydantic"] + {%- endif -%} + + # Used to have proper type annotations for library code. + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.6.1 + hooks: + - id: mypy + args: [] + additional_dependencies: [] + exclude: (/test_|setup.py|/tests/|docs/|notebooks/) # Finds common security issues in Python code. - repo: https://github.com/PyCQA/bandit diff --git a/{{ cookiecutter.repo_name }}/pyproject.toml b/{{ cookiecutter.repo_name }}/pyproject.toml index 10da5a8..28a9b2a 100644 --- a/{{ cookiecutter.repo_name }}/pyproject.toml +++ b/{{ cookiecutter.repo_name }}/pyproject.toml @@ -5,6 +5,50 @@ requires = [ ] build-backend = "setuptools.build_meta" +[tool.pytest] +norecursedirs=[ + '.git', + '.tox', + '.env', + 'dist', + 'build', + 'migrations', + 'docker', + 'config', + 'notebooks', + 'research', +] +python_files = ['test_*.py'] +addopts = [ + '-ra', + '--showlocals', + '--strict-markers', + '--ignore=docs/conf.py', + '--ignore=setup.py', + '--ignore=ci', + '--ignore=.eggs', + '--doctest-modules', + '--doctest-glob=\*.rst', + '--tb=short', +] + +testpaths = ['tests'] + +[tool.mypy] +warn_unused_configs = true +ignore_missing_imports = true +warn_unused_ignores = false +show_error_codes = true +check_untyped_defs = true +no_implicit_optional = true +mypy_path=['src'] + +[[tool.mypy.overrides]] +module = "{{ cookiecutter.__package_name }}.*" +ignore_missing_imports = false +disallow_untyped_defs = true + +{% if cookiecutter.linting_base == "stable" -%} [tool.isort] multi_line_output=3 line_length=120 @@ -52,55 +96,12 @@ skip_gitignore=true [tool.black] line_length=120 -[tool.pytest] -norecursedirs=[ - '.git', - '.tox', - '.env', - 'dist', - 'build', - 'migrations', - 'docker', - 'config', - 'notebooks', - 'research', -] -python_files = ['test_*.py'] -addopts = [ - '-ra', - '--showlocals', - '--strict-markers', - '--ignore=docs/conf.py', - '--ignore=setup.py', - '--ignore=ci', - '--ignore=.eggs', - '--doctest-modules', - '--doctest-glob=\*.rst', - '--tb=short', -] - -testpaths = ['tests'] - -[tool.mypy] -warn_unused_configs = true -ignore_missing_imports = true -warn_unused_ignores = false -show_error_codes = true -check_untyped_defs = true -no_implicit_optional = true -mypy_path=['src'] - -[[tool.mypy.overrides]] -module = "{{ cookiecutter.__package_name }}.*" -ignore_missing_imports = false -disallow_untyped_defs = true - [tool.pylint.basic] good-names="i,j,x,y,z,x1,y1,z1,x2,y2,z2,cv,df,dx,dy,dz,w,h,c,b,g,qa,q,a" max-args=8 [tool.pylint.main] -load-plugins=["pylint.extensions.docparams"] +load-plugins=["pylint.extensions.docparams", "pylint_pydantic"] [tool.pylint.messages_control] disable=[ @@ -137,9 +138,55 @@ max-locals=20 [tool.pylint.similarities] min-similarity-lines=10 +{%- endif %} +{% if cookiecutter.linting_base == "ruff" -%} +[tool.ruff] +line-length=120 + +select = [ + # Pyflakes + "F", + # Pycodestyle + "E", "W", + # Isort + "I001", "I002", + # Pydocstyle + # "D", + # Pylint + "PL", + # flake8-builtins + "A", + # flake8-bugbear + "B", + # flake8-print + "T20", + # flake8-simplify + "SIM", + # flake8-comprehensions + "C4" +] + +ignore = [ + # line too long - is to be checked by black + "E501", + # Missing module docstring + "D104", + # Disables imperative mood in docstrings + "D401", + # Missing docstring in __init__ + "D107", + # allow print() + "T201", +] +fix = true +fixable = ["I001"] + +[tool.ruff.pydocstyle] +convention = "google" +{%- endif %} [tool.bandit] -exclude_dirs = ["venv",] +exclude_dirs = ["venv"] # B101 disables errors for asserts in the code # remember to not use asserts for security and control flows skips = ["B101"] \ No newline at end of file