projects
/
python_utils.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Make subdirs type clean too.
[python_utils.git]
/
unittest_utils.py
diff --git
a/unittest_utils.py
b/unittest_utils.py
index 4a9669d3a21f66e35004e1968cc85b65d711fd5c..ba9ca28f091bc70bd232cb6f059116cfc70d7fb9 100644
(file)
--- a/
unittest_utils.py
+++ b/
unittest_utils.py
@@
-7,7
+7,6
@@
caveat emptor.
"""
caveat emptor.
"""
-from abc import ABC, abstractmethod
import contextlib
import functools
import inspect
import contextlib
import functools
import inspect
@@
-16,20
+15,20
@@
import os
import pickle
import random
import statistics
import pickle
import random
import statistics
-import time
import tempfile
import tempfile
-from typing import Callable, Dict, List
+import time
import unittest
import warnings
import unittest
import warnings
+from abc import ABC, abstractmethod
+from typing import Any, Callable, Dict, List, Optional
+
+import sqlalchemy as sa
import bootstrap
import config
import function_utils
import scott_secrets
import bootstrap
import config
import function_utils
import scott_secrets
-import sqlalchemy as sa
-
-
logger = logging.getLogger(__name__)
cfg = config.add_commandline_args(
f'Logging ({__file__})', 'Args related to function decorators'
logger = logging.getLogger(__name__)
cfg = config.add_commandline_args(
f'Logging ({__file__})', 'Args related to function decorators'
@@
-83,13
+82,11
@@
class PerfRegressionDataPersister(ABC):
pass
@abstractmethod
pass
@abstractmethod
- def load_performance_data(self) -> Dict[str, List[float]]:
+ def load_performance_data(self
, method_id: str
) -> Dict[str, List[float]]:
pass
@abstractmethod
pass
@abstractmethod
- def save_performance_data(
- self, method_id: str, data: Dict[str, List[float]]
- ):
+ def save_performance_data(self, method_id: str, data: Dict[str, List[float]]):
pass
@abstractmethod
pass
@abstractmethod
@@
-100,15
+97,13
@@
class PerfRegressionDataPersister(ABC):
class FileBasedPerfRegressionDataPersister(PerfRegressionDataPersister):
def __init__(self, filename: str):
self.filename = filename
class FileBasedPerfRegressionDataPersister(PerfRegressionDataPersister):
def __init__(self, filename: str):
self.filename = filename
- self.traces_to_delete = []
+ self.traces_to_delete
: List[str]
= []
def load_performance_data(self, method_id: str) -> Dict[str, List[float]]:
with open(self.filename, 'rb') as f:
return pickle.load(f)
def load_performance_data(self, method_id: str) -> Dict[str, List[float]]:
with open(self.filename, 'rb') as f:
return pickle.load(f)
- def save_performance_data(
- self, method_id: str, data: Dict[str, List[float]]
- ):
+ def save_performance_data(self, method_id: str, data: Dict[str, List[float]]):
for trace in self.traces_to_delete:
if trace in data:
data[trace] = []
for trace in self.traces_to_delete:
if trace in data:
data[trace] = []
@@
-132,15
+127,13
@@
class DatabasePerfRegressionDataPersister(PerfRegressionDataPersister):
f'SELECT * FROM runtimes_by_function WHERE function = "{method_id}";'
)
)
f'SELECT * FROM runtimes_by_function WHERE function = "{method_id}";'
)
)
- ret = {method_id: []}
+ ret
: Dict[str, List[float]]
= {method_id: []}
for result in results.all():
ret[method_id].append(result['runtime'])
results.close()
return ret
for result in results.all():
ret[method_id].append(result['runtime'])
results.close()
return ret
- def save_performance_data(
- self, method_id: str, data: Dict[str, List[float]]
- ):
+ def save_performance_data(self, method_id: str, data: Dict[str, List[float]]):
self.delete_performance_data(method_id)
for (method_id, perf_data) in data.items():
sql = 'INSERT INTO runtimes_by_function (function, runtime) VALUES '
self.delete_performance_data(method_id)
for (method_id, perf_data) in data.items():
sql = 'INSERT INTO runtimes_by_function (function, runtime) VALUES '
@@
-164,6
+157,9
@@
def check_method_for_perf_regressions(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper_perf_monitor(*args, **kwargs):
@functools.wraps(func)
def wrapper_perf_monitor(*args, **kwargs):
+ if config.config['unittests_ignore_perf']:
+ return func(*args, **kwargs)
+
if config.config['unittests_persistance_strategy'] == 'FILE':
filename = config.config['unittests_perfdb_filename']
helper = FileBasedPerfRegressionDataPersister(filename)
if config.config['unittests_persistance_strategy'] == 'FILE':
filename = config.config['unittests_perfdb_filename']
helper = FileBasedPerfRegressionDataPersister(filename)
@@
-174,9
+170,7
@@
def check_method_for_perf_regressions(func: Callable) -> Callable:
)
helper = DatabasePerfRegressionDataPersister(dbspec)
else:
)
helper = DatabasePerfRegressionDataPersister(dbspec)
else:
- raise Exception(
- 'Unknown/unexpected --unittests_persistance_strategy value'
- )
+ raise Exception('Unknown/unexpected --unittests_persistance_strategy value')
func_id = function_utils.function_identifier(func)
func_name = func.__name__
func_id = function_utils.function_identifier(func)
func_name = func.__name__
@@
-212,17
+206,11
@@
def check_method_for_perf_regressions(func: Callable) -> Callable:
stdev = statistics.stdev(hist)
logger.debug(f'For {func_name}, performance stdev={stdev}')
slowest = hist[-1]
stdev = statistics.stdev(hist)
logger.debug(f'For {func_name}, performance stdev={stdev}')
slowest = hist[-1]
- logger.debug(
- f'For {func_name}, slowest perf on record is {slowest:f}s'
- )
+ logger.debug(f'For {func_name}, slowest perf on record is {slowest:f}s')
limit = slowest + stdev * 4
limit = slowest + stdev * 4
- logger.debug(
- f'For {func_name}, max acceptable runtime is {limit:f}s'
- )
- logger.debug(
- f'For {func_name}, actual observed runtime was {run_time:f}s'
- )
- if run_time > limit and not config.config['unittests_ignore_perf']:
+ logger.debug(f'For {func_name}, max acceptable runtime is {limit:f}s')
+ logger.debug(f'For {func_name}, actual observed runtime was {run_time:f}s')
+ if run_time > limit:
msg = f'''{func_id} performance has regressed unacceptably.
{slowest:f}s is the slowest runtime on record in {len(hist)} perf samples.
It just ran in {run_time:f}s which is 4+ stdevs slower than the slowest.
msg = f'''{func_id} performance has regressed unacceptably.
{slowest:f}s is the slowest runtime on record in {len(hist)} perf samples.
It just ran in {run_time:f}s which is 4+ stdevs slower than the slowest.
@@
-289,18
+277,21
@@
class RecordStdout(object):
... print("This is a test!")
>>> print({record().readline()})
{'This is a test!\\n'}
... print("This is a test!")
>>> print({record().readline()})
{'This is a test!\\n'}
+ >>> record().close()
"""
def __init__(self) -> None:
self.destination = tempfile.SpooledTemporaryFile(mode='r+')
"""
def __init__(self) -> None:
self.destination = tempfile.SpooledTemporaryFile(mode='r+')
- self.recorder = None
+ self.recorder
: Optional[contextlib.redirect_stdout]
= None
def __enter__(self) -> Callable[[], tempfile.SpooledTemporaryFile]:
self.recorder = contextlib.redirect_stdout(self.destination)
def __enter__(self) -> Callable[[], tempfile.SpooledTemporaryFile]:
self.recorder = contextlib.redirect_stdout(self.destination)
+ assert self.recorder
self.recorder.__enter__()
return lambda: self.destination
self.recorder.__enter__()
return lambda: self.destination
- def __exit__(self, *args) -> bool:
+ def __exit__(self, *args) -> Optional[bool]:
+ assert self.recorder
self.recorder.__exit__(*args)
self.destination.seek(0)
return None
self.recorder.__exit__(*args)
self.destination.seek(0)
return None
@@
-315,18
+306,21
@@
class RecordStderr(object):
... print("This is a test!", file=sys.stderr)
>>> print({record().readline()})
{'This is a test!\\n'}
... print("This is a test!", file=sys.stderr)
>>> print({record().readline()})
{'This is a test!\\n'}
+ >>> record().close()
"""
def __init__(self) -> None:
self.destination = tempfile.SpooledTemporaryFile(mode='r+')
"""
def __init__(self) -> None:
self.destination = tempfile.SpooledTemporaryFile(mode='r+')
- self.recorder = None
+ self.recorder
: Optional[contextlib.redirect_stdout[Any]]
= None
def __enter__(self) -> Callable[[], tempfile.SpooledTemporaryFile]:
def __enter__(self) -> Callable[[], tempfile.SpooledTemporaryFile]:
- self.recorder = contextlib.redirect_stderr(self.destination)
+ self.recorder = contextlib.redirect_stderr(self.destination) # type: ignore
+ assert self.recorder
self.recorder.__enter__()
return lambda: self.destination
self.recorder.__enter__()
return lambda: self.destination
- def __exit__(self, *args) -> bool:
+ def __exit__(self, *args) -> Optional[bool]:
+ assert self.recorder
self.recorder.__exit__(*args)
self.destination.seek(0)
return None
self.recorder.__exit__(*args)
self.destination.seek(0)
return None
@@
-340,7
+334,7
@@
class RecordMultipleStreams(object):
def __init__(self, *files) -> None:
self.files = [*files]
self.destination = tempfile.SpooledTemporaryFile(mode='r+')
def __init__(self, *files) -> None:
self.files = [*files]
self.destination = tempfile.SpooledTemporaryFile(mode='r+')
- self.saved_writes = []
+ self.saved_writes
: List[Callable[..., Any]]
= []
def __enter__(self) -> Callable[[], tempfile.SpooledTemporaryFile]:
for f in self.files:
def __enter__(self) -> Callable[[], tempfile.SpooledTemporaryFile]:
for f in self.files:
@@
-348,10
+342,11
@@
class RecordMultipleStreams(object):
f.write = self.destination.write
return lambda: self.destination
f.write = self.destination.write
return lambda: self.destination
- def __exit__(self, *args) ->
bool
:
+ def __exit__(self, *args) ->
Optional[bool]
:
for f in self.files:
f.write = self.saved_writes.pop()
self.destination.seek(0)
for f in self.files:
f.write = self.saved_writes.pop()
self.destination.seek(0)
+ return None
if __name__ == '__main__':
if __name__ == '__main__':