Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Adopt ruff. #201

Merged
merged 4 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading