feat(py): SQLite.
This commit is contained in:
parent
e3c99a1143
commit
175cc13022
@ -69,6 +69,7 @@
|
|||||||
"anp_browser_action_not_done" : "La acción '{i}' de tipo '{action}' no ha sido ejecutada correctamente en el navegador '{key}'.",
|
"anp_browser_action_not_done" : "La acción '{i}' de tipo '{action}' no ha sido ejecutada correctamente en el navegador '{key}'.",
|
||||||
"anp_browser_action_not_supported" : "La acción '{i}' de tipo '{action}' no es compatible con el navegador '{key}'.",
|
"anp_browser_action_not_supported" : "La acción '{i}' de tipo '{action}' no es compatible con el navegador '{key}'.",
|
||||||
"anp_browser_action_not_action" : "El elemento '{i}' no es una acción válida en el navegador '{key}'.",
|
"anp_browser_action_not_action" : "El elemento '{i}' no es una acción válida en el navegador '{key}'.",
|
||||||
|
"anp_browser_abstract_do_action" : "Ejecutando la acción '{i}' de tipo '{action}' en el navegador '{key}'.",
|
||||||
"AnP_BrowserAbstract_end" : null,
|
"AnP_BrowserAbstract_end" : null,
|
||||||
|
|
||||||
"AnP_DirectoryCloneModel_start" : null,
|
"AnP_DirectoryCloneModel_start" : null,
|
||||||
|
|||||||
@ -2,12 +2,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Any, Self, Sequence, Optional, Callable
|
from typing import Any, Self, Sequence, Optional, Callable
|
||||||
from abc import ABC, abstractmethod
|
from abc import abstractmethod
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
from AnP.Models.AIResponseModel import AIResponseModel
|
from AnP.Models.AIResponseModel import AIResponseModel
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
class AIInterpretersAbstract(ABC):
|
class AIInterpretersAbstract(ModelAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, key:str, inputs:str|dict[str, Any|None]|Sequence[Any|None]) -> None:
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:str|dict[str, Any|None]|Sequence[Any|None]) -> None:
|
||||||
|
|
||||||
|
|||||||
@ -11,17 +11,16 @@ from AnP.DSLs.ScrapDSL import (
|
|||||||
)
|
)
|
||||||
from AnP.Utils.Common import Common
|
from AnP.Utils.Common import Common
|
||||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
|
from AnP.Models.BrowserTabsModel import BrowserBoxModel
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
class BrowserAbstract(ModelAbstract):
|
class BrowserAbstract(ModelAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, key:str, TabType:T, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
self.anp:AnPInterface = anp
|
self.anp:AnPInterface = anp
|
||||||
self.key:str = key
|
self.key:str = key
|
||||||
self.working:bool = True
|
self.working:bool = True
|
||||||
self.tabs:dict[str, T] = {}
|
|
||||||
self.tab_selected:str = ""
|
|
||||||
self.human_time:float|int|Sequence[float|int] = Common.get_value("human_time", inputs, 0.0)
|
self.human_time:float|int|Sequence[float|int] = Common.get_value("human_time", inputs, 0.0)
|
||||||
self.actions:dict[Action, Callable[[Action, dict[str, Any|None], Optional[Any]], None]] = {
|
self.actions:dict[Action, Callable[[Action, dict[str, Any|None], Optional[Any]], None]] = {
|
||||||
Execute : self.execute,
|
Execute : self.execute,
|
||||||
@ -35,9 +34,13 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
ForEach : self.foreach,
|
ForEach : self.foreach,
|
||||||
And : self._and,
|
And : self._and,
|
||||||
Or : self._or,
|
Or : self._or,
|
||||||
Not : self._not
|
Not : self._not,
|
||||||
|
If : self._if,
|
||||||
|
While : self._while,
|
||||||
|
DoWhile : self.do_while,
|
||||||
|
Download : self.download
|
||||||
}
|
}
|
||||||
self.__is_working:dict[str, Callable[[], bool]] = {}
|
self.__print_actions:bool = Common.get_value("print_actions", inputs, True)
|
||||||
|
|
||||||
def start(self:Self) -> None:
|
def start(self:Self) -> None:
|
||||||
self.working = True
|
self.working = True
|
||||||
@ -47,33 +50,23 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
|
|
||||||
def remove(self:Self) -> None:
|
def remove(self:Self) -> None:
|
||||||
self.stop()
|
self.stop()
|
||||||
self.tabs.clear()
|
|
||||||
self.tab_selected = ""
|
|
||||||
|
|
||||||
def is_working(self:Self, shared:Optional[dict[str, Any|None]] = None) -> bool:
|
def is_working(self:Self, box:BrowserBoxModel) -> bool:
|
||||||
return self.working and self.anp.working() and (
|
return self.working and self.anp.working() and (
|
||||||
shared is None or
|
box.is_working is None or box.is_working()
|
||||||
"__is_working_key__" not in shared or
|
|
||||||
shared["__is_working_key__"] not in self.__is_working or
|
|
||||||
self.__is_working[shared["__is_working_key__"]]()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def run(self:Self,
|
def run(self:Self,
|
||||||
actions:Sequence[Action],
|
actions:Sequence[Action],
|
||||||
shared:dict[str, Any|None] = {},
|
shared:dict[str, Any|None] = {},
|
||||||
key:Optional[str] = None,
|
|
||||||
is_working:Optional[Callable[[], bool]] = None
|
is_working:Optional[Callable[[], bool]] = None
|
||||||
) -> dict[str, Any|None]:
|
) -> dict[str, Any|None]:
|
||||||
|
|
||||||
if key is not None and is_working is not None:
|
|
||||||
self.__is_working[key] = is_working
|
|
||||||
shared["__is_working_key__"] = key
|
|
||||||
|
|
||||||
self.do(Do(*actions), shared)
|
self.do(Do(*actions), shared, BrowserBoxModel(is_working))
|
||||||
|
|
||||||
return shared
|
return shared
|
||||||
|
|
||||||
def execute(self:Self, action:Execute, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def execute(self:Self, action:Execute, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
try:
|
try:
|
||||||
action.callback(shared)
|
action.callback(shared)
|
||||||
action.done = True
|
action.done = True
|
||||||
@ -81,30 +74,30 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
action.exception = exception
|
action.exception = exception
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def open(self:Self, action:Open, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
def open(self:Self, action:Open, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:pass
|
||||||
|
|
||||||
@abstractmethod
|
def close(self:Self, action:Close, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
action.done = box.close(action.key)
|
||||||
|
|
||||||
@abstractmethod
|
def switch(self:Self, action:Switch, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
action.done = box.switch(action.key)
|
||||||
|
|
||||||
def wait(self:Self, action:Wait, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def wait(self:Self, action:Wait, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
date:float = timestamp()
|
date:float = timestamp()
|
||||||
time:int|float = (
|
time:int|float = (
|
||||||
action.time if action.is_fixed else
|
action.time if action.is_fixed else
|
||||||
Common.random_number(*action.time[0]) if action.is_range else
|
Common.random_number(*action.time) if action.is_range else
|
||||||
Common.random(*action.time))
|
Common.random(*action.time))
|
||||||
|
|
||||||
while self.is_working(shared):
|
while self.is_working(box):
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
if timestamp() - date >= time:
|
if timestamp() - date >= time:
|
||||||
break
|
break
|
||||||
|
|
||||||
action.done = True
|
action.done = True
|
||||||
|
|
||||||
def do(self:Self, action:Do, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def do(self:Self, action:Do, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
subaction:Action
|
subaction:Action
|
||||||
i:int
|
i:int
|
||||||
@ -112,10 +105,16 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
action.done = True
|
action.done = True
|
||||||
|
|
||||||
for i, subaction in enumerate(action.actions):
|
for i, subaction in enumerate(action.actions):
|
||||||
if not self.is_working(shared):
|
if not self.is_working(box):
|
||||||
action.done = False
|
action.done = False
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.__print_actions and self.anp.print("info", "anp_browser_abstract_do_action", {
|
||||||
|
"key" : self.key,
|
||||||
|
"i" : i,
|
||||||
|
"action" : subaction.__class__.__name__
|
||||||
|
})
|
||||||
|
|
||||||
if isinstance(subaction, Action):
|
if isinstance(subaction, Action):
|
||||||
subaction.done = False
|
subaction.done = False
|
||||||
subaction.exception = None
|
subaction.exception = None
|
||||||
@ -124,7 +123,7 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
|
|
||||||
ok:bool
|
ok:bool
|
||||||
|
|
||||||
self.actions[subaction.__class__](subaction, shared, last_item)
|
self.actions[subaction.__class__](subaction, shared, box)
|
||||||
ok = subaction.done and subaction.exception is None
|
ok = subaction.done and subaction.exception is None
|
||||||
|
|
||||||
if not ok and not subaction.ignore_fail:
|
if not ok and not subaction.ignore_fail:
|
||||||
@ -144,7 +143,7 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if subaction.wait:
|
if subaction.wait:
|
||||||
self.wait(Wait(self.human_time, True))
|
self.wait(Wait(self.human_time, True), shared, box)
|
||||||
|
|
||||||
ok and subaction.print_ok and self.anp.print("info", "anp_browser_action_done", {
|
ok and subaction.print_ok and self.anp.print("info", "anp_browser_action_done", {
|
||||||
"key" : self.key,
|
"key" : self.key,
|
||||||
@ -182,10 +181,10 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def go(self:Self, action:Go, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
def go(self:Self, action:Go, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_selector(self:Self, selector:Selector, from_item:Optional[Any] = None, force_multiple:bool = False) -> Any|list[Any]|None:pass
|
def get_selector(self:Self, selector:Selector, box:BrowserBoxModel, force_multiple:bool = False) -> Any|list[Any]|None:pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_value(action:Get, value:str) -> str:
|
def get_value(action:Get, value:str) -> str:
|
||||||
@ -194,19 +193,20 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
return action.pattern.sub(action.matches, value)
|
return action.pattern.sub(action.matches, value)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get(self:Self, action:Get, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
def get(self:Self, action:Get, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:pass
|
||||||
|
|
||||||
def foreach(self:Self, action:ForEach, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def foreach(self:Self, action:ForEach, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
item:Any|None
|
item:Any|None
|
||||||
done:bool = True
|
done:bool = True
|
||||||
is_selector:bool = isinstance(action.items, Selector)
|
is_selector:bool = isinstance(action.items, Selector)
|
||||||
|
last:Any|None = box.get_last()
|
||||||
|
|
||||||
for item in (
|
for item in (
|
||||||
self.get_selector(action.items, last_item, True) if is_selector else
|
self.get_selector(action.items, box, True) if is_selector else
|
||||||
action.items):
|
action.items):
|
||||||
|
|
||||||
if not self.is_working(shared):
|
if not self.is_working(box):
|
||||||
done = False
|
done = False
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -220,91 +220,86 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
|
|
||||||
subactions:Do = Do(*action.actions)
|
subactions:Do = Do(*action.actions)
|
||||||
|
|
||||||
self.do(subactions, shared, item if is_selector else last_item)
|
box.set_last(item)
|
||||||
|
|
||||||
|
self.do(subactions, shared, box)
|
||||||
if not subactions.done or subactions.exception is not None:
|
if not subactions.done or subactions.exception is not None:
|
||||||
action.exception = subactions.exception
|
action.exception = subactions.exception
|
||||||
done = False
|
done = False
|
||||||
break
|
break
|
||||||
|
|
||||||
|
box.reset()
|
||||||
|
box.set_last(last)
|
||||||
|
|
||||||
action.done = done
|
action.done = done
|
||||||
|
|
||||||
def _and(self:Self, action:And, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:
|
def __condition(self:Self,
|
||||||
|
action:Condition|bool|Selector|Callable[[dict[str, Any|None]], bool],
|
||||||
|
shared:dict[str, Any|None],
|
||||||
|
box:BrowserBoxModel
|
||||||
|
) -> bool:
|
||||||
|
|
||||||
|
if isinstance(action, And):
|
||||||
|
self._and(action, shared, box)
|
||||||
|
return action.ok
|
||||||
|
elif isinstance(action, Or):
|
||||||
|
self._or(action, shared, box)
|
||||||
|
return action.ok
|
||||||
|
elif isinstance(action, Not):
|
||||||
|
self._not(action, shared, box)
|
||||||
|
return action.ok
|
||||||
|
elif isinstance(action, bool):
|
||||||
|
return action
|
||||||
|
elif isinstance(action, Selector):
|
||||||
|
return self.get_selector(action, box)
|
||||||
|
elif callable(action):
|
||||||
|
try:
|
||||||
|
return action(shared)
|
||||||
|
except Exception as exception:
|
||||||
|
action.exception = exception
|
||||||
|
else:
|
||||||
|
action.print_errors and self.anp.print("warning", "anp_browser_condition_not_supported", {
|
||||||
|
"key" : self.key
|
||||||
|
})
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _and(self:Self, action:And, shared:dict[str, Any|None], box:BrowserBoxModel) -> bool:
|
||||||
|
|
||||||
condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition
|
condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition
|
||||||
|
|
||||||
action.ok = True
|
action.ok = True
|
||||||
|
|
||||||
for condition in action.conditions:
|
for condition in action.conditions:
|
||||||
if isinstance(condition, Condition):
|
if not self.__condition(condition, shared, box):
|
||||||
self.do(condition, shared, last_item)
|
action.ok = False
|
||||||
if not condition.ok:
|
break
|
||||||
action.ok = False
|
|
||||||
break
|
|
||||||
elif isinstance(condition, Selector):
|
|
||||||
if not self.get_selector(condition, last_item):
|
|
||||||
action.ok = False
|
|
||||||
break
|
|
||||||
elif callable(condition):
|
|
||||||
try:
|
|
||||||
if not condition(shared):
|
|
||||||
action.ok = False
|
|
||||||
break
|
|
||||||
except Exception as exception:
|
|
||||||
action.exception = exception
|
|
||||||
action.ok = False
|
|
||||||
break
|
|
||||||
|
|
||||||
def _or(self:Self, action:Or, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:
|
def _or(self:Self, action:Or, shared:dict[str, Any|None], box:BrowserBoxModel) -> bool:
|
||||||
|
|
||||||
condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition
|
condition:Callable[[dict[str, Any|None]], bool]|Selector|Condition
|
||||||
|
|
||||||
action.ok = False
|
action.ok = False
|
||||||
|
|
||||||
for condition in action.conditions:
|
for condition in action.conditions:
|
||||||
if isinstance(condition, Condition):
|
if self.__condition(condition, shared, box):
|
||||||
self.do(condition, shared, last_item)
|
action.ok = True
|
||||||
if condition.ok:
|
break
|
||||||
action.ok = True
|
|
||||||
break
|
|
||||||
elif isinstance(condition, Selector):
|
|
||||||
if self.get_selector(condition, last_item):
|
|
||||||
action.ok = True
|
|
||||||
break
|
|
||||||
elif callable(condition):
|
|
||||||
try:
|
|
||||||
if condition(shared):
|
|
||||||
action.ok = True
|
|
||||||
break
|
|
||||||
except Exception as exception:
|
|
||||||
action.exception = exception
|
|
||||||
action.ok = False
|
|
||||||
break
|
|
||||||
|
|
||||||
def _not(self:Self, action:Not, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:
|
def _not(self:Self, action:Not, shared:dict[str, Any|None], box:BrowserBoxModel) -> bool:
|
||||||
if isinstance(action.condition, Condition):
|
return not self.__condition(action.condition, shared, box)
|
||||||
self.do(action.condition, shared, last_item)
|
|
||||||
action.ok = not action.condition.ok
|
|
||||||
elif isinstance(action.condition, Selector):
|
|
||||||
action.ok = not self.get_selector(action.condition, last_item)
|
|
||||||
elif callable(action.condition):
|
|
||||||
try:
|
|
||||||
action.ok = not action.condition(shared)
|
|
||||||
except Exception as exception:
|
|
||||||
action.exception = exception
|
|
||||||
action.ok = False
|
|
||||||
|
|
||||||
def _if(self:Self, action:If, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def _if(self:Self, action:If, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
if not isinstance(action.condition, Condition):
|
if not isinstance(action.condition, Condition):
|
||||||
action.condition = Condition((action.condition,))
|
action.condition = Condition((action.condition,))
|
||||||
|
|
||||||
self.do(action.condition, shared, last_item)
|
self.do(action.condition, shared, box)
|
||||||
|
|
||||||
if action.condition.done and action.condition.exception is None:
|
if action.condition.done and action.condition.exception is None:
|
||||||
|
|
||||||
subactions:Do = Do(*((action.if_actions if action.condition.ok else action.else_actions) or []))
|
subactions:Do = Do(*((action.if_actions if action.condition.ok else action.else_actions) or []))
|
||||||
|
|
||||||
self.do(subactions, shared, last_item)
|
self.do(subactions, shared, box)
|
||||||
action.done = subactions.done and subactions.exception is None
|
action.done = subactions.done and subactions.exception is None
|
||||||
action.exception = subactions.exception
|
action.exception = subactions.exception
|
||||||
|
|
||||||
@ -312,17 +307,17 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
action.done = action.condition.done
|
action.done = action.condition.done
|
||||||
action.exception = action.condition.exception
|
action.exception = action.condition.exception
|
||||||
|
|
||||||
def _while(self:Self, action:While, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def _while(self:Self, action:While, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
if not isinstance(action.condition, Condition):
|
if not isinstance(action.condition, Condition):
|
||||||
action.condition = Condition((action.condition,))
|
action.condition = Condition((action.condition,))
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if not self.is_working(shared):
|
if not self.is_working(box):
|
||||||
action.done = False
|
action.done = False
|
||||||
break
|
break
|
||||||
|
|
||||||
self.do(action.condition, shared, last_item)
|
self.do(action.condition, shared, box)
|
||||||
|
|
||||||
if not action.condition.done or action.condition.exception is not None:
|
if not action.condition.done or action.condition.exception is not None:
|
||||||
action.done = action.condition.done
|
action.done = action.condition.done
|
||||||
@ -333,7 +328,7 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
|
|
||||||
subactions:Do = Do(*action.actions)
|
subactions:Do = Do(*action.actions)
|
||||||
|
|
||||||
self.do(subactions, shared, last_item)
|
self.do(subactions, shared, box)
|
||||||
if not subactions.done or subactions.exception is not None:
|
if not subactions.done or subactions.exception is not None:
|
||||||
action.exception = subactions.exception
|
action.exception = subactions.exception
|
||||||
action.done = False
|
action.done = False
|
||||||
@ -343,25 +338,26 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
action.done = True
|
action.done = True
|
||||||
break
|
break
|
||||||
|
|
||||||
def do_while(self:Self, action:DoWhile, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def do_while(self:Self, action:DoWhile, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
if not isinstance(action.condition, Condition):
|
if not isinstance(action.condition, Condition):
|
||||||
action.condition = Condition((action.condition,))
|
action.condition = Condition((action.condition,))
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if not self.is_working(shared):
|
if not self.is_working(box):
|
||||||
action.done = False
|
action.done = False
|
||||||
break
|
break
|
||||||
|
|
||||||
subactions:Do = Do(*action.actions)
|
subactions:Do = Do(*action.actions)
|
||||||
|
|
||||||
self.do(subactions, shared, last_item)
|
self.do(subactions, shared, box)
|
||||||
if not subactions.done or subactions.exception is not None:
|
if not subactions.done or subactions.exception is not None:
|
||||||
action.exception = subactions.exception
|
action.exception = subactions.exception
|
||||||
action.done = False
|
action.done = False
|
||||||
break
|
break
|
||||||
|
|
||||||
self.do(action.condition, shared, last_item)
|
subactions = Do(*action.actions)
|
||||||
|
self.do(subactions, shared, box)
|
||||||
|
|
||||||
if not action.condition.done or action.condition.exception is not None:
|
if not action.condition.done or action.condition.exception is not None:
|
||||||
action.done = action.condition.done
|
action.done = action.condition.done
|
||||||
@ -373,4 +369,4 @@ class BrowserAbstract(ModelAbstract):
|
|||||||
break
|
break
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def download(self:Self, action:Download, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
def download(self:Self, action:Download, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:pass
|
||||||
70
Python/AnP/Abstracts/DatabaseAbstract.py
Normal file
70
Python/AnP/Abstracts/DatabaseAbstract.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Sequence, Optional
|
||||||
|
from abc import abstractmethod
|
||||||
|
from time import time as timestamp
|
||||||
|
from threading import Lock, Thread
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Models.DatabaseResponseModel import DatabaseResponseModel
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
|
from AnP.Utils.Common import Common
|
||||||
|
|
||||||
|
class DatabaseAbstract(ModelAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface, inputs:dict[str, Any|None]|Sequence[Any|None]) -> None:
|
||||||
|
|
||||||
|
self.anp:AnPInterface = anp
|
||||||
|
self.__lock:Lock = Lock()
|
||||||
|
self.__busy:bool = False
|
||||||
|
self.__working:bool = True
|
||||||
|
self.__connection_timer:float|int = Common.get_value("connection_timer", inputs, 300.0)
|
||||||
|
self.__last_connection:Any = 0.0
|
||||||
|
self.__thread:Thread = Thread(target = self.__connection_controller)
|
||||||
|
file:str
|
||||||
|
|
||||||
|
self.__thread.start()
|
||||||
|
|
||||||
|
for file in Common.get_texts(Common.get_value("execute", inputs, [])):
|
||||||
|
self.execute_file(file)
|
||||||
|
|
||||||
|
def close(self:Self) -> None:
|
||||||
|
self.disconnect()
|
||||||
|
self.__working = False
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def is_disconnected(self:Self) -> bool:pass
|
||||||
|
|
||||||
|
def __connection_controller(self:Self) -> None:
|
||||||
|
while self.__working and self.anp.working():
|
||||||
|
if self.is_disconnected():
|
||||||
|
if timestamp() - self.__last_connection > self.__connection_timer:
|
||||||
|
self.disconnect()
|
||||||
|
self.anp.wait(1.0)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def connect(self:Self) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def disconnect(self:Self) -> None:pass
|
||||||
|
|
||||||
|
def _ready(self:Self) -> None:
|
||||||
|
while self.anp.working():
|
||||||
|
with self.__lock:
|
||||||
|
if self.__busy:
|
||||||
|
self.anp.wait(1.0)
|
||||||
|
else:
|
||||||
|
self.__last_connection = timestamp()
|
||||||
|
self.__busy = True
|
||||||
|
break
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def execute(self:Self, query:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> DatabaseResponseModel:pass
|
||||||
|
|
||||||
|
def execute_file(self:Self, path:str, inputs:Optional[dict[str, Any|None]] = None) -> DatabaseResponseModel:
|
||||||
|
return self.execute(self.anp.files.load(path), inputs)
|
||||||
|
|
||||||
|
def _unbusy(self:Self) -> None:
|
||||||
|
with self.__lock:
|
||||||
|
self.__busy = False
|
||||||
|
self.__last_connection = timestamp()
|
||||||
@ -2,14 +2,15 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Any, Optional, Self, Sequence
|
from typing import Any, Optional, Self, Sequence
|
||||||
from abc import ABC, abstractmethod
|
from abc import abstractmethod
|
||||||
from os.path import dirname as directory_name, abspath as absolute_path
|
from os.path import dirname as directory_name, abspath as absolute_path
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
from AnP.Utils.Common import Common
|
from AnP.Utils.Common import Common
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
from AnP.Utils.Patterns import RE
|
from AnP.Utils.Patterns import RE
|
||||||
|
|
||||||
class FilesAbstract(ABC):
|
class FilesAbstract(ModelAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __init__(self:Self, anp:AnPInterface, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
self.anp:AnPInterface = anp
|
self.anp:AnPInterface = anp
|
||||||
@ -95,4 +96,7 @@ class FilesAbstract(ABC):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def list_directory_items(self:Self, path:str) -> list[str]:pass
|
def list_directory_items(self:Self, path:str) -> list[str]:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def prepare_directory(self:Self, path:str) -> bool:pass
|
||||||
@ -1,14 +1,15 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import abstractmethod
|
||||||
from typing import Any, Self, Optional, Sequence
|
from typing import Any, Self, Optional, Sequence
|
||||||
from re import Match as REMath
|
from re import Match as REMath
|
||||||
import datetime
|
import datetime
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
from AnP.Utils.Common import Common
|
from AnP.Utils.Common import Common
|
||||||
|
|
||||||
class HTTPServersAbstract(ABC):
|
class HTTPServersAbstract(ModelAbstract):
|
||||||
|
|
||||||
DEFAULT_PORT:int = 8000
|
DEFAULT_PORT:int = 8000
|
||||||
DEFAULT_HOST:str = ""
|
DEFAULT_HOST:str = ""
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
class ModelAbstract:pass
|
from abc import ABC
|
||||||
|
|
||||||
|
class ModelAbstract(ABC):pass
|
||||||
@ -2,12 +2,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Any, Self, Optional, Sequence
|
from typing import Any, Self, Optional, Sequence
|
||||||
from abc import ABC, abstractmethod
|
from abc import abstractmethod
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||||
from AnP.Application.Event import Event
|
from AnP.Application.Event import Event
|
||||||
from AnP.Utils.Common import Common
|
from AnP.Utils.Common import Common
|
||||||
|
|
||||||
class WebSocketServersAbstract(ABC):
|
class WebSocketServersAbstract(ModelAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
self.anp:AnPInterface = anp
|
self.anp:AnPInterface = anp
|
||||||
|
|||||||
@ -16,6 +16,7 @@ from AnP.Managers.ModelsManager import ModelsManager
|
|||||||
from AnP.Managers.UniqueKeysManager import UniqueKeysManager
|
from AnP.Managers.UniqueKeysManager import UniqueKeysManager
|
||||||
from AnP.Managers.QueusManager import QueuesManager
|
from AnP.Managers.QueusManager import QueuesManager
|
||||||
from AnP.Managers.SessionsManager import SessionsManager
|
from AnP.Managers.SessionsManager import SessionsManager
|
||||||
|
from AnP.Managers.DatabasesManager import DatabasesManager
|
||||||
from AnP.Managers.ControllersManager import ControllersManager
|
from AnP.Managers.ControllersManager import ControllersManager
|
||||||
from AnP.Managers.DispatchesManager import DispatchesManager
|
from AnP.Managers.DispatchesManager import DispatchesManager
|
||||||
from AnP.Managers.IndexesManager import IndexesManager
|
from AnP.Managers.IndexesManager import IndexesManager
|
||||||
@ -56,6 +57,7 @@ class AnP:
|
|||||||
self.unique_keys:UniqueKeysManager = UniqueKeysManager(self)
|
self.unique_keys:UniqueKeysManager = UniqueKeysManager(self)
|
||||||
self.queues:QueuesManager = QueuesManager(self)
|
self.queues:QueuesManager = QueuesManager(self)
|
||||||
self.sessions:SessionsManager = SessionsManager(self)
|
self.sessions:SessionsManager = SessionsManager(self)
|
||||||
|
self.databases:DatabasesManager = DatabasesManager(self)
|
||||||
self.controllers:ControllersManager = ControllersManager(self)
|
self.controllers:ControllersManager = ControllersManager(self)
|
||||||
self.dispatches:DispatchesManager = DispatchesManager(self)
|
self.dispatches:DispatchesManager = DispatchesManager(self)
|
||||||
self.indexes:IndexesManager = IndexesManager(self)
|
self.indexes:IndexesManager = IndexesManager(self)
|
||||||
@ -77,6 +79,7 @@ class AnP:
|
|||||||
self.unique_keys.update()
|
self.unique_keys.update()
|
||||||
self.queues.update()
|
self.queues.update()
|
||||||
self.sessions.update()
|
self.sessions.update()
|
||||||
|
self.databases.update()
|
||||||
self.controllers.update()
|
self.controllers.update()
|
||||||
self.dispatches.update()
|
self.dispatches.update()
|
||||||
self.indexes.update()
|
self.indexes.update()
|
||||||
@ -97,6 +100,7 @@ class AnP:
|
|||||||
self.unique_keys.reset()
|
self.unique_keys.reset()
|
||||||
self.queues.reset()
|
self.queues.reset()
|
||||||
self.sessions.reset()
|
self.sessions.reset()
|
||||||
|
self.databases.reset()
|
||||||
self.controllers.reset()
|
self.controllers.reset()
|
||||||
self.dispatches.reset()
|
self.dispatches.reset()
|
||||||
self.indexes.reset()
|
self.indexes.reset()
|
||||||
@ -115,6 +119,7 @@ class AnP:
|
|||||||
self.http_servers.close()
|
self.http_servers.close()
|
||||||
self.browsers.close()
|
self.browsers.close()
|
||||||
self.directories_clones.close()
|
self.directories_clones.close()
|
||||||
|
self.databases.close()
|
||||||
|
|
||||||
def working(self:Self) -> bool:
|
def working(self:Self) -> bool:
|
||||||
return self.__working
|
return self.__working
|
||||||
|
|||||||
@ -12,6 +12,7 @@ class Action:
|
|||||||
self.print_ok:bool = False
|
self.print_ok:bool = False
|
||||||
self.done:bool = False
|
self.done:bool = False
|
||||||
self.wait:bool = True
|
self.wait:bool = True
|
||||||
|
self.ignore_fail:bool = False
|
||||||
|
|
||||||
class Execute(Action):
|
class Execute(Action):
|
||||||
def __init__(self:Self, callback:Callable[[dict[str, Any|None]], None]) -> None:
|
def __init__(self:Self, callback:Callable[[dict[str, Any|None]], None]) -> None:
|
||||||
|
|||||||
@ -11,11 +11,10 @@ from os import (
|
|||||||
listdir as list_directory_items
|
listdir as list_directory_items
|
||||||
)
|
)
|
||||||
from shutil import rmtree as remove_directory
|
from shutil import rmtree as remove_directory
|
||||||
from AnP.Abstracts.FilesAbstract import FilesAbstract
|
from AnP.Abstracts.FilesAbstract import FilesAbstract, abstractmethod
|
||||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
class FilesDriver(FilesAbstract, ModelAbstract):
|
class FilesDriver(FilesAbstract):
|
||||||
|
|
||||||
def get_absolute_path(self:Self, path:str) -> str|None:
|
def get_absolute_path(self:Self, path:str) -> str|None:
|
||||||
|
|
||||||
@ -124,4 +123,9 @@ class FilesDriver(FilesAbstract, ModelAbstract):
|
|||||||
"path" : path,
|
"path" : path,
|
||||||
"only_names" : only_names
|
"only_names" : only_names
|
||||||
})
|
})
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
def prepare_directory(self:Self, path:str) -> bool:
|
||||||
|
if self.exists(path):
|
||||||
|
return True
|
||||||
|
return self.make_directory(path)
|
||||||
@ -6,11 +6,10 @@ from threading import Thread
|
|||||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||||
from http.cookies import SimpleCookie
|
from http.cookies import SimpleCookie
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
|
||||||
from AnP.Models.RequestModel import RequestModel
|
from AnP.Models.RequestModel import RequestModel
|
||||||
from AnP.Abstracts.HTTPServersAbstract import HTTPServersAbstract
|
from AnP.Abstracts.HTTPServersAbstract import HTTPServersAbstract
|
||||||
|
|
||||||
class HTTPServerDriver(HTTPServersAbstract, ModelAbstract):
|
class HTTPServerDriver(HTTPServersAbstract):
|
||||||
|
|
||||||
class HTTPRequestHandler(BaseHTTPRequestHandler):
|
class HTTPRequestHandler(BaseHTTPRequestHandler):
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,17 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Sequence
|
||||||
|
from AnP.Abstracts.DatabaseAbstract import DatabaseAbstract
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Utils.Common import Common
|
||||||
|
|
||||||
|
class MySQLDriver(DatabaseAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface, inputs:dict[str, Any|None]|Sequence[Any|None]) -> None:
|
||||||
|
self.anp:AnPInterface = anp
|
||||||
|
self.__host:str = Common.get_value("host", inputs)
|
||||||
|
self.__port:int = Common.get_value("port", inputs)
|
||||||
|
self.__user:str = Common.get_value("user", inputs)
|
||||||
|
self.__password:str = Common.get_value("password", inputs)
|
||||||
|
self.__database:str = Common.get_value("database", inputs)
|
||||||
@ -3,15 +3,13 @@
|
|||||||
|
|
||||||
from typing import Any, Optional, Self, Sequence, Callable
|
from typing import Any, Optional, Self, Sequence, Callable
|
||||||
from requests import post as Post, Response
|
from requests import post as Post, Response
|
||||||
# from pydantic import BaseModel
|
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
from AnP.Abstracts.AIInterpretersAbstract import AIInterpretersAbstract
|
from AnP.Abstracts.AIInterpretersAbstract import AIInterpretersAbstract
|
||||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
|
||||||
from AnP.Models.AIResponseModel import AIResponseModel
|
from AnP.Models.AIResponseModel import AIResponseModel
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
from AnP.Utils.Common import Common
|
from AnP.Utils.Common import Common
|
||||||
|
|
||||||
class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
|
class OllamaDriver(AIInterpretersAbstract):
|
||||||
|
|
||||||
def __init__(self:Self,
|
def __init__(self:Self,
|
||||||
anp:AnPInterface,
|
anp:AnPInterface,
|
||||||
|
|||||||
17
Python/AnP/Drivers/PostgreSQLDriver.py
Normal file
17
Python/AnP/Drivers/PostgreSQLDriver.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Sequence
|
||||||
|
from AnP.Abstracts.DatabaseAbstract import DatabaseAbstract
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Utils.Common import Common
|
||||||
|
|
||||||
|
class PostgreSQLDriver(DatabaseAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface, inputs:dict[str, Any|None]|Sequence[Any|None]) -> None:
|
||||||
|
self.anp:AnPInterface = anp
|
||||||
|
self.__host:str = Common.get_value("host", inputs)
|
||||||
|
self.__port:int = Common.get_value("port", inputs)
|
||||||
|
self.__user:str = Common.get_value("user", inputs)
|
||||||
|
self.__password:str = Common.get_value("password", inputs)
|
||||||
|
self.__database:str = Common.get_value("database", inputs)
|
||||||
@ -1,2 +1,17 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Sequence
|
||||||
|
from AnP.Abstracts.DatabaseAbstract import DatabaseAbstract
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Utils.Common import Common
|
||||||
|
|
||||||
|
class SQLServerDriver(DatabaseAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface, inputs:dict[str, Any|None]|Sequence[Any|None]) -> None:
|
||||||
|
self.anp:AnPInterface = anp
|
||||||
|
self.__host:str = Common.get_value("host", inputs)
|
||||||
|
self.__port:int = Common.get_value("port", inputs)
|
||||||
|
self.__user:str = Common.get_value("user", inputs)
|
||||||
|
self.__password:str = Common.get_value("password", inputs)
|
||||||
|
self.__database:str = Common.get_value("database", inputs)
|
||||||
@ -1,2 +1,166 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Sequence, Optional
|
||||||
|
from sqlite3 import Connection, connect as sqlite_connect, Cursor
|
||||||
|
from re import Match as REMatch
|
||||||
|
from AnP.Abstracts.DatabaseAbstract import DatabaseAbstract
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Models.DatabaseResponseModel import DatabaseResponseModel
|
||||||
|
from AnP.Utils.Common import Common
|
||||||
|
from AnP.Utils.Patterns import RE
|
||||||
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
|
class SQLiteDriver(DatabaseAbstract):
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface, inputs:dict[str, Any|None]|Sequence[Any|None]) -> None:
|
||||||
|
self.__connection:Connection|None = None
|
||||||
|
self.__path:str = Common.get_value("path", inputs)
|
||||||
|
super().__init__(anp, inputs)
|
||||||
|
|
||||||
|
def connect(self:Self) -> bool:
|
||||||
|
if self.__connection is None:
|
||||||
|
try:
|
||||||
|
|
||||||
|
directory:str = self.anp.files.get_parent(self.__path)
|
||||||
|
|
||||||
|
self.anp.files.prepare_directory(directory)
|
||||||
|
self.__connection = sqlite_connect(self.__path, check_same_thread = False)
|
||||||
|
|
||||||
|
except Exception as exception:
|
||||||
|
self.anp.exception(exception, "anp_sqlite_driver_connection_exception")
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def is_disconnected(self:Self) -> bool:
|
||||||
|
return self.__connection is None
|
||||||
|
|
||||||
|
def disconnect(self:Self) -> bool:
|
||||||
|
if self.__connection is not None:
|
||||||
|
try:
|
||||||
|
self.__connection.close()
|
||||||
|
self.__connection = None
|
||||||
|
return True
|
||||||
|
except Exception as exception:
|
||||||
|
self.anp.exception(exception, "anp_sqlite_driver_disconnection_exception")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __set_variables(self:Self, query:str, inputs:Optional[dict[str, Any|None]] = None) -> str:
|
||||||
|
|
||||||
|
def callback(matches:REMatch) -> str:
|
||||||
|
|
||||||
|
key:str = matches.group(1)
|
||||||
|
|
||||||
|
if key in inputs:
|
||||||
|
|
||||||
|
value:Any|None = inputs[key]
|
||||||
|
|
||||||
|
return (
|
||||||
|
"null" if value is None else
|
||||||
|
"'" + value.replace("'", "''") + "'" if Check.is_string(value) else
|
||||||
|
("1" if value is True else "0") if Check.is_boolean(value) else
|
||||||
|
# "'" + value.strftime("%Y-%m-%d %H:%M:%S") + "'" if Check.is_date(value) else
|
||||||
|
"'" + value.isoformat(sep = " ") + "'" if Check.is_date(value) else
|
||||||
|
str(value))
|
||||||
|
return matches.group(0)
|
||||||
|
|
||||||
|
return RE.STRING_VARIABLES.sub(callback, query.strip())
|
||||||
|
|
||||||
|
def __process(self:Self, query:str, inputs:Optional[dict[str, Any|None]] = None) -> Any|None:
|
||||||
|
|
||||||
|
sentences:list[str] = []
|
||||||
|
variables:list[str] = []
|
||||||
|
positions:dict[str, int|None] = {
|
||||||
|
";" : -1,
|
||||||
|
"\"" : -1,
|
||||||
|
"'" : -1
|
||||||
|
}
|
||||||
|
character:str
|
||||||
|
position:int|None
|
||||||
|
subquery:str = ""
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
lower:str|None = None
|
||||||
|
|
||||||
|
for character, position in positions.items():
|
||||||
|
if position is None:
|
||||||
|
continue
|
||||||
|
if position < 0:
|
||||||
|
positions[character] = query.find(character)
|
||||||
|
if positions[character] == -1:
|
||||||
|
positions[character] = None
|
||||||
|
continue
|
||||||
|
if lower is None or positions[character] < positions[lower]:
|
||||||
|
lower = character
|
||||||
|
|
||||||
|
if lower is None:
|
||||||
|
subquery = (subquery + query).strip()
|
||||||
|
if len(subquery):
|
||||||
|
sentences.append(self.__set_variables(subquery, inputs))
|
||||||
|
break
|
||||||
|
|
||||||
|
subquery += query[:positions[lower] + 1]
|
||||||
|
query = query[positions[lower] + 1:]
|
||||||
|
|
||||||
|
if lower == ";":
|
||||||
|
subquery = subquery.strip()
|
||||||
|
if len(subquery):
|
||||||
|
sentences.append(self.__set_variables(subquery, inputs))
|
||||||
|
subquery = ""
|
||||||
|
|
||||||
|
if not len(query):
|
||||||
|
break
|
||||||
|
|
||||||
|
for character in positions.keys():
|
||||||
|
if positions[character] is not None:
|
||||||
|
positions[character] -= positions[lower] + 1
|
||||||
|
|
||||||
|
return sentences, variables
|
||||||
|
|
||||||
|
def execute(self:Self, query:str, inputs:Optional[dict[str, Any|None]] = None) -> DatabaseResponseModel:
|
||||||
|
|
||||||
|
response:DatabaseResponseModel = DatabaseResponseModel()
|
||||||
|
|
||||||
|
self._ready()
|
||||||
|
|
||||||
|
if self.connect():
|
||||||
|
|
||||||
|
sentences:list[str]
|
||||||
|
variables:list[str]
|
||||||
|
sentence:str
|
||||||
|
i:int
|
||||||
|
cursor:Cursor = self.__connection.cursor()
|
||||||
|
|
||||||
|
sentences, variables = self.__process(query, inputs)
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
for i, sentence in enumerate(sentences):
|
||||||
|
|
||||||
|
row:list[Any]
|
||||||
|
columns:list[str]
|
||||||
|
|
||||||
|
cursor.execute(sentence)
|
||||||
|
columns = [
|
||||||
|
column[0] for column in cursor.description
|
||||||
|
] if cursor.description is not None else []
|
||||||
|
self.__connection.commit()
|
||||||
|
|
||||||
|
for row in cursor.fetchall():
|
||||||
|
response.add(i, dict(zip(columns, row)))
|
||||||
|
|
||||||
|
self.__connection.commit()
|
||||||
|
|
||||||
|
except Exception as exception:
|
||||||
|
self.anp.exception(exception, "anp_sqlite_driver_execution_exception", {
|
||||||
|
"i" : i,
|
||||||
|
"sentence" : sentence
|
||||||
|
})
|
||||||
|
self.__connection.rollback()
|
||||||
|
|
||||||
|
response.set(variables)
|
||||||
|
|
||||||
|
self._unbusy()
|
||||||
|
|
||||||
|
return response
|
||||||
@ -13,11 +13,11 @@ from seleniumwire.request import Request
|
|||||||
from selenium.webdriver.common.action_chains import ActionChains
|
from selenium.webdriver.common.action_chains import ActionChains
|
||||||
from AnP.DSLs.ScrapDSL import (
|
from AnP.DSLs.ScrapDSL import (
|
||||||
Open, Close, Switch, Go, Selector, XPath, CSS, Name, LinkText, Class, ID,
|
Open, Close, Switch, Go, Selector, XPath, CSS, Name, LinkText, Class, ID,
|
||||||
Get, Download
|
Get, Download, Action
|
||||||
)
|
)
|
||||||
from AnP.Interfaces.Application import AnPInterface
|
from AnP.Interfaces.Application import AnPInterface
|
||||||
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
||||||
from AnP.Models.SeleniumTabModel import SeleniumTabModel
|
from AnP.Models.BrowserTabsModel import BrowserBoxModel
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
WireWebDriver = Union[WebDriver, webdriver.Firefox]
|
WireWebDriver = Union[WebDriver, webdriver.Firefox]
|
||||||
@ -25,61 +25,104 @@ WireWebDriver = Union[WebDriver, webdriver.Firefox]
|
|||||||
class SeleniumDriver(BrowserAbstract):
|
class SeleniumDriver(BrowserAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
super().__init__(anp, key, SeleniumTabModel, inputs)
|
super().__init__(anp, key, inputs)
|
||||||
self.browser:WireWebDriver = None
|
|
||||||
self.__cache_directory:str = self.anp.settings.get(("selenium_cache_directory", "cache_directory"), inputs, "/Data/Cache/Selenium")
|
self.__cache_directory:str = self.anp.settings.get(("selenium_cache_directory", "cache_directory"), inputs, "/Data/Cache/Selenium")
|
||||||
self.__download_timeout:int = self.anp.settings.get(("selenium_download_timeout", "download_timeout"), inputs, 60)
|
self.__download_timeout:int = self.anp.settings.get(("selenium_download_timeout", "download_timeout"), inputs, 60)
|
||||||
|
|
||||||
def remove(self:Self) -> None:
|
def remove(self:Self) -> None:
|
||||||
self.stop()
|
self.stop()
|
||||||
self.browser and self.browser.quit()
|
self.browser is None or self.browser.quit()
|
||||||
self.tabs.clear()
|
self.tabs.clear()
|
||||||
self.tab_selected = ""
|
self.tab_selected = ""
|
||||||
|
|
||||||
def __load(self:Self, url:str|Callable[[dict[str, Any|None]], str], shared:dict[str, Any|None] = {}) -> None:
|
def __load(self:Self,
|
||||||
|
action:Action,
|
||||||
|
raw_url:str|Callable[[dict[str, Any|None]], str],
|
||||||
|
shared:dict[str, Any|None]
|
||||||
|
) -> None:
|
||||||
|
|
||||||
if Check.is_function(url):
|
url:str = (
|
||||||
url = url(shared)
|
shared[raw_url] if raw_url in shared else
|
||||||
|
raw_url if Check.is_string(raw_url) else
|
||||||
|
raw_url(shared) if Check.is_function(raw_url) else
|
||||||
|
None)
|
||||||
|
|
||||||
self.browser.get(shared[url] if url in shared else url)
|
if url is not None:
|
||||||
|
try:
|
||||||
self.browser.set_script_timeout(10)
|
|
||||||
self.browser.execute_async_script("""
|
|
||||||
if(document.readyState == "complete")
|
|
||||||
arguments[arguments.length - 1](200);
|
|
||||||
else
|
|
||||||
window.addEventListener("load", () => arguments[arguments.length - 1](200));
|
|
||||||
""")
|
|
||||||
|
|
||||||
def open(self:Self, action:Open, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
self.browser.get(url)
|
||||||
if self.browser is None:
|
|
||||||
self.browser = webdriver.Firefox()
|
self.browser.set_script_timeout(10)
|
||||||
|
self.browser.execute_async_script("""
|
||||||
|
if(document.readyState == "complete")
|
||||||
|
arguments[arguments.length - 1](200);
|
||||||
|
else
|
||||||
|
window.addEventListener("load", () => arguments[arguments.length - 1](200));
|
||||||
|
""")
|
||||||
|
action.done = True
|
||||||
|
|
||||||
|
except Exception as exception:
|
||||||
|
action.done = False
|
||||||
|
action.exception = exception
|
||||||
else:
|
else:
|
||||||
self.browser.switch_to.new_window("tab")
|
action.done = False
|
||||||
self.tabs[action.key] = self.browser.current_window_handle
|
|
||||||
self.tab_selected = action.key
|
|
||||||
if action.url is not None:
|
|
||||||
self.__load(action.url, shared)
|
|
||||||
|
|
||||||
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def __set_selected(self:Self, key:str, box:BrowserBoxModel, id:str) -> None:
|
||||||
self.browser.close()
|
box.variables[key] = id
|
||||||
del self.tabs[action.key]
|
box.variables["__selected__"] = key
|
||||||
self.tab_selected = ""
|
|
||||||
action.done = True
|
def __get_selected(self:Self, key:str, box:BrowserBoxModel) -> str|None:
|
||||||
|
if "__selected__" in box.variables and box.variables["__selected__"] in box.variables:
|
||||||
|
return box.variables[key]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def open(self:Self, action:Open, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
try:
|
||||||
|
if self.browser is None:
|
||||||
|
self.browser = webdriver.Firefox()
|
||||||
|
box.set_base(self.browser)
|
||||||
|
else:
|
||||||
|
self.browser.switch_to.new_window("tab")
|
||||||
|
box.set(action.key, self.browser)
|
||||||
|
box.variables[action.key] = self.browser.current_window_handle
|
||||||
|
box.variables["__selected__"] = action.key
|
||||||
|
self.__load(action, action.url, shared, box)
|
||||||
|
except Exception as exception:
|
||||||
|
action.done = False
|
||||||
|
action.exception = exception
|
||||||
|
|
||||||
|
def close(self:Self, action:Close, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
try:
|
||||||
|
|
||||||
|
current:str = box.get_last()
|
||||||
|
tab:str = box.get(action.key)
|
||||||
|
|
||||||
|
self.browser.switch_to.window(tab)
|
||||||
|
self.browser.close()
|
||||||
|
box.close(tab)
|
||||||
|
self.browser.switch_to.window(current)
|
||||||
|
|
||||||
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
|
||||||
if action.key in self.tabs:
|
|
||||||
self.browser.switch_to.window(self.tabs[action.key])
|
|
||||||
self.tab_selected = action.key
|
|
||||||
action.done = True
|
action.done = True
|
||||||
|
|
||||||
def go(self:Self, action:Go, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
except Exception as exception:
|
||||||
self.__load(action.url, shared)
|
action.done = False
|
||||||
action.done = True
|
action.exception = exception
|
||||||
|
|
||||||
|
def switch(self:Self, action:Switch, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
|
tab:str = box.get(action.key)
|
||||||
|
|
||||||
|
if tab is not None:
|
||||||
|
self.browser.switch_to.window(tab)
|
||||||
|
self.switch(tab)
|
||||||
|
action.done = True
|
||||||
|
|
||||||
|
def go(self:Self, action:Go, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
self.__load(action, action.url, shared)
|
||||||
|
|
||||||
def get_selector(self:Self,
|
def get_selector(self:Self,
|
||||||
selector:Selector,
|
selector:Selector,
|
||||||
from_item:Optional[WebDriver|WebElement] = None,
|
box:BrowserBoxModel,
|
||||||
force_multiple:bool = False
|
force_multiple:bool = False
|
||||||
) -> list[WebElement]|WebElement|None:
|
) -> list[WebElement]|WebElement|None:
|
||||||
if self.tab_selected in self.tabs:
|
if self.tab_selected in self.tabs:
|
||||||
@ -92,17 +135,16 @@ class SeleniumDriver(BrowserAbstract):
|
|||||||
By.PARTIAL_LINK_TEXT if isinstance(selector, LinkText) else
|
By.PARTIAL_LINK_TEXT if isinstance(selector, LinkText) else
|
||||||
By.NAME if isinstance(selector, Name) else
|
By.NAME if isinstance(selector, Name) else
|
||||||
By.CSS_SELECTOR)
|
By.CSS_SELECTOR)
|
||||||
|
from_item:WebElement|WebDriver = box.get_base()
|
||||||
if from_item is None:
|
|
||||||
from_item = self.browser
|
|
||||||
|
|
||||||
if force_multiple or selector.multiple:
|
if force_multiple or selector.multiple:
|
||||||
return from_item.find_elements(mode, selector.selector)
|
return from_item.find_elements(mode, selector.selector)
|
||||||
return from_item.find_element(mode, selector.selector)
|
return from_item.find_element(mode, selector.selector)
|
||||||
return [] if force_multiple or selector.multiple else None
|
return [] if force_multiple or selector.multiple else None
|
||||||
|
|
||||||
def get(self:Self, action:Get, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def get(self:Self, action:Get, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
|
last_item:WebElement|None = box.get_last()
|
||||||
item:WebElement = last_item or self.browser if action.selector is None else self.get_selector(action.selector, last_item)
|
item:WebElement = last_item or self.browser if action.selector is None else self.get_selector(action.selector, last_item)
|
||||||
multiple:bool = action.selector is not None and action.selector.multiple
|
multiple:bool = action.selector is not None and action.selector.multiple
|
||||||
|
|
||||||
@ -125,18 +167,9 @@ class SeleniumDriver(BrowserAbstract):
|
|||||||
"textContent" if action.attribute == "CDATA" else
|
"textContent" if action.attribute == "CDATA" else
|
||||||
action.attribute))
|
action.attribute))
|
||||||
|
|
||||||
# if multiple:
|
|
||||||
# shared[action.key].extend(
|
|
||||||
# [self.get_value(action, element.text) for element in item] if action.attribute == "CDATA" else
|
|
||||||
# [self.get_value(action, element.get_attribute(action.attribute)) for element in item])
|
|
||||||
# else:
|
|
||||||
# shared[action.key] = (
|
|
||||||
# self.get_value(action, item.text) if action.attribute == "CDATA" else
|
|
||||||
# self.get_value(action, item.get_attribute(action.attribute)))
|
|
||||||
|
|
||||||
action.done = True
|
action.done = True
|
||||||
|
|
||||||
def __download_from_cache(self:Self, url:str, timeout:Optional[int|float] = None) -> bytes|None:
|
def __download_from_cache(self:Self, url:str, box:BrowserBoxModel, timeout:Optional[int|float] = None) -> bytes|None:
|
||||||
|
|
||||||
request:Request
|
request:Request
|
||||||
date:float = timestamp()
|
date:float = timestamp()
|
||||||
@ -157,9 +190,9 @@ class SeleniumDriver(BrowserAbstract):
|
|||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __download_by_anchor_label(self:Self, url:str) -> bytes|None:
|
def __download_by_anchor_label(self:Self, url:str, box:BrowserBoxModel) -> bytes|None:
|
||||||
|
|
||||||
# l:int = len(self.browser.window_handles)
|
l:int = len(self.browser.window_handles)
|
||||||
data:bytes|None = None
|
data:bytes|None = None
|
||||||
|
|
||||||
self.browser.execute_script("""
|
self.browser.execute_script("""
|
||||||
@ -174,19 +207,19 @@ class SeleniumDriver(BrowserAbstract):
|
|||||||
|
|
||||||
""", url)
|
""", url)
|
||||||
|
|
||||||
data = self.__download_from_cache(url)
|
data = self.__download_from_cache(url, box)
|
||||||
|
|
||||||
# if l < len(self.browser.window_handles):
|
if l < len(self.browser.window_handles):
|
||||||
# self.browser.switch_to.window(self.browser.window_handles[-1])
|
self.browser.switch_to.window(self.browser.window_handles[-1])
|
||||||
# self.browser.close()
|
self.browser.close()
|
||||||
# self.browser.switch_to.window(self.browser.window_handles[-1])
|
self.browser.switch_to.window(box.get_last())
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def __download_by_url(self:Self, url:str) -> bytes|None:
|
def __download_by_url(self:Self, url:str, box:BrowserBoxModel) -> bytes|None:
|
||||||
return self.browser.get(url)
|
return self.browser.get(url)
|
||||||
|
|
||||||
def download(self:Self, action:Download, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def download(self:Self, action:Download, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
url:str = action.url(shared) if Check.is_function(action.url) else action.url
|
url:str = action.url(shared) if Check.is_function(action.url) else action.url
|
||||||
method:Callable[[str], bytes|None]
|
method:Callable[[str], bytes|None]
|
||||||
@ -200,7 +233,7 @@ class SeleniumDriver(BrowserAbstract):
|
|||||||
# self.__download_by_url
|
# self.__download_by_url
|
||||||
):
|
):
|
||||||
|
|
||||||
data:bytes|None = method(url)
|
data:bytes|None = method(url, box)
|
||||||
|
|
||||||
if data is not None:
|
if data is not None:
|
||||||
if action.key:
|
if action.key:
|
||||||
|
|||||||
0
Python/AnP/Drivers/WebSocketClientDriver.py
Normal file
0
Python/AnP/Drivers/WebSocketClientDriver.py
Normal file
@ -7,11 +7,10 @@ from http.cookies import SimpleCookie
|
|||||||
from websockets.sync.server import serve as server_serve
|
from websockets.sync.server import serve as server_serve
|
||||||
from websockets import Server as WebSocketServer, ClientConnection as WebSocketClient
|
from websockets import Server as WebSocketServer, ClientConnection as WebSocketClient
|
||||||
from AnP.Abstracts.WebSocketServersAbstract import WebSocketServersAbstract
|
from AnP.Abstracts.WebSocketServersAbstract import WebSocketServersAbstract
|
||||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
class WebSocketServerDriver(WebSocketServersAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
super().__init__(anp, key, inputs)
|
super().__init__(anp, key, inputs)
|
||||||
|
|||||||
@ -1,76 +1,68 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Self, Any, Optional, Sequence, Callable
|
from typing import Self, Any, Callable
|
||||||
from requests import get, Response
|
from requests import get, Response
|
||||||
from parsel import Selector as ParseSelector, SelectorList as ParseSelectorList
|
from parsel import Selector as ParseSelector, SelectorList as ParseSelectorList
|
||||||
from AnP.DSLs.ScrapDSL import (
|
from AnP.DSLs.ScrapDSL import (
|
||||||
Selector, CSS, XPath, Name, LinkText, Class, ID, Open, Close, Switch,
|
Selector, CSS, XPath, Name, LinkText, Class, ID, Open,
|
||||||
Go, Get, ForEach, Do, Condition, And, Or, Not, If, While, DoWhile, Download,
|
Go, Get, Download, Action
|
||||||
Action
|
|
||||||
)
|
)
|
||||||
from AnP.Interfaces.Application import AnPInterface
|
|
||||||
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
||||||
from AnP.Models.XMLScrapTabModel import XMLScrapTabModel
|
from AnP.Models.BrowserTabsModel import BrowserBoxModel
|
||||||
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
class XMLScrapDriver(BrowserAbstract):
|
class XMLScrapDriver(BrowserAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __load(self:Self,
|
||||||
super().__init__(anp, key, XMLScrapTabModel, inputs)
|
action:Action,
|
||||||
|
key:str|None,
|
||||||
|
raw_url:str|Callable[[dict[str, Any|None]], str],
|
||||||
|
shared:dict[str, Any|None],
|
||||||
|
box:BrowserBoxModel
|
||||||
|
) -> None:
|
||||||
|
|
||||||
def __load(self:Self, url:str) -> Exception|None:
|
url:str = (
|
||||||
try:
|
shared[raw_url] if raw_url in shared else
|
||||||
|
raw_url if Check.is_string(raw_url) else
|
||||||
|
raw_url(shared) if Check.is_function(raw_url) else
|
||||||
|
None)
|
||||||
|
|
||||||
response:Response
|
|
||||||
|
|
||||||
with get(url) as response:
|
|
||||||
self.tabs[self.tab_selected].set(response.text)
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
return exception
|
|
||||||
return None
|
|
||||||
|
|
||||||
def open(self:Self, action:Open, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
|
||||||
|
|
||||||
url:str = shared[action.url] if action.url in shared and isinstance(shared[action.url], str) else action.url
|
|
||||||
|
|
||||||
self.tabs[action.key] = XMLScrapTabModel(action.key, url)
|
|
||||||
self.tab_selected = action.key
|
|
||||||
if url is not None:
|
if url is not None:
|
||||||
action.exception = self.__load(url)
|
try:
|
||||||
action.done = action.exception is None
|
|
||||||
|
|
||||||
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
response:Response
|
||||||
if action.key in self.tabs:
|
|
||||||
del self.tabs[action.key]
|
|
||||||
if len(self.tabs):
|
|
||||||
self.tab_selected = list(self.tabs.keys())[-1]
|
|
||||||
action.done = True
|
|
||||||
|
|
||||||
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
with get(url) as response:
|
||||||
if action.key in self.tabs:
|
box.set(key or box.get_selected(), ParseSelector(text = response.text, type = "html"))
|
||||||
self.tab_selected = action.key
|
|
||||||
action.done = True
|
|
||||||
|
|
||||||
def go(self:Self, action:Go, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
action.done = True
|
||||||
|
except Exception as exception:
|
||||||
|
action.done = False
|
||||||
|
action.exception = exception
|
||||||
|
else:
|
||||||
|
action.done = False
|
||||||
|
|
||||||
url:str = shared[action.url] if action.url in shared and isinstance(shared[action.url], str) else action.url
|
def open(self:Self, action:Open, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
self.__load(action, action.key, action.url, shared, box)
|
||||||
action.exception = self.__load(url)
|
|
||||||
action.done = action.exception is None
|
|
||||||
|
|
||||||
def get_selector(self:Self, selector:str, from_item:Optional[Selector] = None, force_multiple:bool = False) -> Any|list[Any]|None:
|
def go(self:Self, action:Go, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
if self.tab_selected in self.tabs:
|
self.__load(action, action.key, action.url, shared, box)
|
||||||
|
|
||||||
|
def get_selector(self:Self, selector:Selector, box:BrowserBoxModel, force_multiple:bool = False) -> Any|list[Any]|None:
|
||||||
|
|
||||||
|
path:ParseSelector|None = box.get_last()
|
||||||
|
|
||||||
|
if path is not None:
|
||||||
|
|
||||||
path:ParseSelector = self.tabs[self.tab_selected].selector
|
|
||||||
items:ParseSelectorList = (
|
items:ParseSelectorList = (
|
||||||
path.css(selector) if isinstance(selector, CSS) else
|
path.css(selector.selector) if isinstance(selector, CSS) else
|
||||||
path.xpath(selector) if isinstance(selector, XPath) else
|
path.xpath(selector.selector) if isinstance(selector, XPath) else
|
||||||
path.css(f"[name='{selector}']") if isinstance(selector, Name) else
|
path.css(f"[name='{selector.selector}']") if isinstance(selector, Name) else
|
||||||
path.css(f"a:contains('{selector}')") if isinstance(selector, LinkText) else
|
path.css(f"a:contains('{selector.selector}')") if isinstance(selector, LinkText) else
|
||||||
path.css(f".{selector}") if isinstance(selector, Class) else
|
path.css(f".{selector.selector}") if isinstance(selector, Class) else
|
||||||
path.css(f"#{selector}") if isinstance(selector, ID) else
|
path.css(f"#{selector.selector}") if isinstance(selector, ID) else
|
||||||
path.css(selector))
|
path.css(selector.selector))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
items if force_multiple or selector.multiple else
|
items if force_multiple or selector.multiple else
|
||||||
@ -78,9 +70,9 @@ class XMLScrapDriver(BrowserAbstract):
|
|||||||
None)
|
None)
|
||||||
return [] if force_multiple or selector.multiple else None
|
return [] if force_multiple or selector.multiple else None
|
||||||
|
|
||||||
def get(self:Self, action:Get, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def get(self:Self, action:Get, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
|
|
||||||
item:ParseSelector|ParseSelectorList|None = last_item if action.selector is None else self.get_selector(action.selector, last_item)
|
item:ParseSelector|ParseSelectorList|None = box.get_last() if action.selector is None else self.get_selector(action.selector, box)
|
||||||
multiple:bool = action.selector is not None and action.selector.multiple
|
multiple:bool = action.selector is not None and action.selector.multiple
|
||||||
attribute:str = "::text" if action.attribute == "CDATA" else f"::attr({action.attribute})"
|
attribute:str = "::text" if action.attribute == "CDATA" else f"::attr({action.attribute})"
|
||||||
|
|
||||||
@ -96,7 +88,7 @@ class XMLScrapDriver(BrowserAbstract):
|
|||||||
|
|
||||||
action.done = True
|
action.done = True
|
||||||
|
|
||||||
def download(self:Self, action:Download, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
def download(self:Self, action:Download, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||||
if action.key or action.path:
|
if action.key or action.path:
|
||||||
try:
|
try:
|
||||||
|
|
||||||
@ -120,4 +112,5 @@ class XMLScrapDriver(BrowserAbstract):
|
|||||||
action.done = True
|
action.done = True
|
||||||
|
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
|
print(exception)
|
||||||
action.exception = exception
|
action.exception = exception
|
||||||
@ -50,4 +50,7 @@ class FilesAbstractInterface(ABC, ModelAbstract):
|
|||||||
def load_json(self:Self, inputs:Any|None, only_dictionaries:bool = True) -> list[dict[str, Any|None]|Sequence[Any|None]]:pass
|
def load_json(self:Self, inputs:Any|None, only_dictionaries:bool = True) -> list[dict[str, Any|None]|Sequence[Any|None]]:pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def list_directory_items(self:Self, path:str) -> list[str]:pass
|
def list_directory_items(self:Self, path:str) -> list[str]:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def prepare_directory(self:Self, path:str) -> bool:pass
|
||||||
@ -12,6 +12,7 @@ from AnP.Interfaces.Managers.ModelsManagerInterface import ModelsManagerInterfac
|
|||||||
from AnP.Interfaces.Managers.UniqueKeysManagerInterface import UniqueKeysManagerInterface
|
from AnP.Interfaces.Managers.UniqueKeysManagerInterface import UniqueKeysManagerInterface
|
||||||
from AnP.Interfaces.Managers.QueusManagerInterface import QueusManagerInterface
|
from AnP.Interfaces.Managers.QueusManagerInterface import QueusManagerInterface
|
||||||
from AnP.Interfaces.Managers.SessionsManagerInterface import SessionsManagerInterface
|
from AnP.Interfaces.Managers.SessionsManagerInterface import SessionsManagerInterface
|
||||||
|
from AnP.Interfaces.Managers.DatabasesManagerInterface import DatabasesManagerInterface
|
||||||
from AnP.Interfaces.Managers.ControllersManagerInterface import ControllersManagerInterface
|
from AnP.Interfaces.Managers.ControllersManagerInterface import ControllersManagerInterface
|
||||||
from AnP.Interfaces.Managers.DispatchesManagerInterface import DispatchesManagerInterface
|
from AnP.Interfaces.Managers.DispatchesManagerInterface import DispatchesManagerInterface
|
||||||
from AnP.Interfaces.Managers.IndexesManagerInterface import IndexesManagerInterface
|
from AnP.Interfaces.Managers.IndexesManagerInterface import IndexesManagerInterface
|
||||||
@ -35,6 +36,7 @@ class AnPInterface(ABC):
|
|||||||
self.unique_keys:UniqueKeysManagerInterface = None
|
self.unique_keys:UniqueKeysManagerInterface = None
|
||||||
self.queues:QueusManagerInterface = None
|
self.queues:QueusManagerInterface = None
|
||||||
self.sessions:SessionsManagerInterface = None
|
self.sessions:SessionsManagerInterface = None
|
||||||
|
self.databases:DatabasesManagerInterface = None
|
||||||
self.controllers:ControllersManagerInterface = None
|
self.controllers:ControllersManagerInterface = None
|
||||||
self.dispatches:DispatchesManagerInterface = None
|
self.dispatches:DispatchesManagerInterface = None
|
||||||
self.indexes:IndexesManagerInterface = None
|
self.indexes:IndexesManagerInterface = None
|
||||||
|
|||||||
31
Python/AnP/Interfaces/Managers/DatabasesManagerInterface.py
Normal file
31
Python/AnP/Interfaces/Managers/DatabasesManagerInterface.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Optional, TypeVar
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from AnP.Models.DatabaseResponseModel import DatabaseResponseModel
|
||||||
|
|
||||||
|
ControllerType = TypeVar("ControllerType", bound = DatabaseResponseModel)
|
||||||
|
|
||||||
|
class DatabasesManagerInterface(ABC):
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def reset(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def close(self:Self) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def execute(self:Self, key:str, query:str, inputs:Optional[dict[str, Any|None]] = None) -> DatabaseResponseModel:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def execute_file(self:Self, key:str, path:str, inputs:Optional[dict[str, Any|None]] = None) -> DatabaseResponseModel:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get(self:Self, key:str, Type:type[ControllerType]) -> ControllerType|None:pass
|
||||||
@ -1,9 +1,12 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Any, Self
|
from typing import Any, Self, TypeVar
|
||||||
|
from AnP.Abstracts.DispatchAbstract import DispatchAbstract
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
DispatchType = TypeVar("DispatchType", bound = DispatchAbstract)
|
||||||
|
|
||||||
class DispatchesManagerInterface(ABC):
|
class DispatchesManagerInterface(ABC):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@ -16,4 +19,7 @@ class DispatchesManagerInterface(ABC):
|
|||||||
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass
|
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def execute(self:Self, key:str, method:str, *arguments:list[Any|None]) -> bool:pass
|
def execute(self:Self, via:str, key:str, method:str, *arguments:list[Any|None]) -> bool:pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get(self:Self, via:str, key:str, Type:type[DispatchType]) -> DispatchType|None:pass
|
||||||
@ -1,12 +1,14 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Any, Self
|
from typing import Any, Self, TypeVar
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
from AnP.Abstracts.ControllerAbstract import ControllerAbstract
|
from AnP.Abstracts.ControllerAbstract import ControllerAbstract
|
||||||
from AnP.Models.RequestModel import RequestModel
|
from AnP.Models.RequestModel import RequestModel
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
|
ControllerType = TypeVar("ControllerType", bound = ControllerAbstract)
|
||||||
|
|
||||||
class ControllersManager:
|
class ControllersManager:
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface) -> None:
|
def __init__(self:Self, anp:AnPInterface) -> None:
|
||||||
@ -64,4 +66,9 @@ class ControllersManager:
|
|||||||
if key in self.__controllers and hasattr(self.__controllers[key], method):
|
if key in self.__controllers and hasattr(self.__controllers[key], method):
|
||||||
getattr(self.__controllers[key], method)(request)
|
getattr(self.__controllers[key], method)(request)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get(self:Self, key:str, Type:type[ControllerType]) -> ControllerType|None:
|
||||||
|
if key in self.__controllers and isinstance(self.__controllers[key], Type):
|
||||||
|
return self.__controllers[key]
|
||||||
|
return None
|
||||||
79
Python/AnP/Managers/DatabasesManager.py
Normal file
79
Python/AnP/Managers/DatabasesManager.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Optional
|
||||||
|
from inspect import isclass
|
||||||
|
from AnP.Abstracts.DatabaseAbstract import DatabaseAbstract
|
||||||
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
|
from AnP.Utils.Checks import Check
|
||||||
|
from AnP.Models.DatabaseResponseModel import DatabaseResponseModel
|
||||||
|
|
||||||
|
class DatabasesManager:
|
||||||
|
|
||||||
|
def __init__(self:Self, anp:AnPInterface) -> None:
|
||||||
|
self.anp:AnPInterface = anp
|
||||||
|
self.__databases:dict[str, DatabaseAbstract] = {}
|
||||||
|
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self:Self) -> None:
|
||||||
|
|
||||||
|
key:str
|
||||||
|
|
||||||
|
for key in (
|
||||||
|
"default_databases_files", "databases_files",
|
||||||
|
"default_databases", "databases"
|
||||||
|
):
|
||||||
|
self.add(self.anp.settings.get(key), True)
|
||||||
|
|
||||||
|
def reset(self:Self) -> None:
|
||||||
|
self.close()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def close(self:Self) -> None:
|
||||||
|
|
||||||
|
database:DatabaseAbstract
|
||||||
|
|
||||||
|
for database in self.__databases.values():
|
||||||
|
database.close()
|
||||||
|
|
||||||
|
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
||||||
|
|
||||||
|
subinputs:dict[str, Any|None]
|
||||||
|
|
||||||
|
for subinputs in self.anp.files.load_json(inputs, True):
|
||||||
|
|
||||||
|
key:str
|
||||||
|
database:Any|None
|
||||||
|
|
||||||
|
for key, database in subinputs.items():
|
||||||
|
if Check.is_mark_key(key) and database is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
DatabaseClass:type[DatabaseAbstract]|None
|
||||||
|
|
||||||
|
if Check.is_string(database):
|
||||||
|
DatabaseClass = self.anp.models.get(DatabaseAbstract, database)
|
||||||
|
elif isclass(database) and issubclass(database, DatabaseAbstract):
|
||||||
|
DatabaseClass = database
|
||||||
|
elif Check.is_dictionary(database) and "type" in database and Check.is_string(database["type"]):
|
||||||
|
DatabaseClass = self.anp.models.get(DatabaseAbstract, database["type"])
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if DatabaseClass and (
|
||||||
|
overwrite or key not in self.__databases
|
||||||
|
):
|
||||||
|
self.__databases[key] = DatabaseClass(
|
||||||
|
self.anp, database if Check.is_dictionary(database) else
|
||||||
|
{})
|
||||||
|
|
||||||
|
def execute(self:Self, key:str, query:str, inputs:Optional[dict[str, Any|None]] = None) -> DatabaseResponseModel:
|
||||||
|
if key in self.__databases:
|
||||||
|
return self.__databases[key].execute(query, inputs)
|
||||||
|
return DatabaseResponseModel()
|
||||||
|
|
||||||
|
def execute_file(self:Self, key:str, path:str, inputs:Optional[dict[str, Any|None]] = None) -> DatabaseResponseModel:
|
||||||
|
if key in self.__databases:
|
||||||
|
return self.__databases[key].execute_file(path, inputs)
|
||||||
|
return DatabaseResponseModel()
|
||||||
@ -1,17 +1,19 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Any, Self
|
from typing import Any, Self, TypeVar
|
||||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||||
from AnP.Abstracts.DispatchAbstract import DispatchAbstract
|
from AnP.Abstracts.DispatchAbstract import DispatchAbstract
|
||||||
from AnP.Utils.Checks import Check
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
|
DispatchType = TypeVar("DispatchType", bound = DispatchAbstract)
|
||||||
|
|
||||||
class DispatchesManager:
|
class DispatchesManager:
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface) -> None:
|
def __init__(self:Self, anp:AnPInterface) -> None:
|
||||||
|
|
||||||
self.anp:AnPInterface = anp
|
self.anp:AnPInterface = anp
|
||||||
self.__dispatches:dict[str, DispatchAbstract] = {}
|
self.__dispatches:dict[str, dict[str, DispatchAbstract]] = {}
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
@ -35,32 +37,46 @@ class DispatchesManager:
|
|||||||
for subinputs in self.anp.files.load_json(inputs, True):
|
for subinputs in self.anp.files.load_json(inputs, True):
|
||||||
|
|
||||||
key:str
|
key:str
|
||||||
dispatch:Any|None
|
subinputs:dict[str, Any|None]
|
||||||
|
# dispatch:Any|None
|
||||||
|
|
||||||
for key, dispatch in subinputs.items():
|
for key, subinputs in subinputs.items():
|
||||||
if Check.is_mark_key(key) and dispatch is None:
|
if Check.is_mark_key(key) and dispatch is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
DispatchClass:type[DispatchAbstract]|None
|
via:str
|
||||||
|
dispatch:Any|None
|
||||||
|
|
||||||
if Check.is_string(dispatch):
|
for via, dispatch in subinputs.items():
|
||||||
DispatchClass = self.anp.models.get(DispatchAbstract, dispatch)
|
|
||||||
elif issubclass(dispatch, DispatchAbstract):
|
|
||||||
DispatchClass = dispatch
|
|
||||||
elif Check.is_dictionary(dispatch) and "type" in dispatch and Check.is_string(dispatch["type"]):
|
|
||||||
DispatchClass = self.anp.models.get(DispatchAbstract, dispatch["type"])
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if DispatchClass and (
|
DispatchClass:type[DispatchAbstract]|None
|
||||||
overwrite or key not in self.__dispatches
|
|
||||||
):
|
|
||||||
self.__dispatches[key] = DispatchClass(
|
|
||||||
self.anp, dispatch if Check.is_dictionary(dispatch) else
|
|
||||||
None)
|
|
||||||
|
|
||||||
def execute(self:Self, key:str, method:str, *arguments:list[Any|None]) -> bool:
|
if via not in self.__dispatches:
|
||||||
if key in self.__dispatches and hasattr(self.__dispatches[key], method):
|
self.__dispatches[via] = {}
|
||||||
getattr(self.__dispatches[key], method)(*arguments)
|
|
||||||
|
if Check.is_string(dispatch):
|
||||||
|
DispatchClass = self.anp.models.get(DispatchAbstract, dispatch)
|
||||||
|
elif issubclass(dispatch, DispatchAbstract):
|
||||||
|
DispatchClass = dispatch
|
||||||
|
elif Check.is_dictionary(dispatch) and "type" in dispatch and Check.is_string(dispatch["type"]):
|
||||||
|
DispatchClass = self.anp.models.get(DispatchAbstract, dispatch["type"])
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if DispatchClass and (
|
||||||
|
overwrite or key not in self.__dispatches[via]
|
||||||
|
):
|
||||||
|
self.__dispatches[via][key] = DispatchClass(
|
||||||
|
self.anp, dispatch if Check.is_dictionary(dispatch) else
|
||||||
|
None)
|
||||||
|
|
||||||
|
def execute(self:Self, via:str, key:str, method:str, *arguments:list[Any|None]) -> bool:
|
||||||
|
if via in self.__dispatches and key in self.__dispatches[via] and hasattr(self.__dispatches[via][key], method):
|
||||||
|
getattr(self.__dispatches[via][key], method)(*arguments)
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get(self:Self, via:str, key:str, Type:type[DispatchType]) -> DispatchType|None:
|
||||||
|
if via in self.__dispatches and key in self.__dispatches[via] and isinstance(self.__dispatches[via][key], Type):
|
||||||
|
return self.__dispatches[via][key]
|
||||||
|
return None
|
||||||
@ -44,9 +44,11 @@ class TerminalManager:
|
|||||||
|
|
||||||
def __handler(self:Self) -> None:
|
def __handler(self:Self) -> None:
|
||||||
while self.anp.working():
|
while self.anp.working():
|
||||||
|
|
||||||
|
order:str = input()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
||||||
order:str = input()
|
|
||||||
command:str = order.split(" ")[0].lower()
|
command:str = order.split(" ")[0].lower()
|
||||||
parameters:dict[str, Any|None] = {}
|
parameters:dict[str, Any|None] = {}
|
||||||
arguments:list[Any|None] = []
|
arguments:list[Any|None] = []
|
||||||
@ -64,7 +66,9 @@ class TerminalManager:
|
|||||||
})
|
})
|
||||||
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
self.anp.exception(error, "terminal_manager_exception")
|
self.anp.exception(error, "terminal_manager_exception", {
|
||||||
|
"command" : order
|
||||||
|
})
|
||||||
|
|
||||||
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
||||||
if Check.is_array(inputs):
|
if Check.is_array(inputs):
|
||||||
|
|||||||
86
Python/AnP/Models/BrowserTabsModel.py
Normal file
86
Python/AnP/Models/BrowserTabsModel.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any, Optional, Callable, Sequence
|
||||||
|
from AnP.Utils.Checks import Check
|
||||||
|
|
||||||
|
class BrowserTabsModel:
|
||||||
|
|
||||||
|
def __init__(self:Self, item:Any) -> None:
|
||||||
|
self.item:Any = item
|
||||||
|
self.last:Any = item
|
||||||
|
|
||||||
|
def set_last(self:Self, item:Any) -> None:
|
||||||
|
self.last = item
|
||||||
|
|
||||||
|
def reset(self:Self) -> None:
|
||||||
|
self.last = self.item
|
||||||
|
|
||||||
|
class BrowserBoxModel:
|
||||||
|
|
||||||
|
def __init__(self:Self, is_working:Optional[Callable[[], bool]] = None) -> None:
|
||||||
|
self.tabs:dict[str, BrowserTabsModel] = {}
|
||||||
|
self.tab_selected:str = ""
|
||||||
|
self.variables:dict[str, Any|None] = {}
|
||||||
|
self.is_working:Callable[[], bool]|None = is_working
|
||||||
|
self._base:Any|None = None
|
||||||
|
|
||||||
|
def set_base(self:Self, item:Any) -> None:
|
||||||
|
self._base = item
|
||||||
|
|
||||||
|
def get_base(self:Self) -> Any|None:
|
||||||
|
return self._base
|
||||||
|
|
||||||
|
def get_selected(self:Self) -> str:
|
||||||
|
return self.tab_selected
|
||||||
|
|
||||||
|
def get_last(self:Self) -> Any|None:
|
||||||
|
if self.tab_selected in self.tabs:
|
||||||
|
return self.tabs[self.tab_selected].last
|
||||||
|
return None
|
||||||
|
|
||||||
|
def set(self:Self, key:str, item:Any) -> None:
|
||||||
|
self.tabs[key] = BrowserTabsModel(item)
|
||||||
|
self.tab_selected = key
|
||||||
|
|
||||||
|
def change(self:Self, key:str) -> bool:
|
||||||
|
if key in self.tabs:
|
||||||
|
self.tab_selected = key
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def set_last(self:Self, item:Any) -> bool:
|
||||||
|
if self.tab_selected in self.tabs:
|
||||||
|
self.tabs[self.tab_selected].set_last(item)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def reset(self:Self) -> bool:
|
||||||
|
if self.tab_selected in self.tabs:
|
||||||
|
self.tabs[self.tab_selected].reset()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def close(self:Self, keys:Optional[str|Sequence[str]] = None) -> bool:
|
||||||
|
|
||||||
|
ok:bool = True
|
||||||
|
|
||||||
|
for key in (
|
||||||
|
keys if Check.is_array(keys) else
|
||||||
|
[keys] if Check.is_key(keys) else
|
||||||
|
list(self.tabs.keys()) if keys is None else
|
||||||
|
[]):
|
||||||
|
if key in self.tabs:
|
||||||
|
del self.tabs[key]
|
||||||
|
if self.tab_selected == key:
|
||||||
|
self.tab_selected = next(iter(self.tabs), "")
|
||||||
|
else:
|
||||||
|
ok = False
|
||||||
|
|
||||||
|
return ok
|
||||||
|
|
||||||
|
def switch(self:Self, key:str) -> bool:
|
||||||
|
if key in self.tabs:
|
||||||
|
self.tab_selected = key
|
||||||
|
return True
|
||||||
|
return False
|
||||||
29
Python/AnP/Models/DatabaseResponseModel.py
Normal file
29
Python/AnP/Models/DatabaseResponseModel.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from typing import Self, Any
|
||||||
|
|
||||||
|
class DatabaseResponseModel:
|
||||||
|
|
||||||
|
def __init__(self:Self) -> None:
|
||||||
|
self.tables:list[list[dict[str, Any|None]]] = []
|
||||||
|
self.variables:dict[str, Any|None] = {}
|
||||||
|
|
||||||
|
def add(self:Self, table:int, row:dict[str, Any|None]) -> None:
|
||||||
|
while len(self.tables) <= table:
|
||||||
|
self.tables.append([])
|
||||||
|
self.tables[table].append(row)
|
||||||
|
|
||||||
|
def set(self:Self, variables:list[str]) -> None:
|
||||||
|
|
||||||
|
variable:str
|
||||||
|
|
||||||
|
for variable in variables:
|
||||||
|
|
||||||
|
table:list[dict[str, Any|None]] = []
|
||||||
|
|
||||||
|
for table in reversed(self.tables):
|
||||||
|
if len(table) == 1:
|
||||||
|
if variable in table[0]:
|
||||||
|
self.variables[variable] = table[0][variable]
|
||||||
|
break
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from typing import Self
|
|
||||||
from parsel import Selector
|
|
||||||
|
|
||||||
class XMLScrapTabModel:
|
|
||||||
|
|
||||||
def __init__(self:Self, key:str, url:str) -> None:
|
|
||||||
self.key:str = key
|
|
||||||
self.url:str = url
|
|
||||||
self.data:str = ""
|
|
||||||
self.selector:Selector|None = None
|
|
||||||
|
|
||||||
def set(self:Self, data:str) -> None:
|
|
||||||
self.data = data
|
|
||||||
self.selector = Selector(text = data, type = "xml")
|
|
||||||
@ -5,6 +5,7 @@ from typing import Any, Self, Sequence
|
|||||||
from re import Pattern as REPattern
|
from re import Pattern as REPattern
|
||||||
from os.path import isfile as is_file
|
from os.path import isfile as is_file
|
||||||
from json import loads as json_decode
|
from json import loads as json_decode
|
||||||
|
import datetime
|
||||||
from AnP.Utils.Patterns import RE
|
from AnP.Utils.Patterns import RE
|
||||||
|
|
||||||
class Check:
|
class Check:
|
||||||
@ -84,4 +85,8 @@ class Check:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_file(path:str) -> bool:
|
def is_file(path:str) -> bool:
|
||||||
return is_file(path)
|
return is_file(path)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_date(item:Any|None) -> bool:
|
||||||
|
return isinstance(item, (datetime.date, datetime.datetime))
|
||||||
@ -10,6 +10,7 @@ from AnP.Drivers.OllamaDriver import OllamaDriver
|
|||||||
from AnP.Drivers.FilesDriver import FilesDriver
|
from AnP.Drivers.FilesDriver import FilesDriver
|
||||||
from AnP.Drivers.XMLScrapDriver import XMLScrapDriver
|
from AnP.Drivers.XMLScrapDriver import XMLScrapDriver
|
||||||
from AnP.Drivers.SeleniumDriver import SeleniumDriver
|
from AnP.Drivers.SeleniumDriver import SeleniumDriver
|
||||||
|
from AnP.Drivers.SQLiteDriver import SQLiteDriver
|
||||||
from AnP.Controllers.CloneController import CloneController
|
from AnP.Controllers.CloneController import CloneController
|
||||||
from AnP.Controllers.AITranslateController import AITranslateController
|
from AnP.Controllers.AITranslateController import AITranslateController
|
||||||
|
|
||||||
@ -24,7 +25,8 @@ inputs:dict[str, dict[str, Any|None]] = {
|
|||||||
"OllamaDriver" : OllamaDriver,
|
"OllamaDriver" : OllamaDriver,
|
||||||
"FilesDriver" : FilesDriver,
|
"FilesDriver" : FilesDriver,
|
||||||
"XMLScrapDriver" : XMLScrapDriver,
|
"XMLScrapDriver" : XMLScrapDriver,
|
||||||
"SeleniumDriver" : SeleniumDriver
|
"SeleniumDriver" : SeleniumDriver,
|
||||||
|
"SQLiteDriver" : SQLiteDriver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
55
README.md
55
README.md
@ -2,7 +2,19 @@
|
|||||||
|
|
||||||
Framework.
|
Framework.
|
||||||
|
|
||||||
Secrets Python file:
|
# Instalations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
apt update && apt -y upgrade && apt -y autoclean && apt -y autoremove
|
||||||
|
pyp3 install websockets selenium selenium-wire --break-system-packages
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
|
||||||
|
## Root Paths
|
||||||
|
|
||||||
```py
|
```py
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
@ -18,7 +30,7 @@ secrets:dict[str, Any|None] = {
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Web Socket Server Settings:
|
## Web Socket Server
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -32,7 +44,7 @@ Web Socket Server Settings:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
HTTP Settings:
|
## HTTP Server
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -47,7 +59,7 @@ HTTP Settings:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
AI Interpreters Settings:
|
## AI Interpreters
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -82,7 +94,7 @@ AI Interpreters Settings:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Directory Cloner Settings:
|
## Directory Cloner
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@ -98,4 +110,35 @@ Directory Cloner Settings:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Browsers
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"default_browsers" : {
|
||||||
|
"selenium" : {
|
||||||
|
"type" : "Selenium",
|
||||||
|
"print_actions" : false
|
||||||
|
},
|
||||||
|
"xml" : {
|
||||||
|
"type" : "XMLScrap",
|
||||||
|
"print_actions" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Scrappers
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"default_scrappers_files" : {
|
||||||
|
"mt" : {
|
||||||
|
"type" : "MTScrapper",
|
||||||
|
"browser" : "selenium",
|
||||||
|
"url" : "https://www43.mejortorrent.eu/inicio",
|
||||||
|
"autorun" : true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user