<commit_before>from __future__ import absolute_import, division, print_function
#import __builtin__
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
from . import qtype
from .guitool_decorators import checks_qt_error, signal_
from .api_thumb_delegate import APIThumbDelegate
from itertools import izip
import functools
import utool
(print, print_, printDBG, rrr, profile) = utool.inject(
    __name__, '[APITableModel]', DEBUG=False)

#API_MODEL_BASE = QtCore.QAbstractTableModel
API_MODEL_BASE = QtCore.QAbstractItemModel


class ChangeLayoutContext(object):
    """
    Context manager emitting layoutChanged before body,
    not updating durring body, and then updating after body.
    """
    @utool.accepts_scalar_input
    def __init__(self, model_list, *args):
        #print('Changing: %r' % (model_list,))
        self.model_list = list(model_list) + list(args)

    def __enter__(self):
        for model in self.model_list:
            if model._context_id is not None:
                continue
            model._context_id = id(self)
            model._about_to_change()
            model._changeblocked = True
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        for model in self.model_list:
            if model._context_id == id(self):
                model._context_id = None
                model._changeblocked = False
                model._change()


def default_method_decorator(func):
    """ Dummy decorator """
    return checks_qt_error(profile(func))
    #func_name = func.func_name
    ##func_ = checks_qt_error(profile(func))
    #func_ = func
    #@functools.wraps(func)
    #def wrapper(*args, **kwargs):
    #    __builtin__.print('func_name = ' + func_name)
    #    return func_(*args, **kwargs)
    #return wrapper


def updater(func):
    """
    Decorates a function by executing layoutChanged signals if not already in
    the middle of a layout changed
    """
    func = default_method_decorator(func)
    #@checks_qt_error
    @functools.wraps(func)
    def upd_wrapper(model, *args, **kwargs):
        with ChangeLayoutContext([model]):
            return func(model, *args, **kwargs)
    return upd_wrapper


class APITableModel(API_MODEL_BASE):
    """ Item model for displaying a list of columns """
    _rows_updated = signal_(str, int)
    EditableItemColor = QtGui.QColor(220, 220, 255)
    TrueItemColor     = QtGui.QColor(230, 250, 230)
    FalseItemColor    = QtGui.QColor(250, 230, 230)

    #
    # Non-Qt Init Functions
    def __init__(model, headers=None, parent=None):
        """
        ider          : function which returns ids for setters and getters
        col_name_list : list of keys or SQL-like name for column to reference
                        abstracted data storage using getters and setters
        col_type_list : list of column value (Python) types
        col_nice_list : list of well-formatted names of the columns
        col_edit_list : list of booleans for if column should be editable
        ----
        col_setter_list : list of setter functions
        col_getter_list : list of getter functions
        ----
        col_sort_index : index into col_name_list for sorting
        col_sort_reverse : boolean of if to reverse the sort ordering
        ----
        """
        model.view = parent
        API_MODEL_BASE.__init__(model, parent=parent)
        # Internal Flags
        model._abouttochange   = False
        model._context_id      = None
        model._haschanged      = True
        model._changeblocked   = False
        # Model Data And Accessors
        model.name             = 'None'
        model.nice             = 'None'
        model.ider             = lambda: []
        model.col_name_list    = []
        model.col_type_list    = []
        model.col_nice_list    = []
        model.col_edit_list    = []
        model.col_setter_list  = []
        model.col_getter_list  = []
        model.col_sort_index   = None
        model.col_sort_reverse = False
        model.row_index_list = []
        model.cache = None  # FIXME: This is not sustainable
        # Initialize member variables
        #model._about_to_change()
        if headers is not None:
            model._update_headers(**headers)

    @default_method_decorator
    def _about_to_change(model, force=False):
        N = range(0, 10)  # NOQA
        if force or (not model._abouttochange and not model._changeblocked):
            #printDBG('ABOUT TO CHANGE: %r' % (model.name,))
            #printDBG('caller=%r' % (utool.get_caller_name(N=N)))
            model._abouttochange = True
            model.layoutAboutToBeChanged.emit()
            return True
        else:
            #printDBG('NOT ABOUT TO CHANGE')
            return False

    @default_method_decorator
    def _change(model, force=False):
        N = range(0, 10)  # NOQA
        if force or (model._abouttochange and not model._changeblocked):
            #printDBG('LAYOUT CHANGED:  %r' % (model.name,))
            #printDBG('caller=%r' % (utool.get_caller_name(N=N)))
            #model._abouttochange = False
            model._abouttochange = False
            printDBG('CHANGE: CACHE INVALIDATED!')
            model.cache = {}
            model.layoutChanged.emit()
            return True
        else:
            #printDBG('NOT CHANGING')
            #print('NOT LAYOU CHANGED: %r, caller=%r' % (model.name, utool.get_caller_name(N=N)))
            return False

    @updater
    def _update_headers(model,
                        ider=None,
                        name=None,
                        nice=None,
                        col_name_list=None,
                        col_type_list=None,
                        col_nice_list=None,
                        col_edit_list=None,
                        col_setter_list=None,
                        col_getter_list=None,
                        col_sort_index=None,
                        col_sort_reverse=False):
        model.cache = {}  # FIXME: This is not sustainable
        model.name = str(name)
        model.nice = str(nice)
        # Initialize class
        model._set_ider(ider)
        model._set_col_name_type(col_name_list, col_type_list)
        model._set_col_nice(col_nice_list)
        model._set_col_edit(col_edit_list)
        model._set_col_setter(col_setter_list)
        model._set_col_getter(col_getter_list)
        # calls model._update_rows()
        model._set_sort(col_sort_index, col_sort_reverse)

    @default_method_decorator
    def _update(model, newrows=False):
        #if newrows:
        model._update_rows()
        printDBG('UPDATE: CACHE INVALIDATED!')
        model.cache = {}

    @updater
    def _update_rows(model):
        """
        Uses the current ider and col_sort_index to create
        row_indicies
        """
        #printDBG('UPDATE ROWS!')
        print('UPDATE model(%s) rows' % model.name)
        ids_ = model.ider()
        if len(ids_) == 0:
            model.row_index_list = []
        else:
            # start sort
            if model.col_sort_index is None:
                values = ids_
            else:
                getter = model.col_getter_list[model.col_sort_index]
                values = getter(ids_)
            reverse = model.col_sort_reverse
            sorted_pairs = sorted(izip(values, ids_), reverse=reverse)
            row_indices = [id_ for (value, id_) in sorted_pairs]
            # end sort
            assert row_indices is not None, 'no indices'
            model.row_index_list = row_indices
        model._rows_updated.emit(model.name, len(model.row_index_list))

    @updater
    def _set_ider(model, ider=None):
        #printDBG('NEW IDER')
        if ider is None:
            ider = lambda: []
        assert utool.is_funclike(ider), 'bad type: %r' % type(ider)
        model.ider = ider

    @updater
    def _set_col_name_type(model, col_name_list=None, col_type_list=None):
        if col_name_list is None:
            col_name_list = []
        if col_type_list is None:
            col_type_list = []
        assert len(col_name_list) == len(col_type_list), \
            'inconsistent colnametype'
        model.col_name_list = col_name_list
        model.col_type_list = col_type_list
        # Check if any of the column types are specified as delegates
        for colx in xrange(len(model.col_type_list)):
            coltype_ = col_type_list[colx]
            if coltype_ == 'PIXMAP':
                model.view.setItemDelegateForColumn(colx, APIThumbDelegate(model.view))
            
    @updater
    def _set_col_nice(model, col_nice_list=None):
        if col_nice_list is None:
            col_nice_list = model.col_name_list[:]
        assert len(model.col_name_list) == len(col_nice_list), \
            'inconsistent colnice'
        model.col_nice_list = col_nice_list

    @default_method_decorator
    def _set_col_edit(model, col_edit_list=None):
        if col_edit_list is None:
            col_edit_list = [False] * len(model.col_name_list)
        assert len(model.col_name_list) == len(col_edit_list), \
            'inconsistent coledit'
        model.col_edit_list = col_edit_list

    @default_method_decorator
    def _set_col_setter(model, col_setter_list=None):
        if col_setter_list is None:
            col_setter_list = []<commit_msg>Adding try catch for PIXMAP<commit_after>from __future__ import absolute_import, division, print_function
#import __builtin__
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
from . import qtype
from .guitool_decorators import checks_qt_error, signal_
from .api_thumb_delegate import APIThumbDelegate
from itertools import izip
import functools
import utool
(print, print_, printDBG, rrr, profile) = utool.inject(
    __name__, '[APITableModel]', DEBUG=False)

#API_MODEL_BASE = QtCore.QAbstractTableModel
API_MODEL_BASE = QtCore.QAbstractItemModel


class ChangeLayoutContext(object):
    """
    Context manager emitting layoutChanged before body,
    not updating durring body, and then updating after body.
    """
    @utool.accepts_scalar_input
    def __init__(self, model_list, *args):
        #print('Changing: %r' % (model_list,))
        self.model_list = list(model_list) + list(args)

    def __enter__(self):
        for model in self.model_list:
            if model._context_id is not None:
                continue
            model._context_id = id(self)
            model._about_to_change()
            model._changeblocked = True
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        for model in self.model_list:
            if model._context_id == id(self):
                model._context_id = None
                model._changeblocked = False
                model._change()


def default_method_decorator(func):
    """ Dummy decorator """
    return checks_qt_error(profile(func))
    #func_name = func.func_name
    ##func_ = checks_qt_error(profile(func))
    #func_ = func
    #@functools.wraps(func)
    #def wrapper(*args, **kwargs):
    #    __builtin__.print('func_name = ' + func_name)
    #    return func_(*args, **kwargs)
    #return wrapper


def updater(func):
    """
    Decorates a function by executing layoutChanged signals if not already in
    the middle of a layout changed
    """
    func = default_method_decorator(func)
    #@checks_qt_error
    @functools.wraps(func)
    def upd_wrapper(model, *args, **kwargs):
        with ChangeLayoutContext([model]):
            return func(model, *args, **kwargs)
    return upd_wrapper


class APITableModel(API_MODEL_BASE):
    """ Item model for displaying a list of columns """
    _rows_updated = signal_(str, int)
    EditableItemColor = QtGui.QColor(220, 220, 255)
    TrueItemColor     = QtGui.QColor(230, 250, 230)
    FalseItemColor    = QtGui.QColor(250, 230, 230)

    #
    # Non-Qt Init Functions
    def __init__(model, headers=None, parent=None):
        """
        ider          : function which returns ids for setters and getters
        col_name_list : list of keys or SQL-like name for column to reference
                        abstracted data storage using getters and setters
        col_type_list : list of column value (Python) types
        col_nice_list : list of well-formatted names of the columns
        col_edit_list : list of booleans for if column should be editable
        ----
        col_setter_list : list of setter functions
        col_getter_list : list of getter functions
        ----
        col_sort_index : index into col_name_list for sorting
        col_sort_reverse : boolean of if to reverse the sort ordering
        ----
        """
        model.view = parent
        API_MODEL_BASE.__init__(model, parent=parent)
        # Internal Flags
        model._abouttochange   = False
        model._context_id      = None
        model._haschanged      = True
        model._changeblocked   = False
        # Model Data And Accessors
        model.name             = 'None'
        model.nice             = 'None'
        model.ider             = lambda: []
        model.col_name_list    = []
        model.col_type_list    = []
        model.col_nice_list    = []
        model.col_edit_list    = []
        model.col_setter_list  = []
        model.col_getter_list  = []
        model.col_sort_index   = None
        model.col_sort_reverse = False
        model.row_index_list = []
        model.cache = None  # FIXME: This is not sustainable
        # Initialize member variables
        #model._about_to_change()
        if headers is not None:
            model._update_headers(**headers)

    @default_method_decorator
    def _about_to_change(model, force=False):
        N = range(0, 10)  # NOQA
        if force or (not model._abouttochange and not model._changeblocked):
            #printDBG('ABOUT TO CHANGE: %r' % (model.name,))
            #printDBG('caller=%r' % (utool.get_caller_name(N=N)))
            model._abouttochange = True
            model.layoutAboutToBeChanged.emit()
            return True
        else:
            #printDBG('NOT ABOUT TO CHANGE')
            return False

    @default_method_decorator
    def _change(model, force=False):
        N = range(0, 10)  # NOQA
        if force or (model._abouttochange and not model._changeblocked):
            #printDBG('LAYOUT CHANGED:  %r' % (model.name,))
            #printDBG('caller=%r' % (utool.get_caller_name(N=N)))
            #model._abouttochange = False
            model._abouttochange = False
            printDBG('CHANGE: CACHE INVALIDATED!')
            model.cache = {}
            model.layoutChanged.emit()
            return True
        else:
            #printDBG('NOT CHANGING')
            #print('NOT LAYOU CHANGED: %r, caller=%r' % (model.name, utool.get_caller_name(N=N)))
            return False

    @updater
    def _update_headers(model,
                        ider=None,
                        name=None,
                        nice=None,
                        col_name_list=None,
                        col_type_list=None,
                        col_nice_list=None,
                        col_edit_list=None,
                        col_setter_list=None,
                        col_getter_list=None,
                        col_sort_index=None,
                        col_sort_reverse=False):
        model.cache = {}  # FIXME: This is not sustainable
        model.name = str(name)
        model.nice = str(nice)
        # Initialize class
        model._set_ider(ider)
        model._set_col_name_type(col_name_list, col_type_list)
        model._set_col_nice(col_nice_list)
        model._set_col_edit(col_edit_list)
        model._set_col_setter(col_setter_list)
        model._set_col_getter(col_getter_list)
        # calls model._update_rows()
        model._set_sort(col_sort_index, col_sort_reverse)

    @default_method_decorator
    def _update(model, newrows=False):
        #if newrows:
        model._update_rows()
        printDBG('UPDATE: CACHE INVALIDATED!')
        model.cache = {}

    @updater
    def _update_rows(model):
        """
        Uses the current ider and col_sort_index to create
        row_indicies
        """
        #printDBG('UPDATE ROWS!')
        print('UPDATE model(%s) rows' % model.name)
        ids_ = model.ider()
        if len(ids_) == 0:
            model.row_index_list = []
        else:
            # start sort
            if model.col_sort_index is None:
                values = ids_
            else:
                getter = model.col_getter_list[model.col_sort_index]
                values = getter(ids_)
            reverse = model.col_sort_reverse
            sorted_pairs = sorted(izip(values, ids_), reverse=reverse)
            row_indices = [id_ for (value, id_) in sorted_pairs]
            # end sort
            assert row_indices is not None, 'no indices'
            model.row_index_list = row_indices
        model._rows_updated.emit(model.name, len(model.row_index_list))

    @updater
    def _set_ider(model, ider=None):
        #printDBG('NEW IDER')
        if ider is None:
            ider = lambda: []
        assert utool.is_funclike(ider), 'bad type: %r' % type(ider)
        model.ider = ider

    @updater
    def _set_col_name_type(model, col_name_list=None, col_type_list=None):
        if col_name_list is None:
            col_name_list = []
        if col_type_list is None:
            col_type_list = []
        assert len(col_name_list) == len(col_type_list), \
            'inconsistent colnametype'
        model.col_name_list = col_name_list
        model.col_type_list = col_type_list
        # Check if any of the column types are specified as delegates
        for colx in xrange(len(model.col_type_list)):
            coltype_ = col_type_list[colx]
            if coltype_ == 'PIXMAP':
                try:
                    model.view.setItemDelegateForColumn(colx, APIThumbDelegate(model.view))
                except:
                    print("IGNORING")
            
    @updater
    def _set_col_nice(model, col_nice_list=None):
        if col_nice_list is None:
            col_nice_list = model.col_name_list[:]
        assert len(model.col_name_list) == len(col_nice_list), \
            'inconsistent colnice'
        model.col_nice_list = col_nice_list

    @default_method_decorator
    def _set_col_edit(model, col_edit_list=None):
        if col_edit_list is None:
            col_edit_list = [False] * len(model.col_name_list)
        assert len(model.col_name_list) == len(col_edit_list), \
            'inconsistent coledit'
        model.col_edit_list = col_edit_list

    @default_method_decorator
    def _set_col_setter(model, col_setter_list=None):
        if col_setter_list is None:
            col_setter_list = []
{'fraction_non_alphanumeric': 0.08606840789403691, 'fraction_numerical': 0.0038299909569657962, 'mean_word_length': 2.1302031302031303, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4522710', 'n_tokens_mistral': 5737, 'n_tokens_neox': 5582, 'n_words': 1275}