feat(py): SQLite.

This commit is contained in:
KyMAN 2026-07-06 07:12:34 +02:00
parent e3c99a1143
commit 175cc13022
35 changed files with 911 additions and 296 deletions

View File

@ -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,

View File

@ -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:

View File

@ -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

View 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()

View File

@ -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

View File

@ -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 = ""

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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,

View 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)

View File

@ -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)

View File

@ -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

View File

@ -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:

View 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)

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View 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()

View File

@ -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

View File

@ -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):

View 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

View 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

View File

@ -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")

View File

@ -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))

View File

@ -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
} }
} }

View File

@ -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
}
}
}