Skip to content

Commit

Permalink
Modernize tooling (#37)
Browse files Browse the repository at this point in the history
* Replace black/isort by ruff
* Type all the codebase
  • Loading branch information
multani authored Sep 21, 2024
1 parent 63f4e38 commit 06d9a4a
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 58 deletions.
13 changes: 5 additions & 8 deletions .github/workflows/build-test-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,13 @@ jobs:
run: hatch run pytest --color=yes

- name: mypy
run: hatch run mypy structlog_gcp
run: hatch run mypy

- name: ruff
run: hatch run ruff check structlog_gcp
- name: lint
run: hatch run ruff check

- name: black
run: hatch run black --check --diff structlog_gcp

- name: isort
run: hatch run isort --check --diff structlog_gcp
- name: format
run: hatch run ruff format --diff

- name: Build
run: hatch build --clean
Expand Down
19 changes: 4 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
DIRS = structlog_gcp

all: lint fmt

.PHONY: lint
lint:
$(MAKE) ruff
$(MAKE) mypy

.PHONY: ruff
ruff:
hatch run ruff check $(DIRS)
all: fmt mypy test

.PHONY: mypy
mypy:
hatch run mypy $(DIRS)
hatch run mypy

.PHONY: fmt
fmt:
hatch run black $(DIRS)
hatch run isort $(DIRS)
hatch run ruff format
hatch run ruff check --fix

.PHONY: test
test:
Expand Down
23 changes: 5 additions & 18 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "structlog-gcp"
description = 'A structlog set of processors to output as Google Cloud Logging format'
description = "A structlog set of processors to output as Google Cloud Logging format"
readme = "README.md"
requires-python = ">=3.10"
license = "MIT"
Expand All @@ -15,9 +15,9 @@ authors = [
classifiers = [
"Development Status :: 4 - Beta",
"Programming Language :: Python",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
]
Expand All @@ -36,9 +36,7 @@ path = "structlog_gcp/__about__.py"

[tool.hatch.envs.default]
dependencies = [
"black",
"ruff",
"isort",
"mypy",
"pytest",
"pytest-cov",
Expand Down Expand Up @@ -67,20 +65,9 @@ omit = [
"structlog_gcp/__about__.py",
]

[tool.coverage.report]
exclude_lines = [
"no cov",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
]

[tool.isort]
profile = "black"

[tool.mypy]
strict = true
files = ["structlog_gcp", "tests"]

[tool.ruff]
ignore = [
"E501",
]
[tool.ruff.lint]
extend-select = ["I"]
13 changes: 8 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from typing import Callable, Generator
from unittest.mock import patch

import pytest
import structlog
from _pytest.capture import CaptureFixture
from structlog.typing import WrappedLogger

import structlog_gcp

from . import fakes


@pytest.fixture
def mock_logger_env():
def mock_logger_env() -> Generator[None, None, None]:
with (
patch(
"structlog.processors.CallsiteParameterAdder",
Expand All @@ -24,7 +27,7 @@ def mock_logger_env():


@pytest.fixture
def logger(mock_logger_env):
def logger(mock_logger_env: None) -> Generator[WrappedLogger, None, None]:
"""Setup a logger for testing and return it"""

structlog.reset_defaults()
Expand All @@ -38,10 +41,10 @@ def logger(mock_logger_env):


@pytest.fixture
def stdout(capsys):
def read():
def stdout(capsys: CaptureFixture[str]) -> Callable[[], str]:
def read() -> str:
output = capsys.readouterr()
assert "" == output.err
return output.out

yield read
return read
21 changes: 16 additions & 5 deletions tests/fakes.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
"""Fake implementations of structlog processors with side-effects"""

from typing import Collection

from structlog.processors import CallsiteParameter
from structlog.typing import EventDict, WrappedLogger


class CallsiteParameterAdder:
def __init__(self, *args, **kwargs):
def __init__(self, parameters: Collection[CallsiteParameter]) -> None:
pass

def __call__(self, logger, method_name, event_dict):
def __call__(
self, logger: WrappedLogger, method_name: str, event_dict: EventDict
) -> EventDict:
event_dict["pathname"] = "/app/test.py"
event_dict["lineno"] = 42
event_dict["module"] = "test"
Expand All @@ -14,15 +21,19 @@ def __call__(self, logger, method_name, event_dict):


class TimeStamper:
def __init__(self, *args, **kwargs):
def __init__(self, fmt: str) -> None:
pass

def __call__(self, logger, method_name, event_dict):
def __call__(
self, logger: WrappedLogger, method_name: str, event_dict: EventDict
) -> EventDict:
event_dict["timestamp"] = "2023-04-01T08:00:00.000000Z"
return event_dict


def format_exc_info(logger, method_name, event_dict):
def format_exc_info(
logger: WrappedLogger, method_name: str, event_dict: EventDict
) -> EventDict:
exc_info = event_dict.pop("exc_info", None)
if exc_info:
event_dict["exception"] = "Traceback blabla"
Expand Down
17 changes: 10 additions & 7 deletions tests/test_log.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import datetime
import json
from typing import Callable
from unittest.mock import patch

import structlog
from structlog.typing import WrappedLogger

import structlog_gcp

T_stdout = Callable[[], str]

def test_normal(stdout, logger):

def test_normal(stdout: T_stdout, logger: WrappedLogger) -> None:
logger.info("test")

msg = json.loads(stdout())
Expand All @@ -25,7 +29,7 @@ def test_normal(stdout, logger):
assert msg == expected


def test_error(stdout, logger):
def test_error(stdout: T_stdout, logger: WrappedLogger) -> None:
try:
1 / 0
except ZeroDivisionError:
Expand Down Expand Up @@ -60,7 +64,7 @@ def test_error(stdout, logger):
assert msg == expected


def test_service_context_default(stdout, logger):
def test_service_context_default(stdout: T_stdout, logger: WrappedLogger) -> None:
try:
1 / 0
except ZeroDivisionError:
Expand All @@ -75,7 +79,7 @@ def test_service_context_default(stdout, logger):


@patch.dict("os.environ", {"K_SERVICE": "test-service", "K_REVISION": "test-version"})
def test_service_context_envvar(stdout, mock_logger_env):
def test_service_context_envvar(stdout: T_stdout, mock_logger_env: None) -> None:
processors = structlog_gcp.build_processors()
structlog.configure(processors=processors)
logger = structlog.get_logger()
Expand All @@ -93,7 +97,7 @@ def test_service_context_envvar(stdout, mock_logger_env):
}


def test_service_context_custom(stdout, mock_logger_env):
def test_service_context_custom(stdout: T_stdout, mock_logger_env: None) -> None:
processors = structlog_gcp.build_processors(
service="my-service",
version="deadbeef",
Expand All @@ -114,7 +118,7 @@ def test_service_context_custom(stdout, mock_logger_env):
}


def test_extra_labels(stdout, logger):
def test_extra_labels(stdout: T_stdout, logger: WrappedLogger) -> None:
logger.info(
"test",
test1="test1",
Expand All @@ -135,7 +139,6 @@ def test_extra_labels(stdout, logger):
"severity": "INFO",
"time": "2023-04-01T08:00:00.000000Z",
"message": "test",

# This should be parsed automatically by Cloud Logging into dedicated keys and saved into a JSON payload.
# See: https://cloud.google.com/logging/docs/structured-logging#special-payload-fields
"test1": "test1",
Expand Down

0 comments on commit 06d9a4a

Please sign in to comment.