class File(object): """ Manage files from a module. """ logger = logging.getLogger("application.File") def __init__( self, module: str, filename: str, sha: Optional[str] = None, basedir: Optional[str] = None, db_name: Optional[str] = None, ) -> None: """ Constructor. @param module. Identificador del módulo propietario @param filename. Nombre del fichero @param sha. Código sha1 del contenido del fichero @param basedir. Ruta al fichero en cache """ self.module = module self.filename = filename self.sha = sha if filename.endswith(".qs.py"): self.ext = ".qs.py" self.name = os.path.splitext(os.path.splitext(filename)[0])[0] else: self.name, self.ext = os.path.splitext(filename) if self.sha: self.filekey = "%s/%s/file%s/%s/%s%s" % ( db_name, module, self.ext, self.name, sha, self.ext, ) else: self.filekey = filename self.basedir = basedir def path(self) -> str: """ Return absolute path to file. @return Ruta absoluta del fichero """ if self.basedir: # Probablemente porque es local . . . return _dir(self.basedir, self.filename) else: # Probablemente es remoto (DB) y es una caché . . . return _dir("cache", *(self.filekey.split("/")))
import xml.etree.ElementTree as ET from multiprocessing import Pool from typing import List, Tuple, TypeVar, cast, Dict, Optional from pineboolib.core.utils import logging from pineboolib.core.utils.struct import ActionStruct from pineboolib.application.parsers import qsaparser from pineboolib.application.parsers.qsaparser import postparse, pytnyzer class Action(ActionStruct): """Represent actions from XML.""" modname: str = "" logger = logging.getLogger("pyconvert") ModPath = TypeVar("ModPath", bound=str) ModName = TypeVar("ModName", bound=str) ModList = List[Tuple[ModPath, ModName]] CPU_COUNT: int = os.cpu_count() or 1 def _touch(path: str) -> bool: """Create a file if does not exist.""" if not os.path.exists(path): logger.info("Creating empty file %r", path) open(path, "a").close() return True return False
# -*- coding: utf-8 -*- """Check the application dependencies.""" import sys from pineboolib.core.utils import logging from pineboolib.core.utils.utils_base import is_deployed from pineboolib.core.utils.check_dependencies import get_dependency_errors from pineboolib.core.utils.check_dependencies import DependencyCheck, DependencyError from pineboolib import application LOGGER = logging.getLogger(__name__) def check_dependencies(dict_: DependencyCheck, exit: bool = True) -> bool: """ Check if a package is installed and return the result. @param dict_. Dict with the name of the agency and the module to be checked. @param exit . Exit if dependence fails. """ dep_error: DependencyError = get_dependency_errors(dict_) if not dep_error: return True msg = "" LOGGER.debug("Error trying to import modules:\n%s", "\n\n".join(dep_error.values())) LOGGER.warning("Unmet dependences:") for (dep, suggestedpkg), errormsg in dep_error.items(): LOGGER.warning("Install package %s for %s", suggestedpkg, dep) msg += "Instale el paquete %s.\n%s" % (suggestedpkg, errormsg) if dep == "pyfpdf":
# -*- coding: utf-8 -*- """ AQS package. Main entrance to the different AQS resources. """ from PyQt5 import QtCore, QtWidgets, QtGui, QtXml from pineboolib.core.utils import logging from typing import Any, Optional, Union from . import aqshttp, aqods logger = logging.getLogger("AQS") class SMTP(object): """Smtp enumerate class.""" SmtpSslConnection: int = 1 SmtpTlsConnection: int = 2 SmtpAuthPlain: int = 1 SmtpAuthLogin: int = 2 SmtpSendOk: int = 11 SmtpError: int = 7 SmtpMxDnsError: int = 10 SmtpSocketError: int = 12 SmtpAttachError: int = 15 SmtpServerError: int = 16
from typing import Any, Dict, Optional, List, Union, cast from PyQt5 import QtCore, QtWidgets, QtXml from pineboolib.core.settings import config from pineboolib.core import decorators from pineboolib.core.utils.utils_base import ustr, filedir from pineboolib.core.utils import logging from pineboolib import application from pineboolib.application import connections from pineboolib.application.process import Process LOGGER = logging.getLogger("fllegacy.systype") class SysBaseType(object): """ Obtain useful data from the application. """ time_user_ = QtCore.QDateTime.currentDateTime() @classmethod def nameUser(self) -> str: """Get current database user.""" ret_ = None if application.PROJECT.DGI.use_alternative_credentials():
from pineboolib.core.utils import logging from pineboolib.core import settings, decorators from pineboolib.application.qsatypes import sysbasetype import os # from pineboolib.fllegacy.flutil import FLUtil # from pineboolib.fllegacy import flapplication # from pineboolib.fllegacy.flcheckbox import FLCheckBox from typing import Any, List, Optional, cast, TYPE_CHECKING if TYPE_CHECKING: from pineboolib.interfaces import iconnection logger = logging.getLogger(__name__) class AQStaticDirInfo(object): """Store information about a filesystem folder.""" active_: bool path_: str def __init__(self, *args) -> None: """Inicialize.""" if len(args) == 1: self.active_ = args[0] self.path_ = "" else:
"""Manage the data of a field in a table.""" from pineboolib.core.utils.utils_base import aqtt from pineboolib.core.utils import logging from pineboolib.interfaces import IFieldMetaData from typing import List, Optional, Union, Any, TYPE_CHECKING from .pnrelationmetadata import PNRelationMetaData if TYPE_CHECKING: from pineboolib.application.metadata.pntablemetadata import PNTableMetaData LOGGER = logging.getLogger("PNFieldMetadata") class PNFieldMetaData(IFieldMetaData): """PNFieldMetaData Class.""" Serial = "serial" Unlock = "unlock" Check = "check" count_ = 0 def __init__(self, *args, **kwargs) -> None: """ Initialize the metadata with the collected data. @param n Field Name.
Provide some functions based on data. """ from pineboolib.core.utils import logging from pineboolib.application import types from pineboolib import application from . import pnsqlcursor, pnsqlquery from typing import Any, Union, List, Optional, TYPE_CHECKING if TYPE_CHECKING: from pineboolib.interfaces import iconnection, isqlcursor # noqa : F401 LOGGER = logging.getLogger("database.utils") def next_counter( name_or_series: str, cursor_or_name: Union[str, "isqlcursor.ISqlCursor"], cursor_: Optional["isqlcursor.ISqlCursor"] = None, ) -> Optional[Union[str, int]]: """ Return the following value of a counter type field of a table. This method is very useful when inserting records in which the reference is sequential and we don't remember which one was the last number used The return value is a QVariant of the field type is the one that looks for the last reference. The most advisable thing is that the type of the field be 'String' because this way it can be formatted and be
class PNCursorTableModel(QtCore.QAbstractTableModel): """ Link between FLSqlCursor and database. """ logger = logging.getLogger("CursorTableModel") rows: int cols: int _use_timer = True _rows_loaded: int where_filter: str where_filters: Dict[str, str] = {} _metadata: Optional["pntablemetadata.PNTableMetaData"] _sort_order = "" _disable_refresh: bool color_function_ = None need_update = False _driver_sql = None _show_pixmap: bool _size = None parent_view: Optional["fldatatable.FLDataTable"] sql_str = "" _can_fetch_more_rows: bool _curname: str _parent: "isqlcursor.ISqlCursor" _initialized: Optional[ bool ] = None # Usa 3 estado None, True y False para hacer un primer refresh retardado si pertenece a un fldatatable _check_column: Dict[str, QtWidgets.QCheckBox] _data: List[List[Any]] _vdata: List[Optional[List[Any]]] sql_fields: List[str] sql_fields_omited: List[str] sql_fields_without_check: List[str] pkpos: List[int] ckpos: List[int] pkidx: Dict[Tuple, int] ckidx: Dict[Tuple, int] _column_hints: List[int] _cursor_db: "iapicursor.IApiCursor" _current_row_data: List _current_row_index: int _tablename: str _order: str grid_row_tmp: Dict[int, List[Any]] def __init__(self, conn: "iconnection.IConnection", parent: "isqlcursor.ISqlCursor") -> None: """ Constructor. @param conn. PNConnection Object @param parent. related FLSqlCursor """ super(PNCursorTableModel, self).__init__() if parent is None: raise ValueError("Parent is mandatory") self._cursor_connection = conn self._parent = parent self.parent_view = None metadata = self._parent.private_cursor.metadata_ self._rows_loaded = 0 self.rows = 0 self.cols = 0 self._metadata = None if not metadata: return self._metadata = metadata self._driver_sql = self.db().driver() # self._use_timer = self.driver_sql().useTimer() # if not self._use_timer: # self._use_timer = True # self.logger.warning("SQL Driver supports neither Timer, defaulting to Timer") # self._use_timer = True self._rows_loaded = 0 self.rows = 0 self.cols = 0 self.sql_fields = [] self.sql_fields_omited = [] self.sql_fields_without_check = [] # self.field_aliases = [] # self.field_type = [] # self.field_metaData = [] self.col_aliases: List[str] = [] self._current_row_data = [] self._current_row_index = -1 # Indices de busqueda segun PK y CK. Los array "pos" guardan las posiciones # de las columnas afectadas. PK normalmente valdrá [0,]. # CK puede ser [] o [2,3,4] por ejemplo. # En los IDX tendremos como clave el valor compuesto, en array, de la clave. # Como valor del IDX tenemos la posicion de la fila. # Si se hace alguna operación en _data como borrar filas intermedias hay # que invalidar los indices. Opcionalmente, regenerarlos. self.pkpos = [] self.ckpos = [] self.pkidx = {} self.ckidx = {} self._check_column = {} # Establecer a False otra vez si el contenido de los indices es erróneo. self.indexes_valid = False # self._data = [] self._vdata = [] self._column_hints = [] self.updateColumnsCount() # self._rows_loaded = 0 # self.pendingRows = 0 # self.lastFetch = 0.0 # self._fetched_rows = 0 self._show_pixmap = True self.color_function_ = None # self.color_dict_ = {} self.where_filter = "1=1" self.where_filters = {} self.where_filters["main-filter"] = "" self.where_filters["filter"] = "" self.sql_str = "" self._tablename = "" self._order = "" self._curname = "" # self.timer = QtCore.QTimer() # self.timer.timeout.connect(self.updateRows) # self.timer.start(1000) # self._can_fetch_more_rows = True self._disable_refresh = False self._cursor_db = self.db().cursor() self._initialized = None self.grid_row_tmp = {} # self.refresh() if self.metadata().isQuery(): query = self.db().connManager().manager().query(self.metadata().query()) if query is None: raise Exception("query is empty!") self._tablename = query.from_() else: self._tablename = self.metadata().name() def disable_refresh(self, disable: bool) -> None: """ Disable refresh. e.g. FLSqlQuery.setForwardOnly(True). @param disable. True or False """ self._disable_refresh = disable def sort(self, column: int, order: QtCore.Qt.SortOrder = QtCore.Qt.AscendingOrder) -> None: """ Change order by used ASC/DESC and column. @param col. Column to sort by @param order. 0 ASC, 1 DESC """ col = column # order 0 ascendente , 1 descendente ord = "ASC" if order == 1: ord = "DESC" field_mtd = self.metadata().indexFieldObject(col) if field_mtd.type() == "check": return col_name = field_mtd.name() order_list: List[str] = [] found_ = False if self._sort_order: for column_name in self._sort_order.split(","): if col_name in column_name and ord in column_name: found_ = True order_list.append("%s %s" % (col_name, ord)) else: order_list.append(column_name) if not found_: self.logger.debug( "%s. Se intenta ordernar por una columna (%s) que no está definida en el order by previo (%s). " "El order by previo se perderá" % (__name__, col_name, self._sort_order) ) else: self._sort_order = ",".join(order_list) if not found_: self._sort_order = "%s %s" % (col_name, ord) self.refresh() def getSortOrder(self) -> str: """ Get current sort order. Returns string with sortOrder value. @return string with info about column and order """ return self._sort_order def setSortOrder(self, sort_order: str) -> None: """ Set current ORDER BY. """ self._sort_order = "" # if isinstance(sort_order, list): # self._sort_order = ",".join(sort_order) # else: self._sort_order = sort_order # def setColorFunction(self, f): # self.color_function_ = f # def dict_color_function(self): # return self.color_function_ def data(self, index: QtCore.QModelIndex, role: int = QtCore.Qt.DisplayRole) -> Any: """ Retrieve information about a record. (overload of QAbstractTableModel) Could return alignment, backgroun color, value... depending on role. @param index. Register position @param role. information type required @return solicited data """ row = index.row() col = index.column() field = self.metadata().indexFieldObject(col) _type = field.type() res_color_function: List[str] = [] if _type != "check": # r = [x for x in self._data[row]] # self._data[row] = r # d = r[col] # self.seekRow(row) # d = self._current_row_data[col] # d = self._data[row][col] result: Any = None if row not in self.grid_row_tmp.keys(): self.grid_row_tmp = {} self.grid_row_tmp[row] = self.driver_sql().getRow( row, self._curname, self.cursorDB() ) if not self.grid_row_tmp[row]: # refresh grid if cursor is deleted. self.refresh() return tuple = self.grid_row_tmp[row] if tuple: result = tuple[col] else: primary_key = str(self.value(row, self.metadata().primaryKey())) if primary_key not in self._check_column.keys(): result = QtWidgets.QCheckBox() self._check_column[primary_key] = result if self.parent_view and role in [QtCore.Qt.BackgroundRole, QtCore.Qt.ForegroundRole]: fun_get_color, iface = self.parent_view.functionGetColor() if fun_get_color is not None: context_ = None fun_name_ = None if fun_get_color.find(".") > -1: list_ = fun_get_color.split(".") from pineboolib.application.safeqsa import SafeQSA qsa_widget = SafeQSA.get_any(list_[0]) fun_name_ = list_[1] if qsa_widget: context_ = qsa_widget.iface else: context_ = iface fun_name_ = fun_get_color function_color = getattr(context_, fun_name_, None) if function_color is not None: field_name = field.name() field_value = result cursor = self._parent selected = False res_color_function = function_color( field_name, field_value, cursor, selected, _type ) else: raise Exception( "No se ha resuelto functionGetColor %s desde %s" % (fun_get_color, context_) ) # print("Data ", index, role) # print("Registros", self.rowCount()) # roles # 0 QtCore.Qt.DisplayRole # 1 QtCore.Qt.DecorationRole # 2 QtCore.Qt.EditRole # 3 QtCore.Qt.ToolTipRole # 4 QtCore.Qt.StatusTipRole # 5 QtCore.Qt.WhatThisRole # 6 QtCore.Qt.FontRole # 7 QtCore.Qt.TextAlignmentRole # 8 QtCore.Qt.BackgroundRole # 9 QtCore.Qt.ForegroundRole if role == QtCore.Qt.CheckStateRole and _type == "check": if primary_key in self._check_column.keys(): if self._check_column[primary_key].isChecked(): return QtCore.Qt.Checked return QtCore.Qt.Unchecked elif role == QtCore.Qt.TextAlignmentRole: result = QtCore.Qt.AlignVCenter if _type in ("int", "double", "uint"): result = result | QtCore.Qt.AlignRight elif _type in ("bool", "date", "time"): result = result | QtCore.Qt.AlignCenter elif _type in ("unlock", "pixmap"): result = result | QtCore.Qt.AlignHCenter return result elif role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole): if not field.visible(): result = None # r = self._vdata[row] elif _type == "bool": if result in (True, "1"): result = "Sí" else: result = "No" elif _type in ("unlock", "pixmap"): result = None elif _type in ("string", "stringlist", "timestamp") and not result: result = "" elif _type == "time" and result: result = str(result) elif _type == "date": # Si es str lo paso a datetime.date if isinstance(result, str): if len(result.split("-")[0]) == 4: result = date_conversion.date_amd_to_dma(result) if result: list_ = result.split("-") result = datetime.date(int(list_[2]), int(list_[1]), int(list_[0])) if isinstance(result, datetime.date): # Cogemos el locale para presentar lo mejor posible la fecha try: locale.setlocale(locale.LC_TIME, "") if os.name == "nt": date_format = "%%d/%%m/%%y" else: date_format = locale.nl_langinfo(locale.D_FMT) date_format = date_format.replace("y", "Y") # Año con 4 dígitos date_format = date_format.replace("/", "-") # Separadores result = result.strftime(date_format) except AttributeError: import platform self.logger.warning( "locale specific date format is not yet implemented for %s", platform.system(), ) elif _type == "check": return elif _type == "double": if result is not None: # d = QtCore.QLocale.system().toString(float(d), "f", field.partDecimal()) result = utils_base.format_double( result, field.partInteger(), field.partDecimal() ) elif _type in ("int", "uint"): if result is not None: result = QtCore.QLocale.system().toString(int(result)) if self.parent_view is not None: self.parent_view.resize_column(col, result) return result elif role == QtCore.Qt.DecorationRole: pixmap = None if _type in ("unlock", "pixmap") and self.parent_view: row_height = self.parent_view.rowHeight(row) # Altura row row_width = self.parent_view.columnWidth(col) if _type == "unlock": if result in (True, "1"): pixmap = QtGui.QPixmap( utils_base.filedir("./core/images/icons", "unlock.png") ) else: pixmap = QtGui.QPixmap( utils_base.filedir("./core/images/icons", "lock.png") ) else: if not self._parent.private_cursor._is_system_table: data = self.db().connManager().manager().fetchLargeValue(result) else: data = xpm.cache_xpm(result) pixmap = QtGui.QPixmap(data) if not pixmap.isNull(): new_size = row_height - 1 if new_size > row_width: new_size = row_width pixmap = pixmap.scaled(new_size, new_size) if self.parent_view.showAllPixmap() or row == self.parent_view.cur.at(): if pixmap and not pixmap.isNull() and self.parent_view: new_pixmap = QtGui.QPixmap(row_width, row_height) # w , h center_width = (row_width - pixmap.width()) / 2 center_height = (row_height - pixmap.height()) / 2 new_pixmap.fill(QtCore.Qt.transparent) painter = Qt.QPainter(new_pixmap) painter.drawPixmap( center_width, center_height, pixmap.width(), pixmap.height(), pixmap ) pixmap = new_pixmap return pixmap elif role == QtCore.Qt.BackgroundRole: if _type == "bool": if result in (True, "1"): result = QtGui.QBrush(QtCore.Qt.green) else: result = QtGui.QBrush(QtCore.Qt.red) elif _type == "check": obj_ = self._check_column[primary_key] result = ( QtGui.QBrush(QtCore.Qt.green) if obj_.isChecked() else QtGui.QBrush(QtCore.Qt.white) ) else: if res_color_function and len(res_color_function) and res_color_function[0] != "": color_ = QtGui.QColor(res_color_function[0]) style_ = getattr(QtCore.Qt, res_color_function[2], None) result = QtGui.QBrush(color_) result.setStyle(style_) else: result = None return result elif role == QtCore.Qt.ForegroundRole: if _type == "bool": if result in (True, "1"): result = QtGui.QBrush(QtCore.Qt.black) else: result = QtGui.QBrush(QtCore.Qt.white) else: if res_color_function and len(res_color_function) and res_color_function[1] != "": color_ = QtGui.QColor(res_color_function[1]) style_ = getattr(QtCore.Qt, res_color_function[2], None) result = QtGui.QBrush(color_) result.setStyle(style_) else: result = None return result # else: # print("role desconocido", role) return None def updateRows(self) -> None: """ Update virtual records managed by its model. """ parent = QtCore.QModelIndex() torow = self.rows - 1 self._rows_loaded = torow + 1 self.beginInsertRows(parent, 0, torow) self.endInsertRows() top_left = self.index(0, 0) bottom_right = self.index(torow, self.cols - 1) self.dataChanged.emit(top_left, bottom_right) self.indexes_valid = True def _refresh_field_info(self) -> None: """ Check if query fields do exist. If any field does not exist it gets marked as ommitted. """ is_query = self.metadata().isQuery() qry_tables = [] qry = None # if qry is None: # return if is_query: qry = self.db().connManager().manager().query(self.metadata().query()) if qry is None: raise Exception(" The query %s return empty value" % self.metadata().query()) qry_select = [x.strip() for x in (qry.select()).split(",")] qry_fields: Dict[str, str] = { fieldname.split(".")[-1]: fieldname for fieldname in qry_select } for table in qry.tablesList(): mtd = self.db().connManager().manager().metadata(table, True) if mtd: qry_tables.append((table, mtd)) for number, field in enumerate(self.metadata().fieldList()): # if field.visibleGrid(): # sql_fields.append(field.name()) if field.isPrimaryKey(): self.pkpos.append(number) if field.isCompoundKey(): self.ckpos.append(number) if is_query: if field.name() in qry_fields: self.sql_fields.append(qry_fields[field.name()]) else: found = False for table, mtd in qry_tables: if field.name() in mtd.fieldNames(): self.sql_fields.append("%s.%s" % (table, field.name())) found = True break # Omito los campos que aparentemente no existen if not found and not field.name() in self.sql_fields_omited: if qry is None: raise Exception("The qry is empty!") # NOTE: Esto podría ser por ejemplo porque no entendemos los campos computados. self.logger.error( "CursorTableModel.refresh(): Omitiendo campo '%s' referenciado en query %s. El campo no existe en %s ", field.name(), self.metadata().name(), qry.tablesList(), ) self.sql_fields_omited.append(field.name()) else: if field.type() != field.Check: self.sql_fields_without_check.append(field.name()) self.sql_fields.append(field.name()) def refresh(self) -> None: """ Refresh information mananged by this class. """ if ( self._initialized is None and self.parent_view ): # Si es el primer refresh y estoy conectado a un FLDatatable() self._initialized = True QtCore.QTimer.singleShot(1, self.refresh) return if ( self._initialized ): # Si estoy inicializando y no me ha enviado un sender, cancelo el refesh if not self.sender(): return self._initialized = False # if self._disable_refresh and self.rows > 0: # return if not self.metadata(): self.logger.warning( "ERROR: CursorTableModel :: No hay tabla %s", self.metadata().name() ) return """ FILTRO WHERE """ where_filter = "" for k, wfilter in sorted(self.where_filters.items()): # if wfilter is None: # continue wfilter = wfilter.strip() if not wfilter: continue if not where_filter: where_filter = wfilter elif wfilter not in where_filter: if where_filter not in wfilter: where_filter += " AND " + wfilter if not where_filter: where_filter = "1 = 1" self.where_filter = where_filter self._order = self.getSortOrder() # Si no existe un orderBy y se ha definido uno desde FLTableDB ... if self.where_filter.find("ORDER BY") == -1 and self.getSortOrder(): if self.where_filter.find(";") > -1: # Si el where termina en ; ... self.where_filter = self.where_filter.replace(";", " ORDER BY %s;" % self._order) else: self.where_filter = "%s ORDER BY %s" % (self.where_filter, self._order) """ FIN """ parent = QtCore.QModelIndex() self.beginRemoveRows(parent, 0, self.rows) self.endRemoveRows() if self.rows > 0: cast(QtCore.pyqtSignal, self.rowsRemoved).emit(parent, 0, self.rows - 1) self.rows = 0 self._rows_loaded = 0 self._fetched_rows = 0 self.sql_fields = [] self.sql_fields_without_check = [] self._refresh_field_info() if self.sql_fields_without_check: self.sql_str = ", ".join(self.sql_fields_without_check) else: self.sql_str = ", ".join(self.sql_fields) self._current_row_data = [] self._current_row_index = -1 if self._curname: self.driver_sql().deleteCursor(self._curname, self.cursorDB()) self._curname = "cur_%s_%08d" % (self.metadata().name(), next(CURSOR_COUNT)) self.rows = self.size() if not self.rows: # Si no hay tamaño, no declara/crea el cursor/consulta return self.driver_sql().declareCursor( self._curname, self.sql_str, self._tablename, self.where_filter, self.cursorDB(), self.db(), ) self.grid_row_tmp = {} self.need_update = False self._column_hints = [120] * len(self.sql_fields) self.updateRows() def value(self, row: Optional[int], field_name: str) -> Any: """ Retrieve column value for a row. @param row. Row number to retrieve @param field_name. Field name. @return Value """ if row is None or row < 0: return None col = None if not self.metadata().isQuery(): col = self.metadata().indexPos(field_name) else: # Comparo con los campos de la qry, por si hay algun hueco que no se detectaria con indexPos for number, field in enumerate(self.sql_fields): if field_name == field[field.find(".") + 1 :]: col = number break if not col: return None mtdfield = self.metadata().field(field_name) if mtdfield is None: raise Exception("field_name: %s not found" % field_name) type_ = mtdfield.type() if type_ == "check": return None if self._current_row_index != row: if not self.seekRow(row): return None campo: Any = None if self._current_row_data: campo = self._current_row_data[col] if type_ in ("serial", "uint", "int"): if campo not in (None, "None"): campo = int(campo) elif campo == "None": self.logger.warning("Campo no deberia ser un string 'None'") return campo def seekRow(self, row: int) -> bool: """Seek to a row possition.""" if not self.rows: return False if row != self._current_row_index: result = self.driver_sql().getRow(row, self._curname, self.cursorDB()) if not result: return False self._current_row_index = row self._current_row_data = list(result) return True def setValuesDict(self, row: int, update_dict: Dict[str, Any]) -> None: """ Set value to a row using a Dict. @param row. Row to update @param update_dict. Key-Value where key is the fieldname and value is the value to update """ if DEBUG: self.logger.info("CursorTableModel.setValuesDict(row %s) = %r", row, update_dict) try: self.seekRow(row) self._current_row_data = list(self._current_row_data) colsnotfound = [] for fieldname, value in update_dict.items(): # col = self.metadata().indexPos(fieldname) try: col = self.sql_fields.index(fieldname) # self._data[row][col] = value self._current_row_data[col] = value # r[col] = value except ValueError: colsnotfound.append(fieldname) if colsnotfound: self.logger.warning( "CursorTableModel.setValuesDict:: columns not found: %r", colsnotfound ) # self.indexUpdateRow(row) except Exception: self.logger.exception( "CursorTableModel.setValuesDict(row %s) = %r :: ERROR:", row, update_dict ) self._current_row_index = -1 def setValue(self, row: int, fieldname: str, value: Any) -> None: """ Set value to a cell. @param row. related row @param fieldname. name of the field to update. @param value. Value to write. Text, Pixmap, etc. """ # Reimplementación para que todo pase por el método genérico. self.setValuesDict(row, {fieldname: value}) def insert( self, fl_cursor: "isqlcursor.ISqlCursor" ) -> bool: # FIXME: Should be "insert" in lowercase. """ Create new row in TableModel. @param buffer . PNBuffer to be added. """ # Metemos lineas en la tabla de la bd # pKValue = None buffer = fl_cursor.buffer() if buffer is None: raise Exception("Cursor has no buffer") campos = "" valores = "" for buffer_field in buffer.fieldsList(): value: Any = None if buffer.value(buffer_field.name) is None: mtdfield = fl_cursor.metadata().field(buffer_field.name) if mtdfield is None: raise Exception("field %s not found" % buffer_field.name) value = mtdfield.defaultValue() else: value = buffer.value(buffer_field.name) if value is not None: # si el campo se rellena o hay valor default # if b.name == fl_cursor.metadata().primaryKey(): # pKValue = value if buffer_field.type_ in ("string", "stringlist") and isinstance(value, str): value = self.db().normalizeValue(value) value = ( self.db().connManager().manager().formatValue(buffer_field.type_, value, False) ) if not campos: campos = buffer_field.name valores = value else: campos = u"%s,%s" % (campos, buffer_field.name) valores = u"%s,%s" % (valores, value) if campos: sql = """INSERT INTO %s (%s) VALUES (%s)""" % (fl_cursor.curName(), campos, valores) # conn = self._cursor_connection.db() try: # print(sql) self.db().execute_query(sql) # self.refresh() # if pKValue is not None: # fl_cursor.move(self.findPKRow((pKValue,))) self.need_update = True except Exception: self.logger.exception( "CursorTableModel.%s.Insert() :: SQL: %s", self.metadata().name(), sql ) # self._cursor.execute("ROLLBACK") return False # conn.commit() return True return False def update(self, pk_value: Any, dict_update: Dict[str, Any]) -> bool: """ Update record data from tableModel into DB. @param pk_value. Pirmary Key of the record to be updated @param dict_update. Fields to be updated """ self.logger.trace( "updateValuesDB: init: pk_value %s, dict_update %s", pk_value, dict_update ) row = self.findPKRow([pk_value]) # if row is None: # raise AssertionError( # "Los indices del CursorTableModel no devolvieron un registro (%r)" % (pk_value)) if row is None: return False if self.value(row, self.pK()) != pk_value: raise AssertionError( "Los indices del CursorTableModel devolvieron un registro erroneo: %r != %r" % (self.value(row, self.pK()), pk_value) ) self.setValuesDict(row, dict_update) pkey_name = self.metadata().primaryKey() # TODO: la conversion de mogrify de bytes a STR va a dar problemas con los acentos... mtdfield = self.metadata().field(pkey_name) if mtdfield is None: raise Exception("Primary Key %s not found" % pkey_name) pkey_type = mtdfield.type() pk_value = self.db().connManager().manager().formatValue(pkey_type, pk_value, False) # if pkey_type == "string" or pkey_type == "pixmap" or pkey_type == "stringlist" or pkey_type == "time" or pkey_type == "date": # pk_value = str("'" + pk_value + "'") where_filter = "%s = %s" % (pkey_name, pk_value) update_set = [] for key, value in dict_update.items(): mtdfield = self.metadata().field(key) if mtdfield is None: raise Exception("Field %s not found" % key) type_ = mtdfield.type() # if type_ == "string" or type_ == "pixmap" or type_ == "stringlist" or type_ == "time" or type_ == "date": # value = str("'" + value + "'") if type_ in ("string", "stringlist", "timestamp"): value = self.db().normalizeValue(value) value = self.db().connManager().manager().formatValue(type_, value, False) # update_set.append("%s = %s" % (key, (self._cursor.mogrify("%s",[value])))) update_set.append("%s = %s" % (key, value)) if len(update_set) == 0: return False update_set_txt = ", ".join(update_set) sql = self.driver_sql().queryUpdate(self.metadata().name(), update_set_txt, where_filter) # print("MODIFYING SQL :: ", sql) try: self.db().execute_query(sql) except Exception: self.logger.exception("ERROR: CursorTableModel.Update %s:", self.metadata().name()) # self._cursor.execute("ROLLBACK") return False try: if self.cursorDB().description: returning_fields = [x[0] for x in self.cursorDB().description] for orow in self.cursorDB(): dict_update = dict(zip(returning_fields, orow)) self.setValuesDict(row, dict_update) except Exception: self.logger.exception( "updateValuesDB: Error al assignar los valores de vuelta al buffer" ) self.need_update = True return True def delete(self, cursor: "isqlcursor.ISqlCursor") -> bool: """ Delete a row from tableModel. @param cursor . FLSqlCursor object """ pk_name = self.pK() pk_type = self.fieldType(pk_name) val = ( self.db() .connManager() .manager() .formatValue(pk_type, self.value(cursor.currentRegister(), pk_name)) ) sql = "DELETE FROM %s WHERE %s = %s" % (self._tablename, pk_name, val) # conn = self._cursor_connection.db() try: self.db().execute_query(sql) self.need_update = True except Exception: self.logger.exception("CursorTableModel.%s.Delete() :: ERROR:", self._tablename) # self._cursor.execute("ROLLBACK") return False return True # conn.commit() def findPKRow(self, pklist: Iterable[Any]) -> Optional[int]: """ Retrieve row index of a record given a primary key. @param pklist. Primary Key list to find. Use a List [] even for a single record. @return row index. """ if not isinstance(pklist, (tuple, list)): raise ValueError( "findPKRow expects a list as first argument. Enclose PK inside brackets [self.pkvalue]" ) pklist = tuple(pklist) if not pklist or pklist[0] is None: raise ValueError("Primary Key can't be null") ret = None if self.pK(): ret = self.driver_sql().findRow( self.cursorDB(), self._curname, self.sql_fields.index(self.pK()), pklist[0] ) return ret def pK(self) -> str: """ Get field name of the primary key. @return field name """ return self.metadata().primaryKey() def fieldType(self, field_name: str) -> str: """ Retrieve field type for a given field name. @param field_name. required field name. @return field type. """ field = self.metadata().field(field_name) if field is None: raise Exception("field %s not found" % field_name) return field.type() def alias(self, field_name: str) -> str: """ Retrieve alias name for a field name. @param field_name. field name requested. @return alias for the field. """ field = self.metadata().field(field_name) if field is None: raise Exception("field %s not found" % field_name) return field.alias() def columnCount(self, *args: List[Any]) -> int: # type: ignore [override] # noqa F821 """ Get current column count. @return Number of columns present. """ # if args: # self.logger.warning("columnCount%r: wrong arg count", args, stack_info=True) return self.cols def updateColumnsCount(self) -> None: """ Set number of columns in tableModel. """ self.cols = len(self.metadata().fieldList()) self.loadColAliases() if self.metadata().isQuery(): self._refresh_field_info() def rowCount(self, parent: QtCore.QModelIndex = None) -> int: """ Get current row count. @return Row number present in table. """ return self._rows_loaded def size(self) -> int: """ Get amount of data selected on the cursor. @return number of retrieved rows. """ size = 0 mtd = self.metadata() if mtd and self.db().isOpen(): where_ = self.where_filter # from_ = self.metadata().name() # if mtd.isQuery(): # qry = self.db().connManager().manager().query(self.metadata().query()) # if qry is None: # raise Exception("Query not found") # from_ = qry.from_() if self.where_filter.find("ORDER BY") > -1: where_ = self.where_filter[: self.where_filter.find("ORDER BY")] where_ = self.driver_sql().fix_query(where_) # q = pnsqlquery.PNSqlQuery(None, self.db()) sql = "SELECT COUNT(%s) FROM %s WHERE %s" % (self.pK(), self._tablename, where_) cursor = self.driver_sql().execute_query(sql) result = cursor.fetchone() if result is not None: size = result[0] # q.exec_(sql) # if q.first(): # size = q.value(0) return size def headerData( self, section: int, orientation: QtCore.Qt.Orientation, role: int = QtCore.Qt.DisplayRole ) -> Any: """ Retrieve header data. @param section. Column @param orientation. Horizontal, Vertical @param role. QtCore.Qt.DisplayRole only. Every other option is ommitted. @return info for section, orientation and role. """ if role == QtCore.Qt.DisplayRole: if orientation == QtCore.Qt.Horizontal: if not self.col_aliases: self.loadColAliases() return self.col_aliases[section] elif orientation == QtCore.Qt.Vertical: return section + 1 return None def loadColAliases(self) -> None: """ Load column alias for every column. """ self.col_aliases = [ str(self.metadata().indexFieldObject(i).alias()) for i in range(self.cols) ] def field_metadata(self, field_name: str) -> "pnfieldmetadata.PNFieldMetaData": """ Retrieve FLFieldMetadata for given field name. @param field_name. field name. @return FLFieldMetadata """ field = self.metadata().field(field_name) if field is None: raise Exception("field_name %s not found" % field_name) return field def metadata(self) -> "pntablemetadata.PNTableMetaData": """ Retrieve FLTableMetaData for this tableModel. @return Objeto FLTableMetaData """ if self._metadata is None: raise Exception("metadata is empty!") return self._metadata def driver_sql(self) -> Any: """Get SQL Driver used.""" return self._driver_sql def cursorDB(self) -> "iapicursor.IApiCursor": """ Get currently used database cursor. @return cursor object """ return self._cursor_db def db(self) -> "iconnection.IConnection": """Get current connection.""" return self._cursor_connection def set_parent_view(self, parent_view: "fldatatable.FLDataTable") -> None: """Set the parent view.""" self.parent_view = parent_view
"""Converter to and from action_.""" from pineboolib.core.utils import logging from typing import Union, cast, TYPE_CHECKING from pineboolib import application from pineboolib.application.metadata import pnaction if TYPE_CHECKING: from pineboolib.application.xmlaction import XMLAction LOGGER = logging.getLogger("application.utils.convert_action_") def convert_from_flaction(action: pnaction.PNAction) -> "XMLAction": """ Convert a PNAction to XMLAction. @param action. action_ object. @return XMLAction object. """ if action.name() not in application.PROJECT.actions.keys(): raise KeyError("Action %s not loaded in current project" % action.name()) return cast("XMLAction", application.PROJECT.actions[action.name()]) def convert_to_flaction(action: Union[str, "XMLAction"]) -> pnaction.PNAction: """ Convert a XMLAction to action_.
"""Messagebox module.""" # -*- coding: utf-8 -*- from PyQt5 import QtCore from PyQt5.QtWidgets import QMessageBox, QApplication # type: ignore from pineboolib.core.utils import logging from typing import Any logger = logging.getLogger("messageBox") class MessageBox(QMessageBox): """MessageBox class.""" @classmethod def msgbox(cls, typename, text, button0, button1=None, button2=None, title=None, form=None) -> Any: """Return a messageBox.""" from pineboolib import application if application.PROJECT._splash: application.PROJECT._splash.hide() if not isinstance(text, str): logger.warning("MessageBox help!", stack_info=True) # temp = text
""" QSADictModules. Manages read and writting QSA dynamic properties that are loaded during project startup. """ from typing import Any, TYPE_CHECKING from pineboolib.core.utils import logging from pineboolib.application.xmlaction import XMLAction from pineboolib.application.proxy import DelayedObjectProxyLoader from pineboolib.application.safeqsa import SafeQSA LOGGER = logging.getLogger("qsadictmodules") class QSADictModules: """ Manage read and write dynamic properties for QSA. """ _qsa_dict_modules: Any = None @classmethod def qsa_dict_modules(cls) -> Any: """Retrieve QSA module, hidding it from MyPy.""" if cls._qsa_dict_modules is None: # FIXME: This loads from QSA module. Avoid if possible. (how?) if TYPE_CHECKING: qsa_dict_modules: Any = None else: from pineboolib.qsa import qsa as qsa_dict_modules
"""Test_pnsqlcursor module.""" import unittest from pineboolib.loader.main import init_testing, finish_testing from pineboolib.core.utils import logging from pineboolib.application.database import pnsqlcursor LOGGER = logging.getLogger("test") class TestInsertData(unittest.TestCase): """TestInsertData Class.""" @classmethod def setUpClass(cls) -> None: """Ensure pineboo is initialized for testing.""" init_testing() def test_basic(self) -> None: """Insert data into a database.""" cursor = pnsqlcursor.PNSqlCursor("flareas") cursor.setModeAccess(cursor.Insert) cursor.refreshBuffer() cursor.setValueBuffer("bloqueo", True) cursor.setValueBuffer("idarea", "T") cursor.setValueBuffer("descripcion", "Área de prueba T") self.assertTrue(cursor.commitBuffer()) mode_access = cursor.modeAccess() self.assertEqual(mode_access, cursor.Edit) @classmethod
class XMLAction(struct.ActionStruct): """ Information related to actions specified in XML modules. """ logger = logging.getLogger("main.XMLAction") mod: Optional["moduleactions.ModuleActions"] alias: str def __init__(self, *args, project: "projectmodule.Project", name: Optional[str] = None, **kwargs) -> None: """ Constructor. """ super(XMLAction, self).__init__(*args, **kwargs) self.mod = None self.project = project if not self.project: raise ValueError("XMLActions must belong to a project") self.form = self._v("form") self.name = name or self._rv("name") # Mandatory self.description = self._v("description") self.caption = self._v("caption") alias = self._v("alias") if alias: self.alias = alias self.scriptform = self._v("scriptform") self.table = self._v("table") self.mainform = self._v("mainform") self.mainscript = self._v("mainscript") self.formrecord = self._v("formrecord") self.scriptformrecord = self._v("scriptformrecord") self.mainform_widget: Optional[flformdb.FLFormDB] = None self.formrecord_widget: Optional[flformrecorddb.FLFormRecordDB] = None self._loaded = False def loadRecord( self, cursor: Optional["isqlcursor.ISqlCursor"] ) -> "flformrecorddb.FLFormRecordDB": """ Load FLFormRecordDB by default. @param cursor. Asigna un cursor al FLFormRecord @return widget con form inicializado """ self._loaded = getattr(self.formrecord_widget, "_loaded", False) if not self._loaded: if self.formrecord_widget and getattr(self.formrecord_widget, "widget", None): self.formrecord_widget.widget.doCleanUp() # self.formrecord_widget.widget = None # if self.project.DGI.useDesktop(): # FIXME: looks like code duplication. Bet both sides of the IF do the same. # self.formrecord_widget = cast( # flformrecorddb.FLFormRecordDB, # self.project.conn_manager.managerModules().createFormRecord( # action=self, parent_or_cursor=cursor # ), # ) # else: # self.script = getattr(self, "script", None) # if isinstance(self.script, str) or self.script is None: # script = load_script.load_script(self.scriptformrecord, self) # self.formrecord_widget = script.form # if self.formrecord_widget is None: # raise Exception("After loading script, no form was loaded") # self.formrecord_widget.widget = self.formrecord_widget # self.formrecord_widget.iface = self.formrecord_widget.widget.iface # self.formrecord_widget._loaded = True # self.formrecord_widget.setWindowModality(Qt.ApplicationModal) self.logger.debug("Loading record action %s . . . ", self.name) self.formrecord_widget = cast( flformrecorddb.FLFormRecordDB, self.project.conn_manager.managerModules().createFormRecord( action=self, parent_or_cursor=cursor), ) self.logger.debug( "End of record action load %s (iface:%s ; widget:%s)", self.name, getattr(self.formrecord_widget, "iface", None), getattr(self.formrecord_widget, "widget", None), ) if self.formrecord_widget is None: raise Exception("Unexpected: No formrecord loaded") if cursor: self.formrecord_widget.setCursor(cursor) return self.formrecord_widget def load(self) -> "flformdb.FLFormDB": """ Load master form. """ self._loaded = getattr(self.mainform_widget, "_loaded", False) if not self._loaded: if self.mainform_widget is not None and getattr( self.mainform_widget, "widget", None): self.mainform_widget.widget.doCleanUp() # if self.project.DGI.useDesktop(): # self.logger.info("Loading action %s (createForm). . . ", self.name) # self.mainform_widget = cast( # flformdb.FLFormDB, # self.project.conn_manager.managerModules().createForm(action=self), # ) # else: # self.logger.info( # "Loading action %s (load_script %s). . . ", self.name, self.scriptform # ) # script = load_script.load_script(self.scriptform, self) # self.mainform_widget = script.form # FormDBWidget FIXME: Add interface for types # if self.mainform_widget is None: # raise Exception("After loading script, no form was loaded") # self.mainform_widget.widget = self.mainform_widget # self.mainform_widget.iface = self.mainform_widget.widget.iface # self.mainform_widget._loaded = True self.logger.info("Loading action %s (createForm). . . ", self.name) self.mainform_widget = cast( flformdb.FLFormDB, self.project.conn_manager.managerModules().createForm( action=self), ) self.logger.debug( "End of action load %s (iface:%s ; widget:%s)", self.name, getattr(self.mainform_widget, "iface", None), getattr(self.mainform_widget, "widget", None), ) if self.mainform_widget is None: raise Exception("Unexpected: No form loaded") return self.mainform_widget def execMainScript(self, name: str) -> None: """ Execute function for main action. """ action = self.project.conn_manager.manager().action(name) if not action: self.logger.warning("No existe la acción %s", name) return self.project.call("%s.main" % action.name(), [], None, False) def formRecordWidget(self) -> "flformrecorddb.FLFormRecordDB": """ Return formrecord widget. This is needed because sometimes there isn't a FLFormRecordDB initialized yet. @return wigdet del formRecord. """ if not getattr(self.formrecord_widget, "_loaded", None): self.loadRecord(None) if self.formrecord_widget is None: raise Exception("Unexpected: No form loaded") return self.formrecord_widget def openDefaultFormRecord(self, cursor: "isqlcursor.ISqlCursor", wait: bool = True) -> None: """ Open FLFormRecord specified on defaults. @param cursor. Cursor a usar por el FLFormRecordDB """ if self.formrecord_widget is not None: if getattr(self.formrecord_widget, "_loaded", False): if self.formrecord_widget.showed: QtWidgets.QMessageBox.information( QtWidgets.QApplication.activeWindow(), "Aviso", "Ya hay abierto un formulario de edición de resgistro para esta tabla.\n" "No se abrirán mas para evitar ciclos repetitivos de edición de registros.", QtWidgets.QMessageBox.Yes, ) return self.logger.info("Opening default formRecord for Action %s", self.name) widget = self.loadRecord(cursor) # w.init() if widget: if wait: widget.show_and_wait() else: widget.show() def openDefaultForm(self) -> None: """ Open Main FLForm specified on defaults. """ self.logger.info("Opening default form for Action %s", self.name) widget = self.load() if widget: if self.project.DGI.localDesktop(): widget.show() def execDefaultScript(self) -> None: """ Execute script specified on default. """ self.logger.info("Executing default script for Action %s", self.name) script = load_script.load_script(self.scriptform, self) self.mainform_widget = script.form if self.mainform_widget is None: raise Exception("Unexpected: No form loaded") main = None iface = getattr(script.form, "iface", None) if iface is not None: main = getattr(iface, "main", None) if main is None: main = getattr(script.form, "main", None) if main is None: raise Exception("main function not found!") else: main() # if self.mainform_widget.widget.iface is not None: # self.mainform_widget.iface.main() # else: # self.mainform_widget.widget.main() def unknownSlot(self) -> None: """Log error for actions with unknown slots or scripts.""" self.logger.error("Executing unknown script for Action %s", self.name)
def main() -> None: """Get options and start conversion.""" filter_mod = sys.argv[1] if len(sys.argv) > 1 else None filter_file = sys.argv[2] if len(sys.argv) > 2 else None pytnyzer.STRICT_MODE = False log_format = "%(levelname)s: %(name)s: %(message)s" logging.basicConfig(format=log_format, level=0) blib_logger = logging.getLogger("blib2to3.pgen2.driver") blib_logger.setLevel(logging.WARNING) logger.info("Cpu count %d", CPU_COUNT) source_folder = "." package_name = "pymodules" src_path = os.path.abspath(source_folder) dst_path = os.path.abspath(os.path.join(src_path, package_name)) # Step 1 - Create base package path _touch_dir(dst_path) _touch(os.path.join(dst_path, "__init__.py")) mypy_ini = os.path.join(src_path, "mypy.ini") if not os.path.exists(mypy_ini): with open(mypy_ini, "w") as f1: f1.write("[mypy]\n") f1.write("python_version = 3.7\n") f1.write("check_untyped_defs = True\n") # Step 2 - Create module folders module_files_in: ModList = get_modules(src_path) known_modules: Dict[str, Tuple[str, str]] = {} module_files_ok: ModList = [] for mpath, mname in module_files_in: xml_name = os.path.join(mpath, "%s.xml" % mname) if not os.path.exists(os.path.join(src_path, xml_name)): logger.warn("File not found %r. Ignoring module." % xml_name) continue if os.sep in mpath: mpath_list = mpath.split(os.sep) if len(mpath_list) > 2: logger.warn("Path %r is not supported, maximum is depth 2" % mpath) continue mpath_parent = mpath_list[0] _touch_dir(os.path.join(dst_path, mpath_parent)) _touch(os.path.join(dst_path, mpath_parent, "__init__.py")) _touch_dir(os.path.join(dst_path, mpath)) _touch(os.path.join(dst_path, mpath, "__init__.py")) known_modules[mname] = (package_name + "." + mpath.replace(os.sep, "."), mname) module_files_ok.append((mpath, mname)) # Step 3 - Read module XML and identify objects for mpath, mname in module_files_ok: xml_name = os.path.join(mpath, "%s.xml" % mname) actions = mod_xml_parse(os.path.join(src_path, xml_name), mname) if actions is None: continue for action in actions.values(): if action.scriptform: module_pubname = "form%s" % action.name known_modules[module_pubname] = ( package_name + "." + mpath.replace(os.sep, "."), action.scriptform, ) if action.scriptformrecord: module_pubname = "formRecord%s" % action.name known_modules[module_pubname] = ( package_name + "." + mpath.replace(os.sep, "."), action.scriptformrecord, ) if filter_mod is not None: for alias, (path, name) in known_modules.items(): if filter_mod not in path and filter_mod not in name: continue logger.debug("from %s import %s as %s", path, name, alias) # Step 4 - Retrieve QS file list for conversion logger.info("Retrieving QS File list...") qs_files: List[Tuple[str, str]] = [] for mpath, mname in module_files_ok: if filter_mod is not None and filter_mod not in mpath and filter_mod not in mname: continue rootdir = os.path.join(src_path, mpath) for root, subFolders, files in os.walk(rootdir): def get_fname_pair(fname: str) -> Tuple[str, str]: src_filename = os.path.join(root, fname) dst_filename = os.path.join(dst_path, mpath, fname.replace(".qs", ".py")) return src_filename, dst_filename if filter_file is not None: files = [fname for fname in files if filter_file in fname] qs_files += [ get_fname_pair(fname) for fname in files if fname.endswith(".qs") ] # Step 5 - Convert QS into Python logger.info("Converting %d QS files...", len(qs_files)) itemlist = [ PythonifyItem(src=src, dst=dst, n=n, len=len(qs_files), known=known_modules) for n, (src, dst) in enumerate(qs_files) ] pycode_list: List[bool] = [] if qsaparser.USE_THREADS: with Pool(CPU_COUNT) as p: # TODO: Add proper signatures to Python files to avoid reparsing pycode_list = p.map(pythonify_item, itemlist, chunksize=2) else: for item in itemlist: pycode_list.append(pythonify_item(item)) if not all(pycode_list): raise Exception("Conversion failed for some files")
from pineboolib.q3widgets import qdateedit from pineboolib.q3widgets import qtable from pineboolib.core.utils import logging import inspect import weakref import re import types from typing import Callable, Any, Dict, Tuple, Optional, TYPE_CHECKING if TYPE_CHECKING: from pineboolib.q3widgets import formdbwidget # noqa F401 LOGGER = logging.getLogger("application.connections") class ProxySlot: """ Proxies a method so it doesn't need to be resolved on connect. """ PROXY_FUNCTIONS: Dict[str, Callable] = {} def __init__(self, remote_fn: types.MethodType, receiver: QtCore.QObject, slot: str) -> None: """Create a proxy for a method.""" self.key = "%r.%r->%r" % (remote_fn, receiver, slot) if self.key not in self.PROXY_FUNCTIONS: weak_fn = weakref.WeakMethod(remote_fn)
"""Load_script module.""" from pineboolib.core.utils import logging from .utils.path import _path from typing import Optional, Any from pineboolib.core.utils.struct import ActionStruct import shutil import os LOGGER = logging.getLogger("load_script") def load_script(scriptname: Optional[str], action_: ActionStruct) -> Any: # returns loaded script """ Transform QS script into Python and starts it up. @param scriptname. Nombre del script a convertir @param parent. Objecto al que carga el script, si no se especifica es a self.script """ from pineboolib import application project = application.PROJECT if scriptname: scriptname = scriptname.replace(".qs", "") LOGGER.debug("Loading script %s for action %s", scriptname, action_.name) else: LOGGER.info("No script to load for action %s", action_.name)
class ModuleActions(object): """ Generate tree with actions from modules. """ logger = logging.getLogger("application.ModuleActions") def __init__(self, module: Any, path: str, modulename: str) -> None: """ Constructor. @param module. Identificador del módulo @param path. Ruta del módulo @param modulename. Nombre del módulo """ if TYPE_CHECKING: # To avoid circular dependency on pytype self.project = module else: self.project = application.PROJECT self.mod = module # application.Module self.path = path self.module_name = modulename if not self.path: self.logger.error("El módulo no tiene un path válido %s", self.module_name) def load(self) -> None: """Load module actions into project.""" # Ojo: Almacena un arbol con los módulos cargados from pineboolib.application.qsadictmodules import QSADictModules tree = load2xml(self.path) self.root = tree.getroot() action = XMLAction(project=self.project, name=self.mod.name) if action is None: raise Exception("action is empty!") action.mod = self action.alias = self.mod.name # action.form = self.mod.name action.form = None action.table = None action.scriptform = self.mod.name self.project.actions[ action.name ] = action # FIXME: Actions should be loaded to their parent, not the singleton QSADictModules.save_action_for_root_module(action) for xmlaction in self.root: action_xml = XMLAction(xmlaction, project=self.project) action_xml.mod = self name = action_xml.name if not name or name == "unnamed": continue if QSADictModules.save_action_for_mainform(action_xml): self.project.actions[ name ] = action_xml # FIXME: Actions should be loaded to their parent, not the singleton QSADictModules.save_action_for_formrecord(action_xml) def __contains__(self, k) -> bool: """Determine if it is the owner of an action.""" return ( k in self.project.actions ) # FIXME: Actions should be loaded to their parent, not the singleton def __getitem__(self, name) -> Any: """ Retrieve particular action by name. @param name. Nombre de la action @return Retorna el XMLAction de la action dada """ return self.project.actions[ name ] # FIXME: Actions should be loaded to their parent, not the singleton def __setitem__(self, name, action_) -> NoReturn: """ Add action to a module property. @param name. Nombre de la action @param action_. Action a añadir a la propiedad del módulo """ raise ForbiddenError("Actions are not writable!")