-
-
Notifications
You must be signed in to change notification settings - Fork 186
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
Log file sizes and free mem #305
Changes from all commits
a4f3027
f752538
3143a01
bd02e9a
2cac445
07bd34a
4621b00
f28d9a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import os | ||
from collections import defaultdict | ||
from typing import Optional, Iterable, Union, Any, List, Dict | ||
from typing import Optional, Iterable, Union, Any, List, Dict, Callable, Tuple | ||
|
||
import junitparser | ||
from junitparser import Element, JUnitXml, TestCase, TestSuite, Skipped | ||
|
@@ -98,7 +98,10 @@ def end(self, tag: Union[str, bytes]) -> Element: | |
self._stack.pop() | ||
|
||
|
||
def parse_junit_xml_files(files: Iterable[str], time_factor: float = 1.0, drop_testcases: bool = False) -> ParsedUnitTestResults: | ||
def parse_junit_xml_files(files: Iterable[str], | ||
time_factor: float = 1.0, | ||
drop_testcases: bool = False, | ||
progress: Callable[[Tuple[str, Any]], Tuple[str, Any]] = lambda x: x) -> ParsedUnitTestResults: | ||
"""Parses junit xml files and returns aggregated statistics as a ParsedUnitTestResults.""" | ||
def parse(path: str) -> Union[str, Any]: | ||
if not os.path.exists(path): | ||
|
@@ -114,7 +117,7 @@ def parse(path: str) -> Union[str, Any]: | |
except BaseException as e: | ||
return e | ||
|
||
parsed_files = [(result_file, parse(result_file)) | ||
parsed_files = [progress((result_file, parse(result_file))) | ||
for result_file in files] | ||
junits = [(result_file, junit) | ||
for result_file, junit in parsed_files | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unable to unpack: Unable to unpack Reply with "@sonatype-lift help" for more info. When talking to LiftBot, you need to refresh the page to see its response. Click here to get to know more about LiftBot commands. Was this a good recommendation? |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
from datetime import datetime | ||
from logging import Logger | ||
from threading import Timer | ||
from typing import Generic, TypeVar, Optional, Callable, Type, Any | ||
import contextlib | ||
|
||
import humanize | ||
|
||
T = TypeVar('T') | ||
|
||
|
||
@contextlib.contextmanager | ||
def progress_logger(items: int, | ||
interval_seconds: int, | ||
progress_template: str, | ||
finish_template: Optional[str], | ||
logger: Logger, | ||
progress_item_type: Type[T] = Any) -> Callable[[T], T]: | ||
progress = Progress[progress_item_type](items) | ||
plogger = ProgressLogger(progress, interval_seconds, progress_template, logger).start() | ||
try: | ||
yield progress.observe | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incompatible return type: Expected Reply with "@sonatype-lift help" for more info. When talking to LiftBot, you need to refresh the page to see its response. Click here to get to know more about LiftBot commands. Was this a good recommendation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incompatible return type: Expected Reply with "@sonatype-lift help" for more info. When talking to LiftBot, you need to refresh the page to see its response. Click here to get to know more about LiftBot commands. Was this a good recommendation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incompatible return type: Expected Reply with "@sonatype-lift help" for more info. When talking to LiftBot, you need to refresh the page to see its response. Click here to get to know more about LiftBot commands. Was this a good recommendation? |
||
finally: | ||
plogger.finish(finish_template) | ||
|
||
|
||
class Progress(Generic[T]): | ||
def __init__(self, items: int): | ||
self.items = items | ||
self.observations = 0 | ||
|
||
def observe(self, observation: T) -> T: | ||
self.observations = self.observations + 1 | ||
return observation | ||
|
||
def get_progress(self) -> str: | ||
return f'{self.observations} of {self.items}' | ||
|
||
|
||
class ProgressLogger: | ||
def __init__(self, progress: Progress, interval_seconds: int, template: str, logger: Logger): | ||
self._progress = progress | ||
self._interval_seconds = interval_seconds | ||
self._template = template | ||
self._logger = logger | ||
|
||
self._start = None | ||
self._duration = None | ||
self._timer = self._get_progress_timer() | ||
|
||
def start(self) -> 'ProgressLogger': | ||
self._start = datetime.utcnow() | ||
self._timer.start() | ||
return self | ||
|
||
def finish(self, template: Optional[str] = None): | ||
self._duration = datetime.utcnow() - self._start | ||
self._start = None | ||
self._timer.cancel() | ||
|
||
if template: | ||
self._logger.info(template.format(items=self._progress.items, | ||
observations=self._progress.observations, | ||
duration=self.duration)) | ||
|
||
@property | ||
def duration(self) -> str: | ||
return humanize.precisedelta(self._duration) | ||
|
||
def _get_progress_timer(self): | ||
timer = Timer(self._interval_seconds, self._log_progress) | ||
timer.setDaemon(daemonic=True) | ||
return timer | ||
|
||
def _log_progress(self): | ||
if self._start is None: | ||
return | ||
|
||
delta = datetime.utcnow() - self._start | ||
self._logger.info(self._template.format(progress=self._progress.get_progress(), time=humanize.precisedelta(delta))) | ||
self._timer = self._get_progress_timer() | ||
self._timer.start() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
# dataclasses does not exist before Python3.7, needed as dependency | ||
dataclasses;python_version<"3.7" | ||
humanize==3.14.0 | ||
junitparser==2.5.0 | ||
psutil==5.9.1 | ||
PyGithub==1.55 | ||
requests==2.27.1 | ||
urllib3==1.26.9 | ||
requests==2.27.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import unittest | ||
from datetime import datetime, timezone | ||
|
||
import mock | ||
|
||
from publish.progress import Progress, ProgressLogger | ||
|
||
|
||
class TestProgress(unittest.TestCase): | ||
def test_get_progress(self): | ||
progress = Progress(10) | ||
self.assertEqual('0 of 10', progress.get_progress()) | ||
self.assertEqual('0 of 10', progress.get_progress()) | ||
self.assertEqual('item', progress.observe('item')) | ||
self.assertEqual('1 of 10', progress.get_progress()) | ||
self.assertEqual('1 of 10', progress.get_progress()) | ||
self.assertEqual(1, progress.observe(1)) | ||
self.assertEqual('2 of 10', progress.get_progress()) | ||
self.assertEqual('2 of 10', progress.get_progress()) | ||
self.assertEqual(1.2, progress.observe(1.2)) | ||
self.assertEqual('3 of 10', progress.get_progress()) | ||
self.assertEqual('3 of 10', progress.get_progress()) | ||
obj = object() | ||
self.assertEqual(obj, progress.observe(obj)) | ||
self.assertEqual('4 of 10', progress.get_progress()) | ||
self.assertEqual('4 of 10', progress.get_progress()) | ||
|
||
|
||
class TestProgressLogger(unittest.TestCase): | ||
def test(self): | ||
progress = Progress(10) | ||
logger = mock.MagicMock(info=mock.Mock()) | ||
plogger = ProgressLogger(progress, 60, 'progress: {progress} in {time}', logger) | ||
try: | ||
ts = datetime(2022, 6, 1, 12, 34, 56, tzinfo=timezone.utc) | ||
with mock.patch('publish.progress.datetime', utcnow=mock.Mock(return_value=ts)): | ||
plogger.start() | ||
logger.info.assert_not_called() | ||
|
||
progress.observe('item') | ||
logger.info.assert_not_called() | ||
|
||
ts = datetime(2022, 6, 1, 12, 35, 00, tzinfo=timezone.utc) | ||
with mock.patch('publish.progress.datetime', utcnow=mock.Mock(return_value=ts)): | ||
plogger._log_progress() | ||
self.assertEqual([mock.call('progress: 1 of 10 in 4 seconds')], logger.info.call_args_list) | ||
logger.info.reset_mock() | ||
|
||
progress.observe('item') | ||
progress.observe('item') | ||
logger.info.assert_not_called() | ||
|
||
ts = datetime(2022, 6, 1, 12, 40, 00, tzinfo=timezone.utc) | ||
with mock.patch('publish.progress.datetime', utcnow=mock.Mock(return_value=ts)): | ||
plogger._log_progress() | ||
self.assertEqual([mock.call('progress: 3 of 10 in 5 minutes and 4 seconds')], logger.info.call_args_list) | ||
logger.info.reset_mock() | ||
finally: | ||
ts = datetime(2022, 6, 1, 12, 41, 23, tzinfo=timezone.utc) | ||
with mock.patch('publish.progress.datetime', utcnow=mock.Mock(return_value=ts)): | ||
plogger.finish('finished: {observations} of {items} in {duration}') | ||
self.assertEqual([mock.call('finished: 3 of 10 in 6 minutes and 27 seconds')], logger.info.call_args_list) | ||
logger.info.reset_mock() | ||
|
||
self.assertEqual('6 minutes and 27 seconds', plogger.duration) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incompatible parameter type: Expected
Variable[T]
for 1st positional only parameter to anonymous call but gottyping.Tuple[str, typing.Any]
.Reply with "@sonatype-lift help" for more info.
Reply with "@sonatype-lift ignore" to tell LiftBot to leave out the above finding from this PR.
Reply with "@sonatype-lift ignoreall" to tell LiftBot to leave out all the findings from this PR and from the status bar in Github.
When talking to LiftBot, you need to refresh the page to see its response. Click here to get to know more about LiftBot commands.
Was this a good recommendation?
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]