shrinkray 25.12.27.1__tar.gz → 25.12.27.3__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.
Files changed (69) hide show
  1. {shrinkray-25.12.27.1/src/shrinkray.egg-info → shrinkray-25.12.27.3}/PKG-INFO +1 -28
  2. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/README.md +0 -27
  3. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/pyproject.toml +1 -1
  4. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/__main__.py +25 -11
  5. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/bytes.py +8 -7
  6. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/definitions.py +3 -67
  7. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/genericlanguages.py +14 -10
  8. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/json.py +2 -2
  9. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/sat.py +2 -7
  10. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/problem.py +257 -11
  11. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/reducer.py +9 -2
  12. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/state.py +199 -67
  13. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/client.py +2 -0
  14. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/protocol.py +8 -0
  15. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/worker.py +67 -17
  16. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/tui.py +114 -92
  17. shrinkray-25.12.27.3/src/shrinkray/validation.py +403 -0
  18. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3/src/shrinkray.egg-info}/PKG-INFO +1 -28
  19. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/SOURCES.txt +3 -0
  20. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_byte_reduction_passes.py +44 -2
  21. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_definitions.py +2 -2
  22. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_dimacs_cnf.py +1 -1
  23. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_generic_language.py +3 -4
  24. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_json_passes.py +1 -2
  25. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_main.py +40 -35
  26. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_misc_reduction_performance.py +1 -1
  27. shrinkray-25.12.27.3/tests/test_natural_sort_orders.py +547 -0
  28. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_problem.py +10 -17
  29. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_reducer.py +29 -5
  30. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_reduction_passes.py +33 -7
  31. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_sat.py +8 -5
  32. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_state.py +264 -7
  33. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_worker.py +98 -1
  34. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_tui.py +158 -155
  35. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_tui_snapshots.py +108 -0
  36. shrinkray-25.12.27.3/tests/test_validation.py +1131 -0
  37. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/LICENSE +0 -0
  38. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/setup.cfg +0 -0
  39. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/__init__.py +0 -0
  40. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/cli.py +0 -0
  41. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/display.py +0 -0
  42. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/formatting.py +0 -0
  43. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/__init__.py +0 -0
  44. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/clangdelta.py +0 -0
  45. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/patching.py +0 -0
  46. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/python.py +0 -0
  47. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/sequences.py +0 -0
  48. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/process.py +0 -0
  49. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/py.typed +0 -0
  50. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/__init__.py +0 -0
  51. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/ui.py +0 -0
  52. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/work.py +0 -0
  53. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/dependency_links.txt +0 -0
  54. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/entry_points.txt +0 -0
  55. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/requires.txt +0 -0
  56. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/top_level.txt +0 -0
  57. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_clang_delta.py +0 -0
  58. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_cli.py +0 -0
  59. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_display.py +0 -0
  60. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_formatting.py +0 -0
  61. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_generic_shrinking_properties.py +0 -0
  62. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_patching.py +0 -0
  63. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_process.py +0 -0
  64. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_python_reducers.py +0 -0
  65. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_client.py +0 -0
  66. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_integration.py +0 -0
  67. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_protocol.py +0 -0
  68. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_ui.py +0 -0
  69. {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_work.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shrinkray
3
- Version: 25.12.27.1
3
+ Version: 25.12.27.3
4
4
  Summary: Shrink Ray
5
5
  Author-email: "David R. MacIver" <david@drmaciver.com>
6
6
  License: MIT
@@ -159,30 +159,3 @@ not to handle well, but it's easy to extend with additional transformations.
159
159
  It is also fairly easy to add support for new formats as needed.
160
160
 
161
161
  If you run into a test case and interestingness test that you care about that shrink ray handles badly please let me know and I'll likely see about improving its handling of that format.
162
-
163
- ## Parallelism
164
-
165
- You can control the number of parallel tasks shrinkray will run with the `--parallelism` flag. By default this will be the number of CPU cores you have available
166
-
167
- Shrink Ray is designed to be able to run heavily in parallel, with a basic heuristic of aiming to be embarrassingly parallel when making no progress, mostly sequential when making progress, and smoothly scaling in between the two. It mostly succeeds at this.
168
-
169
- Currently the bottleneck on scaling to a very large number of cores is how fast the controlling Python program can generate variant test cases to try and pass them to the interestingness test. This isn't well optimised at present and I don't currently have good benchmarks for it, but I'd expect you to be able to get linear speedups on most workflows while running 10-20 test cases in parallel, and to start to struggle past that.
170
-
171
- This also depends on the performance of the interestingness test - the slower your test is to run, the more you'll be able to scale linearly with the number of cores available.
172
-
173
- I'm quite interested in getting this part to scale well, so please let me know if you find examples where it doesn't seem to work.
174
-
175
- ## Bug Reports
176
-
177
- Shrink Ray is still pretty new and under-tested software, so it definitely has bugs. If you run into any, [please file an issue](https://github.com/DRMacIver/shrinkray/issues).
178
-
179
- As well as obvious bugs (crashes, etc) I'm also very interested in hearing about usability issues and cases where the reduced test case isn't very good.
180
-
181
- Requests for new features, new supported formats, etc. also welcome although I'm less likely to jump right on them.
182
-
183
- ## Sponsorship
184
-
185
- Shrink Ray is something of a labour of love - I wanted to have a tool that actually put into practice many of my ideas about test-case reduction, as I think the previous state of the art was well behind where I'd like it to be.
186
-
187
- That being said, it is first and foremost designed to be a useful tool for practical engineering problems.
188
- If you find it useful as such, please [consider sponsoring my development of it](https://github.com/sponsors/DRMacIver).
@@ -119,30 +119,3 @@ not to handle well, but it's easy to extend with additional transformations.
119
119
  It is also fairly easy to add support for new formats as needed.
120
120
 
121
121
  If you run into a test case and interestingness test that you care about that shrink ray handles badly please let me know and I'll likely see about improving its handling of that format.
122
-
123
- ## Parallelism
124
-
125
- You can control the number of parallel tasks shrinkray will run with the `--parallelism` flag. By default this will be the number of CPU cores you have available
126
-
127
- Shrink Ray is designed to be able to run heavily in parallel, with a basic heuristic of aiming to be embarrassingly parallel when making no progress, mostly sequential when making progress, and smoothly scaling in between the two. It mostly succeeds at this.
128
-
129
- Currently the bottleneck on scaling to a very large number of cores is how fast the controlling Python program can generate variant test cases to try and pass them to the interestingness test. This isn't well optimised at present and I don't currently have good benchmarks for it, but I'd expect you to be able to get linear speedups on most workflows while running 10-20 test cases in parallel, and to start to struggle past that.
130
-
131
- This also depends on the performance of the interestingness test - the slower your test is to run, the more you'll be able to scale linearly with the number of cores available.
132
-
133
- I'm quite interested in getting this part to scale well, so please let me know if you find examples where it doesn't seem to work.
134
-
135
- ## Bug Reports
136
-
137
- Shrink Ray is still pretty new and under-tested software, so it definitely has bugs. If you run into any, [please file an issue](https://github.com/DRMacIver/shrinkray/issues).
138
-
139
- As well as obvious bugs (crashes, etc) I'm also very interested in hearing about usability issues and cases where the reduced test case isn't very good.
140
-
141
- Requests for new features, new supported formats, etc. also welcome although I'm less likely to jump right on them.
142
-
143
- ## Sponsorship
144
-
145
- Shrink Ray is something of a labour of love - I wanted to have a tool that actually put into practice many of my ideas about test-case reduction, as I think the previous state of the art was well behind where I'd like it to be.
146
-
147
- That being said, it is first and foremost designed to be a useful tool for practical engineering problems.
148
- If you find it useful as such, please [consider sponsoring my development of it](https://github.com/sponsors/DRMacIver).
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "shrinkray"
3
- version = "25.12.27.1"
3
+ version = "25.12.27.3"
4
4
  description = "Shrink Ray"
5
5
  authors = [
6
6
  {name = "David R. MacIver", email = "david@drmaciver.com"}
@@ -17,18 +17,19 @@ from shrinkray.cli import (
17
17
  validate_command,
18
18
  validate_ui,
19
19
  )
20
+ from shrinkray.formatting import determine_formatter_command
20
21
  from shrinkray.passes.clangdelta import (
21
22
  C_FILE_EXTENSIONS,
22
23
  ClangDelta,
23
24
  find_clang_delta,
24
25
  )
25
- from shrinkray.problem import InvalidInitialExample
26
26
  from shrinkray.state import (
27
27
  ShrinkRayDirectoryState,
28
28
  ShrinkRayState,
29
29
  ShrinkRayStateSingleFile,
30
30
  )
31
31
  from shrinkray.ui import BasicUI, ShrinkRayUI
32
+ from shrinkray.validation import run_validation
32
33
  from shrinkray.work import Volume
33
34
 
34
35
 
@@ -39,12 +40,9 @@ async def run_shrink_ray(
39
40
  """Run the shrink ray reduction process."""
40
41
  async with trio.open_nursery() as nursery:
41
42
  problem = state.problem
42
- try:
43
- await problem.setup()
44
- except* InvalidInitialExample as excs:
45
- assert len(excs.exceptions) == 1
46
- (e,) = excs.exceptions
47
- await state.report_error(e)
43
+ # Validation runs before run_shrink_ray is called, so setup() should
44
+ # always succeed. If it doesn't, there's a bug and we want it to propagate.
45
+ await problem.setup()
48
46
 
49
47
  reducer = state.reducer
50
48
 
@@ -273,6 +271,26 @@ def main(
273
271
  if not backup:
274
272
  backup = filename + os.extsep + "bak"
275
273
 
274
+ # Run initial validation before any state setup
275
+ # This validates the interestingness test and formatter with proper output streaming
276
+ formatter_command = None
277
+ if not os.path.isdir(filename) and formatter.lower() != "none":
278
+ formatter_command = determine_formatter_command(formatter, filename)
279
+
280
+ validation_result = run_validation(
281
+ file_path=filename,
282
+ test=test,
283
+ input_type=input_type,
284
+ in_place=in_place,
285
+ formatter_command=formatter_command,
286
+ )
287
+
288
+ if not validation_result.success:
289
+ print(f"\nError: {validation_result.error_message}", file=sys.stderr)
290
+ sys.exit(1)
291
+
292
+ print("\nStarting reduction...", file=sys.stderr, flush=True)
293
+
276
294
  state_kwargs: dict[str, Any] = {
277
295
  "input_type": input_type,
278
296
  "in_place": in_place,
@@ -307,8 +325,6 @@ def main(
307
325
 
308
326
  state = ShrinkRayDirectoryState(initial=initial, **state_kwargs)
309
327
 
310
- trio.run(state.check_formatter)
311
-
312
328
  else:
313
329
  try:
314
330
  os.remove(backup)
@@ -323,8 +339,6 @@ def main(
323
339
 
324
340
  state = ShrinkRayStateSingleFile(initial=initial, **state_kwargs)
325
341
 
326
- trio.run(state.check_formatter)
327
-
328
342
  if ui_type == UIType.textual:
329
343
  from shrinkray.tui import run_textual_ui
330
344
 
@@ -24,8 +24,8 @@ from collections.abc import Sequence
24
24
 
25
25
  from attrs import define
26
26
 
27
- from shrinkray.passes.definitions import Format, ReductionProblem
28
27
  from shrinkray.passes.patching import Cuts, Patches, apply_patches
28
+ from shrinkray.problem import Format, ReductionProblem
29
29
 
30
30
 
31
31
  @define(frozen=True)
@@ -739,12 +739,13 @@ async def line_sorter(problem: ReductionProblem[bytes]):
739
739
  while i < len(lines):
740
740
  j = i
741
741
  while j > 0:
742
- u = lines[j - 1]
743
- v = lines[j]
744
- if v + u < u + v:
745
- attempt = list(lines)
746
- attempt[j - 1], attempt[j] = attempt[j], attempt[j - 1]
747
- if not await problem.is_interesting(b"\n".join(attempt)):
742
+ attempt = list(lines)
743
+ attempt[j - 1], attempt[j] = attempt[j], attempt[j - 1]
744
+ new_test_case = b"\n".join(attempt)
745
+ if problem.sort_key(new_test_case) < problem.sort_key(
746
+ problem.current_test_case
747
+ ):
748
+ if not await problem.is_interesting(new_test_case):
748
749
  break
749
750
  else:
750
751
  j -= 1
@@ -4,20 +4,20 @@ This module defines the core type aliases and abstractions for reduction:
4
4
 
5
5
  - ReductionPass[T]: A function that attempts to reduce a test case
6
6
  - ReductionPump[T]: A function that may temporarily increase test case size
7
- - Format[S, T]: A bidirectional transformation between types
8
7
  - compose(): Combines a Format with a pass to work on a different type
9
8
 
10
9
  These abstractions enable format-agnostic reduction: the same pass
11
10
  (e.g., "delete duplicate elements") can work on bytes, lines, tokens,
12
11
  JSON arrays, or any other sequence-like type.
12
+
13
+ Note: Format, ParseError, and DumpError are defined in shrinkray.problem.
13
14
  """
14
15
 
15
- from abc import ABC, abstractmethod
16
16
  from collections.abc import Awaitable, Callable
17
17
  from functools import wraps
18
18
  from typing import TypeVar
19
19
 
20
- from shrinkray.problem import ReductionProblem
20
+ from shrinkray.problem import Format, ParseError, ReductionProblem
21
21
 
22
22
 
23
23
  S = TypeVar("S")
@@ -36,70 +36,6 @@ ReductionPass = Callable[[ReductionProblem[T]], Awaitable[None]]
36
36
  ReductionPump = Callable[[ReductionProblem[T]], Awaitable[T]]
37
37
 
38
38
 
39
- class ParseError(Exception):
40
- """Raised when a Format cannot parse its input."""
41
-
42
- pass
43
-
44
-
45
- class DumpError(Exception):
46
- """Raised when a Format cannot serialize its output.
47
-
48
- This occurs because not all internal representations map to valid
49
- output in the target format. For example, a reduction might create
50
- an invalid AST structure that cannot be converted back to source code.
51
- """
52
-
53
- pass
54
-
55
-
56
- class Format[S, T](ABC):
57
- """A bidirectional transformation between two types.
58
-
59
- Formats enable format-agnostic passes by abstracting the
60
- parse/serialize cycle. For example:
61
-
62
- - Split(b"\\n"): bytes <-> list[bytes] (lines)
63
- - Tokenize(): bytes <-> list[bytes] (tokens)
64
- - JSON: bytes <-> Any (Python objects)
65
- - DimacsCNF: bytes <-> list[list[int]] (SAT clauses)
66
-
67
- A Format must satisfy the round-trip property:
68
- dumps(parse(x)) should be equivalent to x
69
- (possibly with normalization)
70
-
71
- Example usage:
72
- # Delete duplicate lines
73
- compose(Split(b"\\n"), delete_duplicates)
74
-
75
- # Reduce integer literals in source code
76
- compose(IntegerFormat(), reduce_integer)
77
- """
78
-
79
- @property
80
- def name(self) -> str:
81
- """Human-readable name for this format, used in pass names."""
82
- return repr(self)
83
-
84
- @abstractmethod
85
- def parse(self, input: S) -> T:
86
- """Parse input into the target type. Raises ParseError on failure."""
87
- ...
88
-
89
- def is_valid(self, input: S) -> bool:
90
- """Check if input can be parsed by this format."""
91
- try:
92
- self.parse(input)
93
- return True
94
- except ParseError:
95
- return False
96
-
97
- @abstractmethod
98
- def dumps(self, input: T) -> S:
99
- """Serialize the target type back to the source type."""
100
- ...
101
-
102
-
103
39
  def compose(format: Format[S, T], reduction_pass: ReductionPass[T]) -> ReductionPass[S]:
104
40
  """Wrap a reduction pass to work through a Format transformation.
105
41
 
@@ -3,7 +3,7 @@ Module of reduction passes designed for "things that look like programming langu
3
3
  """
4
4
 
5
5
  import re
6
- from collections.abc import Callable, Sized
6
+ from collections.abc import Callable
7
7
  from functools import wraps
8
8
  from string import ascii_lowercase, ascii_uppercase
9
9
  from typing import AnyStr
@@ -12,9 +12,15 @@ import trio
12
12
  from attr import define
13
13
 
14
14
  from shrinkray.passes.bytes import ByteReplacement, delete_intervals
15
- from shrinkray.passes.definitions import Format, ParseError, ReductionPass
15
+ from shrinkray.passes.definitions import ReductionPass
16
16
  from shrinkray.passes.patching import PatchApplier, Patches, apply_patches
17
- from shrinkray.problem import BasicReductionProblem, ReductionProblem
17
+ from shrinkray.problem import (
18
+ BasicReductionProblem,
19
+ Format,
20
+ ParseError,
21
+ ReductionProblem,
22
+ sort_key_for_initial,
23
+ )
18
24
  from shrinkray.work import NotFound
19
25
 
20
26
 
@@ -240,10 +246,6 @@ async def simplify_brackets(problem: ReductionProblem[bytes]) -> None:
240
246
  IDENTIFIER = re.compile(rb"(\b[A-Za-z][A-Za-z0-9_]*\b)|([0-9]+)")
241
247
 
242
248
 
243
- def shortlex[T: Sized](s: T) -> tuple[int, T]:
244
- return (len(s), s)
245
-
246
-
247
249
  async def normalize_identifiers(problem: ReductionProblem[bytes]) -> None:
248
250
  """Replace identifiers with shorter alternatives.
249
251
 
@@ -261,8 +263,10 @@ async def normalize_identifiers(problem: ReductionProblem[bytes]) -> None:
261
263
  replacements.add(c)
262
264
  break
263
265
 
264
- replacements = sorted(replacements, key=shortlex)
265
- targets = sorted(identifiers, key=shortlex, reverse=True)
266
+ sort_key = sort_key_for_initial(problem.current_test_case)
267
+
268
+ replacements = sorted(replacements, key=sort_key)
269
+ targets = sorted(identifiers, key=sort_key, reverse=True)
266
270
 
267
271
  # TODO: This could use better parallelisation.
268
272
  for t in targets:
@@ -272,7 +276,7 @@ async def normalize_identifiers(problem: ReductionProblem[bytes]) -> None:
272
276
  continue
273
277
 
274
278
  async def can_replace(r):
275
- if shortlex(r) >= shortlex(t):
279
+ if sort_key(r) >= sort_key(t):
276
280
  return False
277
281
  attempt = pattern.sub(r, source)
278
282
  assert attempt != source
@@ -4,9 +4,9 @@ from typing import Any
4
4
 
5
5
  from attrs import define
6
6
 
7
- from shrinkray.passes.definitions import Format, ParseError, ReductionPass
7
+ from shrinkray.passes.definitions import ReductionPass
8
8
  from shrinkray.passes.patching import Patches, apply_patches
9
- from shrinkray.problem import ReductionProblem
9
+ from shrinkray.problem import Format, ParseError, ReductionProblem
10
10
 
11
11
 
12
12
  def is_json(s: bytes) -> bool:
@@ -1,15 +1,10 @@
1
1
  from collections import Counter, defaultdict
2
2
  from collections.abc import Callable, Iterable, Iterator
3
3
 
4
- from shrinkray.passes.definitions import (
5
- DumpError,
6
- Format,
7
- ParseError,
8
- ReductionPass,
9
- )
4
+ from shrinkray.passes.definitions import ReductionPass
10
5
  from shrinkray.passes.patching import Conflict, SetPatches, apply_patches
11
6
  from shrinkray.passes.sequences import delete_elements
12
- from shrinkray.problem import ReductionProblem
7
+ from shrinkray.problem import DumpError, Format, ParseError, ReductionProblem
13
8
 
14
9
 
15
10
  Clause = list[int]