sflkit 0.5.2__tar.gz → 0.5.4__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 (85) hide show
  1. {sflkit-0.5.2/src/sflkit.egg-info → sflkit-0.5.4}/PKG-INFO +1 -1
  2. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/__init__.py +1 -1
  3. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/factory.py +80 -40
  4. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/vector.py +1 -1
  5. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/meta.py +5 -2
  6. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/model/parallel.py +6 -4
  7. sflkit-0.5.4/src/sflkit/model/scope.py +82 -0
  8. {sflkit-0.5.2 → sflkit-0.5.4/src/sflkit.egg-info}/PKG-INFO +1 -1
  9. sflkit-0.5.4/tests/test_scope.py +43 -0
  10. sflkit-0.5.2/src/sflkit/model/scope.py +0 -39
  11. sflkit-0.5.2/tests/test_scope.py +0 -20
  12. {sflkit-0.5.2 → sflkit-0.5.4}/LICENSE +0 -0
  13. {sflkit-0.5.2 → sflkit-0.5.4}/README.md +0 -0
  14. {sflkit-0.5.2 → sflkit-0.5.4}/pyproject.toml +0 -0
  15. {sflkit-0.5.2 → sflkit-0.5.4}/setup.cfg +0 -0
  16. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/__init__.py +0 -0
  17. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/analysis_type.py +0 -0
  18. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/analyzer.py +0 -0
  19. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/mapping.py +0 -0
  20. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/predicate.py +0 -0
  21. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/similarity.py +0 -0
  22. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/spectra.py +0 -0
  23. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/analysis/suggestion.py +0 -0
  24. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/cli.py +0 -0
  25. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/color.py +0 -0
  26. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/config.py +0 -0
  27. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/evaluation.py +0 -0
  28. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/events/__init__.py +0 -0
  29. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/events/event_file.py +0 -0
  30. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/events/mapping.py +0 -0
  31. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/__init__.py +0 -0
  32. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/handler.py +0 -0
  33. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/features/value.py +0 -0
  34. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/instrumentation/__init__.py +0 -0
  35. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/instrumentation/dir_instrumentation.py +0 -0
  36. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/instrumentation/file_instrumentation.py +0 -0
  37. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/__init__.py +0 -0
  38. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/extract.py +0 -0
  39. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/finder.py +0 -0
  40. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/__init__.py +0 -0
  41. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/extract.py +0 -0
  42. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/factory.py +0 -0
  43. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/finder.py +0 -0
  44. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/java/visitor.py +0 -0
  45. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/language.py +0 -0
  46. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/__init__.py +0 -0
  47. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/extract.py +0 -0
  48. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/factory.py +0 -0
  49. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/finder.py +0 -0
  50. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/python/visitor.py +0 -0
  51. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/language/visitor.py +0 -0
  52. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/logger.py +0 -0
  53. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/model/__init__.py +0 -0
  54. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/model/model.py +0 -0
  55. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/runners/__init__.py +0 -0
  56. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/runners/run.py +0 -0
  57. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/weights/__init__.py +0 -0
  58. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/weights/analyzer.py +0 -0
  59. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit/weights/models.py +0 -0
  60. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/SOURCES.txt +0 -0
  61. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/dependency_links.txt +0 -0
  62. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/entry_points.txt +0 -0
  63. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/requires.txt +0 -0
  64. {sflkit-0.5.2 → sflkit-0.5.4}/src/sflkit.egg-info/top_level.txt +0 -0
  65. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_analysis_objects.py +0 -0
  66. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_analyzer.py +0 -0
  67. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_cli.py +0 -0
  68. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_color.py +0 -0
  69. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_config.py +0 -0
  70. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_coverage.py +0 -0
  71. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_dependency_weights.py +0 -0
  72. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_evaluation.py +0 -0
  73. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_events.py +0 -0
  74. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_execution.py +0 -0
  75. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_features.py +0 -0
  76. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_instrumentation.py +0 -0
  77. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_language.py +0 -0
  78. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_parallelization.py +0 -0
  79. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_predicates.py +0 -0
  80. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_runner.py +0 -0
  81. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_runner_parallel.py +0 -0
  82. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_runner_pytest_versions.py +0 -0
  83. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_spectra.py +0 -0
  84. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_suggestions.py +0 -0
  85. {sflkit-0.5.2 → sflkit-0.5.4}/tests/test_visitors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sflkit
3
- Version: 0.5.2
3
+ Version: 0.5.4
4
4
  Summary: SFLKit: : A Workbench for Statistical Fault Localization
5
5
  Author-email: Marius Smytzek <marius.smytzek@cispa.de>
6
6
  Project-URL: Homepage, https://github.com/smythi93/sflkit/
@@ -6,7 +6,7 @@ from sflkit.config import Config, parse_config
6
6
  from sflkit.instrumentation.dir_instrumentation import DirInstrumentation
7
7
 
8
8
 
9
- __version__ = "0.5.2"
9
+ __version__ = "0.5.4"
10
10
 
11
11
 
12
12
  def instrument_config(conf: Config):
@@ -85,7 +85,7 @@ class LineFactory(AnalysisFactory):
85
85
  if key not in self.objects:
86
86
  self.objects[key] = Line(event)
87
87
  return [self.objects[key]]
88
- return None
88
+ return []
89
89
 
90
90
 
91
91
  class BranchFactory(AnalysisFactory):
@@ -117,7 +117,7 @@ class BranchFactory(AnalysisFactory):
117
117
  return [self.objects[key], self.objects[else_key]]
118
118
  return [self.objects[key]]
119
119
 
120
- return None
120
+ return []
121
121
 
122
122
 
123
123
  class FunctionFactory(AnalysisFactory):
@@ -130,7 +130,7 @@ class FunctionFactory(AnalysisFactory):
130
130
  if key not in self.objects:
131
131
  self.objects[key] = Function(event)
132
132
  return [self.objects[key]]
133
- return None
133
+ return []
134
134
 
135
135
 
136
136
  class LoopFactory(AnalysisFactory):
@@ -170,27 +170,70 @@ class LoopFactory(AnalysisFactory):
170
170
  elif event.event_type == EventType.LOOP_END:
171
171
  return self.objects[key][:]
172
172
  return list()
173
- return None
173
+ return []
174
174
 
175
175
 
176
176
  class DefUseFactory(AnalysisFactory):
177
177
  def __init__(self):
178
178
  super().__init__()
179
179
  self.id_to_def: dict[EventFile, dict[tuple[str, int], DefEvent]] = dict()
180
+ self.def_stack: dict[EventFile, dict[int, dict[tuple[str, int], DefEvent]]] = (
181
+ dict()
182
+ )
180
183
 
181
184
  def reset(self, event_file: EventFile):
182
- with self._lock:
183
- self.id_to_def[event_file] = dict()
185
+ if event_file in self.id_to_def:
186
+ del self.id_to_def[event_file]
187
+ if event_file in self.def_stack:
188
+ del self.def_stack[event_file]
189
+
190
+ def _find_def_event(
191
+ self,
192
+ event_file: EventFile,
193
+ scope_id: int,
194
+ var_name: str,
195
+ var_id: int,
196
+ ) -> DefEvent:
197
+ # Strategy 1: Check in scope
198
+ def_event = None
199
+ if event_file in self.def_stack and scope_id in self.def_stack[event_file]:
200
+ def_event = self.def_stack[event_file][scope_id].get(
201
+ (var_name, var_id), None
202
+ )
203
+
204
+ # Strategy 2: Look up in the global DEF stack (other threads)
205
+ if def_event is None:
206
+ if event_file in self.id_to_def:
207
+ def_event = self.id_to_def[event_file].get((var_name, var_id), None)
208
+
209
+ return def_event
184
210
 
185
211
  def get_analysis(
186
212
  self, event, event_file: EventFile, scope: Scope = None
187
213
  ) -> List[AnalysisObject]:
214
+ thread_id = event.thread_id
215
+ scope_id = scope.id if scope else 0
216
+
188
217
  if event.event_type == EventType.DEF:
189
- with self._lock:
190
- self.id_to_def[event_file][(event.var, event.var_id)] = event
218
+ key = (event.var, event.var_id)
219
+
220
+ # Initialize structures if needed
221
+ if event_file not in self.id_to_def:
222
+ self.id_to_def[event_file] = dict()
223
+ if event_file not in self.def_stack:
224
+ self.def_stack[event_file] = dict()
225
+ if scope_id not in self.def_stack[event_file]:
226
+ self.def_stack[event_file][scope_id] = dict()
227
+
228
+ # Store the DEF event
229
+ self.id_to_def[event_file][key] = event
230
+ self.def_stack[event_file][scope_id][key] = event
231
+
191
232
  elif event.event_type == EventType.USE:
192
- with self._lock:
193
- def_event = self.id_to_def[event_file].get((event.var, event.var_id))
233
+ def_event = self._find_def_event(
234
+ event_file, scope_id, event.var, event.var_id
235
+ )
236
+
194
237
  if def_event:
195
238
  key = (
196
239
  DefUse.analysis_type(),
@@ -204,7 +247,7 @@ class DefUseFactory(AnalysisFactory):
204
247
  if key not in self.objects:
205
248
  self.objects[key] = DefUse(def_event, event)
206
249
  return [self.objects[key]]
207
- return None
250
+ return []
208
251
 
209
252
 
210
253
  class ConditionFactory(AnalysisFactory):
@@ -267,24 +310,23 @@ class ScalarPairFactory(ComparisonFactory):
267
310
  for types in (["int", "float", "bool"], ["str"], ["bytes"]):
268
311
  if event.type_ in types:
269
312
  for variable in variables:
270
- if variable.var != event.var:
271
- if variable.type_ in types:
272
- for comp in self.comparators:
273
- key = (
274
- ScalarPair.analysis_type(),
275
- event.file,
276
- event.line,
277
- event.var,
278
- variable.var,
279
- comp,
280
- types[0],
281
- )
282
- with self._lock:
283
- if key not in self.objects:
284
- self.objects[key] = ScalarPair(
285
- event, comp, variable.var
286
- )
287
- objects.append(self.objects[key])
313
+ if variable.type_ in types:
314
+ for comp in self.comparators:
315
+ key = (
316
+ ScalarPair.analysis_type(),
317
+ event.file,
318
+ event.line,
319
+ event.var,
320
+ variable.var,
321
+ comp,
322
+ types[0],
323
+ )
324
+ with self._lock:
325
+ if key not in self.objects:
326
+ self.objects[key] = ScalarPair(
327
+ event, comp, variable.var
328
+ )
329
+ objects.append(self.objects[key])
288
330
  else:
289
331
  for variable in variables:
290
332
  if variable.type_ == event.type_:
@@ -306,7 +348,7 @@ class ScalarPairFactory(ComparisonFactory):
306
348
  )
307
349
  objects.append(self.objects[key])
308
350
  return objects
309
- return None
351
+ return []
310
352
 
311
353
 
312
354
  class VariableFactory(ComparisonFactory):
@@ -333,7 +375,7 @@ class VariableFactory(ComparisonFactory):
333
375
  self.objects[key] = VariablePredicate(event, comp)
334
376
  objects.append(self.objects[key])
335
377
  return objects
336
- return None
378
+ return []
337
379
 
338
380
 
339
381
  class ReturnFactory(ComparisonFactory):
@@ -403,7 +445,7 @@ class ReturnFactory(ComparisonFactory):
403
445
  )
404
446
  objects.append(self.objects[key])
405
447
  return objects
406
- return None
448
+ return []
407
449
 
408
450
 
409
451
  class ConstantCompFactory(AnalysisFactory):
@@ -430,7 +472,7 @@ class ConstantCompFactory(AnalysisFactory):
430
472
  self.objects[key] = self.class_(event)
431
473
  objects.append(self.objects[key])
432
474
  return objects
433
- return None
475
+ return []
434
476
 
435
477
 
436
478
  class NoneFactory(ConstantCompFactory):
@@ -468,7 +510,7 @@ class PredicateFunctionFactory(AnalysisFactory):
468
510
  # noinspection PyArgumentList
469
511
  self.objects[key] = self.class_(event)
470
512
  return [self.objects[key]]
471
- return None
513
+ return []
472
514
 
473
515
 
474
516
  class IsAsciiFactory(PredicateFunctionFactory):
@@ -519,7 +561,7 @@ class LengthFactory(AnalysisFactory):
519
561
  Length(event, Length.evaluate_length_more)
520
562
  )
521
563
  return self.objects[key][:]
522
- return None
564
+ return []
523
565
 
524
566
 
525
567
  class FunctionErrorFactory(AnalysisFactory):
@@ -531,11 +573,9 @@ class FunctionErrorFactory(AnalysisFactory):
531
573
  self, event, event_file: EventFile, scope: Scope = None
532
574
  ) -> List[AnalysisObject]:
533
575
  if event.event_type == EventType.FUNCTION_ENTER:
534
- with self._lock:
535
- self.function_mapping[event.function_id] = event.line
576
+ self.function_mapping[event.function_id] = event.line
536
577
  if event.event_type in (EventType.FUNCTION_ERROR, EventType.FUNCTION_EXIT):
537
- with self._lock:
538
- line = self.function_mapping.get(event.function_id, event.line)
578
+ line = self.function_mapping.get(event.function_id, event.line)
539
579
  key = (
540
580
  FunctionErrorPredicate.analysis_type(),
541
581
  event.file,
@@ -548,7 +588,7 @@ class FunctionErrorFactory(AnalysisFactory):
548
588
  event.file, line, event.function
549
589
  )
550
590
  return [self.objects[key]]
551
- return None
591
+ return []
552
592
 
553
593
 
554
594
  analysis_factory_mapping = {
@@ -9,7 +9,7 @@ from sflkit.runners.run import TestResult
9
9
  class FeatureVector:
10
10
  def __init__(
11
11
  self,
12
- run_id: EventFile,
12
+ run_id: EventFile | int,
13
13
  result: TestResult,
14
14
  ):
15
15
  self.run_id = run_id
@@ -1,5 +1,6 @@
1
1
  import random
2
2
  from abc import ABC
3
+ from threading import Lock
3
4
  from typing import List, Type, Any
4
5
 
5
6
  from sflkitlib.events.event import Event
@@ -60,10 +61,12 @@ class Injection:
60
61
  class IDGenerator:
61
62
  def __init__(self):
62
63
  self.current_id = 0
64
+ self.lock = Lock()
63
65
 
64
66
  def get_next_id(self):
65
- id_ = self.current_id
66
- self.current_id += 1
67
+ with self.lock:
68
+ id_ = self.current_id
69
+ self.current_id += 1
67
70
  return id_
68
71
 
69
72
 
@@ -42,7 +42,7 @@ class ParallelModel(Model):
42
42
  self.returns[event_file].add(
43
43
  event.function, event.return_value, event.type_
44
44
  )
45
- self.handle_event(event, event_file, self.returns)
45
+ self.handle_event(event, event_file, self.returns[event_file])
46
46
  else:
47
47
  self.returns_map[event_file].setdefault(event.thread_id, Scope()).add(
48
48
  event.function, event.return_value, event.type_
@@ -67,10 +67,10 @@ class ParallelModel(Model):
67
67
  def handle_def_event(self, event: DefEvent, event_file: EventFile):
68
68
  if event.thread_id is None:
69
69
  self.variables[event_file].add(event.var, event.value, event.type_)
70
- self.handle_event(event, event_file, self.variables)
70
+ self.handle_event(event, event_file, self.variables[event_file])
71
71
  else:
72
72
  self.variables_map[event_file].setdefault(
73
- event.thread_id, self.variables
73
+ event.thread_id, self.variables[event_file]
74
74
  ).add(event.var, event.value, event.type_)
75
75
  self.handle_event(
76
76
  event, event_file, self.variables_map[event_file][event.thread_id]
@@ -83,7 +83,9 @@ class ParallelModel(Model):
83
83
  self.handle_event(
84
84
  event,
85
85
  event_file,
86
- self.variables_map[event_file].get(event.thread_id, self.variables),
86
+ self.variables_map[event_file].get(
87
+ event.thread_id, self.variables[event_file]
88
+ ),
87
89
  )
88
90
 
89
91
  def enter_parallel_scope(self, thread_id: int, event_file: EventFile):
@@ -0,0 +1,82 @@
1
+ from threading import Lock
2
+ from typing import List
3
+
4
+
5
+ class Var(object):
6
+ def __init__(self, var, value, type_, id_: int = None):
7
+ self.var = var
8
+ self.value = value
9
+ self.type_ = type_
10
+ self.id = id_ if id_ is not None else hash(self)
11
+
12
+ def __hash__(self):
13
+ return hash(self.var)
14
+
15
+ def __eq__(self, other):
16
+ return isinstance(other, Var) and self.var == other.var
17
+
18
+
19
+ class IDGenerator:
20
+ def __init__(self):
21
+ self.current_id = 0
22
+ self.lock = Lock()
23
+
24
+ def get_next_id(self):
25
+ with self.lock:
26
+ self.current_id += 1
27
+ return self.current_id
28
+
29
+
30
+ class Scope(object):
31
+
32
+ SCOPE_ID = IDGenerator()
33
+
34
+ def __init__(self, parent=None):
35
+ self.parent = parent
36
+ self.variables = dict()
37
+ self.id = Scope.SCOPE_ID.get_next_id()
38
+
39
+ def __hash__(self):
40
+ return hash(self.id)
41
+
42
+ def __eq__(self, other):
43
+ return isinstance(other, Scope) and self.id == other.id
44
+
45
+ def enter(self):
46
+ return Scope(parent=self)
47
+
48
+ def exit(self):
49
+ if self.parent is not None:
50
+ return self.parent
51
+ else:
52
+ return self
53
+
54
+ def __contains__(self, var: str) -> bool:
55
+ current = self
56
+ while current is not None:
57
+ if var in current.variables:
58
+ return True
59
+ current = current.parent
60
+ return False
61
+
62
+ def value(self, var: str) -> Var:
63
+ current = self
64
+ while current is not None:
65
+ if var in current.variables:
66
+ return current.variables[var].value
67
+ current = current.parent
68
+ return None
69
+
70
+ def add(self, var, value, type_, id_: int = None):
71
+ self.variables[var] = Var(var, value, type_, id_)
72
+
73
+ def get_all_vars_dict(self):
74
+ current = self
75
+ variables = dict()
76
+ while current is not None:
77
+ variables = {**current.variables, **variables}
78
+ current = current.parent
79
+ return variables
80
+
81
+ def get_all_vars(self) -> List[Var]:
82
+ return list(self.get_all_vars_dict().values())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sflkit
3
- Version: 0.5.2
3
+ Version: 0.5.4
4
4
  Summary: SFLKit: : A Workbench for Statistical Fault Localization
5
5
  Author-email: Marius Smytzek <marius.smytzek@cispa.de>
6
6
  Project-URL: Homepage, https://github.com/smythi93/sflkit/
@@ -0,0 +1,43 @@
1
+ import unittest
2
+
3
+ from sflkit.model.scope import Var, Scope
4
+
5
+
6
+ class TestScope(unittest.TestCase):
7
+ def test_var_eq(self):
8
+ var_1 = Var("x", 2, int)
9
+ var_2 = Var("y", 2, int)
10
+ var_3 = Var("x", "", str)
11
+ self.assertEqual(var_1, var_3)
12
+ self.assertNotEqual(var_1, var_2)
13
+ self.assertNotEqual(var_2, var_3)
14
+ self.assertEqual(hash(var_1), hash(var_3))
15
+ self.assertNotEqual(hash(var_1), hash(var_2))
16
+ self.assertNotEqual(hash(var_2), hash(var_3))
17
+
18
+ def test_scope_without_parent(self):
19
+ scope = Scope()
20
+ self.assertIs(scope, scope.exit())
21
+
22
+ def test_scope_with_parent(self):
23
+ parent_scope = Scope()
24
+ child_scope = parent_scope.enter()
25
+ self.assertIs(parent_scope, child_scope.exit())
26
+
27
+ def test_scope_contains(self):
28
+ scope = Scope()
29
+ scope.variables["x"] = Var("x", 10, int)
30
+ self.assertIn("x", scope)
31
+ self.assertNotIn("y", scope)
32
+
33
+ def test_scope_all_vars(self):
34
+ parent_scope = Scope()
35
+ parent_scope.variables["x"] = Var("x", 10, int)
36
+ child_scope = parent_scope.enter()
37
+ child_scope.variables["y"] = Var("y", 20, int)
38
+
39
+ all_vars = child_scope.get_all_vars_dict()
40
+ self.assertIn("x", all_vars)
41
+ self.assertIn("y", all_vars)
42
+ self.assertEqual(all_vars["x"].value, 10)
43
+ self.assertEqual(all_vars["y"].value, 20)
@@ -1,39 +0,0 @@
1
- from typing import List
2
-
3
-
4
- class Var(object):
5
- def __init__(self, var, value, type_):
6
- self.var = var
7
- self.value = value
8
- self.type_ = type_
9
-
10
- def __hash__(self):
11
- return hash(self.var)
12
-
13
- def __eq__(self, other):
14
- return isinstance(other, Var) and self.var == other.var
15
-
16
-
17
- class Scope(object):
18
- def __init__(self, parent=None, variables: dict = None):
19
- self.parent = parent
20
- self.variables = dict() if variables is None else variables.copy()
21
-
22
- def enter(self):
23
- return Scope(parent=self, variables=self.variables)
24
-
25
- def exit(self):
26
- if self.parent is not None:
27
- return self.parent
28
- else:
29
- return self
30
-
31
- def value(self, var: str) -> Var:
32
- if var in self.variables:
33
- return self.variables[var].value
34
-
35
- def add(self, var, value, type_):
36
- self.variables[var] = Var(var, value, type_)
37
-
38
- def get_all_vars(self) -> List[Var]:
39
- return list(self.variables.values())
@@ -1,20 +0,0 @@
1
- import unittest
2
-
3
- from sflkit.model.scope import Var, Scope
4
-
5
-
6
- class TestScope(unittest.TestCase):
7
- def test_var_eq(self):
8
- var_1 = Var("x", 2, int)
9
- var_2 = Var("y", 2, int)
10
- var_3 = Var("x", "", str)
11
- self.assertEqual(var_1, var_3)
12
- self.assertNotEqual(var_1, var_2)
13
- self.assertNotEqual(var_2, var_3)
14
- self.assertEqual(hash(var_1), hash(var_3))
15
- self.assertNotEqual(hash(var_1), hash(var_2))
16
- self.assertNotEqual(hash(var_2), hash(var_3))
17
-
18
- def test_scope_without_parent(self):
19
- scope = Scope()
20
- self.assertIs(scope, scope.exit())
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes