Skip to content

Commit

Permalink
chore: Adopt ruff. (#201)
Browse files Browse the repository at this point in the history
* chore: Apply ruff formatting.

* chore: Apply ruff automatic unsafe-fixes.

* chore: Apply non-automatic linting fixes.

* chore: Update CI/deps to use ruff.
  • Loading branch information
DanCardin authored Feb 1, 2024
1 parent 4d08df2 commit 7ef324e
Show file tree
Hide file tree
Showing 36 changed files with 791 additions and 922 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
- name: Install specific pytest-asyncio version
run: pip install 'pytest-asyncio~=${{ matrix.pytest-asyncio-version }}'

- if: ${{ matrix.python-version == '3.9' && matrix.sqlalchemy-version == '1.4.0' }}
- if: ${{ matrix.python-version == '3.9' && matrix.sqlalchemy-version == '2.0.0' }}
run: poetry run make lint

- run: poetry run make test-base
Expand Down
12 changes: 5 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,13 @@ test: test-parallel

## Lint
lint:
flake8 src tests || exit 1
isort --check-only --diff src tests || exit 1
pydocstyle src tests || exit 1
black --check src tests || exit 1
mypy src tests || exit 1
ruff --fix src tests || exit 1
ruff format -q src tests || exit 1
mypy src tests --show-error-codes || exit 1

format:
isort src tests
black src tests
ruff src tests --fix
ruff format src tests

## Build
build-package:
Expand Down
1,188 changes: 516 additions & 672 deletions poetry.lock

Large diffs are not rendered by default.

46 changes: 31 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,14 @@ filelock = {version = "*", optional = true}
python-on-whales = {version = ">=0.22.0", optional = true}

[tool.poetry.dev-dependencies]
black = "22.3.0"
botocore = ">=1.31.63"
coverage = "*"
flake8 = "*"
isort = ">=5.0"
moto = ">=2.3.2"
mypy = {version = "0.982"}
pydocstyle = {version = "*"}
pytest-asyncio = "*"
pytest-xdist = "*"
responses = ">=0.23.0"
sqlalchemy-stubs = {version = "*"}
sqlalchemy2-stubs = "^0.0.2-alpha.19"
ruff = "0.1.15"
types-PyMySQL = "^1.0.2"
types-dataclasses = "^0.6.5"
types-filelock = "^3.2.7"
Expand All @@ -90,16 +85,37 @@ pytest_mock_resources = "pytest_mock_resources"
[tool.poetry.scripts]
pmr = "pytest_mock_resources.cli:main"

[tool.isort]
profile = 'black'
known_first_party = 'app,tests'
line_length = 100
float_to_top=true
order_by_type = false
use_parentheses = true
[tool.ruff]
src = ["src", "tests"]
line-length = 100

target-version = "py37"
select = ["C", "D", "E", "F", "I", "N", "Q", "RET", "RUF", "S", "T", "UP", "YTT"]
ignore = [
"D1",
"D203",
"D204",
"D213",
"D215",
"D400",
"D404",
"D406",
"D407",
"D408",
"D409",
"D413",
"C901",
"E501",
"S101",
]

[tool.ruff.isort]
known-first-party = ["pytest_mock_resources", "tests"]
order-by-type = false

[tool.ruff.per-file-ignores]
"tests/**/*.py" = ["D", "S", "RUF012", "N801"]

[tool.black]
line_length = 100

[tool.mypy]
strict_optional = true
Expand Down
4 changes: 2 additions & 2 deletions src/pytest_mock_resources/action.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import abc
from typing import ClassVar, Iterable, Optional
from typing import ClassVar, Iterable


class AbstractAction(metaclass=abc.ABCMeta):
Expand All @@ -13,7 +13,7 @@ def apply(self, conn):
"""Execute an action against the provided fixture connection."""


def validate_actions(actions, *, fixture: Optional[str], additional_types: Iterable = ()):
def validate_actions(actions, *, fixture: str | None, additional_types: Iterable = ()):
for action in actions:
if not isinstance(action, (AbstractAction, *additional_types)):
extra_types_str = ", ".join(
Expand Down
5 changes: 3 additions & 2 deletions src/pytest_mock_resources/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import argparse
import importlib
import sys

from pytest_mock_resources.config import DockerContainerConfig
from pytest_mock_resources.container.base import container_name, get_container
Expand All @@ -12,7 +13,7 @@ class StubPytestConfig:
pmr_multiprocess_safe = False
pmr_cleanup_container = False

class option:
class option: # noqa: N801
pmr_multiprocess_safe = False
pmr_cleanup_container = False

Expand Down Expand Up @@ -84,7 +85,7 @@ def execute(fixture: str, pytestconfig: StubPytestConfig, start=True, stop=False
try:
container = docker.container.inspect(name)
except Exception:
print(f"Failed to stop {fixture} container")
sys.stderr.write(f"Failed to stop {fixture} container\n")
else:
container.kill()

Expand Down
2 changes: 1 addition & 1 deletion src/pytest_mock_resources/compat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pytest_mock_resources.compat.import_ import ImportAdaptor

# isort: split
from pytest_mock_resources.compat import sqlalchemy # noqa
from pytest_mock_resources.compat import sqlalchemy

try:
import psycopg2
Expand Down
2 changes: 1 addition & 1 deletion src/pytest_mock_resources/compat/sqlalchemy.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
else:
from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta

URL = sqlalchemy.engine.url.URL
URL = sqlalchemy.engine.url.URL # type: ignore[assignment]

asyncio = ImportAdaptor(
"SQLAlchemy",
Expand Down
22 changes: 10 additions & 12 deletions src/pytest_mock_resources/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import functools
import os
import socket
from typing import ClassVar, Dict, Iterable, Type
from typing import ClassVar, Iterable

_DOCKER_HOST = "host.docker.internal"

Expand All @@ -23,7 +23,7 @@ def is_docker_host():


def get_env_config(name, kind, default=None):
env_var = "PMR_{name}_{kind}".format(name=name.upper(), kind=kind.upper())
env_var = f"PMR_{name.upper()}_{kind.upper()}"
return os.environ.get(env_var, default)


Expand Down Expand Up @@ -53,10 +53,10 @@ def wrapper(self):
class DockerContainerConfig:
name: ClassVar[str]

_fields: Iterable = {"image", "host", "port", "ci_port", "container_args"}
_fields_defaults: Dict = {}
_fields: ClassVar[Iterable] = {"image", "host", "port", "ci_port", "container_args"}
_fields_defaults: ClassVar[dict] = {}

subclasses: Dict[str, Type[DockerContainerConfig]] = {}
subclasses: ClassVar[dict[str, type[DockerContainerConfig]]] = {}

@classmethod
def __init_subclass__(cls):
Expand All @@ -67,28 +67,26 @@ def __init__(self, **kwargs):
if field not in self._fields:
continue

attr = "_{}".format(field)
attr = f"_{field}"
setattr(self, attr, value)

def __repr__(self):
cls_name = self.__class__.__name__
return "{cls_name}({attrs})".format(
cls_name=cls_name,
attrs=", ".join(
"{}={}".format(attr, repr(getattr(self, attr))) for attr in self._fields
),
attrs=", ".join(f"{attr}={getattr(self, attr)!r}" for attr in self._fields),
)

def has(self, attr):
attr_name = "_{attr}".format(attr=attr)
attr_name = f"_{attr}"
return hasattr(self, attr_name)

def get(self, attr):
attr_name = "_{attr}".format(attr=attr)
attr_name = f"_{attr}"
return getattr(self, attr_name)

def set(self, attr, value):
attr_name = "_{attr}".format(attr=attr)
attr_name = f"_{attr}"
return setattr(self, attr_name, value)

@fallback
Expand Down
17 changes: 8 additions & 9 deletions src/pytest_mock_resources/container/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import socket
import time
import types
from typing import Awaitable, Callable, Optional, TYPE_CHECKING, TypeVar
from typing import Awaitable, Callable, TYPE_CHECKING, TypeVar

from pytest_mock_resources.hooks import (
get_docker_client,
Expand All @@ -17,21 +17,20 @@
try:
import responses as _responses

responses: Optional[types.ModuleType] = _responses
responses: types.ModuleType | None = _responses
del _responses
except ImportError:
responses = None

if TYPE_CHECKING:

from python_on_whales.docker_client import DockerClient


DEFAULT_RETRIES = 40
DEFAULT_INTERVAL = 0.5


class ContainerCheckFailed(Exception):
class ContainerCheckFailed(Exception): # noqa: N818
"""Unable to connect to a Container."""


Expand Down Expand Up @@ -142,11 +141,11 @@ def wait_for_container(

check_fn = config.check_fn
run_args = (config.image,)
run_kwargs = dict(
publish=[(dest, source) for source, dest in config.ports().items()],
envs=config.environment(),
name=container_name(config.name, config.port),
)
run_kwargs = {
"publish": [(dest, source) for source, dest in config.ports().items()],
"envs": config.environment(),
"name": container_name(config.name, config.port),
}

try:
from python_on_whales.exceptions import DockerException
Expand Down
10 changes: 5 additions & 5 deletions src/pytest_mock_resources/container/mongo.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import ClassVar, Iterable

from pytest_mock_resources.compat import pymongo
from pytest_mock_resources.config import DockerContainerConfig, fallback
from pytest_mock_resources.container.base import ContainerCheckFailed
Expand All @@ -21,8 +23,8 @@ class MongoConfig(DockerContainerConfig):

name = "mongo"

_fields = {"image", "host", "port", "ci_port", "root_database"}
_fields_defaults = {
_fields: ClassVar[Iterable] = {"image", "host", "port", "ci_port", "root_database"}
_fields_defaults: ClassVar[dict] = {
"image": "mongo:3.6",
"port": 28017,
"ci_port": 27017,
Expand All @@ -43,7 +45,5 @@ def check_fn(self):
db.command("ismaster")
except pymongo.errors.ConnectionFailure:
raise ContainerCheckFailed(
"Unable to connect to a presumed MongoDB test container via given config: {}".format(
self
)
f"Unable to connect to a presumed MongoDB test container via given config: {self}"
)
12 changes: 6 additions & 6 deletions src/pytest_mock_resources/container/moto.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import ClassVar, Iterable

from pytest_mock_resources.config import DockerContainerConfig
from pytest_mock_resources.container.base import ContainerCheckFailed

Expand All @@ -18,8 +20,8 @@ class MotoConfig(DockerContainerConfig):

name = "moto"

_fields = {"image", "host", "port"}
_fields_defaults = {
_fields: ClassVar[Iterable] = {"image", "host", "port"}
_fields_defaults: ClassVar[dict] = {
"image": "motoserver/moto:4.0.6",
"port": 5555,
}
Expand All @@ -32,12 +34,10 @@ def check_fn(self):

try:
url = endpoint_url(self)
requests.get(url)
requests.get(url, timeout=60)
except requests.exceptions.RequestException:
raise ContainerCheckFailed(
"Unable to connect to a presumed moto test container via given config: {}".format(
self
)
f"Unable to connect to a presumed moto test container via given config: {self}"
)


Expand Down
18 changes: 13 additions & 5 deletions src/pytest_mock_resources/container/mysql.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import ClassVar, Iterable

import sqlalchemy

from pytest_mock_resources import compat
Expand Down Expand Up @@ -26,8 +28,16 @@ class MysqlConfig(DockerContainerConfig):
"""

name = "mysql"
_fields = {"image", "host", "port", "ci_port", "username", "password", "root_database"}
_fields_defaults = {
_fields: ClassVar[Iterable] = {
"image",
"host",
"port",
"ci_port",
"username",
"password",
"root_database",
}
_fields_defaults: ClassVar[dict] = {
"image": "mysql:5.6",
"port": 3406,
"ci_port": 3306,
Expand Down Expand Up @@ -64,9 +74,7 @@ def check_fn(self):
get_sqlalchemy_engine(self, self.root_database)
except sqlalchemy.exc.OperationalError:
raise ContainerCheckFailed(
"Unable to connect to a presumed MySQL test container via given config: {}".format(
self
)
f"Unable to connect to a presumed MySQL test container via given config: {self}"
)


Expand Down
Loading

0 comments on commit 7ef324e

Please sign in to comment.