Skip to content

Commit ea4f3d6

Browse files
authored
Merge pull request #13 from smythi93/main
0.5.1
2 parents 9d61287 + b573864 commit ea4f3d6

25 files changed

+1353
-599
lines changed

.github/workflows/release.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,30 @@ jobs:
1212
name: Release push
1313
runs-on: ubuntu-latest
1414
steps:
15-
- name: Extract version from pyproject.toml
15+
- uses: actions/checkout@v4
16+
- name: Extract version from __init__.py
1617
id: get_version
1718
run: |
18-
version=$(grep '^version =' pyproject.toml | sed -E "s/version = ['\"]([^'\"]+)['\"]/\\1/")
19+
version=$(grep '__version__' src/sflkit/__init__.py | sed -E 's/^__version__ = "(.+)"$/\1/')
20+
echo "Extracted version: $version"
21+
if [ -z "$version" ]; then
22+
echo "Error: Failed to extract version from __init__.py"
23+
exit 1
24+
fi
1925
echo "version=$version" >> $GITHUB_OUTPUT
2026
- name: Create GitHub release
2127
env:
2228
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
23-
tag: ${{ github.ref_name }}
2429
run: |
25-
gh release create "${{ steps.get_version.outputs.version }}" \
30+
VERSION="${{ steps.get_version.outputs.version }}"
31+
echo "Creating release for version: $VERSION"
32+
if [ -z "$VERSION" ]; then
33+
echo "Error: Version is empty"
34+
exit 1
35+
fi
36+
gh release create "$VERSION" \
2637
--repo="$GITHUB_REPOSITORY" \
27-
--title="${{ steps.get_version.outputs.version }}" \
38+
--title="$VERSION" \
2839
--generate-notes
2940
pypi-publish:
3041
name: Upload release to PyPI

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ classifiers = [
2525
"Topic :: Software Development :: Testing"
2626
]
2727
dependencies = [
28-
"sflkitlib>=0.2.1",
28+
"sflkitlib>=0.2.2",
2929
"numpy>=2.1.3",
3030
"matplotlib>=3.10.0",
3131
"pandas>=2.2.3",

src/sflkit/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from sflkit.instrumentation.dir_instrumentation import DirInstrumentation
77

88

9-
__version__ = "0.5.0"
9+
__version__ = "0.5.1"
1010

1111

1212
def instrument_config(conf: Config):

src/sflkit/analysis/analysis_type.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
import abc
12
import enum
2-
from abc import abstractmethod
3-
from typing import List, Type, Optional
3+
from typing import List, Type, Optional, Any
44

55
from sflkit.events.event_file import EventFile
66
from sflkit.model.scope import Scope
@@ -43,7 +43,7 @@ def __repr__(self):
4343
"""
4444

4545

46-
class AnalysisObject:
46+
class AnalysisObject(abc.ABC):
4747
function_finder = None
4848
loop_finder = None
4949
branch_finder = None
@@ -58,17 +58,17 @@ def set_finder(function_finder, loop_finder, branch_finder):
5858
def __init__(self):
5959
self.suspiciousness: float = 0
6060
self.last_evaluation: EvaluationResult = EvaluationResult.UNOBSERVED
61-
self.hits = dict()
61+
self.hits: dict[EventFile, dict[Optional[int], Any]] = dict()
6262

6363
def adjust_weight(self, event_file: EventFile, weight: float):
6464
pass
6565

66-
@abstractmethod
66+
@abc.abstractmethod
6767
def serialize(self) -> dict:
6868
pass
6969

7070
@staticmethod
71-
@abstractmethod
71+
@abc.abstractmethod
7272
def deserialize(s: dict) -> "AnalysisObject":
7373
pass
7474

@@ -82,7 +82,7 @@ def __str__(self):
8282
return f"{self.analysis_type()}"
8383

8484
@staticmethod
85-
@abstractmethod
85+
@abc.abstractmethod
8686
def analysis_type() -> AnalysisType:
8787
raise NotImplementedError()
8888

@@ -93,19 +93,19 @@ def analyze(self, passed: List, failed: List):
9393
def calculate(self):
9494
pass
9595

96-
@abstractmethod
96+
@abc.abstractmethod
9797
def finalize(self, passed: List, failed: List):
9898
raise NotImplementedError()
9999

100-
@abstractmethod
101-
def hit(self, id_, event, scope_: Scope = None):
100+
@abc.abstractmethod
101+
def hit(self, id_: EventFile, event, scope: Scope = None):
102102
raise NotImplementedError()
103103

104-
@abstractmethod
104+
@abc.abstractmethod
105105
def get_suggestion(self):
106106
raise NotImplementedError()
107107

108-
@abstractmethod
108+
@abc.abstractmethod
109109
def assign_suspiciousness(self):
110110
raise NotImplementedError()
111111

@@ -114,7 +114,7 @@ def handle(event, events: List[Type]):
114114
return any(map(lambda e: isinstance(event, e), events))
115115

116116
@staticmethod
117-
@abstractmethod
117+
@abc.abstractmethod
118118
def events() -> List[Type]:
119119
raise NotImplementedError()
120120

src/sflkit/analysis/analyzer.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import os
3+
from concurrent.futures import ThreadPoolExecutor
34
from typing import List, Callable, Set, Dict, Optional, Any, Type
45

56
from sflkit.analysis.analysis_type import AnalysisType, AnalysisObject
@@ -42,6 +43,7 @@ def __init__(
4243
meta_model: Optional[MetaModel] = None,
4344
model_class: Type[Model] = None,
4445
parallel: bool = False,
46+
workers: int = 4,
4547
):
4648
if (
4749
relevant_event_files is None
@@ -64,6 +66,7 @@ def __init__(
6466
else:
6567
model_class = Model
6668
self.model = model_class(factory)
69+
self.workers = workers
6770
self.paths: Dict[int, os.PathLike] = dict()
6871
self.max_suspiciousness = 0
6972
self.min_suspiciousness = 0
@@ -76,7 +79,7 @@ def _analyze(self, event_file):
7679
self.model.prepare(event_file)
7780
with event_file:
7881
for event in event_file.load():
79-
event.handle(self.model)
82+
event.handle(self.model, event_file)
8083
self.model.follow_up(event_file)
8184

8285
def _finalize(self):
@@ -87,9 +90,16 @@ def _finalize(self):
8790
def analyze(self):
8891
if self.meta:
8992
raise NotImplementedError("Not implemented for meta/loaded analyzer")
90-
for event_file in self.relevant_event_files + self.irrelevant_event_files:
91-
self.paths[event_file.run_id] = event_file.path
92-
self._analyze(event_file)
93+
if self.workers > 1:
94+
event_files = self.relevant_event_files + self.irrelevant_event_files
95+
for event_file in event_files:
96+
self.paths[event_file.run_id] = event_file.path
97+
with ThreadPoolExecutor(max_workers=self.workers) as executor:
98+
list(executor.map(self._analyze, event_files))
99+
else:
100+
for event_file in self.relevant_event_files + self.irrelevant_event_files:
101+
self.paths[event_file.run_id] = event_file.path
102+
self._analyze(event_file)
93103
self._finalize()
94104

95105
def dump(self, path: os.PathLike, indent: Optional[int] = None):

0 commit comments

Comments
 (0)