base-aux 0.0.1__py3-none-any.whl
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.
- base_aux/_NEW/__init__.py +22 -0
- base_aux/_NEW/main.py +53 -0
- base_aux/__init__.py +0 -0
- base_aux/alerts/__init__.py +20 -0
- base_aux/alerts/_examples.py +103 -0
- base_aux/alerts/base.py +266 -0
- base_aux/alerts/smtp.py +76 -0
- base_aux/alerts/telegram.py +45 -0
- base_aux/bits/__init__.py +19 -0
- base_aux/bits/bits.py +155 -0
- base_aux/buses/__init__.py +81 -0
- base_aux/buses/_examples.py +24 -0
- base_aux/buses/_explore.py +45 -0
- base_aux/buses/history.py +132 -0
- base_aux/buses/i2c_client.py +98 -0
- base_aux/buses/params_schema.py +149 -0
- base_aux/buses/parser.py +72 -0
- base_aux/buses/serial_client.py +1435 -0
- base_aux/buses/serial_derivatives.py +58 -0
- base_aux/buses/serial_server.py +505 -0
- base_aux/classes/__init__.py +210 -0
- base_aux/classes/annot_1_aux.py +150 -0
- base_aux/classes/annot_2_all_defined.py +71 -0
- base_aux/classes/annot_3_iter_values.py +44 -0
- base_aux/classes/annot_4_cls_keys_as_values.py +125 -0
- base_aux/classes/breeder_1_str_1_series.py +127 -0
- base_aux/classes/breeder_1_str_2_stack.py +182 -0
- base_aux/classes/breeder_2_objects.py +277 -0
- base_aux/classes/cmp.py +71 -0
- base_aux/classes/getattr_0_echo.py +62 -0
- base_aux/classes/getattr_1_aux.py +37 -0
- base_aux/classes/getattr_2_anycase.py +14 -0
- base_aux/classes/getattr_3_prefix_1_inst.py +123 -0
- base_aux/classes/getattr_3_prefix_2_cls.py +52 -0
- base_aux/classes/middle_group.py +213 -0
- base_aux/classes/number.py +280 -0
- base_aux/classes/singleton.py +206 -0
- base_aux/classes/singleton_examples.py +41 -0
- base_aux/classes/static.py +12 -0
- base_aux/classes/valid_0_aux.py +224 -0
- base_aux/classes/valid_1_base.py +323 -0
- base_aux/classes/valid_1_base_derivatives.py +65 -0
- base_aux/classes/valid_2_chains.py +104 -0
- base_aux/classes/valid_3_regexp.py +54 -0
- base_aux/classes/value_1_variants.py +139 -0
- base_aux/classes/value_2_unit.py +296 -0
- base_aux/cli/__init__.py +35 -0
- base_aux/cli/_examples.py +69 -0
- base_aux/cli/main.py +315 -0
- base_aux/funcs/__init__.py +98 -0
- base_aux/funcs/args.py +85 -0
- base_aux/funcs/arrays.py +64 -0
- base_aux/funcs/ensure.py +81 -0
- base_aux/funcs/iterables.py +147 -0
- base_aux/funcs/pytest_aux.py +218 -0
- base_aux/funcs/result_cum.py +168 -0
- base_aux/funcs/static.py +55 -0
- base_aux/funcs/strings.py +55 -0
- base_aux/funcs/value_0_explicit.py +96 -0
- base_aux/loggers/__init__.py +20 -0
- base_aux/loggers/main.py +187 -0
- base_aux/monitors/__init__.py +48 -0
- base_aux/monitors/_examples.py +71 -0
- base_aux/monitors/imap.py +205 -0
- base_aux/monitors/url_tag.py +227 -0
- base_aux/monitors/url_tag__derivatives.py +235 -0
- base_aux/objects/__init__.py +114 -0
- base_aux/objects/_examples.py +308 -0
- base_aux/objects/info.py +379 -0
- base_aux/objects/primitives.py +466 -0
- base_aux/objects/types.py +254 -0
- base_aux/privates/__init__.py +74 -0
- base_aux/privates/_examples.py +125 -0
- base_aux/privates/auto.py +38 -0
- base_aux/privates/base.py +187 -0
- base_aux/privates/csv.py +90 -0
- base_aux/privates/derivatives.py +26 -0
- base_aux/privates/env.py +48 -0
- base_aux/privates/ini.py +43 -0
- base_aux/privates/json.py +43 -0
- base_aux/privates/static.py +22 -0
- base_aux/pyqt/__init__.py +64 -0
- base_aux/pyqt/_explore.py +12 -0
- base_aux/pyqt/_from_t8.py +158 -0
- base_aux/pyqt/base.py +36 -0
- base_aux/pyqt/fonts.py +32 -0
- base_aux/pyqt/gui.py +943 -0
- base_aux/pyqt/hl.py +360 -0
- base_aux/pyqt/signals.py +35 -0
- base_aux/pyqt/th.py +84 -0
- base_aux/pyqt/tm.py +330 -0
- base_aux/requirements/__init__.py +75 -0
- base_aux/requirements/_examples.py +16 -0
- base_aux/requirements/pkgs.py +687 -0
- base_aux/requirements/strings.py +291 -0
- base_aux/requirements/versions.py +405 -0
- base_aux/servers/__init__.py +80 -0
- base_aux/servers/_examples.py +6 -0
- base_aux/servers/client_requests.py +226 -0
- base_aux/servers/server_aiohttp.py +261 -0
- base_aux/servers/server_fastapi.py +645 -0
- base_aux/servers/url.py +38 -0
- base_aux/testplans/DEVICES/__init__.py +0 -0
- base_aux/testplans/DEVICES/atc.py +47 -0
- base_aux/testplans/DEVICES/dut.py +34 -0
- base_aux/testplans/DEVICES/ptb.py +92 -0
- base_aux/testplans/TESTCASES/__init__.py +3 -0
- base_aux/testplans/TESTCASES/tc01_exist1_ptb.py +21 -0
- base_aux/testplans/TESTCASES/tc01_exist2_psu.py +20 -0
- base_aux/testplans/TESTCASES/tc0_groups.py +17 -0
- base_aux/testplans/TESTCASES/tc0_test_tcinst_startup_fail.py +15 -0
- base_aux/testplans/TESTCASES/tc1_direct.py +22 -0
- base_aux/testplans/TESTCASES/tc2_reverse.py +31 -0
- base_aux/testplans/TESTCASES/tc3_atc.py +34 -0
- base_aux/testplans/TESTCASES/tc4_dut_ptb.py +41 -0
- base_aux/testplans/TESTCASES/tc5_group_1.py +16 -0
- base_aux/testplans/TESTCASES/tc5_group_2.py +15 -0
- base_aux/testplans/TESTCASES/tc5_group_3.py +16 -0
- base_aux/testplans/__init__.py +87 -0
- base_aux/testplans/_explore.py +72 -0
- base_aux/testplans/api.py +109 -0
- base_aux/testplans/devices.py +118 -0
- base_aux/testplans/gui.py +289 -0
- base_aux/testplans/main.py +423 -0
- base_aux/testplans/models.py +63 -0
- base_aux/testplans/results.py +34 -0
- base_aux/testplans/tc.py +539 -0
- base_aux/testplans/tc_groups.py +69 -0
- base_aux/testplans/tc_types.py +11 -0
- base_aux/testplans/tm.py +277 -0
- base_aux/threads/__init__.py +27 -0
- base_aux/threads/_examples.py +32 -0
- base_aux/threads/main.py +215 -0
- base_aux-0.0.1.dist-info/LICENSE +22 -0
- base_aux-0.0.1.dist-info/METADATA +248 -0
- base_aux-0.0.1.dist-info/RECORD +138 -0
- base_aux-0.0.1.dist-info/WHEEL +5 -0
- base_aux-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# =====================================================================================================================
|
|
2
|
+
# VERSION = (0, 0, 1) # use import EXACT_OBJECTS! not *
|
|
3
|
+
# from .main import * # INcorrect
|
|
4
|
+
# from .main import EXACT_OBJECTS # CORRECT
|
|
5
|
+
# VERSION = (0, 0, 2) # del blank lines
|
|
6
|
+
# VERSION = (0, 0, 3) # separate all types/exx into static.py!
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# =====================================================================================================================
|
|
10
|
+
# TEMPLATE
|
|
11
|
+
# from .static import (
|
|
12
|
+
# # TYPES
|
|
13
|
+
# # EXX
|
|
14
|
+
# )
|
|
15
|
+
# from .main import (
|
|
16
|
+
# # BASE
|
|
17
|
+
# # AUX
|
|
18
|
+
# )
|
|
19
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# =====================================================================================================================
|
base_aux/_NEW/main.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
from typing import *
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# =====================================================================================================================
|
|
6
|
+
TYPE__PATH = Union[str, pathlib.Path]
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# =====================================================================================================================
|
|
10
|
+
class NEW_CLASS____:
|
|
11
|
+
"""
|
|
12
|
+
NOTE
|
|
13
|
+
----
|
|
14
|
+
|
|
15
|
+
GOAL
|
|
16
|
+
----
|
|
17
|
+
|
|
18
|
+
USEFUL IDEAS
|
|
19
|
+
------------
|
|
20
|
+
|
|
21
|
+
CREATED SPECIALLY FOR
|
|
22
|
+
---------------------
|
|
23
|
+
REPLACE:
|
|
24
|
+
|
|
25
|
+
CONSTRAINTS
|
|
26
|
+
-----------
|
|
27
|
+
|
|
28
|
+
BEST USAGE
|
|
29
|
+
----------
|
|
30
|
+
|
|
31
|
+
SAME AS/OTHER VARIANTS
|
|
32
|
+
----------------------
|
|
33
|
+
DIFFERENCE:
|
|
34
|
+
|
|
35
|
+
WHY NOT: 1?
|
|
36
|
+
----------
|
|
37
|
+
|
|
38
|
+
WHY NOT: 2?
|
|
39
|
+
----------
|
|
40
|
+
|
|
41
|
+
REFERENCE
|
|
42
|
+
---------
|
|
43
|
+
|
|
44
|
+
"""
|
|
45
|
+
def meth(self):
|
|
46
|
+
"""
|
|
47
|
+
CREATED SPECIALLY FOR
|
|
48
|
+
---------------------
|
|
49
|
+
"""
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# =====================================================================================================================
|
base_aux/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# =====================================================================================================================
|
|
2
|
+
# VERSION = (0, 0, 1) # use import EXACT_OBJECTS! not *
|
|
3
|
+
# from .main import * # INcorerct
|
|
4
|
+
# from .main import EXACT_OBJECTS # CORERCT
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# =====================================================================================================================
|
|
8
|
+
from .base import AlertBase
|
|
9
|
+
from .smtp import SmtpAddress, SmtpServers, AlertSmtp
|
|
10
|
+
from .telegram import RecipientTgID, AlertTelegram
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# =====================================================================================================================
|
|
14
|
+
# FIXME: move to main!
|
|
15
|
+
class AlertSelect:
|
|
16
|
+
SMTP_DEF = AlertSmtp
|
|
17
|
+
TELEGRAM_DEF = AlertTelegram
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# =====================================================================================================================
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# =========================================================================================
|
|
2
|
+
### 0. BEST PRACTICE
|
|
3
|
+
from base_aux.alerts import *
|
|
4
|
+
|
|
5
|
+
class AlertADX(AlertSelect.TELEGRAM_DEF):
|
|
6
|
+
pass
|
|
7
|
+
|
|
8
|
+
AlertADX("hello")
|
|
9
|
+
AlertADX("World")
|
|
10
|
+
AlertADX.threads_wait_all()
|
|
11
|
+
|
|
12
|
+
# =========================================================================================
|
|
13
|
+
# =========================================================================================
|
|
14
|
+
# =========================================================================================
|
|
15
|
+
### AlertSmtp
|
|
16
|
+
#### 1. add new server if not exists
|
|
17
|
+
from base_aux.alerts import *
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SmtpServersMOD(SmtpServers):
|
|
21
|
+
EXAMPLE_RU: SmtpAddress = SmtpAddress("smtp.EXAMPLE.ru", 123)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AlertSmtpMOD(AlertSmtp):
|
|
25
|
+
SERVER_SMTP: SmtpAddress = SmtpServersMOD.EXAMPLE_RU # or direct =SmtpAddress("smtp.EXAMPLE.ru", 123)
|
|
26
|
+
|
|
27
|
+
# =========================================================================================
|
|
28
|
+
#### 2. change authorisation data (see `privates` for details)
|
|
29
|
+
from base_aux.alerts import *
|
|
30
|
+
from base_aux.privates import *
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AlertSmtpMOD(AlertSmtp):
|
|
34
|
+
AUTH: PrivateAuto = PrivateAuto(_section="AUTH_EMAIL_MOD")
|
|
35
|
+
|
|
36
|
+
# =========================================================================================
|
|
37
|
+
#### 3. change other settings (see source for other not mentioned)
|
|
38
|
+
from base_aux.alerts import *
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class AlertSmtpMOD(AlertSmtp):
|
|
42
|
+
RECONNECT_PAUSE: int = 60
|
|
43
|
+
RECONNECT_LIMIT: int = 10
|
|
44
|
+
|
|
45
|
+
TIMEOUT_RATELIMIT: int = 600
|
|
46
|
+
|
|
47
|
+
RECIPIENT_SPECIAL: str = "my_address_2@mail.ru"
|
|
48
|
+
|
|
49
|
+
# =========================================================================================
|
|
50
|
+
#### 4. send
|
|
51
|
+
# if no mods
|
|
52
|
+
from base_aux.alerts import *
|
|
53
|
+
|
|
54
|
+
AlertSmtp(_subj_name="Hello", body="World!")
|
|
55
|
+
|
|
56
|
+
# with mods
|
|
57
|
+
from base_aux.alerts import *
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class AlertSmtpMOD(AlertSmtp):
|
|
61
|
+
pass # changed
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
AlertSmtpMOD(_subj_name="Hello", body="World!")
|
|
65
|
+
|
|
66
|
+
# =========================================================================================
|
|
67
|
+
#### 5. using in class with saving alert object
|
|
68
|
+
from base_aux.alerts import *
|
|
69
|
+
|
|
70
|
+
class AlertSmtpMOD(AlertSmtp):
|
|
71
|
+
pass # changed
|
|
72
|
+
|
|
73
|
+
class MyMonitor:
|
|
74
|
+
ALERT = AlertSmtpMOD
|
|
75
|
+
|
|
76
|
+
monitor = MyMonitor()
|
|
77
|
+
monitor.ALERT("Hello")
|
|
78
|
+
|
|
79
|
+
# =========================================================================================
|
|
80
|
+
# =========================================================================================
|
|
81
|
+
### AlertTelegram
|
|
82
|
+
# All idea is similar to AlertSmtp.
|
|
83
|
+
|
|
84
|
+
# add auth data
|
|
85
|
+
# add pv.json or do smth else (for details see privates.PrivateJsonTgBotAddress)
|
|
86
|
+
# json
|
|
87
|
+
{
|
|
88
|
+
"TG_ID": {"MyTgID": 1234567890},
|
|
89
|
+
"TGBOT_DEF": {
|
|
90
|
+
"LINK_ID": "@my_bot_20230916",
|
|
91
|
+
"NAME": "my_bot",
|
|
92
|
+
"TOKEN": "9876543210xxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# =========================================================================================
|
|
97
|
+
from base_aux.alerts import *
|
|
98
|
+
|
|
99
|
+
class MyMonitor:
|
|
100
|
+
ALERT = AlertTelegram
|
|
101
|
+
|
|
102
|
+
monitor = MyMonitor()
|
|
103
|
+
monitor.ALERT("Hello")
|
base_aux/alerts/base.py
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from typing import *
|
|
3
|
+
|
|
4
|
+
from PyQt5.QtCore import QThread
|
|
5
|
+
|
|
6
|
+
import smtplib
|
|
7
|
+
import telebot
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# =====================================================================================================================
|
|
11
|
+
class _AlertInterface:
|
|
12
|
+
"""Interface for Alerts
|
|
13
|
+
|
|
14
|
+
RULES:
|
|
15
|
+
- if some method cant exists (like for telegram) - just return True!
|
|
16
|
+
- Dont return None!
|
|
17
|
+
- Dont use Try sentences inside - it will be applied in upper logic!
|
|
18
|
+
- Decide inside if it was success or not, and return conclusion True/False only.
|
|
19
|
+
"""
|
|
20
|
+
def _connect_unsafe(self) -> Union[bool, NoReturn]:
|
|
21
|
+
"""establish connection to source
|
|
22
|
+
"""
|
|
23
|
+
return True
|
|
24
|
+
|
|
25
|
+
def _login_unsafe(self) -> Union[bool, NoReturn]:
|
|
26
|
+
"""authorise to source
|
|
27
|
+
"""
|
|
28
|
+
return True
|
|
29
|
+
|
|
30
|
+
def _send_unsafe(self) -> Union[bool, NoReturn]:
|
|
31
|
+
"""send msg
|
|
32
|
+
"""
|
|
33
|
+
return True
|
|
34
|
+
|
|
35
|
+
def _msg_compose(self) -> Union[str, 'MIMEMultipart']:
|
|
36
|
+
"""generate msg from existed data in attributes (passed before on init)
|
|
37
|
+
"""
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
def _recipient_self_get(self) -> str:
|
|
41
|
+
"""RECIPIENT SelfSending, get from obvious class objects!
|
|
42
|
+
"""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# =====================================================================================================================
|
|
47
|
+
class AlertBase(_AlertInterface, QThread): # REM: DONT ADD SINGLETON!!! SNMP WILL NOT WORK!!! and calling logic will be not simle!
|
|
48
|
+
"""Base class for Alert objects.
|
|
49
|
+
|
|
50
|
+
FEATURE:
|
|
51
|
+
- send msg,
|
|
52
|
+
- threading
|
|
53
|
+
- daemons
|
|
54
|
+
- collect all active threads
|
|
55
|
+
- wait all spawned threads finished
|
|
56
|
+
|
|
57
|
+
:ivar SUBJECT_PREFIX: default prefix for subject
|
|
58
|
+
:ivar SUBJECT_NAME: default name for subject
|
|
59
|
+
:ivar body: actual msg body for alert
|
|
60
|
+
:ivar _subtype: it used to change subtype only in smtp (http)
|
|
61
|
+
|
|
62
|
+
:ivar BODY_TIMESTAMP_USE: append timestamp into the body
|
|
63
|
+
:ivar TIMESTAMP: initiation timestamp for created instance
|
|
64
|
+
|
|
65
|
+
:ivar RECONNECT_LIMIT: how many times it will try to reconnect, after - just close object
|
|
66
|
+
:ivar RECONNECT_PAUSE: pause between reconnecting in seconds
|
|
67
|
+
|
|
68
|
+
:ivar RECIPIENT_SPECIAL: recipient for sending msg
|
|
69
|
+
None - if selfSending!
|
|
70
|
+
|
|
71
|
+
:ivar _conn: actual connection object
|
|
72
|
+
:ivar _result: result for alert state
|
|
73
|
+
None - in process,
|
|
74
|
+
False - finished UnSuccess,
|
|
75
|
+
True - finished success!
|
|
76
|
+
|
|
77
|
+
:ivar _threads_active: spawned (only active) threads
|
|
78
|
+
"""
|
|
79
|
+
# SETTINGS ------------------------------------
|
|
80
|
+
SUBJECT_PREFIX: Optional[str] = "[ALERT]"
|
|
81
|
+
SUBJECT_NAME: Optional[str] = None
|
|
82
|
+
body: Union[None, str, dict] = None
|
|
83
|
+
_subtype: Optional[str] = "plain"
|
|
84
|
+
|
|
85
|
+
BODY_TIMESTAMP_USE: bool = True
|
|
86
|
+
TIMESTAMP: str = None
|
|
87
|
+
|
|
88
|
+
TIMEOUT_SEND: float = 1.2
|
|
89
|
+
|
|
90
|
+
RECONNECT_LIMIT: int = 10
|
|
91
|
+
RECONNECT_PAUSE: int = 60
|
|
92
|
+
# TIMEOUT_RATELIMIT: int = 600 # when EXX 451, b'Ratelimit exceeded
|
|
93
|
+
|
|
94
|
+
RECIPIENT_SPECIAL: Optional[Any] = None
|
|
95
|
+
|
|
96
|
+
# AUX -----------------------------------------
|
|
97
|
+
_conn: Union[None, smtplib.SMTP_SSL, telebot.TeleBot] = None
|
|
98
|
+
_result: Optional[bool] = None
|
|
99
|
+
|
|
100
|
+
_threads_active: Set['AlertBase'] = set()
|
|
101
|
+
|
|
102
|
+
# =================================================================================================================
|
|
103
|
+
def __init__(self, body: Optional[Any] = None, _subj_name: Optional[str] = None, _subtype: Optional[str] = None):
|
|
104
|
+
"""Send msg
|
|
105
|
+
|
|
106
|
+
:param body: define msg body
|
|
107
|
+
None - just for research! (maybe deprecated!)
|
|
108
|
+
:param _subj_name: reuse new subject name instead of default
|
|
109
|
+
:param _subtype: reuse new _subtype instead of default
|
|
110
|
+
"""
|
|
111
|
+
super().__init__(daemon=True)
|
|
112
|
+
self.TIMESTAMP = time.strftime("%Y.%m.%d %H:%M:%S")
|
|
113
|
+
|
|
114
|
+
# self._mutex: threading.Lock = threading.Lock()
|
|
115
|
+
self.SUBJECT_NAME = _subj_name or self.SUBJECT_NAME
|
|
116
|
+
self._subtype = _subtype or self._subtype
|
|
117
|
+
|
|
118
|
+
# BODY ---------------
|
|
119
|
+
if body is not None:
|
|
120
|
+
body = str(body)
|
|
121
|
+
if self.BODY_TIMESTAMP_USE:
|
|
122
|
+
body += f"\n{self.TIMESTAMP}"
|
|
123
|
+
self.body = body
|
|
124
|
+
|
|
125
|
+
self.start()
|
|
126
|
+
|
|
127
|
+
# =================================================================================================================
|
|
128
|
+
def RECIPIENT(self) -> str:
|
|
129
|
+
"""RECIPIENT actual/final
|
|
130
|
+
"""
|
|
131
|
+
return self.RECIPIENT_SPECIAL or self._recipient_self_get()
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def SUBJECT(self) -> str:
|
|
135
|
+
"""final msg subject, composed with name and prefix.
|
|
136
|
+
"""
|
|
137
|
+
if self.SUBJECT_NAME is None:
|
|
138
|
+
self.SUBJECT_NAME = self.NAME
|
|
139
|
+
return self.SUBJECT_PREFIX + self.SUBJECT_NAME
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
@property
|
|
143
|
+
def NAME(cls) -> str:
|
|
144
|
+
"""name for AlertClass.
|
|
145
|
+
Accustom ourselves to name you classes recognisable without adding new one redundant attributes.
|
|
146
|
+
"""
|
|
147
|
+
return cls.__name__
|
|
148
|
+
|
|
149
|
+
# =================================================================================================================
|
|
150
|
+
def start(self):
|
|
151
|
+
"""this is just add ability to collect started threads in class
|
|
152
|
+
"""
|
|
153
|
+
self.__class__._threads_active.add(self)
|
|
154
|
+
super().start()
|
|
155
|
+
|
|
156
|
+
def _thread_finished(self):
|
|
157
|
+
"""del thread object from collection.
|
|
158
|
+
called then thread finished.
|
|
159
|
+
"""
|
|
160
|
+
self.__class__._threads_active.discard(self)
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def threads_wait_all(cls):
|
|
164
|
+
"""wait while all spawned active threads will finished.
|
|
165
|
+
"""
|
|
166
|
+
try:
|
|
167
|
+
time.sleep(1)
|
|
168
|
+
while cls._threads_active:
|
|
169
|
+
list(cls._threads_active)[0].wait()
|
|
170
|
+
except:
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
def result_wait(self) -> Optional[bool]:
|
|
174
|
+
"""wait for finish thread and get succession result.
|
|
175
|
+
Created for tests mainly! but you can use!
|
|
176
|
+
"""
|
|
177
|
+
self.wait()
|
|
178
|
+
return self._result
|
|
179
|
+
|
|
180
|
+
# =================================================================================================================
|
|
181
|
+
def _conn__check_exists(self) -> bool:
|
|
182
|
+
"""check if connection object exists
|
|
183
|
+
"""
|
|
184
|
+
return self._conn is not None
|
|
185
|
+
|
|
186
|
+
def _conn__disconnect(self) -> None:
|
|
187
|
+
"""disconnect connection object
|
|
188
|
+
"""
|
|
189
|
+
if self._conn:
|
|
190
|
+
self._conn.quit()
|
|
191
|
+
self._conn__clear()
|
|
192
|
+
|
|
193
|
+
def _conn__clear(self) -> None:
|
|
194
|
+
"""del connection object
|
|
195
|
+
"""
|
|
196
|
+
self._conn = None
|
|
197
|
+
|
|
198
|
+
def _connect(self) -> Optional[bool]:
|
|
199
|
+
"""create connection object
|
|
200
|
+
"""
|
|
201
|
+
result = None
|
|
202
|
+
if not self._conn__check_exists():
|
|
203
|
+
print(f"TRY _connect {self.__class__.__name__}")
|
|
204
|
+
try:
|
|
205
|
+
if self._connect_unsafe():
|
|
206
|
+
print("[READY] connect")
|
|
207
|
+
|
|
208
|
+
except Exception as exx:
|
|
209
|
+
print(f"[CRITICAL] CONNECT [{exx!r}]")
|
|
210
|
+
self._conn__clear()
|
|
211
|
+
|
|
212
|
+
if self._conn__check_exists():
|
|
213
|
+
try:
|
|
214
|
+
result = self._login_unsafe()
|
|
215
|
+
if result:
|
|
216
|
+
print("[READY] login")
|
|
217
|
+
except Exception as exx:
|
|
218
|
+
print(f"[CRITICAL] LOGIN [{exx!r}]")
|
|
219
|
+
self._conn__clear()
|
|
220
|
+
|
|
221
|
+
print("="*100)
|
|
222
|
+
print("="*100)
|
|
223
|
+
print("="*100)
|
|
224
|
+
print()
|
|
225
|
+
|
|
226
|
+
return result
|
|
227
|
+
|
|
228
|
+
# =================================================================================================================
|
|
229
|
+
def run(self) -> None:
|
|
230
|
+
"""main logic which manage started thread
|
|
231
|
+
"""
|
|
232
|
+
counter = 0
|
|
233
|
+
while not self._conn__check_exists() and counter <= self.RECONNECT_LIMIT:
|
|
234
|
+
counter += 1
|
|
235
|
+
if not self._connect():
|
|
236
|
+
print(f"[WARNING]try [{counter=}]")
|
|
237
|
+
print("=" * 100)
|
|
238
|
+
print()
|
|
239
|
+
time.sleep(self.RECONNECT_PAUSE)
|
|
240
|
+
|
|
241
|
+
print("[Try send", "-" * 80)
|
|
242
|
+
print(self._msg_compose())
|
|
243
|
+
print("Try send]", "-" * 80)
|
|
244
|
+
|
|
245
|
+
if self._conn__check_exists():
|
|
246
|
+
try:
|
|
247
|
+
result = self._send_unsafe()
|
|
248
|
+
if result:
|
|
249
|
+
print("[READY] send")
|
|
250
|
+
self._result = True
|
|
251
|
+
except Exception as exx:
|
|
252
|
+
msg = f"[CRITICAL]unexpected [{exx!r}]"
|
|
253
|
+
print(msg)
|
|
254
|
+
self._conn__clear()
|
|
255
|
+
|
|
256
|
+
print()
|
|
257
|
+
print()
|
|
258
|
+
print()
|
|
259
|
+
|
|
260
|
+
if self._result is None:
|
|
261
|
+
self._result = False
|
|
262
|
+
|
|
263
|
+
self._thread_finished()
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
# =====================================================================================================================
|
base_aux/alerts/smtp.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from .base import *
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from typing import *
|
|
5
|
+
|
|
6
|
+
import smtplib
|
|
7
|
+
from email.mime.text import MIMEText
|
|
8
|
+
from email.mime.multipart import MIMEMultipart
|
|
9
|
+
|
|
10
|
+
from base_aux.privates import *
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# =====================================================================================================================
|
|
14
|
+
# TODO: cant solve not to use always connecting - tried many variants!
|
|
15
|
+
# make decision - use only one ability to send - only by instantiating!
|
|
16
|
+
# always will connecting! but always in threads! so dont mind!
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# =====================================================================================================================
|
|
20
|
+
class SmtpAddress(NamedTuple):
|
|
21
|
+
"""class for keeping connection parameters/settings for exact smtp server
|
|
22
|
+
|
|
23
|
+
:ivar ADDR: smtp server address like "smtp.mail.ru"
|
|
24
|
+
:ivar PORT: smtp server port like 465
|
|
25
|
+
"""
|
|
26
|
+
ADDR: str
|
|
27
|
+
PORT: int
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class SmtpServers:
|
|
31
|
+
"""well known servers addresses.
|
|
32
|
+
|
|
33
|
+
Here we must collect servers like MilRu/GmailCom, and not to create it in any new project.
|
|
34
|
+
"""
|
|
35
|
+
MAIL_RU: SmtpAddress = SmtpAddress("smtp.mail.ru", 465)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# =====================================================================================================================
|
|
39
|
+
class AlertSmtp(AlertBase):
|
|
40
|
+
"""SMTP realisation for sending msg (email).
|
|
41
|
+
"""
|
|
42
|
+
# SETTINGS ------------------------------------
|
|
43
|
+
SERVER_SMTP: SmtpAddress = SmtpServers.MAIL_RU
|
|
44
|
+
AUTH: PrivateAuth = PrivateAuto(_section="AUTH_EMAIL_DEF")
|
|
45
|
+
TIMEOUT_SEND = 5
|
|
46
|
+
|
|
47
|
+
# AUX -----------------------------------------
|
|
48
|
+
_conn: smtplib.SMTP_SSL
|
|
49
|
+
|
|
50
|
+
def _connect_unsafe(self) -> Union[bool, NoReturn]:
|
|
51
|
+
self._conn = smtplib.SMTP_SSL(self.SERVER_SMTP.ADDR, self.SERVER_SMTP.PORT, timeout=self.TIMEOUT_SEND)
|
|
52
|
+
return True
|
|
53
|
+
|
|
54
|
+
def _login_unsafe(self) -> Union[bool, NoReturn]:
|
|
55
|
+
response = self._conn.login(self.AUTH.USER, self.AUTH.PWD)
|
|
56
|
+
print(response)
|
|
57
|
+
print("=" * 100)
|
|
58
|
+
return response and response[0] in [235, 503]
|
|
59
|
+
|
|
60
|
+
def _send_unsafe(self) -> Union[bool, NoReturn]:
|
|
61
|
+
self._conn.send_message(self._msg_compose())
|
|
62
|
+
return True
|
|
63
|
+
|
|
64
|
+
def _msg_compose(self) -> MIMEMultipart:
|
|
65
|
+
msg = MIMEMultipart()
|
|
66
|
+
msg["From"] = self.AUTH.USER
|
|
67
|
+
msg["To"] = self.RECIPIENT_SPECIAL or self.AUTH.USER
|
|
68
|
+
msg['Subject'] = self.SUBJECT
|
|
69
|
+
msg.attach(MIMEText(self.body, _subtype=self._subtype))
|
|
70
|
+
return msg
|
|
71
|
+
|
|
72
|
+
def _recipient_self_get(self) -> str:
|
|
73
|
+
return self.AUTH.USER
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# =====================================================================================================================
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from .base import *
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from typing import *
|
|
5
|
+
|
|
6
|
+
import telebot
|
|
7
|
+
|
|
8
|
+
from base_aux.privates import *
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# =====================================================================================================================
|
|
12
|
+
class RecipientTgID(PrivateAuto):
|
|
13
|
+
"""Object to get telegram RecipientId
|
|
14
|
+
"""
|
|
15
|
+
SECTION = "TG_ID"
|
|
16
|
+
MyTgID: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# =====================================================================================================================
|
|
20
|
+
class AlertTelegram(AlertBase):
|
|
21
|
+
"""realisation for sending Telegram msg
|
|
22
|
+
"""
|
|
23
|
+
# SETTINGS ------------------------------------
|
|
24
|
+
SERVER_TG: PrivateTgBotAddressAuto = PrivateTgBotAddressAuto(_section="TGBOT_DEF")
|
|
25
|
+
|
|
26
|
+
# AUX -----------------------------------------
|
|
27
|
+
_conn: telebot.TeleBot
|
|
28
|
+
|
|
29
|
+
def _connect_unsafe(self) -> Union[bool, NoReturn]:
|
|
30
|
+
self._conn = telebot.TeleBot(token=self.SERVER_TG.TOKEN)
|
|
31
|
+
return True
|
|
32
|
+
|
|
33
|
+
def _send_unsafe(self) -> Union[bool, NoReturn]:
|
|
34
|
+
self._conn.send_message(chat_id=self.RECIPIENT, text=self._msg_compose())
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
def _msg_compose(self) -> str:
|
|
38
|
+
msg = f"{self.SUBJECT}\n{self.body}"
|
|
39
|
+
return msg
|
|
40
|
+
|
|
41
|
+
def _recipient_self_get(self) -> str:
|
|
42
|
+
return RecipientTgID().MyTgID
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# =====================================================================================================================
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# =====================================================================================================================
|
|
2
|
+
# VERSION = (0, 0, 1) # use import EXACT_OBJECTS! not *
|
|
3
|
+
# from .main import * # INcorrect
|
|
4
|
+
# from .main import EXACT_OBJECTS # CORRECT
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# =====================================================================================================================
|
|
8
|
+
from .bits import (
|
|
9
|
+
# BASE
|
|
10
|
+
Bitfield, Flags, Bits,
|
|
11
|
+
|
|
12
|
+
# AUX
|
|
13
|
+
|
|
14
|
+
# EXX
|
|
15
|
+
Exx_BitsNoSize, Exx_BitsOutOfRange,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# =====================================================================================================================
|