diff --git a/.cirrus.yml b/.cirrus.yml index cbd26fdc31..dbd648868b 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -6,6 +6,8 @@ TEST_TEMPLATE: &TEST_TEMPLATE - python --version # TODO: Fix lints before enabling - echo hatch run lint + - echo hatch run typecheck + - echo hatch run format - hatch run test linux_arm64_task: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d79427c1da..0861ce59ec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -134,3 +134,9 @@ jobs: - name: Lint run: hatch run lint + + - name: Typecheck + run: hatch run typecheck + + - name: Format + run: hatch run format diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8ba31962b0..63df0509a4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,16 +45,8 @@ repos: # files in pact/v3/** and tests/v3/**. exclude: ^(pact|tests)/(?!v3/).*\.py$ args: [--fix, --exit-non-zero-on-fix] - stages: [pre-push] - - - repo: https://github.com/psf/black - rev: 24.1.1 - hooks: - - id: black - # Exclude python files in pact/** and tests/**, except for the - # files in pact/v3/** and tests/v3/**. + - id: ruff-format exclude: ^(pact|tests)/(?!v3/).*\.py$ - stages: [pre-push] - repo: https://github.com/commitizen-tools/commitizen rev: v3.13.0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f1de75e09..47a5a07bb5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -109,11 +109,11 @@ You can also try using the new [github.dev](https://github.dev/pact-foundation/p - **Most important: Look around.** Match the style you see used in the rest of the project. This includes formatting, naming files, naming things in code, naming things in documentation, etc. - "Attractive" -- We do have Black (a formatter) and Ruff (a syntax linter) to catch most stylistic problems. If you are working locally, they should automatically fix some issues during git commits and push. +- We do have Ruff to catch most stylistic problems (both linting and formatting). If you are working locally, they should automatically fix some issues during git commits and push. Don't worry too much about styles in general—the maintainers will help you fix them as they review your code. -To help catch a lot of simple formatting or linting issues, you can run `hatch run lint` to run Black and Ruff. This process can also be automated by installing [`pre-commit`](https://pre-commit.com/) hooks: +To help catch a lot of simple formatting or linting issues, you can run `hatch run lint` to run the linter and `hatch run format` to format your code. This process can also be automated by installing [`pre-commit`](https://pre-commit.com/) hooks: ```sh pre-commit install diff --git a/Makefile b/Makefile index aa7981fb12..de2363d3a7 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,8 @@ example: .PHONY: lint lint: hatch run lint + hatch run format + hatch run typecheck .PHONY: ci diff --git a/examples/tests/test_00_consumer.py b/examples/tests/test_00_consumer.py index 52f24a36a1..a49f9664a8 100644 --- a/examples/tests/test_00_consumer.py +++ b/examples/tests/test_00_consumer.py @@ -21,10 +21,10 @@ import pytest import requests -from pact import Consumer, Format, Like, Provider from yarl import URL from examples.src.consumer import User, UserConsumer +from pact import Consumer, Format, Like, Provider if TYPE_CHECKING: from pathlib import Path diff --git a/examples/tests/test_01_provider_fastapi.py b/examples/tests/test_01_provider_fastapi.py index 1d011ed7f3..7ccd3128aa 100644 --- a/examples/tests/test_01_provider_fastapi.py +++ b/examples/tests/test_01_provider_fastapi.py @@ -30,11 +30,11 @@ import pytest import uvicorn -from pact import Verifier from pydantic import BaseModel from yarl import URL from examples.src.fastapi import app +from pact import Verifier PROVIDER_URL = URL("http://localhost:8080") diff --git a/examples/tests/test_01_provider_flask.py b/examples/tests/test_01_provider_flask.py index 20a84ee989..ba5c39d432 100644 --- a/examples/tests/test_01_provider_flask.py +++ b/examples/tests/test_01_provider_flask.py @@ -30,10 +30,10 @@ import pytest from flask import request -from pact import Verifier from yarl import URL from examples.src.flask import app +from pact import Verifier PROVIDER_URL = URL("http://localhost:8080") diff --git a/examples/tests/test_02_message_consumer.py b/examples/tests/test_02_message_consumer.py index f49c262ea2..0603b4b964 100644 --- a/examples/tests/test_02_message_consumer.py +++ b/examples/tests/test_02_message_consumer.py @@ -35,9 +35,9 @@ from unittest.mock import MagicMock import pytest -from pact import MessageConsumer, MessagePact, Provider from examples.src.message import Handler +from pact import MessageConsumer, MessagePact, Provider if TYPE_CHECKING: from pathlib import Path diff --git a/examples/tests/test_03_message_provider.py b/examples/tests/test_03_message_provider.py index 9a9ff3f7d4..581bd2391c 100644 --- a/examples/tests/test_03_message_provider.py +++ b/examples/tests/test_03_message_provider.py @@ -29,6 +29,7 @@ from typing import TYPE_CHECKING, Dict from flask import Flask + from pact import MessageProvider if TYPE_CHECKING: diff --git a/pact/v3/__init__.py b/pact/v3/__init__.py index cb0059d954..6edcda7b6d 100644 --- a/pact/v3/__init__.py +++ b/pact/v3/__init__.py @@ -20,7 +20,7 @@ considered deprecated, and will be removed in a future release. """ -from .pact import Interaction, Pact +from pact.v3.pact import Interaction, Pact __all__ = [ "Pact", diff --git a/pact/v3/ffi.py b/pact/v3/ffi.py index 78c025deaa..c0ee4b55c9 100644 --- a/pact/v3/ffi.py +++ b/pact/v3/ffi.py @@ -88,7 +88,7 @@ from enum import Enum from typing import TYPE_CHECKING, Any, List -from ._ffi import ffi, lib # type: ignore[import] +from pact.v3._ffi import ffi, lib # type: ignore[import] if TYPE_CHECKING: from pathlib import Path @@ -5146,7 +5146,7 @@ def with_query_parameter_v2( handle, "version", 0, - json.dumps({ "value": ["2", "3"] }) + json.dumps({"value": ["2", "3"]}), ) ``` @@ -5288,7 +5288,7 @@ def with_header_v2( part, "Accept-Version", 0, - json.dumps({ "value": ["2", "3"] }) + json.dumps({"value": ["2", "3"]}), ) ``` diff --git a/pact/v3/pact.py b/pact/v3/pact.py index bb655d2d31..4958684417 100644 --- a/pact/v3/pact.py +++ b/pact/v3/pact.py @@ -144,8 +144,9 @@ def given( ```python ( - pact.upon_receiving("a request") - .given("a user exists", name="id", value="123") + pact.upon_receiving("a request").given( + "a user exists", name="id", value="123" + ) ) ``` @@ -156,11 +157,13 @@ def given( ```python ( - pact.upon_receiving("a request") - .given("a user exists", parameters={ - "id": "123", - "name": "John", - }) + pact.upon_receiving("a request").given( + "a user exists", + parameters={ + "id": "123", + "name": "John", + }, + ) ) ``` @@ -200,8 +203,9 @@ def given( ```python ( - pact.upon_receiving("a request") - .given("a user exists", name="value", value=parameters) + pact.upon_receiving("a request").given( + "a user exists", name="value", value=parameters + ) ) ``` @@ -503,8 +507,7 @@ def with_header( ```python ( - pact.upon_receiving("a request") - .with_header( + pact.upon_receiving("a request").with_header( "Accept-Version", json.dumps({ "value": "1.2.3", @@ -693,8 +696,7 @@ def with_query_parameter(self, name: str, value: str) -> Self: ```python ( - pact.upon_receiving("a request") - .with_query_parameter( + pact.upon_receiving("a request").with_query_parameter( "name", json.dumps({ "value": ["John", "Mary"], @@ -709,8 +711,7 @@ def with_query_parameter(self, name: str, value: str) -> Self: ```python ( - pact.upon_receiving("a request") - .with_query_parameter( + pact.upon_receiving("a request").with_query_parameter( "version", json.dumps({ "value": "1.2.3", diff --git a/pyproject.toml b/pyproject.toml index 3494246734..d1fe60f1e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,12 +76,7 @@ test = [ "pytest-cov ~= 4.0", "testcontainers ~= 3.0", ] -dev = [ - "pact-python[types]", - "pact-python[test]", - "black ==24.1.1", - "ruff ==0.1.14", -] +dev = ["pact-python[types]", "pact-python[test]", "ruff==0.1.14"] ################################################################################ ## Hatch Build Configuration @@ -127,10 +122,14 @@ extra-dependencies = [ ] [tool.hatch.envs.default.scripts] -lint = ["black --check --diff {args:.}", "ruff {args:.}", "mypy {args:.}"] -test = "pytest {args:tests/}" -example = "pytest examples/ {args}" -all = ["lint", "test", "example"] +lint = "ruff check --show-source --show-fixes {args}" +typecheck = "mypy {args:.}" +format = "ruff format --diff {args}" +test = "pytest tests/ {args}" +example = "pytest examples/ {args}" +all = ["format", "lint", "typecheck", "test", "example"] +docs = ["mkdocs serve {args}"] +docs-build = ["mkdocs build {args}"] # Test environment for running unit tests. This automatically tests against all # supported Python versions. @@ -140,11 +139,6 @@ features = ["test"] [[tool.hatch.envs.test.matrix]] python = ["3.8", "3.9", "3.10", "3.11", "3.12"] -[tool.hatch.envs.test.scripts] -test = "pytest {args:tests/}" -example = "pytest examples/ {args}" -all = ["test", "example"] - ################################################################################ ## PyTest Configuration ################################################################################ @@ -186,17 +180,6 @@ exclude_lines = [ [tool.ruff] target-version = "py38" -select = ["ALL"] - -ignore = [ - "D200", # Require single line docstrings to be on one line. - "D203", # Require blank line before class docstring - "D212", # Multi-line docstring summary must start at the first line - "ANN101", # `self` must be typed - "ANN102", # `cls` must be typed - "FIX002", # Forbid TODO in comments - "TD002", # Assign someone to 'TODO' comments -] # TODO: Remove the explicity extend-exclude once astral-sh/ruff#6262 is fixed. # https://github.com/pact-foundation/pact-python/issues/458 @@ -236,19 +219,38 @@ extend-exclude = [ "tests/test_verify_wrapper.py", ] -[tool.ruff.pyupgrade] +[tool.ruff.lint] +select = ["ALL"] + +ignore = [ + "D200", # Require single line docstrings to be on one line. + "D203", # Require blank line before class docstring + "D212", # Multi-line docstring summary must start at the first line + "ANN101", # `self` must be typed + "ANN102", # `cls` must be typed + "FIX002", # Forbid TODO in comments + "TD002", # Assign someone to 'TODO' comments + + # The following are disabled for compatibility with the formatter + "COM812", # enforce trailing commas + "ISC001", # require imports to be sorted +] + +[tool.ruff.lint.pyupgrade] keep-runtime-typing = true -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] convention = "google" -################################################################################ -## Black Configuration -################################################################################ +[tool.ruff.isort] +known-first-party = ["pact"] + +[tool.ruff.flake8-tidy-imports] +ban-relative-imports = "all" -[tool.black] -target-version = ["py38"] -extend-exclude = '^/(pact|tests)/(?!v3).+\.py$' +[tool.ruff.format] +preview = true +docstring-code-format = true ################################################################################ ## Mypy Configuration diff --git a/tests/v3/compatiblity_suite/test_v1_consumer.py b/tests/v3/compatiblity_suite/test_v1_consumer.py index e402bb6820..8427e07fd7 100644 --- a/tests/v3/compatiblity_suite/test_v1_consumer.py +++ b/tests/v3/compatiblity_suite/test_v1_consumer.py @@ -9,11 +9,11 @@ import pytest import requests -from pact.v3 import Pact from pytest_bdd import given, parsers, scenario, then, when from yarl import URL -from .util import ( # type: ignore[import-untyped] +from pact.v3 import Pact +from tests.v3.compatiblity_suite.util import ( FIXTURES_ROOT, InteractionDefinition, string_to_int, diff --git a/tests/v3/test_async_interaction.py b/tests/v3/test_async_interaction.py index 64e2154815..3dc9a0b321 100644 --- a/tests/v3/test_async_interaction.py +++ b/tests/v3/test_async_interaction.py @@ -7,6 +7,7 @@ import re import pytest + from pact.v3 import Pact diff --git a/tests/v3/test_ffi.py b/tests/v3/test_ffi.py index 496240e1c5..4886d0ccde 100644 --- a/tests/v3/test_ffi.py +++ b/tests/v3/test_ffi.py @@ -9,6 +9,7 @@ import re import pytest + from pact.v3 import ffi diff --git a/tests/v3/test_http_interaction.py b/tests/v3/test_http_interaction.py index 51a6134d04..c328b18e37 100644 --- a/tests/v3/test_http_interaction.py +++ b/tests/v3/test_http_interaction.py @@ -10,6 +10,7 @@ import aiohttp import pytest + from pact.v3 import Pact if TYPE_CHECKING: diff --git a/tests/v3/test_pact.py b/tests/v3/test_pact.py index e919e760a4..56a6d1f588 100644 --- a/tests/v3/test_pact.py +++ b/tests/v3/test_pact.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Literal import pytest + from pact.v3 import Pact if TYPE_CHECKING: diff --git a/tests/v3/test_sync_interaction.py b/tests/v3/test_sync_interaction.py index 64e2154815..3dc9a0b321 100644 --- a/tests/v3/test_sync_interaction.py +++ b/tests/v3/test_sync_interaction.py @@ -7,6 +7,7 @@ import re import pytest + from pact.v3 import Pact