Skip to content

Commit ccfe2ef

Browse files
author
FusionSolutions
committed
Revert "upload"
This reverts commit fe1defb.
1 parent fe1defb commit ccfe2ef

File tree

9 files changed

+82
-111
lines changed

9 files changed

+82
-111
lines changed

.github/workflows/python-package.yml

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,14 @@ jobs:
2323
- name: Install dependencies
2424
run: |
2525
python -m pip install --upgrade pip
26-
python -m pip install mypy pyflakes
26+
python -m pip install mypy
2727
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
2828
- name: MyPy check
2929
run: |
30-
mypy --strict fsSignal
31-
- name: PyFlakes check
32-
run: |
33-
pyflakes fsSignal
30+
mypy fsSignal
3431
- name: Install package
3532
run: |
3633
python setup.py install
37-
- name: Test package
34+
- name: Unittest
3835
run: |
39-
python setup.py test
36+
python -m fsSignal

.github/workflows/python-publish.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
- name: Install dependencies
2727
run: |
2828
python -m pip install --upgrade pip
29+
python -m fsSignal
2930
pip install build
3031
- name: Build package
3132
run: python -m build

fsSignal/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.0.4"
1+
__version__ = "0.0.3"
22
__doc__ = """
33
Signal capturer v{}
44
Copyright (C) 2021 Fusion Solutions KFT <contact@fusionsolutions.io>

fsSignal/__main__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Builtin modules
2+
import unittest
3+
# Local modules
4+
from .fsSignal import SignalTest
5+
# Program
6+
unittest.main(verbosity=2)

fsSignal/fsSignal.py

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,24 @@
11
# Builtin modules
22
from __future__ import annotations
3-
import traceback, signal as _signal
4-
from threading import Event
3+
import os, traceback, unittest, signal as _signal
4+
from threading import Timer, Event
55
from time import monotonic, sleep
66
from typing import Callable, Dict, Any, Iterator, Iterable, Optional, Union
7-
from types import FrameType
8-
# Third party modules
97
# Local modules
108
# Program
11-
Signals = _signal.Signals
12-
139
class KillSignal(Exception): pass
1410

15-
class SignalIterator(Iterator[Any]):
11+
class SignalIterator(Iterator):
1612
__slots__ = ("event", "it", "checkDelay", "lastCheck")
17-
event:Event
18-
it:Iterator[Any]
19-
checkDelay:float
20-
lastCheck:float
21-
def __init__(self, event:Event, it:Iterable[Any], checkDelay:float=1.0):
22-
self.event = event
23-
self.it = it.__iter__()
24-
self.checkDelay = checkDelay
25-
self.lastCheck = monotonic()
26-
def __iter__(self) -> Iterator[Any]:
13+
def __init__(self, event:Event, it:Iterable, checkDelay:float=1.0):
14+
self.event:Event = event
15+
self.it:Iterator = it.__iter__()
16+
self.checkDelay:float = checkDelay
17+
self.lastCheck:float = monotonic()
18+
def __iter__(self) -> Iterator:
2719
return self
2820
def __next__(self) -> Any:
29-
m = monotonic()
21+
m:float = monotonic()
3022
if m-self.lastCheck > self.checkDelay:
3123
self.lastCheck = m
3224
if self.event.is_set():
@@ -36,16 +28,11 @@ def __next__(self) -> Any:
3628
class BaseSignal:
3729
_force:bool
3830
@classmethod
39-
def get(self) -> bool:
31+
def check(self) -> bool:
4032
if not isinstance(Signal._handler, Signal):
4133
return False
4234
return Signal._handler._check(self._force)
4335
@classmethod
44-
def check(self) -> None:
45-
if not isinstance(Signal._handler, Signal):
46-
return
47-
return Signal._handler.get(self._force)
48-
@classmethod
4936
def checkSoft(self) -> bool:
5037
if not isinstance(Signal._handler, Signal):
5138
return False
@@ -61,15 +48,15 @@ def sleep(self, seconds:Union[int, float], raiseOnKill:bool=False) -> None:
6148
return sleep(seconds)
6249
return Signal._handler._sleep(seconds, raiseOnKill, self._force)
6350
@classmethod
64-
def signalSoftKill(self, *args:Any, **kwargs:Any) -> None:
51+
def signalSoftKill(self, *args, **kwargs) -> None:
6552
if isinstance(Signal._handler, Signal):
6653
return Signal._handler._signalSoftKill(*args, **kwargs)
6754
@classmethod
68-
def signalHardKill(self, *args:Any, **kwargs:Any) -> None:
55+
def signalHardKill(self, *args, **kwargs) -> None:
6956
if isinstance(Signal._handler, Signal):
7057
return Signal._handler._signalHardKill(*args, **kwargs)
7158
@classmethod
72-
def iter(self, it:Iterable[Any], checkDelay:float=1.0) -> Iterable[Any]:
59+
def iter(self, it:Iterable, checkDelay:float=1.0) -> Iterable:
7360
if not isinstance(Signal._handler, Signal):
7461
return it
7562
return Signal._handler._iter(it, checkDelay, self._force)
@@ -102,22 +89,16 @@ class HardSignal(BaseSignal):
10289
_force:bool = True
10390

10491
class Signal(HardSignal):
105-
_handler:Optional[Signal] = None
106-
softKillFn:Optional[Callable[[Signals, FrameType], Any]]
107-
hardKillFn:Optional[Callable[[Signals, FrameType], Any]]
108-
forceKillCounterFn:Optional[Callable[[int, int], Any]]
109-
counter:int
110-
forceCounter:int
11192
eSoft:Event
11293
eHard:Event
113-
def __init__(self, softKillFn:Optional[Callable[[Signals, FrameType], Any]]=None,
114-
hardKillFn:Optional[Callable[[Signals, FrameType], Any]]=None,
115-
forceKillCounterFn:Optional[Callable[[int, int], Any]]=None, forceCounter:int=10):
116-
self.softKillFn = softKillFn
117-
self.hardKillFn = hardKillFn
118-
self.forceKillCounterFn = forceKillCounterFn
119-
self.counter = 0
120-
self.forceCounter = forceCounter
94+
_handler:Optional[Signal] = None
95+
def __init__(self, softKillFn:Optional[Callable]=None, hardKillFn:Optional[Callable]=None,
96+
forceKillCounterFn:Optional[Callable]=None, forceCounter:int=10):
97+
self.softKillFn:Optional[Callable] = softKillFn
98+
self.hardKillFn:Optional[Callable] = hardKillFn
99+
self.forceKillCounterFn:Optional[Callable] = forceKillCounterFn
100+
self.counter:int = 0
101+
self.forceCounter:int = forceCounter
121102
self.eSoft = Event()
122103
self.eHard = Event()
123104
Signal._handler = self
@@ -142,21 +123,16 @@ def __setstate__(self, states:Dict[str, Any]) -> None:
142123
def _activate(self) -> None:
143124
_signal.signal(_signal.SIGINT, Signal.signalSoftKill)
144125
_signal.signal(_signal.SIGTERM, Signal.signalHardKill)
145-
def _get(self, force:bool=True) -> bool:
126+
def _check(self, force:bool=True) -> bool:
146127
if force:
147128
return self.eHard.is_set()
148129
return self.eSoft.is_set()
149-
def _check(self, force:bool=True) -> None:
150-
if (force and self.eHard.is_set()) or (not force and self.eSoft.is_set()):
151-
raise KillSignal
152-
return None
153130
def _sleep(self, seconds:Union[int, float], raiseOnKill:bool=False, force:bool=True) -> None:
154131
if (self.eHard if force else self.eSoft).wait(float(seconds)) and raiseOnKill:
155132
raise KillSignal
156-
return None
157-
def _iter(self, it:Iterable[Any], checkDelay:float=1.0, force:bool=True) -> Iterator[Any]:
133+
def _iter(self, it:Iterable, checkDelay:float=1.0, force:bool=True) -> Iterator:
158134
return SignalIterator(self.eHard if force else self.eSoft, it, checkDelay)
159-
def _signalSoftKill(self, *args:Any, **kwargs:Any) -> None:
135+
def _signalSoftKill(self, *args, **kwargs) -> None:
160136
self._softKill()
161137
if not self.eHard.is_set():
162138
self.counter += 1
@@ -167,26 +143,67 @@ def _signalSoftKill(self, *args:Any, **kwargs:Any) -> None:
167143
traceback.print_exc()
168144
if self.counter >= self.forceCounter:
169145
self._hardKill()
170-
def _signalHardKill(self, *args:Any, **kwargs:Any) -> None:
146+
def _signalHardKill(self, *args, **kwargs) -> None:
171147
self._softKill()
172148
self._hardKill()
173149
def _softKill(self) -> None:
174150
if not self.eSoft.is_set():
175151
self.eSoft.set()
176152
if callable(self.softKillFn):
177153
try:
178-
self.softKillFn() # type: ignore
154+
self.softKillFn()
179155
except:
180156
traceback.print_exc()
181157
def _hardKill(self) -> None:
182158
if not self.eHard.is_set():
183159
self.eHard.set()
184160
if callable(self.hardKillFn):
185161
try:
186-
self.hardKillFn() # type: ignore
162+
self.hardKillFn()
187163
except:
188164
traceback.print_exc()
189165
def _reset(self) -> None:
190166
self.eSoft.clear()
191167
self.eHard.clear()
192168
self.counter = 0
169+
170+
class SignalTest(unittest.TestCase):
171+
rootSignal:Signal
172+
@classmethod
173+
def setUpClass(self) -> None:
174+
self.rootSignal = Signal()
175+
def tearDown(self) -> None:
176+
self.rootSignal.reset()
177+
def killmeTimer(self) -> None:
178+
def suicide():
179+
os.kill(os.getpid(), _signal.SIGINT)
180+
Timer(1, suicide).start()
181+
def test_sleep(self) -> None:
182+
t:float = monotonic()
183+
self.rootSignal.sleep(2)
184+
self.assertGreater(monotonic()-t, 2.0)
185+
def test_sleepRaise(self) -> None:
186+
self.killmeTimer()
187+
with self.assertRaises(KillSignal):
188+
self.rootSignal.getSoftSignal().sleep(2, raiseOnKill=True)
189+
def test_iter(self) -> None:
190+
s:list = list(range(5))
191+
d:list = []
192+
i:int
193+
signal:SoftSignal = self.rootSignal.getSoftSignal()
194+
self.killmeTimer()
195+
with self.assertRaises(KillSignal):
196+
for i in s:
197+
signal.sleep(0.5, raiseOnKill=True)
198+
d.append(i)
199+
def test_hardkill(self) -> None:
200+
self.killmeTimer()
201+
sleep(0.1)
202+
self.killmeTimer()
203+
sleep(0.1)
204+
self.killmeTimer()
205+
sleep(0.1)
206+
self.rootSignal.forceCounter = 3
207+
with self.assertRaises(KillSignal):
208+
self.rootSignal.sleep(10, raiseOnKill=True)
209+
self.rootSignal.forceCounter = 10

fsSignal/py.typed

Whitespace-only changes.

fsSignal/test/__init__.py

Whitespace-only changes.

fsSignal/test/fsSignal.py

Lines changed: 0 additions & 49 deletions
This file was deleted.

setup.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@
1717
author_email = "ifa@fusionsolutions.io",
1818
url = "https://github.com/FusionSolutions/python-fssignal",
1919
license = "GPL-3",
20+
package_dir={"fsSignal": "fsSignal"},
2021
packages=["fsSignal"],
2122
long_description=open(os.path.join(pwd, "README.md")).read(),
2223
long_description_content_type="text/markdown",
2324
zip_safe=False,
2425
python_requires=">=3.7.0",
25-
test_suite="fsSignal.test",
26-
package_data={ "":["py.typed"] },
2726
classifiers=[ # https://pypi.org/pypi?%3Aaction=list_classifiers
2827
"Development Status :: 4 - Beta",
2928
"Topic :: Utilities",

0 commit comments

Comments
 (0)