Пример #1
0
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("/")))
Пример #2
0
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
Пример #3
0
# -*- 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":
Пример #4
0
# -*- 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
Пример #5
0
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():
Пример #6
0
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:
Пример #7
0
"""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.
Пример #8
0
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
Пример #9
0
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
Пример #10
0
"""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_.
Пример #11
0
"""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
Пример #12
0
"""
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
Пример #13
0
"""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
Пример #14
0
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)
Пример #15
0
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")
Пример #16
0
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)
Пример #17
0
"""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)
Пример #18
0
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!")