diff --git a/.cirrus.yml b/.cirrus.yml index cbd26fdc3..dbd648868 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 d79427c1d..0861ce59e 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 8ba31962b..63df0509a 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 5f1de75e0..47a5a07bb 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 aa7981fb1..de2363d3a 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 52f24a36a..a49f9664a 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 1d011ed7f..7ccd3128a 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 20a84ee98..ba5c39d43 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 f49c262ea..0603b4b96 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 9a9ff3f7d..581bd2391 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 cb0059d95..6edcda7b6 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 78c025dea..c0ee4b55c 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 bb655d2d3..495868441 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 349424673..d1fe60f1e 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 e402bb682..8427e07fd 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 64e215481..3dc9a0b32 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 496240e1c..4886d0ccd 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 51a6134d0..c328b18e3 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 e919e760a..56a6d1f58 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 64e215481..3dc9a0b32 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