Skip to content

Commit

Permalink
Lint and format with Ruff (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
phillipuniverse authored Nov 26, 2024
1 parent ff71a66 commit a19dc4c
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 20 deletions.
34 changes: 34 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,40 @@
test:
poetry run pytest

.PHONY: rufflintfix
rufflintfix:
poetry run ruff check . --fix

.PHONY: rufflintcheck
rufflintcheck:
@echo "Checking ruff..."
poetry run ruff check .

.PHONY: rufflintwatch
rufflintwatch:
poetry run ruff check . --fix --watch

.PHONY: ruffformatfix
ruffformatfix:
poetry run ruff format . --preview

.PHONY: ruffformatcheck
ruffformatcheck:
poetry run ruff format . --check --preview

.PHONY: poetrycheck
poetrycheck:
poetry check --lock

.PHONY: pyformatcheck
pyformatcheck: poetrycheck rufflintcheck ruffformatcheck

.PHONY: lint
lint: pyformatcheck

.PHONY: autofmt
autofmt: rufflintfix ruffformatfix

.PHONY: patchrelease
patchrelease:
poetry version patch
Expand Down
29 changes: 28 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,51 @@ requests = ">=2.0"
pytest = "^7.4.3"
boto3-stubs = {extras = ["s3"], version = "^1.28.70"}
pytest-asyncio = "^0.21.1"
ruff = "^0.8.0"

[tool.ruff]
target-version = "py38"
line-length = 100

lint.select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"C40", # flake8-comprehensions
"C90", # mccabe
"UP", # pyupgrade
"B", # flake8-bugbear
"A", # flake8-builtins
"T10", # flake8-debugger
"BLE", # flake8-blind-except
"T20", # flake8-print
"DTZ", # flake8-datetimez
"PIE", # flake8-pie
"ERA", # eradicate
"PL", # pylint
"SIM", # flake8-simplify
"ERA", # eradicate,
"RUF", # ruff-specific
"TRY", # tryceratops
"PTH", # flake8-use-pathlib"
"PGH", # pygrep-hooks
"TID", # tidy imports
"ICN"
]
lint.ignore = [
"E501", # line too long, handled by formatter
"B008", # function calls in argument defaults
"C401", # generator syntax for sets vs always force set comprehension
"PLC0414", # allow explicit re-exports using 'as' without forcing __all__
"TRY003", # long messages outside except classes
"PLR2004", # magic values refactor to constants
]


[tool.ruff.format]
docstring-code-format = true


[tool.pytest.ini_options]
testpaths = [
Expand Down
4 changes: 2 additions & 2 deletions pytest_aioboto3/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .aioboto3_fixtures import moto_patch_session, aioboto3_s3_client, aioboto3_s3_resource
from .aioboto3_fixtures import aioboto3_s3_client, aioboto3_s3_resource, moto_patch_session
from .moto_fixtures import moto_services

__all__ = ["moto_services", "moto_patch_session", "aioboto3_s3_client", "aioboto3_s3_resource"]
__all__ = ["aioboto3_s3_client", "aioboto3_s3_resource", "moto_patch_session", "moto_services"]
9 changes: 4 additions & 5 deletions pytest_aioboto3/aioboto3_fixtures.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
AWS asyncio test fixtures
"""

from typing import Any, AsyncIterator, Iterator, Mapping, Type, TypeVar
from unittest import mock

Expand All @@ -15,31 +16,29 @@
def create_fake_session(base_class: Type[T], url_overrides: Mapping[str, str]) -> Type[T]:
class FakeSession(base_class): # type:ignore[valid-type, misc]
def __init__(self, *args: Any, **kwargs: Any) -> None:
super(FakeSession, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)

self.__url_overrides = url_overrides
self.__secret_key = "ABCDEFGABCDEFGABCDEF"
self.__access_key = "YTYHRSshtrsTRHSrsTHRSTrthSRThsrTHsr"

def client(self, *args: Any, **kwargs: Any) -> Any:

if "endpoint_url" not in kwargs and args[0] in self.__url_overrides:
kwargs["endpoint_url"] = self.__url_overrides[args[0]]

kwargs["aws_access_key_id"] = self.__secret_key
kwargs["aws_secret_access_key"] = self.__access_key

return super(FakeSession, self).client(*args, **kwargs)
return super().client(*args, **kwargs)

def resource(self, *args: Any, **kwargs: Any) -> Any:

if "endpoint_url" not in kwargs and args[0] in self.__url_overrides:
kwargs["endpoint_url"] = self.__url_overrides[args[0]]

kwargs["aws_access_key_id"] = self.__secret_key
kwargs["aws_secret_access_key"] = self.__access_key

return super(FakeSession, self).resource(*args, **kwargs)
return super().resource(*args, **kwargs)

return FakeSession

Expand Down
25 changes: 13 additions & 12 deletions pytest_aioboto3/moto_fixtures.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from __future__ import annotations

import logging
import shutil
import signal
import socket
import subprocess
import time
from subprocess import Popen
from typing import Any, Dict, Iterator, Mapping
from typing import Any, Iterator, Mapping

import pytest
import requests
Expand All @@ -31,20 +32,20 @@ def start_moto_server(service_name: str, host: str, port: int) -> Popen[Any]:
)
args = [moto_svr_path, service_name, "-H", host, "-p", str(port)]
# For debugging
# args = f"moto_svr_path service_name -H host -p port 2>&1 | tee -a /tmp/moto.log"
# args = f"moto_svr_path service_name -H host -p port 2>&1 | tee -a /tmp/moto.log" # noqa: ERA001
logger.info(f"Starting moto server: {args}")
process = subprocess.Popen(
args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
) # shell=True
url = f"http://{host}:{port}"

for i in range(0, 30):
for _ in range(30):
output = process.poll()
if output is not None:
logger.error(f"moto_server exited status {output}")
stdout, stderr = process.communicate()
logger.error(f"moto_server stdout: {str(stdout)}")
logger.error(f"moto_server stderr: {str(stderr)}")
logger.error(f"moto_server stdout: {stdout!s}")
logger.error(f"moto_server stderr: {stderr!s}")
pytest.fail(f"Can not start service: {service_name}")

try:
Expand All @@ -55,7 +56,7 @@ def start_moto_server(service_name: str, host: str, port: int) -> Popen[Any]:
time.sleep(0.5)
else:
stop_process(process) # pytest.fail doesn't call stop_process
pytest.fail("Can not start moto service: {}".format(service_name))
pytest.fail(f"Can not start moto service: {service_name}")

logger.info(f"Connected to moto server at {url}")

Expand All @@ -66,12 +67,12 @@ def stop_process(process: Popen[Any]) -> None:
try:
process.send_signal(signal.SIGTERM)
process.communicate(timeout=20)
except subprocess.TimeoutExpired:
except subprocess.TimeoutExpired as te:
process.kill()
outs, errors = process.communicate(timeout=20)
exit_code = process.returncode
msg = "Child process finished {} not in clean way: {} {}".format(exit_code, outs, errors)
raise RuntimeError(msg)
msg = f"Child process finished {exit_code} not in clean way: {outs} {errors}"
raise RuntimeError(msg) from te


def get_free_tcp_port() -> int:
Expand All @@ -90,7 +91,7 @@ def moto_services() -> Iterator[Mapping[str, str]]:
Map of mocked services with moto where the key is the service name and the value is the moto url to that service
"""
processes = []
services: Dict[str, str] = {}
services: dict[str, str] = {}
"""
1. Add a new entry to the 'extras' section in pyproject.toml for types-aiobotocore, moto and boto3-stubs like 'dynamodb' or 'ec2'
Expand All @@ -109,6 +110,6 @@ def moto_services() -> Iterator[Mapping[str, str]]:
try:
stop_process(process)
logger.info(f"Stopped moto process {process.pid}")
except Exception as e:
except Exception:
# Keep going through exceptions to stop as many as possible
logger.exception(f"Problem stopping moto process {process}", e)
logger.exception(f"Problem stopping moto process {process}")

0 comments on commit a19dc4c

Please sign in to comment.