mirror of
https://github.com/kristoferssolo/bunyan-formatter.git
synced 2025-10-21 17:20:35 +00:00
commit
725dd8e624
26
.github/workflows/publish.yaml
vendored
Normal file
26
.github/workflows/publish.yaml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: Publish Python Package
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install build
|
||||||
|
- name: Build package
|
||||||
|
run: python -m build
|
||||||
|
- name: Publish package
|
||||||
|
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
|
||||||
|
with:
|
||||||
|
user: __token__
|
||||||
|
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
26
.github/workflows/tox.yaml
vendored
Normal file
26
.github/workflows/tox.yaml
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
name: Run Tox
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test with ${{ matrix.python-version }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
max-parallel: 4
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install tox tox-gh-actions
|
||||||
|
- name: Run Tox
|
||||||
|
env:
|
||||||
|
TOXENV: py${{ matrix.python-version }}
|
||||||
|
run: tox
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,6 +5,7 @@ build/
|
|||||||
dist/
|
dist/
|
||||||
wheels/
|
wheels/
|
||||||
*.egg-info
|
*.egg-info
|
||||||
|
.tox/
|
||||||
|
|
||||||
# venv
|
# venv
|
||||||
.venv
|
.venv
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "bunyan-formatter"
|
name = "bunyan-formatter"
|
||||||
version = "0.1.0"
|
version = "1.0.0"
|
||||||
description = "Bunyan Formatter for Python"
|
description = "Bunyan Formatter for Python"
|
||||||
dependencies = []
|
dependencies = []
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">= 3.8"
|
requires-python = ">=3.9"
|
||||||
authors = [{ name = "Kristofers Solo", email = "dev@kristofers.xyz" }]
|
authors = [{ name = "Kristofers Solo", email = "dev@kristofers.xyz" }]
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
@ -13,7 +13,13 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[tool.rye]
|
[tool.rye]
|
||||||
managed = true
|
managed = true
|
||||||
dev-dependencies = ["mypy~=1.11", "ruff~=0.6", "pre-commit~=3.8", "pytest~=8.3"]
|
dev-dependencies = [
|
||||||
|
"mypy~=1.11",
|
||||||
|
"ruff~=0.6",
|
||||||
|
"pre-commit~=3.8",
|
||||||
|
"pytest~=8.3",
|
||||||
|
"tox~=4.18",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.hatch.metadata]
|
[tool.hatch.metadata]
|
||||||
allow-direct-references = true
|
allow-direct-references = true
|
||||||
@ -25,7 +31,7 @@ packages = ["src/bunyan_formatter"]
|
|||||||
show-fixes = true
|
show-fixes = true
|
||||||
line-length = 120
|
line-length = 120
|
||||||
indent-width = 4
|
indent-width = 4
|
||||||
target-version = "py38"
|
target-version = "py312"
|
||||||
|
|
||||||
[tool.ruff.lint]
|
[tool.ruff.lint]
|
||||||
extend-select = [
|
extend-select = [
|
||||||
|
|||||||
@ -10,11 +10,18 @@
|
|||||||
# universal: false
|
# universal: false
|
||||||
|
|
||||||
-e file:.
|
-e file:.
|
||||||
|
cachetools==5.5.0
|
||||||
|
# via tox
|
||||||
cfgv==3.4.0
|
cfgv==3.4.0
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
|
chardet==5.2.0
|
||||||
|
# via tox
|
||||||
|
colorama==0.4.6
|
||||||
|
# via tox
|
||||||
distlib==0.3.8
|
distlib==0.3.8
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
filelock==3.16.0
|
filelock==3.16.0
|
||||||
|
# via tox
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
identify==2.6.0
|
identify==2.6.0
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
@ -26,17 +33,25 @@ mypy-extensions==1.0.0
|
|||||||
nodeenv==1.9.1
|
nodeenv==1.9.1
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
packaging==24.1
|
packaging==24.1
|
||||||
|
# via pyproject-api
|
||||||
# via pytest
|
# via pytest
|
||||||
|
# via tox
|
||||||
platformdirs==4.3.2
|
platformdirs==4.3.2
|
||||||
|
# via tox
|
||||||
# via virtualenv
|
# via virtualenv
|
||||||
pluggy==1.5.0
|
pluggy==1.5.0
|
||||||
# via pytest
|
# via pytest
|
||||||
|
# via tox
|
||||||
pre-commit==3.8.0
|
pre-commit==3.8.0
|
||||||
|
pyproject-api==1.7.1
|
||||||
|
# via tox
|
||||||
pytest==8.3.3
|
pytest==8.3.3
|
||||||
pyyaml==6.0.2
|
pyyaml==6.0.2
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
ruff==0.6.4
|
ruff==0.6.4
|
||||||
|
tox==4.18.1
|
||||||
typing-extensions==4.12.2
|
typing-extensions==4.12.2
|
||||||
# via mypy
|
# via mypy
|
||||||
virtualenv==20.26.4
|
virtualenv==20.26.4
|
||||||
# via pre-commit
|
# via pre-commit
|
||||||
|
# via tox
|
||||||
|
|||||||
@ -1,25 +1,28 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from logging import LogRecord
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from bunyan_formatter import BunyanFormatter
|
from bunyan_formatter import BunyanFormatter
|
||||||
|
|
||||||
|
|
||||||
class TestBunyanFormatter(TestCase):
|
class TestBunyanFormatter(TestCase):
|
||||||
def setUp(self):
|
def setUp(self) -> None:
|
||||||
self.project_name = "test_project"
|
self.project_name = "test_project"
|
||||||
self.project_root = Path("/path/to/project")
|
self.project_root = Path("/path/to/project")
|
||||||
self.formatter = BunyanFormatter(self.project_name, self.project_root)
|
self.formatter = BunyanFormatter(self.project_name, self.project_root)
|
||||||
|
|
||||||
def create_log_record(self, level, msg, pathname):
|
def create_log_record(self, level: int, msg: str, pathname: str) -> LogRecord:
|
||||||
return logging.LogRecord(
|
return LogRecord(name="test_logger", level=level, pathname=pathname, lineno=42, msg=msg, args=(), exc_info=None)
|
||||||
name="test_logger", level=level, pathname=pathname, lineno=42, msg=msg, args=(), exc_info=None
|
|
||||||
)
|
|
||||||
|
|
||||||
@patch("socket.gethostname")
|
@patch("socket.gethostname")
|
||||||
def test_format_basic(self, mock_gethostname):
|
def test_format_basic(self, mock_gethostname: Optional[Mock]) -> None:
|
||||||
|
if mock_gethostname is None:
|
||||||
|
raise ValueError("mock_gethostname should not be None")
|
||||||
|
|
||||||
mock_gethostname.return_value = "test_host"
|
mock_gethostname.return_value = "test_host"
|
||||||
record = self.create_log_record(logging.INFO, "Test message", "/path/to/project/test.py")
|
record = self.create_log_record(logging.INFO, "Test message", "/path/to/project/test.py")
|
||||||
|
|
||||||
@ -36,25 +39,27 @@ class TestBunyanFormatter(TestCase):
|
|||||||
assert log_entry["line"] == 42
|
assert log_entry["line"] == 42
|
||||||
assert log_entry["file"] == "test.py"
|
assert log_entry["file"] == "test.py"
|
||||||
|
|
||||||
def test_format_different_levels(self):
|
def test_format_different_levels(self) -> None:
|
||||||
levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]
|
levels = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL]
|
||||||
expected_levels = [20, 30, 40, 50, 60]
|
expected_levels = [20, 30, 40, 50, 60]
|
||||||
|
|
||||||
for level, expected in zip(levels, expected_levels):
|
for level, expected in zip(levels, expected_levels, strict=False):
|
||||||
record = self.create_log_record(level, f"Test {logging.getLevelName(level)}", "/path/to/project/test.py")
|
record = self.create_log_record(level, f"Test {logging.getLevelName(level)}", "/path/to/project/test.py")
|
||||||
formatted = self.formatter.format(record)
|
formatted = self.formatter.format(record)
|
||||||
log_entry = json.loads(formatted)
|
log_entry = json.loads(formatted)
|
||||||
assert log_entry["level"] == expected
|
assert log_entry["level"] == expected
|
||||||
assert log_entry["levelname"] == logging.getLevelName(level)
|
assert log_entry["levelname"] == logging.getLevelName(level)
|
||||||
|
|
||||||
def test_format_file_outside_project(self):
|
def test_format_file_outside_project(self) -> None:
|
||||||
record = self.create_log_record(logging.INFO, "Test message", "/path/outside/project/test.py")
|
record = self.create_log_record(logging.INFO, "Test message", "/path/outside/project/test.py")
|
||||||
formatted = self.formatter.format(record)
|
formatted = self.formatter.format(record)
|
||||||
log_entry = json.loads(formatted)
|
log_entry = json.loads(formatted)
|
||||||
assert log_entry["file"] == "/path/outside/project/test.py"
|
assert log_entry["file"] == "/path/outside/project/test.py"
|
||||||
|
|
||||||
@patch("socket.gethostname")
|
@patch("socket.gethostname")
|
||||||
def test_format_hostname_consistency(self, mock_gethostname):
|
def test_format_hostname_consistency(self, mock_gethostname: Optional[Mock]) -> None:
|
||||||
|
if mock_gethostname is None:
|
||||||
|
raise ValueError("mock_gethostname should not be None")
|
||||||
mock_gethostname.return_value = "test_host"
|
mock_gethostname.return_value = "test_host"
|
||||||
record1 = self.create_log_record(logging.INFO, "Message 1", "/path/to/project/test1.py")
|
record1 = self.create_log_record(logging.INFO, "Message 1", "/path/to/project/test1.py")
|
||||||
record2 = self.create_log_record(logging.INFO, "Message 2", "/path/to/project/test2.py")
|
record2 = self.create_log_record(logging.INFO, "Message 2", "/path/to/project/test2.py")
|
||||||
@ -67,7 +72,7 @@ class TestBunyanFormatter(TestCase):
|
|||||||
|
|
||||||
assert log_entry1["hostname"] == log_entry2["hostname"]
|
assert log_entry1["hostname"] == log_entry2["hostname"]
|
||||||
|
|
||||||
def test_format_time(self):
|
def test_format_time(self) -> None:
|
||||||
record = self.create_log_record(logging.INFO, "Test message", "/path/to/project/test.py")
|
record = self.create_log_record(logging.INFO, "Test message", "/path/to/project/test.py")
|
||||||
formatted = self.formatter.format(record)
|
formatted = self.formatter.format(record)
|
||||||
log_entry = json.loads(formatted)
|
log_entry = json.loads(formatted)
|
||||||
|
|||||||
28
tox.ini
Normal file
28
tox.ini
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
[tox]
|
||||||
|
envlist = py39, py310, py311, py312, format, lint, type, test
|
||||||
|
skipsdist = True
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
deps =
|
||||||
|
hatchling
|
||||||
|
-rrequirements-dev.lock
|
||||||
|
|
||||||
|
[testenv:format]
|
||||||
|
description = Run ruff to format the code
|
||||||
|
skip_install = true
|
||||||
|
deps = ruff
|
||||||
|
commands = ruff format
|
||||||
|
|
||||||
|
[testenv:lint]
|
||||||
|
description = Run ruff to lint the code
|
||||||
|
skip_install = true
|
||||||
|
deps = ruff
|
||||||
|
commands = ruff check --fix
|
||||||
|
|
||||||
|
[testenv:type]
|
||||||
|
description = Run mypy to check type annotations
|
||||||
|
commands = mypy .
|
||||||
|
|
||||||
|
[testenv:test]
|
||||||
|
description = Run pytest to execute the tests
|
||||||
|
commands = pytest
|
||||||
Loading…
Reference in New Issue
Block a user