approval-utilities 14.5.0__tar.gz → 14.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of approval-utilities might be problematic. Click here for more details.
- {approval_utilities-14.5.0/approval_utilities.egg-info → approval_utilities-14.7.1}/PKG-INFO +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/README.md +7 -6
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/approvaltests/core/executable_command.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/approvaltests/core/verifiable.py +1 -0
- approval_utilities-14.7.1/approval_utilities/approvaltests/core/verify_parameters.py +9 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/list_utils.py +3 -3
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/clipboard_utilities.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/deprecated.py +2 -2
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/exceptions/exception_collector.py +5 -5
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/exceptions/exception_utils.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/logger/logging_instance.py +57 -35
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/logger/simple_logger.py +17 -13
- approval_utilities-14.7.1/approval_utilities/utilities/map_reduce.py +17 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/markdown_table.py +10 -3
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/multiline_string_utils.py +2 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/persistence/loader.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/persistence/saver.py +1 -1
- approval_utilities-14.7.1/approval_utilities/utilities/string_wrapper.py +17 -0
- approval_utilities-14.7.1/approval_utilities/utilities/time_utilities.py +28 -0
- approval_utilities-14.7.1/approval_utilities/utilities/wrapper.py +34 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utils.py +9 -7
- {approval_utilities-14.5.0 → approval_utilities-14.7.1/approval_utilities.egg-info}/PKG-INFO +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/setup.py +4 -2
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/setup_utils.py +11 -5
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_approvaltests_temp_dir.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_asserts.py +12 -8
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_build.py +2 -2
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_combinations.py +9 -5
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_compare_file_lists.py +11 -6
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_custom_printers.py +7 -3
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_example_numpy.py +9 -5
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_exception_utils.py +4 -4
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_fileapprover.py +12 -12
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_find_stale_approved_files.py +13 -8
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_inline_approvals.py +24 -36
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_list.py +4 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_multiline_string_utils.py +3 -3
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_namer.py +13 -13
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_options.py +16 -13
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_pairwise_combinations.py +2 -2
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_parse_inputs.py +11 -9
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_python_patterns.py +3 -3
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_scenarios.py +3 -2
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_simple_logger.py +44 -20
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_split_code.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_verify.py +27 -18
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_verify_all.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_verify_argument_parser.py +1 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/tests/test_writer.py +3 -3
- approval_utilities-14.7.1/version.py +1 -0
- approval_utilities-14.5.0/approval_utilities/approvaltests/core/verify_parameters.py +0 -3
- approval_utilities-14.5.0/approval_utilities/utilities/map_reduce.py +0 -6
- approval_utilities-14.5.0/approval_utilities/utilities/string_wrapper.py +0 -12
- approval_utilities-14.5.0/approval_utilities/utilities/time_utilities.py +0 -21
- approval_utilities-14.5.0/approval_utilities/utilities/wrapper.py +0 -27
- approval_utilities-14.5.0/version.py +0 -1
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/LICENSE +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/MANIFEST.in +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/__init__.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/approvaltests/__init__.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/approvaltests/core/__init__.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/py.typed +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/__init__.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/exceptions/__init__.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/exceptions/multiple_exceptions.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/logger/__init__.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/os_utilities.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/persistence/__init__.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/stack_frame_utilities.py +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities.egg-info/SOURCES.txt +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities.egg-info/dependency_links.txt +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities.egg-info/top_level.txt +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/requirements.prod.extras.txt +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/requirements.prod.required.txt +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/requirements.prod.txt +0 -0
- {approval_utilities-14.5.0 → approval_utilities-14.7.1}/setup.cfg +0 -0
|
@@ -85,7 +85,7 @@ golden master.
|
|
|
85
85
|
from approvaltests.approvals import verify
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
def test_simple():
|
|
88
|
+
def test_simple() -> None:
|
|
89
89
|
result = "Hello ApprovalTests"
|
|
90
90
|
verify(result)
|
|
91
91
|
```
|
|
@@ -112,7 +112,7 @@ from approvaltests.approvals import verify
|
|
|
112
112
|
|
|
113
113
|
|
|
114
114
|
class GettingStartedTest(unittest.TestCase):
|
|
115
|
-
def test_simple(self):
|
|
115
|
+
def test_simple(self) -> None:
|
|
116
116
|
verify("Hello ApprovalTests")
|
|
117
117
|
|
|
118
118
|
|
|
@@ -171,7 +171,7 @@ class TestSelectReporterFromClass(unittest.TestCase):
|
|
|
171
171
|
def test_simple(self):
|
|
172
172
|
verify("Hello", options=Options().with_reporter(report_with_beyond_compare()))
|
|
173
173
|
```
|
|
174
|
-
<sup><a href='/tests/samples/test_getting_started.py#
|
|
174
|
+
<sup><a href='/tests/samples/test_getting_started.py#L28-L34' title='Snippet source file'>snippet source</a> | <a href='#snippet-select_reporter_from_class' title='Start of snippet'>anchor</a></sup>
|
|
175
175
|
<!-- endSnippet -->
|
|
176
176
|
|
|
177
177
|
You can also use the `GenericDiffReporterFactory` to find and select the first diff utility that exists on our system.
|
|
@@ -182,6 +182,7 @@ An advantage of this method is you can modify the reporters.json file directly t
|
|
|
182
182
|
<a id='snippet-select_reporter_from_factory'></a>
|
|
183
183
|
```py
|
|
184
184
|
class TestSelectReporter(unittest.TestCase):
|
|
185
|
+
@override
|
|
185
186
|
def setUp(self):
|
|
186
187
|
self.factory = GenericDiffReporterFactory()
|
|
187
188
|
|
|
@@ -190,7 +191,7 @@ class TestSelectReporter(unittest.TestCase):
|
|
|
190
191
|
"Hello", options=Options().with_reporter(self.factory.get("BeyondCompare"))
|
|
191
192
|
)
|
|
192
193
|
```
|
|
193
|
-
<sup><a href='/tests/samples/test_getting_started.py#
|
|
194
|
+
<sup><a href='/tests/samples/test_getting_started.py#L13-L25' title='Snippet source file'>snippet source</a> | <a href='#snippet-select_reporter_from_factory' title='Start of snippet'>anchor</a></sup>
|
|
194
195
|
<!-- endSnippet -->
|
|
195
196
|
|
|
196
197
|
Or you can build your own GenericDiffReporter on the fly
|
|
@@ -207,7 +208,7 @@ class GettingStartedTest(unittest.TestCase):
|
|
|
207
208
|
),
|
|
208
209
|
)
|
|
209
210
|
```
|
|
210
|
-
<sup><a href='/tests/samples/test_getting_started.py#
|
|
211
|
+
<sup><a href='/tests/samples/test_getting_started.py#L37-L48' title='Snippet source file'>snippet source</a> | <a href='#snippet-custom_generic_diff_reporter' title='Start of snippet'>anchor</a></sup>
|
|
211
212
|
<!-- endSnippet -->
|
|
212
213
|
|
|
213
214
|
As long as `C:/my/favorite/diff/utility.exe` can be invoked from the command line using the format `utility.exe file1 file2`
|
|
@@ -315,7 +316,7 @@ The best way to contribute is to [join our weekly mob/ensemble](./docs/Contribut
|
|
|
315
316
|
Pull requests are welcomed, particularly those accompanied by automated tests.
|
|
316
317
|
|
|
317
318
|
To run the self-tests:
|
|
318
|
-
`./
|
|
319
|
+
`./build_and_test.sh`
|
|
319
320
|
|
|
320
321
|
This will run the self-tests on several python versions. We support python 3.8 and above.
|
|
321
322
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import Callable, List, Optional
|
|
1
|
+
from typing import Any, Callable, List, Optional
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
def format_list(alist: List[
|
|
4
|
+
def format_list(alist: List[Any], formatter: Optional[Callable], header: str) -> str:
|
|
5
5
|
if formatter is None:
|
|
6
6
|
formatter = FormatLineItem().print_item
|
|
7
7
|
text = (header + "\n\n") if header else ""
|
|
@@ -14,7 +14,7 @@ class FormatLineItem(object):
|
|
|
14
14
|
def __init__(self) -> None:
|
|
15
15
|
self.index = 0
|
|
16
16
|
|
|
17
|
-
def print_item(self, item:
|
|
17
|
+
def print_item(self, item: Any) -> str:
|
|
18
18
|
text = str(self.index) + ") " + str(item)
|
|
19
19
|
self.index += 1
|
|
20
20
|
return text
|
{approval_utilities-14.5.0 → approval_utilities-14.7.1}/approval_utilities/utilities/deprecated.py
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import warnings
|
|
2
1
|
import functools
|
|
2
|
+
import warnings
|
|
3
3
|
from typing import Callable
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def deprecated(reason: str) -> Callable:
|
|
7
|
-
def decorator(func):
|
|
7
|
+
def decorator(func: Callable) -> Callable:
|
|
8
8
|
"""This is a decorator which can be used to mark functions
|
|
9
9
|
as deprecated. It will result in a warning being emitted
|
|
10
10
|
when the function is used."""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Callable,
|
|
1
|
+
from typing import Any, Callable, List, Sequence
|
|
2
2
|
|
|
3
3
|
from approval_utilities.utilities.exceptions.multiple_exceptions import (
|
|
4
4
|
MultipleExceptions,
|
|
@@ -6,16 +6,16 @@ from approval_utilities.utilities.exceptions.multiple_exceptions import (
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class ExceptionCollector:
|
|
9
|
-
def __init__(self):
|
|
10
|
-
self._exceptions = []
|
|
9
|
+
def __init__(self) -> None:
|
|
10
|
+
self._exceptions: List[Exception] = []
|
|
11
11
|
|
|
12
|
-
def gather(self, code_to_execute: Callable):
|
|
12
|
+
def gather(self, code_to_execute: Callable[[], Any]) -> None:
|
|
13
13
|
try:
|
|
14
14
|
code_to_execute()
|
|
15
15
|
except Exception as exception:
|
|
16
16
|
self._exceptions.append(exception)
|
|
17
17
|
|
|
18
|
-
def release(self):
|
|
18
|
+
def release(self) -> None:
|
|
19
19
|
if len(self._exceptions) == 0:
|
|
20
20
|
return
|
|
21
21
|
if len(self._exceptions) == 1:
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
def to_string(exception:
|
|
1
|
+
def to_string(exception: BaseException) -> str:
|
|
2
2
|
return f"{type(exception).__name__}: {str(exception)}"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import inspect
|
|
3
3
|
import traceback
|
|
4
|
-
from
|
|
5
|
-
|
|
4
|
+
from types import TracebackType
|
|
5
|
+
from typing import Any, Callable, ContextManager, Iterable, Optional, Type, Union
|
|
6
6
|
|
|
7
7
|
from approval_utilities.utilities.exceptions.exception_utils import to_string
|
|
8
|
-
from approval_utilities.utilities.string_wrapper import StringWrapper
|
|
9
8
|
from approval_utilities.utilities.stack_frame_utilities import get_class_name_for_frame
|
|
9
|
+
from approval_utilities.utilities.string_wrapper import StringWrapper
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class Toggles:
|
|
@@ -19,21 +19,21 @@ class Toggles:
|
|
|
19
19
|
self.events = show
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def _is_iterable(arg):
|
|
22
|
+
def _is_iterable(arg: Any) -> bool:
|
|
23
23
|
return isinstance(arg, Iterable) and not isinstance(arg, str)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def print_type(value):
|
|
26
|
+
def print_type(value: Any) -> str:
|
|
27
27
|
return f"<{type(value).__name__}>"
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class LoggingInstance:
|
|
31
|
-
def __init__(self):
|
|
31
|
+
def __init__(self) -> None:
|
|
32
32
|
self.log_stack_traces = True
|
|
33
33
|
self.toggles = Toggles(True)
|
|
34
|
-
self.previous_timestamp = None
|
|
35
|
-
self.logger = lambda t: print(t, end="")
|
|
36
|
-
self.tabbing = 0
|
|
34
|
+
self.previous_timestamp: Optional[datetime.datetime] = None
|
|
35
|
+
self.logger: Callable[[str], None] = lambda t: print(t, end="")
|
|
36
|
+
self.tabbing: int = 0
|
|
37
37
|
self.counter = 0
|
|
38
38
|
self.log_with_timestamps = True
|
|
39
39
|
self.timer: Callable[[], datetime.datetime] = datetime.datetime.now
|
|
@@ -45,53 +45,71 @@ class LoggingInstance:
|
|
|
45
45
|
self.log_stack_traces = False
|
|
46
46
|
return buffer
|
|
47
47
|
|
|
48
|
-
def indent(self) -> ContextManager:
|
|
48
|
+
def indent(self) -> ContextManager[None]:
|
|
49
49
|
class Indent:
|
|
50
|
-
def __init__(self, log):
|
|
50
|
+
def __init__(self, log: "LoggingInstance") -> None:
|
|
51
51
|
self.log = log
|
|
52
52
|
|
|
53
|
-
def __enter__(self):
|
|
53
|
+
def __enter__(self) -> None:
|
|
54
54
|
self.log.tabbing += 1
|
|
55
55
|
|
|
56
|
-
def __exit__(
|
|
56
|
+
def __exit__(
|
|
57
|
+
self,
|
|
58
|
+
exc_type: Optional[Type[BaseException]],
|
|
59
|
+
exc_val: Optional[BaseException],
|
|
60
|
+
exc_tb: Optional[TracebackType],
|
|
61
|
+
) -> None:
|
|
57
62
|
self.log.tabbing -= 1
|
|
58
63
|
|
|
59
64
|
return Indent(self)
|
|
60
65
|
|
|
61
66
|
def use_markers(
|
|
62
|
-
self,
|
|
63
|
-
|
|
67
|
+
self,
|
|
68
|
+
parameter_text: Optional[Union[str, Callable[[], str]]] = None,
|
|
69
|
+
additional_stack: int = 0,
|
|
70
|
+
) -> ContextManager[None]:
|
|
64
71
|
class Nothing:
|
|
65
|
-
def __enter__(self):
|
|
72
|
+
def __enter__(self) -> None:
|
|
66
73
|
pass
|
|
67
74
|
|
|
68
|
-
def __exit__(
|
|
75
|
+
def __exit__(
|
|
76
|
+
self,
|
|
77
|
+
exc_type: Optional[type],
|
|
78
|
+
exc_val: Optional[BaseException],
|
|
79
|
+
exc_tb: Optional[TracebackType],
|
|
80
|
+
) -> None:
|
|
69
81
|
pass
|
|
70
82
|
|
|
71
83
|
if not self.toggles.markers:
|
|
72
84
|
return Nothing()
|
|
73
85
|
|
|
74
86
|
class Markers:
|
|
75
|
-
def __init__(
|
|
87
|
+
def __init__(
|
|
88
|
+
self, log: "LoggingInstance", method_name: str, filename: str
|
|
89
|
+
) -> None:
|
|
76
90
|
self.log = log
|
|
77
91
|
self.method_name = method_name
|
|
78
92
|
self.filename = filename
|
|
79
|
-
self.parameter_text = parameter_text
|
|
80
93
|
|
|
81
|
-
def __enter__(self):
|
|
94
|
+
def __enter__(self) -> None:
|
|
82
95
|
expected = f"-> in: {self.method_name}({self.get_parameters(False)}) in {self.filename}"
|
|
83
96
|
self.log.log_line(expected)
|
|
84
97
|
self.log.tabbing = self.log.tabbing + 1
|
|
85
98
|
|
|
86
|
-
def __exit__(
|
|
99
|
+
def __exit__(
|
|
100
|
+
self,
|
|
101
|
+
exc_type: Optional[type],
|
|
102
|
+
exc_val: Optional[BaseException],
|
|
103
|
+
exc_tb: Optional[TracebackType],
|
|
104
|
+
) -> None:
|
|
87
105
|
self.log.tabbing = self.log.tabbing - 1
|
|
88
106
|
expected = f"<- out: {self.method_name}({self.get_parameters(True)})"
|
|
89
107
|
self.log.log_line(expected)
|
|
90
108
|
|
|
91
|
-
def get_parameters(self, is_exit: bool):
|
|
92
|
-
if
|
|
109
|
+
def get_parameters(self, is_exit: bool) -> str:
|
|
110
|
+
if callable(parameter_text):
|
|
93
111
|
return parameter_text()
|
|
94
|
-
elif
|
|
112
|
+
elif parameter_text is None or is_exit:
|
|
95
113
|
return ""
|
|
96
114
|
else:
|
|
97
115
|
return str(parameter_text)
|
|
@@ -101,9 +119,9 @@ class LoggingInstance:
|
|
|
101
119
|
method_name = stack.function
|
|
102
120
|
|
|
103
121
|
filename = get_class_name_for_frame(stack)
|
|
104
|
-
return Markers(self, method_name, filename
|
|
122
|
+
return Markers(self, method_name, filename)
|
|
105
123
|
|
|
106
|
-
def log_line(self, text: str, use_timestamps=True) -> None:
|
|
124
|
+
def log_line(self, text: str, use_timestamps: bool = True) -> None:
|
|
107
125
|
if self.counter != 0:
|
|
108
126
|
self.logger("\n")
|
|
109
127
|
self.counter = 0
|
|
@@ -152,7 +170,7 @@ class LoggingInstance:
|
|
|
152
170
|
if not self.toggles.variables:
|
|
153
171
|
return
|
|
154
172
|
|
|
155
|
-
def to_type(value: Any, spacing=" ") -> str:
|
|
173
|
+
def to_type(value: Any, spacing: str = " ") -> str:
|
|
156
174
|
return f"{spacing}{print_type(value)}" if show_types else ""
|
|
157
175
|
|
|
158
176
|
if _is_iterable(value):
|
|
@@ -176,12 +194,16 @@ class LoggingInstance:
|
|
|
176
194
|
return
|
|
177
195
|
self.log_line(f"Sql: {query_text}")
|
|
178
196
|
|
|
179
|
-
def message(self, message):
|
|
197
|
+
def message(self, message: str) -> None:
|
|
180
198
|
if not self.toggles.messages:
|
|
181
199
|
return
|
|
182
200
|
self.log_line(f"message: {message}")
|
|
183
201
|
|
|
184
|
-
def warning(
|
|
202
|
+
def warning(
|
|
203
|
+
self,
|
|
204
|
+
text: Union[str, BaseException] = "",
|
|
205
|
+
exception: Optional[BaseException] = None,
|
|
206
|
+
) -> None:
|
|
185
207
|
if isinstance(text, Exception):
|
|
186
208
|
temp = ""
|
|
187
209
|
if exception:
|
|
@@ -206,23 +228,23 @@ class LoggingInstance:
|
|
|
206
228
|
self.log_line(stack_trace, use_timestamps=False)
|
|
207
229
|
self.log_line(warning_stars, use_timestamps=False)
|
|
208
230
|
|
|
209
|
-
def show_queries(self, show):
|
|
231
|
+
def show_queries(self, show: bool) -> None:
|
|
210
232
|
self.toggles.queries = show
|
|
211
233
|
|
|
212
234
|
def show_all(self, show: bool) -> None:
|
|
213
235
|
self.toggles = Toggles(show)
|
|
214
236
|
|
|
215
|
-
def show_messages(self, show):
|
|
237
|
+
def show_messages(self, show: bool) -> None:
|
|
216
238
|
self.toggles.messages = show
|
|
217
239
|
|
|
218
|
-
def show_variables(self, show):
|
|
240
|
+
def show_variables(self, show: bool) -> None:
|
|
219
241
|
self.toggles.variables = show
|
|
220
242
|
|
|
221
|
-
def show_hour_glass(self, show):
|
|
243
|
+
def show_hour_glass(self, show: bool) -> None:
|
|
222
244
|
self.toggles.hour_glass = show
|
|
223
245
|
|
|
224
|
-
def show_markers(self, show):
|
|
246
|
+
def show_markers(self, show: bool) -> None:
|
|
225
247
|
self.toggles.markers = show
|
|
226
248
|
|
|
227
|
-
def show_events(self, show):
|
|
249
|
+
def show_events(self, show: bool) -> None:
|
|
228
250
|
self.toggles.events = show
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import threading
|
|
2
|
-
from typing import Iterator,
|
|
2
|
+
from typing import Any, Callable, ContextManager, Iterator, Optional, Union
|
|
3
3
|
|
|
4
4
|
from approval_utilities.utilities.logger.logging_instance import LoggingInstance
|
|
5
5
|
from approval_utilities.utilities.string_wrapper import StringWrapper
|
|
6
|
-
from approval_utilities.utilities.wrapper import SingleWrapper, ThreadedWrapper
|
|
6
|
+
from approval_utilities.utilities.wrapper import SingleWrapper, ThreadedWrapper, Wrapper
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class SimpleLogger:
|
|
10
|
-
_wrapper = SingleWrapper(LoggingInstance())
|
|
10
|
+
_wrapper: Wrapper[LoggingInstance] = SingleWrapper(LoggingInstance())
|
|
11
11
|
|
|
12
12
|
@staticmethod
|
|
13
13
|
def register_logger(log_method: Callable[[str], None]) -> None:
|
|
14
14
|
SimpleLogger._wrapper.get().logger = log_method
|
|
15
15
|
|
|
16
16
|
@staticmethod
|
|
17
|
-
def log_to_string(log_separate_threads=True) -> StringWrapper:
|
|
17
|
+
def log_to_string(log_separate_threads: bool = True) -> StringWrapper:
|
|
18
18
|
with threading.Lock():
|
|
19
19
|
if log_separate_threads and not isinstance(
|
|
20
20
|
SimpleLogger._wrapper, ThreadedWrapper
|
|
@@ -23,7 +23,9 @@ class SimpleLogger:
|
|
|
23
23
|
return SimpleLogger._wrapper.get().log_to_string()
|
|
24
24
|
|
|
25
25
|
@staticmethod
|
|
26
|
-
def use_markers(
|
|
26
|
+
def use_markers(
|
|
27
|
+
parameter_text: Optional[Union[str, Callable[[], str]]] = None,
|
|
28
|
+
) -> ContextManager[None]:
|
|
27
29
|
return SimpleLogger._wrapper.get().use_markers(
|
|
28
30
|
parameter_text, additional_stack=1
|
|
29
31
|
)
|
|
@@ -53,33 +55,35 @@ class SimpleLogger:
|
|
|
53
55
|
SimpleLogger._wrapper.get().message(message)
|
|
54
56
|
|
|
55
57
|
@staticmethod
|
|
56
|
-
def warning(
|
|
58
|
+
def warning(
|
|
59
|
+
text: Union[str, BaseException] = "", exception: Optional[BaseException] = None
|
|
60
|
+
) -> None:
|
|
57
61
|
SimpleLogger._wrapper.get().warning(text, exception)
|
|
58
62
|
|
|
59
63
|
@staticmethod
|
|
60
|
-
def show_queries(show: bool):
|
|
64
|
+
def show_queries(show: bool) -> None:
|
|
61
65
|
SimpleLogger._wrapper.get().show_queries(show)
|
|
62
66
|
|
|
63
67
|
@staticmethod
|
|
64
|
-
def show_all(show: bool):
|
|
68
|
+
def show_all(show: bool) -> None:
|
|
65
69
|
SimpleLogger._wrapper.get().show_all(show)
|
|
66
70
|
|
|
67
71
|
@staticmethod
|
|
68
|
-
def show_messages(show: bool):
|
|
72
|
+
def show_messages(show: bool) -> None:
|
|
69
73
|
SimpleLogger._wrapper.get().show_messages(show)
|
|
70
74
|
|
|
71
75
|
@staticmethod
|
|
72
|
-
def show_variables(show: bool):
|
|
76
|
+
def show_variables(show: bool) -> None:
|
|
73
77
|
SimpleLogger._wrapper.get().show_variables(show)
|
|
74
78
|
|
|
75
79
|
@staticmethod
|
|
76
|
-
def show_hour_glass(show: bool):
|
|
80
|
+
def show_hour_glass(show: bool) -> None:
|
|
77
81
|
SimpleLogger._wrapper.get().show_hour_glass(show)
|
|
78
82
|
|
|
79
83
|
@staticmethod
|
|
80
|
-
def show_markers(show: bool):
|
|
84
|
+
def show_markers(show: bool) -> None:
|
|
81
85
|
SimpleLogger._wrapper.get().show_markers(show)
|
|
82
86
|
|
|
83
87
|
@staticmethod
|
|
84
|
-
def show_events(show: bool):
|
|
88
|
+
def show_events(show: bool) -> None:
|
|
85
89
|
SimpleLogger._wrapper.get().show_events(show)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
from typing import Any, Callable, Dict, Generator, Sequence
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def first(sequence: Sequence[Any], predicate: Callable[[Any], bool]) -> Any:
|
|
6
|
+
matching = filter(predicate, sequence)
|
|
7
|
+
return next(matching, None)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def product_dict(**kwargs: Sequence[Any]) -> Generator[Dict[str, Any], None, None]:
|
|
11
|
+
"""
|
|
12
|
+
Similar to `itertools.product`, but the resulting combinations retain the names.
|
|
13
|
+
"""
|
|
14
|
+
keys = kwargs.keys()
|
|
15
|
+
vals = kwargs.values()
|
|
16
|
+
for instance in itertools.product(*vals):
|
|
17
|
+
yield dict(zip(keys, instance))
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
from typing import Any, Callable, Iterable
|
|
1
|
+
from typing import TYPE_CHECKING, Any, Callable, Iterable
|
|
2
|
+
|
|
3
|
+
from typing_extensions import override
|
|
2
4
|
|
|
3
5
|
from approval_utilities.approvaltests.core.verifiable import Verifiable
|
|
4
6
|
from approval_utilities.approvaltests.core.verify_parameters import VerifyParameters
|
|
5
7
|
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from approvaltests.core.options import Options
|
|
10
|
+
|
|
6
11
|
|
|
7
12
|
class MarkdownTable(Verifiable):
|
|
8
|
-
def __init__(self):
|
|
9
|
-
self.markdown = ""
|
|
13
|
+
def __init__(self) -> None:
|
|
14
|
+
self.markdown: str = ""
|
|
10
15
|
|
|
16
|
+
@override
|
|
11
17
|
def get_verify_parameters(self, options: "Options") -> VerifyParameters:
|
|
12
18
|
return VerifyParameters(options.for_file.with_extension(".md"))
|
|
13
19
|
|
|
@@ -23,6 +29,7 @@ class MarkdownTable(Verifiable):
|
|
|
23
29
|
self.markdown += MarkdownTable.print_row(*column_names)
|
|
24
30
|
return self
|
|
25
31
|
|
|
32
|
+
@override
|
|
26
33
|
def __str__(self) -> str:
|
|
27
34
|
return self.markdown
|
|
28
35
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import textwrap
|
|
2
|
+
from typing import Optional
|
|
2
3
|
|
|
3
4
|
from approval_utilities.utilities.logger.simple_logger import SimpleLogger
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def remove_indentation_from(text: str) -> str:
|
|
7
|
+
def remove_indentation_from(text: Optional[str]) -> str:
|
|
7
8
|
SimpleLogger.variable("text", text)
|
|
8
9
|
if not text:
|
|
9
10
|
return ""
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing_extensions import override
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class StringWrapper:
|
|
5
|
+
def __init__(self) -> None:
|
|
6
|
+
self.string = ""
|
|
7
|
+
|
|
8
|
+
def append(self, text: str) -> None:
|
|
9
|
+
self.string += text
|
|
10
|
+
|
|
11
|
+
@override
|
|
12
|
+
def __str__(self) -> str:
|
|
13
|
+
return self.string
|
|
14
|
+
|
|
15
|
+
@override
|
|
16
|
+
def __repr__(self) -> str:
|
|
17
|
+
return self.string
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from types import TracebackType
|
|
3
|
+
from typing import Optional, Type
|
|
4
|
+
|
|
5
|
+
from typing_extensions import ContextManager
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def use_utc_timezone() -> ContextManager[None]:
|
|
9
|
+
class TimeZoneSwap:
|
|
10
|
+
def __init__(self) -> None:
|
|
11
|
+
self.timezone: Optional[str] = ""
|
|
12
|
+
|
|
13
|
+
def __enter__(self) -> None:
|
|
14
|
+
self.timezone = os.environ.get("TZ")
|
|
15
|
+
os.environ["TZ"] = "UTC"
|
|
16
|
+
|
|
17
|
+
def __exit__(
|
|
18
|
+
self,
|
|
19
|
+
exc_type: Optional[Type[BaseException]],
|
|
20
|
+
exc_val: Optional[BaseException],
|
|
21
|
+
exc_tb: Optional[TracebackType],
|
|
22
|
+
) -> bool:
|
|
23
|
+
if self.timezone is None:
|
|
24
|
+
os.environ.pop("TZ")
|
|
25
|
+
else:
|
|
26
|
+
os.environ["TZ"] = self.timezone
|
|
27
|
+
|
|
28
|
+
return TimeZoneSwap()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Callable, Generic, TypeVar, cast
|
|
4
|
+
|
|
5
|
+
from typing_extensions import override
|
|
6
|
+
|
|
7
|
+
_T = TypeVar("_T")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Wrapper(ABC, Generic[_T]):
|
|
11
|
+
@abstractmethod
|
|
12
|
+
def get(self) -> _T:
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SingleWrapper(Wrapper[_T]):
|
|
17
|
+
def __init__(self, instance: _T):
|
|
18
|
+
self.instance = instance
|
|
19
|
+
|
|
20
|
+
@override
|
|
21
|
+
def get(self) -> _T:
|
|
22
|
+
return self.instance
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ThreadedWrapper(Wrapper[_T]):
|
|
26
|
+
def __init__(self, generator: Callable[[], _T]):
|
|
27
|
+
self.generator = generator
|
|
28
|
+
self.local = threading.local()
|
|
29
|
+
|
|
30
|
+
@override
|
|
31
|
+
def get(self) -> _T:
|
|
32
|
+
if not hasattr(self.local, "value"):
|
|
33
|
+
self.local.value = self.generator()
|
|
34
|
+
return cast(_T, self.local.value)
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import json
|
|
3
3
|
import os
|
|
4
|
-
|
|
5
4
|
from copy import deepcopy
|
|
6
5
|
from pathlib import Path
|
|
7
|
-
|
|
8
|
-
from typing import Callable, Dict, TypeVar
|
|
6
|
+
from typing import Any, Callable, Dict, Optional, TypeVar
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
def get_adjacent_file(name: str) -> str:
|
|
@@ -14,7 +12,9 @@ def get_adjacent_file(name: str) -> str:
|
|
|
14
12
|
return os.path.join(directory, name)
|
|
15
13
|
|
|
16
14
|
|
|
17
|
-
def write_to_temporary_file(
|
|
15
|
+
def write_to_temporary_file(
|
|
16
|
+
text: str, name: str, file_extention_with_dot: Optional[str] = None
|
|
17
|
+
) -> str:
|
|
18
18
|
import tempfile
|
|
19
19
|
|
|
20
20
|
file_extention_with_dot = file_extention_with_dot or ".txt"
|
|
@@ -25,7 +25,7 @@ def write_to_temporary_file(text: str, name: str, file_extention_with_dot: str =
|
|
|
25
25
|
return temp.name
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
def to_json(object_to_verify) -> str:
|
|
28
|
+
def to_json(object_to_verify: Any) -> str:
|
|
29
29
|
return json.dumps(
|
|
30
30
|
object_to_verify,
|
|
31
31
|
sort_keys=True,
|
|
@@ -78,7 +78,9 @@ def create_directory_if_needed(received_file: str) -> None:
|
|
|
78
78
|
os.makedirs(directory, exist_ok=True)
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
def print_grid(
|
|
81
|
+
def print_grid(
|
|
82
|
+
width: int, height: int, cell_print_func: Callable[[int, int], str]
|
|
83
|
+
) -> str:
|
|
82
84
|
result = ""
|
|
83
85
|
for y in range(height):
|
|
84
86
|
for x in range(width):
|
|
@@ -95,6 +97,6 @@ def filter_values(filter: Callable[[_V], bool], a_dict: Dict[_K, _V]) -> Dict[_K
|
|
|
95
97
|
return {k: v for k, v in a_dict.items() if filter(v)}
|
|
96
98
|
|
|
97
99
|
|
|
98
|
-
def append_to_file(file: Path, text: str):
|
|
100
|
+
def append_to_file(file: Path, text: str) -> None:
|
|
99
101
|
with file.open(mode="a") as f:
|
|
100
102
|
f.write(text)
|