cascade-core 0.1.12__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.
- cascade_core-0.1.12/LICENSE +21 -0
- cascade_core-0.1.12/PKG-INFO +58 -0
- cascade_core-0.1.12/README.md +22 -0
- cascade_core-0.1.12/cascade/__init__.py +6 -0
- cascade_core-0.1.12/cascade/command.py +69 -0
- cascade_core-0.1.12/cascade/commands/__init__.py +1 -0
- cascade_core-0.1.12/cascade/commands/service.py +108 -0
- cascade_core-0.1.12/cascade/logger.py +83 -0
- cascade_core-0.1.12/cascade/operator.py +38 -0
- cascade_core-0.1.12/cascade/pipeline.py +49 -0
- cascade_core-0.1.12/cascade/program.py +6 -0
- cascade_core-0.1.12/cascade/resource.py +9 -0
- cascade_core-0.1.12/cascade/stack.py +26 -0
- cascade_core-0.1.12/cascade_core.egg-info/PKG-INFO +58 -0
- cascade_core-0.1.12/cascade_core.egg-info/SOURCES.txt +18 -0
- cascade_core-0.1.12/cascade_core.egg-info/dependency_links.txt +1 -0
- cascade_core-0.1.12/cascade_core.egg-info/requires.txt +6 -0
- cascade_core-0.1.12/cascade_core.egg-info/top_level.txt +1 -0
- cascade_core-0.1.12/pyproject.toml +24 -0
- cascade_core-0.1.12/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 vadzimshpak
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cascade-core
|
|
3
|
+
Version: 0.1.12
|
|
4
|
+
Summary: Cascade Core
|
|
5
|
+
License: MIT License
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2024 vadzimshpak
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
|
|
27
|
+
Requires-Python: >=3.11
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: mss
|
|
31
|
+
Requires-Dist: python-dotenv
|
|
32
|
+
Requires-Dist: requests
|
|
33
|
+
Provides-Extra: test
|
|
34
|
+
Requires-Dist: pytest; extra == "test"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# Cascade Core
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<img src="./media/logo.png" width="250">
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
Arch:
|
|
44
|
+
- Command - smallest part
|
|
45
|
+
- Pipeline - mix of commands
|
|
46
|
+
- Program - mix of commands and pipelines
|
|
47
|
+
- [Next level...]
|
|
48
|
+
- [Next level...]
|
|
49
|
+
|
|
50
|
+
Philosophy:
|
|
51
|
+
|
|
52
|
+
- Each well-tested and documented command is part of the sucessfull pipeline.
|
|
53
|
+
- Each well-tested and documented pipeline is part of the sucessfull program.
|
|
54
|
+
- Each well-tested and documented program is part of the sucessfull cascade.
|
|
55
|
+
- Each well-tested and documented cascade is part of the sucessfull business.
|
|
56
|
+
|
|
57
|
+
Add submodule to project:
|
|
58
|
+
`git submodule add https://github.com/vadzimshpak/cascade-core cascade`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Cascade Core
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="./media/logo.png" width="250">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
Arch:
|
|
8
|
+
- Command - smallest part
|
|
9
|
+
- Pipeline - mix of commands
|
|
10
|
+
- Program - mix of commands and pipelines
|
|
11
|
+
- [Next level...]
|
|
12
|
+
- [Next level...]
|
|
13
|
+
|
|
14
|
+
Philosophy:
|
|
15
|
+
|
|
16
|
+
- Each well-tested and documented command is part of the sucessfull pipeline.
|
|
17
|
+
- Each well-tested and documented pipeline is part of the sucessfull program.
|
|
18
|
+
- Each well-tested and documented program is part of the sucessfull cascade.
|
|
19
|
+
- Each well-tested and documented cascade is part of the sucessfull business.
|
|
20
|
+
|
|
21
|
+
Add submodule to project:
|
|
22
|
+
`git submodule add https://github.com/vadzimshpak/cascade-core cascade`
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import time
|
|
3
|
+
import random
|
|
4
|
+
from typing import TYPE_CHECKING, Self
|
|
5
|
+
|
|
6
|
+
from .logger import get_logger
|
|
7
|
+
from .stack import Stack
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from .operator import Operator
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
logger = get_logger(__name__)
|
|
15
|
+
random.seed(time.time())
|
|
16
|
+
|
|
17
|
+
class Command:
|
|
18
|
+
def __init__(self):
|
|
19
|
+
self._store_var = None
|
|
20
|
+
self._stack: Stack = None
|
|
21
|
+
self._skip_on_raise = False
|
|
22
|
+
self._jump_on_raise = None
|
|
23
|
+
self._jump_on_success = None
|
|
24
|
+
self._vars = []
|
|
25
|
+
|
|
26
|
+
def execute(self, stack: Stack):
|
|
27
|
+
logger.debug(f"Execute subject: {type(self).__name__}")
|
|
28
|
+
|
|
29
|
+
self._stack = stack
|
|
30
|
+
result = self.body()
|
|
31
|
+
|
|
32
|
+
if type(result) is str:
|
|
33
|
+
logger.debug(f"Got {result if len(result) < 100 else result[:100] + '...'} from {type(self).__name__}")
|
|
34
|
+
else:
|
|
35
|
+
logger.debug(f"Got {result} from {type(self).__name__}")
|
|
36
|
+
|
|
37
|
+
if self._store_var:
|
|
38
|
+
stack.update(self._store_var, result)
|
|
39
|
+
|
|
40
|
+
return result
|
|
41
|
+
|
|
42
|
+
def body(self):
|
|
43
|
+
raise Exception("This subject doesn't have body!")
|
|
44
|
+
|
|
45
|
+
def get_param_value(self, number: int):
|
|
46
|
+
return self._stack.top_value(self._vars[number])
|
|
47
|
+
|
|
48
|
+
def __rshift__(self, command: Operator) -> Self | object | Exception:
|
|
49
|
+
from .operator import Execute, Store, RaiseSkip, JumpOnRaise, JumpOnSuccess
|
|
50
|
+
|
|
51
|
+
if type(command) == Execute:
|
|
52
|
+
try:
|
|
53
|
+
return self.execute(command.stack)
|
|
54
|
+
except Exception as e:
|
|
55
|
+
return e
|
|
56
|
+
|
|
57
|
+
elif type(command) == Store:
|
|
58
|
+
self._store_var = command.var_name
|
|
59
|
+
|
|
60
|
+
elif type(command) == RaiseSkip:
|
|
61
|
+
self._skip_on_raise = True
|
|
62
|
+
|
|
63
|
+
elif type(command) == JumpOnRaise:
|
|
64
|
+
self._jump_on_raise = command.command_index
|
|
65
|
+
|
|
66
|
+
elif type(command) == JumpOnSuccess:
|
|
67
|
+
self._jump_on_success = command.command_index
|
|
68
|
+
|
|
69
|
+
return self
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .service import *
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import random
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from cascade.command import Command
|
|
6
|
+
from cascade.logger import get_logger
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
logger = get_logger(__name__)
|
|
10
|
+
random.seed(time.time())
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SleepCommand(Command):
|
|
14
|
+
"""
|
|
15
|
+
Sleep n seconds
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, secs: int):
|
|
19
|
+
super().__init__()
|
|
20
|
+
self.secs = secs
|
|
21
|
+
|
|
22
|
+
def body(self):
|
|
23
|
+
time.sleep(self.secs)
|
|
24
|
+
|
|
25
|
+
class SleepRandomRangeCommand(Command):
|
|
26
|
+
"""
|
|
27
|
+
Sleep a random number of seconds within a range
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, secs_from: int, secs_to: int):
|
|
31
|
+
super().__init__()
|
|
32
|
+
self.secs_from = secs_from
|
|
33
|
+
self.secs_to = secs_to
|
|
34
|
+
|
|
35
|
+
def body(self):
|
|
36
|
+
time.sleep(random.randrange(self.secs_from, self.secs_to))
|
|
37
|
+
|
|
38
|
+
class LogCommand(Command):
|
|
39
|
+
"""
|
|
40
|
+
Log a message at a specified level
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, level: int, message: str):
|
|
44
|
+
super().__init__()
|
|
45
|
+
self.level = level
|
|
46
|
+
self.message = message
|
|
47
|
+
|
|
48
|
+
def body(self):
|
|
49
|
+
logger.log(self.level, self.message)
|
|
50
|
+
|
|
51
|
+
class LogExceptionCommand(Command):
|
|
52
|
+
"""
|
|
53
|
+
Log an exception at the ERROR level
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(self, exception: object):
|
|
57
|
+
super().__init__()
|
|
58
|
+
self.exception = exception
|
|
59
|
+
|
|
60
|
+
def body(self):
|
|
61
|
+
logger.log(logging.ERROR, self.exception)
|
|
62
|
+
|
|
63
|
+
class DynamicLogCommand(Command):
|
|
64
|
+
"""
|
|
65
|
+
Log a dynamic message at a specified level
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(self, level: int):
|
|
69
|
+
super().__init__()
|
|
70
|
+
self.level = level
|
|
71
|
+
|
|
72
|
+
def body(self):
|
|
73
|
+
message = self.get_param_value(0)
|
|
74
|
+
logger.log(self.level, message)
|
|
75
|
+
|
|
76
|
+
class SetStackCommand(Command):
|
|
77
|
+
"""
|
|
78
|
+
Set the stack to a specified value, need to use with Store(<var>) operator!
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
def __init__(self, value):
|
|
82
|
+
super().__init__()
|
|
83
|
+
self.value = value
|
|
84
|
+
|
|
85
|
+
def body(self):
|
|
86
|
+
return self.value
|
|
87
|
+
|
|
88
|
+
class DebugStackCommand(Command):
|
|
89
|
+
"""
|
|
90
|
+
Debug the current stack
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def __init__(self):
|
|
94
|
+
super().__init__()
|
|
95
|
+
|
|
96
|
+
def body(self):
|
|
97
|
+
logger.debug("Stack: " + repr(self._stack))
|
|
98
|
+
|
|
99
|
+
class RaiseCommand(Command):
|
|
100
|
+
"""
|
|
101
|
+
Raise an exception
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
def __init__(self):
|
|
105
|
+
super().__init__()
|
|
106
|
+
|
|
107
|
+
def body(self):
|
|
108
|
+
raise Exception("Test raise")
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
import requests
|
|
5
|
+
import mss
|
|
6
|
+
import mss.tools
|
|
7
|
+
import io
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ConsoleHandler(logging.StreamHandler):
|
|
11
|
+
def __init__(self, log_level: str, stream):
|
|
12
|
+
super().__init__(stream)
|
|
13
|
+
|
|
14
|
+
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
|
15
|
+
self.setFormatter(formatter)
|
|
16
|
+
self.setLevel(log_level)
|
|
17
|
+
|
|
18
|
+
class TGHandler(logging.Handler):
|
|
19
|
+
def __init__(self, token: str, chats: str, level: str, image_on_error: bool):
|
|
20
|
+
super().__init__()
|
|
21
|
+
self.chats = chats.split(',')
|
|
22
|
+
self.image_on_error = image_on_error
|
|
23
|
+
self.url = f"https://api.telegram.org/bot{token}/sendMessage"
|
|
24
|
+
self.image_url = f"https://api.telegram.org/bot{token}/sendPhoto"
|
|
25
|
+
|
|
26
|
+
formatter = logging.Formatter("%(levelname)s - %(message)s")
|
|
27
|
+
self.setFormatter(formatter)
|
|
28
|
+
self.setLevel(level)
|
|
29
|
+
|
|
30
|
+
def emit(self, record):
|
|
31
|
+
log_entry = self.format(record)
|
|
32
|
+
|
|
33
|
+
for chat in self.chats:
|
|
34
|
+
payload = {
|
|
35
|
+
"chat_id": chat,
|
|
36
|
+
"text": log_entry
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
requests.post(self.url, json=payload)
|
|
40
|
+
|
|
41
|
+
if not self.image_on_error:
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
with mss.mss() as sct:
|
|
45
|
+
monitor = sct.monitors[1]
|
|
46
|
+
sct_img = sct.grab(monitor)
|
|
47
|
+
png_bytes = mss.tools.to_png(sct_img.rgb, sct_img.size)
|
|
48
|
+
|
|
49
|
+
image_file = io.BytesIO(png_bytes)
|
|
50
|
+
image_file.name = 'screenshot.png'
|
|
51
|
+
|
|
52
|
+
for chat in self.chats:
|
|
53
|
+
payload = {'chat_id': chat}
|
|
54
|
+
files = {'photo': image_file}
|
|
55
|
+
|
|
56
|
+
requests.post(self.image_url, data=payload, files=files)
|
|
57
|
+
|
|
58
|
+
class CustomFileHandler(logging.FileHandler):
|
|
59
|
+
def __init__(self, filename, mode = "a", encoding = None, delay = False, errors = None):
|
|
60
|
+
super().__init__(filename, mode, encoding, delay, errors)
|
|
61
|
+
|
|
62
|
+
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
|
63
|
+
self.setFormatter(formatter)
|
|
64
|
+
self.setLevel(logging.DEBUG)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_logger(name: str):
|
|
68
|
+
log_level = os.getenv("LOG_LEVEL", "DEBUG")
|
|
69
|
+
tg_token = os.getenv("TG_BOT_TOKEN", None)
|
|
70
|
+
tg_chats = os.getenv("TG_BOT_CHATS", None)
|
|
71
|
+
tg_log_level = os.getenv("TG_LOG_LEVEL", "INFO")
|
|
72
|
+
tg_image_on_error = os.getenv("TG_IMAGE_ON_ERROR", 0) == "1"
|
|
73
|
+
|
|
74
|
+
logger = logging.getLogger(f"genshin_game.[{name}]")
|
|
75
|
+
logger.setLevel(logging.DEBUG)
|
|
76
|
+
|
|
77
|
+
logger.addHandler(ConsoleHandler(log_level, sys.stdout))
|
|
78
|
+
logger.addHandler(CustomFileHandler("log.txt"))
|
|
79
|
+
|
|
80
|
+
if tg_token and tg_chats:
|
|
81
|
+
logger.addHandler(TGHandler(tg_token, tg_chats, tg_log_level, tg_image_on_error))
|
|
82
|
+
|
|
83
|
+
return logger
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from .stack import Stack
|
|
2
|
+
|
|
3
|
+
class Operator:
|
|
4
|
+
pass
|
|
5
|
+
|
|
6
|
+
class Execute(Operator):
|
|
7
|
+
def __init__(self, stack: Stack):
|
|
8
|
+
self.stack = stack
|
|
9
|
+
|
|
10
|
+
class Store(Operator):
|
|
11
|
+
def __init__(self, var_name):
|
|
12
|
+
self.var_name = var_name
|
|
13
|
+
|
|
14
|
+
class Param(Operator):
|
|
15
|
+
def __init__(self, value, accumulated=None):
|
|
16
|
+
self.values = accumulated if accumulated is not None else []
|
|
17
|
+
self.values.append(value)
|
|
18
|
+
|
|
19
|
+
def __rshift__(self, subject):
|
|
20
|
+
if isinstance(subject, Param):
|
|
21
|
+
return Param(subject.values[0], accumulated=self.values)
|
|
22
|
+
|
|
23
|
+
subject._vars = self.values
|
|
24
|
+
return subject
|
|
25
|
+
|
|
26
|
+
class RaiseSkip(Operator):
|
|
27
|
+
def __init__(self):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
class JumpOnRaise(Operator):
|
|
31
|
+
def __init__(self, command_index: int):
|
|
32
|
+
super().__init__()
|
|
33
|
+
self.command_index = command_index
|
|
34
|
+
|
|
35
|
+
class JumpOnSuccess(Operator):
|
|
36
|
+
def __init__(self, command_index: int):
|
|
37
|
+
super().__init__()
|
|
38
|
+
self.command_index = command_index
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from .command import Command
|
|
2
|
+
from .logger import get_logger
|
|
3
|
+
|
|
4
|
+
logger = get_logger(__name__)
|
|
5
|
+
|
|
6
|
+
class Pipeline(Command):
|
|
7
|
+
def __init__(self):
|
|
8
|
+
super().__init__()
|
|
9
|
+
self.pipeline = []
|
|
10
|
+
|
|
11
|
+
def _process_chain(self, chain: list):
|
|
12
|
+
from .operator import Execute
|
|
13
|
+
self._stack.push({} if not self._stack.top() else self._stack.top().copy())
|
|
14
|
+
self._stack.update("__debug_name", type(self).__name__)
|
|
15
|
+
|
|
16
|
+
i = 0
|
|
17
|
+
while i < len(chain):
|
|
18
|
+
subject = chain[i]
|
|
19
|
+
i += 1
|
|
20
|
+
|
|
21
|
+
if type(subject) == list:
|
|
22
|
+
self._process_chain(subject)
|
|
23
|
+
continue
|
|
24
|
+
|
|
25
|
+
result = subject >> Execute(self._stack)
|
|
26
|
+
|
|
27
|
+
if isinstance(result, Exception):
|
|
28
|
+
if subject._jump_on_raise is not None:
|
|
29
|
+
i = subject._jump_on_raise
|
|
30
|
+
logger.debug(f"{type(self).__name__} jump to {i} subject")
|
|
31
|
+
continue
|
|
32
|
+
|
|
33
|
+
if subject._skip_on_raise:
|
|
34
|
+
logger.debug(f"{type(self).__name__} skip pipeline")
|
|
35
|
+
break
|
|
36
|
+
else:
|
|
37
|
+
logger.debug(f"{type(self).__name__} raise")
|
|
38
|
+
raise result
|
|
39
|
+
|
|
40
|
+
if subject._jump_on_success is not None:
|
|
41
|
+
i = subject._jump_on_success
|
|
42
|
+
logger.debug(f"{type(self).__name__} jump to {i} subject")
|
|
43
|
+
continue
|
|
44
|
+
|
|
45
|
+
result = self._stack.pop()
|
|
46
|
+
return result.get("result")
|
|
47
|
+
|
|
48
|
+
def body(self):
|
|
49
|
+
return self._process_chain(self.pipeline)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class Stack:
|
|
2
|
+
def __init__(self):
|
|
3
|
+
self.stack = [{}]
|
|
4
|
+
|
|
5
|
+
def push(self, data):
|
|
6
|
+
self.stack.append(data)
|
|
7
|
+
|
|
8
|
+
def pop(self):
|
|
9
|
+
return self.stack.pop()
|
|
10
|
+
|
|
11
|
+
def top(self):
|
|
12
|
+
if len(self.stack) == 0:
|
|
13
|
+
return None
|
|
14
|
+
return self.stack[-1]
|
|
15
|
+
|
|
16
|
+
def update(self, key, value):
|
|
17
|
+
self.stack[-1].update({key: value})
|
|
18
|
+
|
|
19
|
+
def raw(self):
|
|
20
|
+
return self.stack
|
|
21
|
+
|
|
22
|
+
def top_value(self, var_name):
|
|
23
|
+
return self.top().get(var_name)
|
|
24
|
+
|
|
25
|
+
def __repr__(self):
|
|
26
|
+
return repr(self.stack)
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cascade-core
|
|
3
|
+
Version: 0.1.12
|
|
4
|
+
Summary: Cascade Core
|
|
5
|
+
License: MIT License
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2024 vadzimshpak
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
|
|
27
|
+
Requires-Python: >=3.11
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: mss
|
|
31
|
+
Requires-Dist: python-dotenv
|
|
32
|
+
Requires-Dist: requests
|
|
33
|
+
Provides-Extra: test
|
|
34
|
+
Requires-Dist: pytest; extra == "test"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# Cascade Core
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<img src="./media/logo.png" width="250">
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
Arch:
|
|
44
|
+
- Command - smallest part
|
|
45
|
+
- Pipeline - mix of commands
|
|
46
|
+
- Program - mix of commands and pipelines
|
|
47
|
+
- [Next level...]
|
|
48
|
+
- [Next level...]
|
|
49
|
+
|
|
50
|
+
Philosophy:
|
|
51
|
+
|
|
52
|
+
- Each well-tested and documented command is part of the sucessfull pipeline.
|
|
53
|
+
- Each well-tested and documented pipeline is part of the sucessfull program.
|
|
54
|
+
- Each well-tested and documented program is part of the sucessfull cascade.
|
|
55
|
+
- Each well-tested and documented cascade is part of the sucessfull business.
|
|
56
|
+
|
|
57
|
+
Add submodule to project:
|
|
58
|
+
`git submodule add https://github.com/vadzimshpak/cascade-core cascade`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
cascade/__init__.py
|
|
5
|
+
cascade/command.py
|
|
6
|
+
cascade/logger.py
|
|
7
|
+
cascade/operator.py
|
|
8
|
+
cascade/pipeline.py
|
|
9
|
+
cascade/program.py
|
|
10
|
+
cascade/resource.py
|
|
11
|
+
cascade/stack.py
|
|
12
|
+
cascade/commands/__init__.py
|
|
13
|
+
cascade/commands/service.py
|
|
14
|
+
cascade_core.egg-info/PKG-INFO
|
|
15
|
+
cascade_core.egg-info/SOURCES.txt
|
|
16
|
+
cascade_core.egg-info/dependency_links.txt
|
|
17
|
+
cascade_core.egg-info/requires.txt
|
|
18
|
+
cascade_core.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cascade
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cascade-core"
|
|
7
|
+
version = "0.1.12"
|
|
8
|
+
description = "Cascade Core"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"mss",
|
|
14
|
+
"python-dotenv",
|
|
15
|
+
"requests",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.optional-dependencies]
|
|
19
|
+
test = [
|
|
20
|
+
"pytest",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[tool.setuptools.packages.find]
|
|
24
|
+
include = ["cascade*"]
|