approval-utilities 14.5.0__tar.gz → 14.6.0__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.

Files changed (76) hide show
  1. {approval_utilities-14.5.0/approval_utilities.egg-info → approval_utilities-14.6.0}/PKG-INFO +1 -1
  2. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/README.md +7 -6
  3. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/approvaltests/core/executable_command.py +1 -1
  4. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/approvaltests/core/verifiable.py +1 -0
  5. approval_utilities-14.6.0/approval_utilities/approvaltests/core/verify_parameters.py +9 -0
  6. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/list_utils.py +3 -3
  7. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/clipboard_utilities.py +1 -1
  8. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/deprecated.py +2 -2
  9. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/exceptions/exception_collector.py +5 -5
  10. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/exceptions/exception_utils.py +1 -1
  11. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/logger/logging_instance.py +57 -35
  12. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/logger/simple_logger.py +17 -13
  13. approval_utilities-14.6.0/approval_utilities/utilities/map_reduce.py +17 -0
  14. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/markdown_table.py +10 -3
  15. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/multiline_string_utils.py +2 -1
  16. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/persistence/loader.py +1 -1
  17. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/persistence/saver.py +1 -1
  18. approval_utilities-14.6.0/approval_utilities/utilities/string_wrapper.py +17 -0
  19. approval_utilities-14.6.0/approval_utilities/utilities/time_utilities.py +28 -0
  20. approval_utilities-14.6.0/approval_utilities/utilities/wrapper.py +34 -0
  21. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utils.py +9 -7
  22. {approval_utilities-14.5.0 → approval_utilities-14.6.0/approval_utilities.egg-info}/PKG-INFO +1 -1
  23. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/setup.py +4 -2
  24. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/setup_utils.py +11 -5
  25. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_approvaltests_temp_dir.py +1 -1
  26. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_asserts.py +12 -8
  27. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_build.py +2 -2
  28. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_combinations.py +9 -5
  29. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_compare_file_lists.py +11 -6
  30. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_custom_printers.py +7 -3
  31. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_example_numpy.py +9 -5
  32. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_exception_utils.py +4 -4
  33. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_fileapprover.py +12 -12
  34. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_find_stale_approved_files.py +13 -8
  35. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_inline_approvals.py +24 -36
  36. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_list.py +4 -1
  37. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_multiline_string_utils.py +3 -3
  38. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_namer.py +13 -13
  39. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_options.py +16 -13
  40. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_pairwise_combinations.py +2 -2
  41. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_parse_inputs.py +11 -9
  42. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_python_patterns.py +3 -3
  43. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_scenarios.py +3 -2
  44. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_simple_logger.py +44 -20
  45. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_split_code.py +1 -1
  46. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_verify.py +27 -18
  47. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_verify_all.py +1 -1
  48. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_verify_argument_parser.py +1 -1
  49. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/tests/test_writer.py +3 -3
  50. approval_utilities-14.6.0/version.py +1 -0
  51. approval_utilities-14.5.0/approval_utilities/approvaltests/core/verify_parameters.py +0 -3
  52. approval_utilities-14.5.0/approval_utilities/utilities/map_reduce.py +0 -6
  53. approval_utilities-14.5.0/approval_utilities/utilities/string_wrapper.py +0 -12
  54. approval_utilities-14.5.0/approval_utilities/utilities/time_utilities.py +0 -21
  55. approval_utilities-14.5.0/approval_utilities/utilities/wrapper.py +0 -27
  56. approval_utilities-14.5.0/version.py +0 -1
  57. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/LICENSE +0 -0
  58. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/MANIFEST.in +0 -0
  59. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/__init__.py +0 -0
  60. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/approvaltests/__init__.py +0 -0
  61. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/approvaltests/core/__init__.py +0 -0
  62. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/py.typed +0 -0
  63. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/__init__.py +0 -0
  64. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/exceptions/__init__.py +0 -0
  65. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/exceptions/multiple_exceptions.py +0 -0
  66. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/logger/__init__.py +0 -0
  67. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/os_utilities.py +0 -0
  68. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/persistence/__init__.py +0 -0
  69. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities/utilities/stack_frame_utilities.py +0 -0
  70. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities.egg-info/SOURCES.txt +0 -0
  71. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities.egg-info/dependency_links.txt +0 -0
  72. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/approval_utilities.egg-info/top_level.txt +0 -0
  73. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/requirements.prod.extras.txt +0 -0
  74. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/requirements.prod.required.txt +0 -0
  75. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/requirements.prod.txt +0 -0
  76. {approval_utilities-14.5.0 → approval_utilities-14.6.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: approval_utilities
3
- Version: 14.5.0
3
+ Version: 14.6.0
4
4
  Summary: Utilities for your production code that work well with approvaltests
5
5
  Home-page: https://github.com/approvals/ApprovalTests.Python
6
6
  Author: ApprovalTests Contributors
@@ -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#L25-L31' title='Snippet source file'>snippet source</a> | <a href='#snippet-select_reporter_from_class' title='Start of snippet'>anchor</a></sup>
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#L11-L22' title='Snippet source file'>snippet source</a> | <a href='#snippet-select_reporter_from_factory' title='Start of snippet'>anchor</a></sup>
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#L34-L45' title='Snippet source file'>snippet source</a> | <a href='#snippet-custom_generic_diff_reporter' title='Start of snippet'>anchor</a></sup>
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
- `./run_tests.sh`
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,4 +1,4 @@
1
- from abc import abstractmethod, ABC
1
+ from abc import ABC, abstractmethod
2
2
 
3
3
 
4
4
  class CommandGetter(ABC):
@@ -1,6 +1,7 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
3
  from approval_utilities.approvaltests.core.verify_parameters import VerifyParameters
4
+ from approvaltests.core.options import Options
4
5
 
5
6
 
6
7
  class Verifiable(ABC):
@@ -0,0 +1,9 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ if TYPE_CHECKING:
4
+ from approvaltests.core.options import Options
5
+
6
+
7
+ class VerifyParameters:
8
+ def __init__(self, options: "Options"):
9
+ self.options = options
@@ -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[str], formatter: Optional[Callable], header: str) -> str:
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: str) -> str:
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
@@ -1,4 +1,4 @@
1
- def copy_to_clipboard(text):
1
+ def copy_to_clipboard(text: str) -> None:
2
2
  """
3
3
  This acts as a wrapper to defer the importing of pyperclip util actual usage
4
4
  """
@@ -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, Sequence, Any
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: Exception) -> str:
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 typing import Callable, Any, Iterable, ContextManager
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__(self, exc_type, exc_val, exc_tb):
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, parameter_text: [str, Callable[[], str]] = None, additional_stack: int = 0
63
- ) -> ContextManager:
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__(self, exc_type, exc_val, exc_tb):
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__(self, log, method_name, filename, parameter_text):
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__(self, exc_type, exc_val, exc_tb):
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 isinstance(self.parameter_text, Callable):
109
+ def get_parameters(self, is_exit: bool) -> str:
110
+ if callable(parameter_text):
93
111
  return parameter_text()
94
- elif self.parameter_text is None or is_exit:
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, parameter_text)
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(self, text: str = "", exception: BaseException = None) -> None:
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, Any, Callable
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(parameter_text: [str, Callable[[], str]] = None) -> Iterator[None]:
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(text: str = "", exception: BaseException = None) -> None:
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 ""
@@ -1,5 +1,5 @@
1
1
  from abc import abstractmethod
2
- from typing import TypeVar, Generic
2
+ from typing import Generic, TypeVar
3
3
 
4
4
  T = TypeVar("T")
5
5
 
@@ -1,5 +1,5 @@
1
1
  from abc import abstractmethod
2
- from typing import TypeVar, Generic
2
+ from typing import Generic, TypeVar
3
3
 
4
4
  T = TypeVar("T")
5
5
 
@@ -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(text: str, name: str, file_extention_with_dot: str = None):
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(width, height, cell_print_func):
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)