Skip to content

Commit

Permalink
Merge v0.2.0 (#5)
Browse files Browse the repository at this point in the history
* Add type hints

* Remove html support

* Refactor plugin

* Update unittests

* Bump triple
  • Loading branch information
Tbruno25 authored Sep 11, 2023
1 parent fb30085 commit e90e9f5
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
python-version: ['3.8', '3.9', '3.10', '3.11']

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The timestamps used depend whether Pytest is running in `verbose` mode.\
**non verbose:** module\
![](https://i.ibb.co/0qLXFjB/Screenshot-from-2022-01-10-22-00-26.png)

Timestamps will also be added to the test report if [pytest-html](https://github.com/pytest-dev/pytest-html) is installed.
***Note:*** *fixture setup/teardown times are omitted from the timestamp*



Expand Down
14 changes: 7 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
[tool.poetry]
name = "pytest-timestamps"
version = "0.1.4"
version = "0.2.0"
description = "A simple plugin to view timestamps for each test"
authors = ["TJ <[email protected]>"]
packages = [{ include = "pytest_timestamps" }]

[tool.poetry.dependencies]
python = ">=3.7, <4.0"
pytest = ">=5.2"
python = ">=3.8, <4.0"
pytest = "^7.3"

[tool.poetry.group.dev.dependencies]
freezegun = "^1.0"
ruff = "^0.0.260"
black = "^23.3.0"
ruff = "^0.0.287"
black = "^23.9.1"
mypy = "^1.5.1"

[tool.poetry.plugins."pytest11"]
timestamps = "pytest_timestamps.plugin"
Expand Down Expand Up @@ -45,4 +45,4 @@ legacy_tox_ini = """
commands =
poetry install --only dev
poetry run pytest -v
"""
"""
115 changes: 46 additions & 69 deletions pytest_timestamps/plugin.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,62 @@
from datetime import datetime

from _pytest.config import Config

import pytest
from _pytest.terminal import TerminalReporter
from _pytest.reports import TestReport

from typing import Final, Optional


def format(timestamp: float) -> str:
return datetime.fromtimestamp(timestamp).strftime("%H:%M:%S")


class Timestamp:
start: Optional[float] = None
stop: Optional[float] = None

def format_timestamp(ts):
return datetime.fromtimestamp(ts).strftime("%H:%M:%S")
def clear(self) -> None:
self.start = None
self.stop = None

def get(self) -> str:
return f"[{format(self.start)} - {format(self.stop)}]" # type: ignore

class Timestamped(TerminalReporter):
color = "blue"
def is_valid(self) -> bool:
return bool(self.start and self.stop)

def __init__(self, reporter):
TerminalReporter.__init__(self, reporter.config)
self._node = None
self._fspath = None
self._last_fspath = None
def update(self, report: TestReport) -> None:
if report.when == "call":
if not self.start:
self.start = report.start
self.stop = report.stop

def _get_timestamps(self):
if self.verbosity > 0:
times = self._node
else:
times = self._fspath
return [format_timestamp(i) for i in times]

def _write_ts_to_terminal(self):
start, stop = self._get_timestamps()
ts_line = f"[{start} - {stop}]"
w = self._width_of_current_line
fill = self._tw.fullwidth - w - 10
self.write(ts_line.rjust(fill), **{self.color: True})
class TimestampReporter(TerminalReporter): # type: ignore
color: str = "blue"
dedent: int = 10
timestamp: Final = Timestamp()

def _write_progress_information_filling_space(self):
self._write_ts_to_terminal()
def __init__(self, config: Config) -> None:
TerminalReporter.__init__(self, config)

def _write_timestamp(self) -> None:
line_width = self._width_of_current_line
total_width = self._tw.fullwidth
fill = total_width - line_width - self.dedent
timestamp = self.timestamp.get().rjust(fill)
self.write(timestamp, **{self.color: True})

def _write_progress_information_filling_space(self) -> None:
if self.timestamp.is_valid():
self._write_timestamp()
super()._write_progress_information_filling_space()
self.timestamp.clear()

def pytest_runtest_logreport(self, report):
if len(report.timestamps) == 3:
if report.fspath != self._last_fspath:
self._last_fspath = report.fspath
self._fspath = report.timestamps[1:3]
else:
self._fspath[1] = report.timestamps[2]
self._node = report.timestamps[1:3]
def pytest_runtest_logreport(self, report: TestReport) -> None:
self.timestamp.update(report)
super().pytest_runtest_logreport(report)


Expand All @@ -51,41 +65,4 @@ def pytest_configure(config):
if config.pluginmanager.has_plugin("terminalreporter"):
reporter = config.pluginmanager.get_plugin("terminalreporter")
config.pluginmanager.unregister(reporter, "terminalreporter")
config.pluginmanager.register(Timestamped(reporter), "terminalreporter")
if config.pluginmanager.has_plugin("html"):
global html
from py.xml import html


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""Record timestamps to the test report."""

if call.when == "setup":
item._timestamps = [call.start]

elif call.when == "call":
item._timestamps.append(call.start)
item._timestamps.append(call.stop)

else:
item._timestamps.append(call.stop)

output = yield
report = output.get_result()
report.timestamps = item._timestamps


@pytest.hookimpl(optionalhook=True)
def pytest_html_results_table_header(cells):
cells.insert(2, html.th("Setup Start"))
cells.insert(3, html.th("Test Start"))
cells.insert(4, html.th("Test Stop"))
cells.insert(5, html.th("Teardown Stop"))


@pytest.hookimpl(optionalhook=True)
def pytest_html_results_table_row(report, cells):
if len(report.timestamps) == 4:
for idx, ts in enumerate(report.timestamps):
cells.insert(idx + 2, html.td(format_timestamp(ts)))
config.pluginmanager.register(TimestampReporter(config), "terminalreporter")
47 changes: 41 additions & 6 deletions tests/test_plugin.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import pytest
from freezegun import freeze_time
from pytest_timestamps.plugin import TimestampReporter

from unittest.mock import patch

pytest_plugins = "pytester"


@pytest.fixture
def timestamp():
ts = "01:01:01"
with freeze_time(f"2000-01-01 {ts}"):
yield f"[{ts} - {ts}]"
instance = TimestampReporter.timestamp

# Prevent times from being cleared once printed to terminal
with patch.object(instance, "clear"):
yield instance

instance.clear()


def test_timestamps_normal(pytester, timestamp):
Expand All @@ -21,8 +27,9 @@ def test_plugin():
"""
)
result = pytester.runpytest()
assert timestamp.is_valid()
result.assert_outcomes(passed=1)
assert timestamp in result.stdout.str()
assert timestamp.get() in result.stdout.str()


def test_timestamps_verbose(pytester, timestamp):
Expand All @@ -35,5 +42,33 @@ def test_plugin():
"""
)
result = pytester.runpytest("-v")
assert timestamp.is_valid()
result.assert_outcomes(passed=1)
assert timestamp in result.stdout.str()
assert timestamp.get() in result.stdout.str()


def test_timestamp_is_cleared(pytester, timestamp):
pytester.makepyfile(
"""
import pytest
def test_plugin():
assert True
"""
)
pytester.runpytest()
timestamp.clear.assert_called_once()


def test_timestamps_with_skip_decorator(pytester):
pytester.makepyfile(
"""
import pytest
@pytest.mark.skip
def test_plugin():
assert True
"""
)
result = pytester.runpytest()
result.assert_outcomes(skipped=1)

0 comments on commit e90e9f5

Please sign in to comment.