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_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_abstract_do_action" : "Ejecutando la acción '{i}' de tipo '{action}' en el navegador '{key}'.",
|
||||
"AnP_BrowserAbstract_end" : null,
|
||||
|
||||
"AnP_DirectoryCloneModel_start" : null,
|
||||
|
||||
@ -2,12 +2,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Models.AIResponseModel import AIResponseModel
|
||||
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:
|
||||
|
||||
|
||||
@ -11,17 +11,16 @@ from AnP.DSLs.ScrapDSL import (
|
||||
)
|
||||
from AnP.Utils.Common import Common
|
||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Models.BrowserTabsModel import BrowserBoxModel
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
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.key:str = key
|
||||
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.actions:dict[Action, Callable[[Action, dict[str, Any|None], Optional[Any]], None]] = {
|
||||
Execute : self.execute,
|
||||
@ -35,9 +34,13 @@ class BrowserAbstract(ModelAbstract):
|
||||
ForEach : self.foreach,
|
||||
And : self._and,
|
||||
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:
|
||||
self.working = True
|
||||
@ -47,33 +50,23 @@ class BrowserAbstract(ModelAbstract):
|
||||
|
||||
def remove(self:Self) -> None:
|
||||
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 (
|
||||
shared is None or
|
||||
"__is_working_key__" not in shared or
|
||||
shared["__is_working_key__"] not in self.__is_working or
|
||||
self.__is_working[shared["__is_working_key__"]]()
|
||||
box.is_working is None or box.is_working()
|
||||
)
|
||||
|
||||
def run(self:Self,
|
||||
actions:Sequence[Action],
|
||||
shared:dict[str, Any|None] = {},
|
||||
key:Optional[str] = None,
|
||||
is_working:Optional[Callable[[], bool]] = 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
|
||||
|
||||
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:
|
||||
action.callback(shared)
|
||||
action.done = True
|
||||
@ -81,30 +74,30 @@ class BrowserAbstract(ModelAbstract):
|
||||
action.exception = exception
|
||||
|
||||
@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] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||
def close(self:Self, action:Close, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||
action.done = box.close(action.key)
|
||||
|
||||
@abstractmethod
|
||||
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:pass
|
||||
def switch(self:Self, action:Switch, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||
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()
|
||||
time:int|float = (
|
||||
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))
|
||||
|
||||
while self.is_working(shared):
|
||||
while self.is_working(box):
|
||||
sleep(.1)
|
||||
if timestamp() - date >= time:
|
||||
break
|
||||
|
||||
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
|
||||
i:int
|
||||
@ -112,10 +105,16 @@ class BrowserAbstract(ModelAbstract):
|
||||
action.done = True
|
||||
|
||||
for i, subaction in enumerate(action.actions):
|
||||
if not self.is_working(shared):
|
||||
if not self.is_working(box):
|
||||
action.done = False
|
||||
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):
|
||||
subaction.done = False
|
||||
subaction.exception = None
|
||||
@ -124,7 +123,7 @@ class BrowserAbstract(ModelAbstract):
|
||||
|
||||
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
|
||||
|
||||
if not ok and not subaction.ignore_fail:
|
||||
@ -144,7 +143,7 @@ class BrowserAbstract(ModelAbstract):
|
||||
break
|
||||
|
||||
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", {
|
||||
"key" : self.key,
|
||||
@ -182,10 +181,10 @@ class BrowserAbstract(ModelAbstract):
|
||||
|
||||
|
||||
@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
|
||||
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
|
||||
def get_value(action:Get, value:str) -> str:
|
||||
@ -194,19 +193,20 @@ class BrowserAbstract(ModelAbstract):
|
||||
return action.pattern.sub(action.matches, value)
|
||||
|
||||
@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
|
||||
done:bool = True
|
||||
is_selector:bool = isinstance(action.items, Selector)
|
||||
last:Any|None = box.get_last()
|
||||
|
||||
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):
|
||||
|
||||
if not self.is_working(shared):
|
||||
if not self.is_working(box):
|
||||
done = False
|
||||
break
|
||||
|
||||
@ -220,91 +220,86 @@ class BrowserAbstract(ModelAbstract):
|
||||
|
||||
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:
|
||||
action.exception = subactions.exception
|
||||
done = False
|
||||
break
|
||||
|
||||
box.reset()
|
||||
box.set_last(last)
|
||||
|
||||
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
|
||||
|
||||
action.ok = True
|
||||
|
||||
for condition in action.conditions:
|
||||
if isinstance(condition, Condition):
|
||||
self.do(condition, shared, last_item)
|
||||
if not condition.ok:
|
||||
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
|
||||
if not self.__condition(condition, shared, box):
|
||||
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
|
||||
|
||||
action.ok = False
|
||||
|
||||
for condition in action.conditions:
|
||||
if isinstance(condition, Condition):
|
||||
self.do(condition, shared, last_item)
|
||||
if condition.ok:
|
||||
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
|
||||
if self.__condition(condition, shared, box):
|
||||
action.ok = True
|
||||
break
|
||||
|
||||
def _not(self:Self, action:Not, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> bool:
|
||||
if isinstance(action.condition, Condition):
|
||||
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 _not(self:Self, action:Not, shared:dict[str, Any|None], box:BrowserBoxModel) -> bool:
|
||||
return not self.__condition(action.condition, shared, box)
|
||||
|
||||
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):
|
||||
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:
|
||||
|
||||
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.exception = subactions.exception
|
||||
|
||||
@ -312,17 +307,17 @@ class BrowserAbstract(ModelAbstract):
|
||||
action.done = action.condition.done
|
||||
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):
|
||||
action.condition = Condition((action.condition,))
|
||||
|
||||
while True:
|
||||
if not self.is_working(shared):
|
||||
if not self.is_working(box):
|
||||
action.done = False
|
||||
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:
|
||||
action.done = action.condition.done
|
||||
@ -333,7 +328,7 @@ class BrowserAbstract(ModelAbstract):
|
||||
|
||||
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:
|
||||
action.exception = subactions.exception
|
||||
action.done = False
|
||||
@ -343,25 +338,26 @@ class BrowserAbstract(ModelAbstract):
|
||||
action.done = True
|
||||
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):
|
||||
action.condition = Condition((action.condition,))
|
||||
|
||||
while True:
|
||||
if not self.is_working(shared):
|
||||
if not self.is_working(box):
|
||||
action.done = False
|
||||
break
|
||||
|
||||
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:
|
||||
action.exception = subactions.exception
|
||||
action.done = False
|
||||
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:
|
||||
action.done = action.condition.done
|
||||
@ -373,4 +369,4 @@ class BrowserAbstract(ModelAbstract):
|
||||
break
|
||||
|
||||
@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 -*-
|
||||
|
||||
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 AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Utils.Common import Common
|
||||
from AnP.Utils.Checks import Check
|
||||
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:
|
||||
self.anp:AnPInterface = anp
|
||||
@ -95,4 +96,7 @@ class FilesAbstract(ABC):
|
||||
return results
|
||||
|
||||
@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
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from abc import abstractmethod
|
||||
from typing import Any, Self, Optional, Sequence
|
||||
from re import Match as REMath
|
||||
import datetime
|
||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Utils.Common import Common
|
||||
|
||||
class HTTPServersAbstract(ABC):
|
||||
class HTTPServersAbstract(ModelAbstract):
|
||||
|
||||
DEFAULT_PORT:int = 8000
|
||||
DEFAULT_HOST:str = ""
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
class ModelAbstract:pass
|
||||
from abc import ABC
|
||||
|
||||
class ModelAbstract(ABC):pass
|
||||
@ -2,12 +2,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
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.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Application.Event import Event
|
||||
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:
|
||||
self.anp:AnPInterface = anp
|
||||
|
||||
@ -16,6 +16,7 @@ from AnP.Managers.ModelsManager import ModelsManager
|
||||
from AnP.Managers.UniqueKeysManager import UniqueKeysManager
|
||||
from AnP.Managers.QueusManager import QueuesManager
|
||||
from AnP.Managers.SessionsManager import SessionsManager
|
||||
from AnP.Managers.DatabasesManager import DatabasesManager
|
||||
from AnP.Managers.ControllersManager import ControllersManager
|
||||
from AnP.Managers.DispatchesManager import DispatchesManager
|
||||
from AnP.Managers.IndexesManager import IndexesManager
|
||||
@ -56,6 +57,7 @@ class AnP:
|
||||
self.unique_keys:UniqueKeysManager = UniqueKeysManager(self)
|
||||
self.queues:QueuesManager = QueuesManager(self)
|
||||
self.sessions:SessionsManager = SessionsManager(self)
|
||||
self.databases:DatabasesManager = DatabasesManager(self)
|
||||
self.controllers:ControllersManager = ControllersManager(self)
|
||||
self.dispatches:DispatchesManager = DispatchesManager(self)
|
||||
self.indexes:IndexesManager = IndexesManager(self)
|
||||
@ -77,6 +79,7 @@ class AnP:
|
||||
self.unique_keys.update()
|
||||
self.queues.update()
|
||||
self.sessions.update()
|
||||
self.databases.update()
|
||||
self.controllers.update()
|
||||
self.dispatches.update()
|
||||
self.indexes.update()
|
||||
@ -97,6 +100,7 @@ class AnP:
|
||||
self.unique_keys.reset()
|
||||
self.queues.reset()
|
||||
self.sessions.reset()
|
||||
self.databases.reset()
|
||||
self.controllers.reset()
|
||||
self.dispatches.reset()
|
||||
self.indexes.reset()
|
||||
@ -115,6 +119,7 @@ class AnP:
|
||||
self.http_servers.close()
|
||||
self.browsers.close()
|
||||
self.directories_clones.close()
|
||||
self.databases.close()
|
||||
|
||||
def working(self:Self) -> bool:
|
||||
return self.__working
|
||||
|
||||
@ -12,6 +12,7 @@ class Action:
|
||||
self.print_ok:bool = False
|
||||
self.done:bool = False
|
||||
self.wait:bool = True
|
||||
self.ignore_fail:bool = False
|
||||
|
||||
class Execute(Action):
|
||||
def __init__(self:Self, callback:Callable[[dict[str, Any|None]], None]) -> None:
|
||||
|
||||
@ -11,11 +11,10 @@ from os import (
|
||||
listdir as list_directory_items
|
||||
)
|
||||
from shutil import rmtree as remove_directory
|
||||
from AnP.Abstracts.FilesAbstract import FilesAbstract
|
||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Abstracts.FilesAbstract import FilesAbstract, abstractmethod
|
||||
from AnP.Utils.Checks import Check
|
||||
|
||||
class FilesDriver(FilesAbstract, ModelAbstract):
|
||||
class FilesDriver(FilesAbstract):
|
||||
|
||||
def get_absolute_path(self:Self, path:str) -> str|None:
|
||||
|
||||
@ -124,4 +123,9 @@ class FilesDriver(FilesAbstract, ModelAbstract):
|
||||
"path" : path,
|
||||
"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.cookies import SimpleCookie
|
||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Models.RequestModel import RequestModel
|
||||
from AnP.Abstracts.HTTPServersAbstract import HTTPServersAbstract
|
||||
|
||||
class HTTPServerDriver(HTTPServersAbstract, ModelAbstract):
|
||||
class HTTPServerDriver(HTTPServersAbstract):
|
||||
|
||||
class HTTPRequestHandler(BaseHTTPRequestHandler):
|
||||
|
||||
|
||||
@ -1,2 +1,17 @@
|
||||
#!/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 requests import post as Post, Response
|
||||
# from pydantic import BaseModel
|
||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||
from AnP.Abstracts.AIInterpretersAbstract import AIInterpretersAbstract
|
||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Models.AIResponseModel import AIResponseModel
|
||||
from AnP.Utils.Checks import Check
|
||||
from AnP.Utils.Common import Common
|
||||
|
||||
class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
|
||||
class OllamaDriver(AIInterpretersAbstract):
|
||||
|
||||
def __init__(self:Self,
|
||||
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
|
||||
# -*- 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
|
||||
# -*- 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 AnP.DSLs.ScrapDSL import (
|
||||
Open, Close, Switch, Go, Selector, XPath, CSS, Name, LinkText, Class, ID,
|
||||
Get, Download
|
||||
Get, Download, Action
|
||||
)
|
||||
from AnP.Interfaces.Application import AnPInterface
|
||||
from AnP.Abstracts.BrowserAbstract import BrowserAbstract
|
||||
from AnP.Models.SeleniumTabModel import SeleniumTabModel
|
||||
from AnP.Models.BrowserTabsModel import BrowserBoxModel
|
||||
from AnP.Utils.Checks import Check
|
||||
|
||||
WireWebDriver = Union[WebDriver, webdriver.Firefox]
|
||||
@ -25,61 +25,104 @@ WireWebDriver = Union[WebDriver, webdriver.Firefox]
|
||||
class SeleniumDriver(BrowserAbstract):
|
||||
|
||||
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)
|
||||
self.browser:WireWebDriver = None
|
||||
super().__init__(anp, key, inputs)
|
||||
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)
|
||||
|
||||
def remove(self:Self) -> None:
|
||||
self.stop()
|
||||
self.browser and self.browser.quit()
|
||||
self.browser is None or self.browser.quit()
|
||||
self.tabs.clear()
|
||||
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 = url(shared)
|
||||
url:str = (
|
||||
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)
|
||||
|
||||
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));
|
||||
""")
|
||||
if url is not None:
|
||||
try:
|
||||
|
||||
def open(self:Self, action:Open, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||
if self.browser is None:
|
||||
self.browser = webdriver.Firefox()
|
||||
self.browser.get(url)
|
||||
|
||||
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:
|
||||
self.browser.switch_to.new_window("tab")
|
||||
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)
|
||||
action.done = False
|
||||
|
||||
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||
self.browser.close()
|
||||
del self.tabs[action.key]
|
||||
self.tab_selected = ""
|
||||
action.done = True
|
||||
def __set_selected(self:Self, key:str, box:BrowserBoxModel, id:str) -> None:
|
||||
box.variables[key] = id
|
||||
box.variables["__selected__"] = key
|
||||
|
||||
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
|
||||
|
||||
def go(self:Self, action:Go, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||
self.__load(action.url, shared)
|
||||
action.done = True
|
||||
except Exception as exception:
|
||||
action.done = False
|
||||
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,
|
||||
selector:Selector,
|
||||
from_item:Optional[WebDriver|WebElement] = None,
|
||||
box:BrowserBoxModel,
|
||||
force_multiple:bool = False
|
||||
) -> list[WebElement]|WebElement|None:
|
||||
if self.tab_selected in self.tabs:
|
||||
@ -92,17 +135,16 @@ class SeleniumDriver(BrowserAbstract):
|
||||
By.PARTIAL_LINK_TEXT if isinstance(selector, LinkText) else
|
||||
By.NAME if isinstance(selector, Name) else
|
||||
By.CSS_SELECTOR)
|
||||
|
||||
if from_item is None:
|
||||
from_item = self.browser
|
||||
from_item:WebElement|WebDriver = box.get_base()
|
||||
|
||||
if force_multiple or selector.multiple:
|
||||
return from_item.find_elements(mode, selector.selector)
|
||||
return from_item.find_element(mode, selector.selector)
|
||||
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)
|
||||
multiple:bool = action.selector is not None and action.selector.multiple
|
||||
|
||||
@ -125,18 +167,9 @@ class SeleniumDriver(BrowserAbstract):
|
||||
"textContent" if action.attribute == "CDATA" else
|
||||
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
|
||||
|
||||
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
|
||||
date:float = timestamp()
|
||||
@ -157,9 +190,9 @@ class SeleniumDriver(BrowserAbstract):
|
||||
)
|
||||
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
|
||||
|
||||
self.browser.execute_script("""
|
||||
@ -174,19 +207,19 @@ class SeleniumDriver(BrowserAbstract):
|
||||
|
||||
""", url)
|
||||
|
||||
data = self.__download_from_cache(url)
|
||||
data = self.__download_from_cache(url, box)
|
||||
|
||||
# if l < len(self.browser.window_handles):
|
||||
# self.browser.switch_to.window(self.browser.window_handles[-1])
|
||||
# self.browser.close()
|
||||
# self.browser.switch_to.window(self.browser.window_handles[-1])
|
||||
if l < len(self.browser.window_handles):
|
||||
self.browser.switch_to.window(self.browser.window_handles[-1])
|
||||
self.browser.close()
|
||||
self.browser.switch_to.window(box.get_last())
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
method:Callable[[str], bytes|None]
|
||||
@ -200,7 +233,7 @@ class SeleniumDriver(BrowserAbstract):
|
||||
# self.__download_by_url
|
||||
):
|
||||
|
||||
data:bytes|None = method(url)
|
||||
data:bytes|None = method(url, box)
|
||||
|
||||
if data is not None:
|
||||
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 import Server as WebSocketServer, ClientConnection as WebSocketClient
|
||||
from AnP.Abstracts.WebSocketServersAbstract import WebSocketServersAbstract
|
||||
from AnP.Abstracts.ModelAbstract import ModelAbstract
|
||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||
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:
|
||||
super().__init__(anp, key, inputs)
|
||||
|
||||
@ -1,76 +1,68 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Self, Any, Optional, Sequence, Callable
|
||||
from typing import Self, Any, Callable
|
||||
from requests import get, Response
|
||||
from parsel import Selector as ParseSelector, SelectorList as ParseSelectorList
|
||||
from AnP.DSLs.ScrapDSL import (
|
||||
Selector, CSS, XPath, Name, LinkText, Class, ID, Open, Close, Switch,
|
||||
Go, Get, ForEach, Do, Condition, And, Or, Not, If, While, DoWhile, Download,
|
||||
Action
|
||||
Selector, CSS, XPath, Name, LinkText, Class, ID, Open,
|
||||
Go, Get, Download, Action
|
||||
)
|
||||
from AnP.Interfaces.Application import AnPInterface
|
||||
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):
|
||||
|
||||
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||
super().__init__(anp, key, XMLScrapTabModel, inputs)
|
||||
def __load(self:Self,
|
||||
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:
|
||||
try:
|
||||
url:str = (
|
||||
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:
|
||||
action.exception = self.__load(url)
|
||||
action.done = action.exception is None
|
||||
try:
|
||||
|
||||
def close(self:Self, action:Close, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||
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
|
||||
response:Response
|
||||
|
||||
def switch(self:Self, action:Switch, shared:dict[str, Any|None] = {}, last_item:Optional[Any] = None) -> None:
|
||||
if action.key in self.tabs:
|
||||
self.tab_selected = action.key
|
||||
action.done = True
|
||||
with get(url) as response:
|
||||
box.set(key or box.get_selected(), ParseSelector(text = response.text, type = "html"))
|
||||
|
||||
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
|
||||
|
||||
action.exception = self.__load(url)
|
||||
action.done = action.exception is None
|
||||
def open(self:Self, action:Open, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||
self.__load(action, action.key, action.url, shared, box)
|
||||
|
||||
def get_selector(self:Self, selector:str, from_item:Optional[Selector] = None, force_multiple:bool = False) -> Any|list[Any]|None:
|
||||
if self.tab_selected in self.tabs:
|
||||
def go(self:Self, action:Go, shared:dict[str, Any|None], box:BrowserBoxModel) -> None:
|
||||
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 = (
|
||||
path.css(selector) if isinstance(selector, CSS) else
|
||||
path.xpath(selector) if isinstance(selector, XPath) else
|
||||
path.css(f"[name='{selector}']") if isinstance(selector, Name) else
|
||||
path.css(f"a:contains('{selector}')") if isinstance(selector, LinkText) else
|
||||
path.css(f".{selector}") if isinstance(selector, Class) else
|
||||
path.css(f"#{selector}") if isinstance(selector, ID) else
|
||||
path.css(selector))
|
||||
path.css(selector.selector) if isinstance(selector, CSS) else
|
||||
path.xpath(selector.selector) if isinstance(selector, XPath) else
|
||||
path.css(f"[name='{selector.selector}']") if isinstance(selector, Name) else
|
||||
path.css(f"a:contains('{selector.selector}')") if isinstance(selector, LinkText) else
|
||||
path.css(f".{selector.selector}") if isinstance(selector, Class) else
|
||||
path.css(f"#{selector.selector}") if isinstance(selector, ID) else
|
||||
path.css(selector.selector))
|
||||
|
||||
return (
|
||||
items if force_multiple or selector.multiple else
|
||||
@ -78,9 +70,9 @@ class XMLScrapDriver(BrowserAbstract):
|
||||
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
|
||||
attribute:str = "::text" if action.attribute == "CDATA" else f"::attr({action.attribute})"
|
||||
|
||||
@ -96,7 +88,7 @@ class XMLScrapDriver(BrowserAbstract):
|
||||
|
||||
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:
|
||||
try:
|
||||
|
||||
@ -120,4 +112,5 @@ class XMLScrapDriver(BrowserAbstract):
|
||||
action.done = True
|
||||
|
||||
except Exception as exception:
|
||||
print(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
|
||||
|
||||
@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.QueusManagerInterface import QueusManagerInterface
|
||||
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.DispatchesManagerInterface import DispatchesManagerInterface
|
||||
from AnP.Interfaces.Managers.IndexesManagerInterface import IndexesManagerInterface
|
||||
@ -35,6 +36,7 @@ class AnPInterface(ABC):
|
||||
self.unique_keys:UniqueKeysManagerInterface = None
|
||||
self.queues:QueusManagerInterface = None
|
||||
self.sessions:SessionsManagerInterface = None
|
||||
self.databases:DatabasesManagerInterface = None
|
||||
self.controllers:ControllersManagerInterface = None
|
||||
self.dispatches:DispatchesManagerInterface = 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
|
||||
# -*- 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
|
||||
|
||||
DispatchType = TypeVar("DispatchType", bound = DispatchAbstract)
|
||||
|
||||
class DispatchesManagerInterface(ABC):
|
||||
|
||||
@abstractmethod
|
||||
@ -16,4 +19,7 @@ class DispatchesManagerInterface(ABC):
|
||||
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:pass
|
||||
|
||||
@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
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Any, Self
|
||||
from typing import Any, Self, TypeVar
|
||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||
from AnP.Abstracts.ControllerAbstract import ControllerAbstract
|
||||
from AnP.Models.RequestModel import RequestModel
|
||||
from AnP.Utils.Checks import Check
|
||||
|
||||
ControllerType = TypeVar("ControllerType", bound = ControllerAbstract)
|
||||
|
||||
class ControllersManager:
|
||||
|
||||
def __init__(self:Self, anp:AnPInterface) -> None:
|
||||
@ -64,4 +66,9 @@ class ControllersManager:
|
||||
if key in self.__controllers and hasattr(self.__controllers[key], method):
|
||||
getattr(self.__controllers[key], method)(request)
|
||||
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
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import Any, Self
|
||||
from typing import Any, Self, TypeVar
|
||||
from AnP.Interfaces.Application.AnPInterface import AnPInterface
|
||||
from AnP.Abstracts.DispatchAbstract import DispatchAbstract
|
||||
from AnP.Utils.Checks import Check
|
||||
|
||||
DispatchType = TypeVar("DispatchType", bound = DispatchAbstract)
|
||||
|
||||
class DispatchesManager:
|
||||
|
||||
def __init__(self:Self, anp:AnPInterface) -> None:
|
||||
|
||||
self.anp:AnPInterface = anp
|
||||
self.__dispatches:dict[str, DispatchAbstract] = {}
|
||||
self.__dispatches:dict[str, dict[str, DispatchAbstract]] = {}
|
||||
|
||||
self.update()
|
||||
|
||||
@ -35,32 +37,46 @@ class DispatchesManager:
|
||||
for subinputs in self.anp.files.load_json(inputs, True):
|
||||
|
||||
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:
|
||||
continue
|
||||
|
||||
DispatchClass:type[DispatchAbstract]|None
|
||||
via:str
|
||||
dispatch:Any|None
|
||||
|
||||
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
|
||||
for via, dispatch in subinputs.items():
|
||||
|
||||
if DispatchClass and (
|
||||
overwrite or key not in self.__dispatches
|
||||
):
|
||||
self.__dispatches[key] = DispatchClass(
|
||||
self.anp, dispatch if Check.is_dictionary(dispatch) else
|
||||
None)
|
||||
DispatchClass:type[DispatchAbstract]|None
|
||||
|
||||
def execute(self:Self, key:str, method:str, *arguments:list[Any|None]) -> bool:
|
||||
if key in self.__dispatches and hasattr(self.__dispatches[key], method):
|
||||
getattr(self.__dispatches[key], method)(*arguments)
|
||||
if via not in self.__dispatches:
|
||||
self.__dispatches[via] = {}
|
||||
|
||||
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 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:
|
||||
while self.anp.working():
|
||||
|
||||
order:str = input()
|
||||
|
||||
try:
|
||||
|
||||
order:str = input()
|
||||
command:str = order.split(" ")[0].lower()
|
||||
parameters:dict[str, Any|None] = {}
|
||||
arguments:list[Any|None] = []
|
||||
@ -64,7 +66,9 @@ class TerminalManager:
|
||||
})
|
||||
|
||||
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:
|
||||
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 os.path import isfile as is_file
|
||||
from json import loads as json_decode
|
||||
import datetime
|
||||
from AnP.Utils.Patterns import RE
|
||||
|
||||
class Check:
|
||||
@ -84,4 +85,8 @@ class Check:
|
||||
|
||||
@staticmethod
|
||||
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.XMLScrapDriver import XMLScrapDriver
|
||||
from AnP.Drivers.SeleniumDriver import SeleniumDriver
|
||||
from AnP.Drivers.SQLiteDriver import SQLiteDriver
|
||||
from AnP.Controllers.CloneController import CloneController
|
||||
from AnP.Controllers.AITranslateController import AITranslateController
|
||||
|
||||
@ -24,7 +25,8 @@ inputs:dict[str, dict[str, Any|None]] = {
|
||||
"OllamaDriver" : OllamaDriver,
|
||||
"FilesDriver" : FilesDriver,
|
||||
"XMLScrapDriver" : XMLScrapDriver,
|
||||
"SeleniumDriver" : SeleniumDriver
|
||||
"SeleniumDriver" : SeleniumDriver,
|
||||
"SQLiteDriver" : SQLiteDriver
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
55
README.md
55
README.md
@ -2,7 +2,19 @@
|
||||
|
||||
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
|
||||
#!/usr/bin/env python3
|
||||
@ -18,7 +30,7 @@ secrets:dict[str, Any|None] = {
|
||||
|
||||
```
|
||||
|
||||
Web Socket Server Settings:
|
||||
## Web Socket Server
|
||||
|
||||
```json
|
||||
{
|
||||
@ -32,7 +44,7 @@ Web Socket Server Settings:
|
||||
}
|
||||
```
|
||||
|
||||
HTTP Settings:
|
||||
## HTTP Server
|
||||
|
||||
```json
|
||||
{
|
||||
@ -47,7 +59,7 @@ HTTP Settings:
|
||||
}
|
||||
```
|
||||
|
||||
AI Interpreters Settings:
|
||||
## AI Interpreters
|
||||
|
||||
```json
|
||||
{
|
||||
@ -82,7 +94,7 @@ AI Interpreters Settings:
|
||||
}
|
||||
```
|
||||
|
||||
Directory Cloner Settings:
|
||||
## Directory Cloner
|
||||
|
||||
```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