<commit_before>import logging
import time
import os

# will change these to specific imports once code is more final
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import uic

BRUSH_WHITE = QBrush(QColor(255, 255, 255), Qt.SolidPattern)
BRUSH_GREEN = QBrush(QColor(0, 255, 0), Qt.SolidPattern)
BRUSH_BLACK = QBrush(QColor(0, 0, 0), Qt.SolidPattern)
BRUSH_DARK_PURPLE = QBrush(QColor(128, 0, 255), Qt.SolidPattern)


class DeviceNode:

    __slots__ = ["_callback", "_name", "_data", "_type", "_brush", "q_name", "q_state", "sub_properties",
                 "sub_properties_appended", "q_time_added"]

    def __init__(self):
        self._callback = None
        self._name = ""
        self._data = {}
        self._type = ""
        self._brush = BRUSH_BLACK

        self.q_name = QStandardItem()
        self.q_state = QStandardItem()
        self.sub_properties = {}
        self.sub_properties_appended = False

        self.q_time_added = QStandardItem()
        self.q_time_added.setData(time.perf_counter(), Qt.DisplayRole)

        self.q_name.setDragEnabled(True)
        self.q_state.setData("", Qt.DisplayRole)

    def setName(self, name):
        self._name = name
        self.q_name.setData(str(self._name), Qt.DisplayRole)
        self.q_state.emitDataChanged()

    def setData(self, data):
        """Set data of device."""
        if data == self._data:
            # do nothing if data did not change
            return

        if not isinstance(data, dict):
            data = {}

        if self._callback:
            self._callback()

        self._data = data

        state_str = str(list(self._data.values())[0])
        if len(self._data) > 1:
            state_str = state_str + " {…}"
        self.q_state.setData(state_str, Qt.DisplayRole)

        for row in self._data:
            if not self.sub_properties_appended:
                q_property = QStandardItem()
                q_value = QStandardItem()
                self.sub_properties.update({row: [q_property, q_value]})
                self.q_name.appendRow(self.sub_properties.get(row))

            self.sub_properties.get(row)[0].setData(str(row), Qt.DisplayRole)
            self.sub_properties.get(row)[1].setData(str(self._data.get(row)), Qt.DisplayRole)

        self.sub_properties_appended = True
        self.q_state.emitDataChanged()
        self._brush = self._calculate_colored_brush()

    def setType(self, type):
        self._type = type
        self._brush = self._calculate_colored_brush()
        self.q_state.emitDataChanged()

    def get_row(self):
        return [self.q_name, self.q_state, self.q_time_added]

    def data(self):
        return self._data

    def type(self):
        return self._type

    def get_colored_brush(self) -> QBrush:
        """Return colored brush for device."""
        return self._brush

    @staticmethod
    def _calculate_color_gamma_correction(color):
        """Perform gamma correction.

        Feel free to fiddle with these constants until it feels right
        With gamma = 0.5 and constant a = 18, the top 54 values are lost,
        but the bottom 25% feels much more normal.
        """
        gamma = 0.5
        a = 18
        corrected = []

        for value in color:
            value = int(pow(value, gamma) * a)
            if value > 255:
                value = 255
            corrected.append(value)

        return corrected

    def _calculate_colored_brush(self):
        if self._type == 'light':
            color = self.data()['color']
            if color == [0, 0, 0]:
                # shortcut for black
                return BRUSH_BLACK
            color = self._calculate_color_gamma_correction(color)
<commit_msg>prevent imaginary numbers on gamma scaling<commit_after>import logging
import time
import os

# will change these to specific imports once code is more final
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import uic

BRUSH_WHITE = QBrush(QColor(255, 255, 255), Qt.SolidPattern)
BRUSH_GREEN = QBrush(QColor(0, 255, 0), Qt.SolidPattern)
BRUSH_BLACK = QBrush(QColor(0, 0, 0), Qt.SolidPattern)
BRUSH_DARK_PURPLE = QBrush(QColor(128, 0, 255), Qt.SolidPattern)


class DeviceNode:

    __slots__ = ["_callback", "_name", "_data", "_type", "_brush", "q_name", "q_state", "sub_properties",
                 "sub_properties_appended", "q_time_added", "log"]

    def __init__(self):
        self._callback = None
        self._name = ""
        self._data = {}
        self._type = ""
        self._brush = BRUSH_BLACK

        self.q_name = QStandardItem()
        self.q_state = QStandardItem()
        self.sub_properties = {}
        self.sub_properties_appended = False

        self.q_time_added = QStandardItem()
        self.q_time_added.setData(time.perf_counter(), Qt.DisplayRole)

        self.q_name.setDragEnabled(True)
        self.q_state.setData("", Qt.DisplayRole)

        self.log = logging.getLogger('Device')

    def setName(self, name):
        self._name = name
        self.q_name.setData(str(self._name), Qt.DisplayRole)
        self.log = logging.getLogger('Device {}'.format(self._name))
        self.q_state.emitDataChanged()

    def setData(self, data):
        """Set data of device."""
        if data == self._data:
            # do nothing if data did not change
            return

        if not isinstance(data, dict):
            data = {}

        if self._callback:
            self._callback()

        self._data = data

        state_str = str(list(self._data.values())[0])
        if len(self._data) > 1:
            state_str = state_str + " {…}"
        self.q_state.setData(state_str, Qt.DisplayRole)

        for row in self._data:
            if not self.sub_properties_appended:
                q_property = QStandardItem()
                q_value = QStandardItem()
                self.sub_properties.update({row: [q_property, q_value]})
                self.q_name.appendRow(self.sub_properties.get(row))

            self.sub_properties.get(row)[0].setData(str(row), Qt.DisplayRole)
            self.sub_properties.get(row)[1].setData(str(self._data.get(row)), Qt.DisplayRole)

        self.sub_properties_appended = True
        self.q_state.emitDataChanged()
        self._brush = self._calculate_colored_brush()

    def setType(self, type):
        self._type = type
        self._brush = self._calculate_colored_brush()
        self.q_state.emitDataChanged()

    def get_row(self):
        return [self.q_name, self.q_state, self.q_time_added]

    def data(self):
        return self._data

    def type(self):
        return self._type

    def get_colored_brush(self) -> QBrush:
        """Return colored brush for device."""
        return self._brush

    def _calculate_color_gamma_correction(self, color):
        """Perform gamma correction.

        Feel free to fiddle with these constants until it feels right
        With gamma = 0.5 and constant a = 18, the top 54 values are lost,
        but the bottom 25% feels much more normal.
        """
        gamma = 0.5
        a = 18
        corrected = []

        for value in color:
            if value < 0 or value > 255:
                self.log.warning("Got value %s for brightness which outside the expected range", value)
                value = 0

            value = int(pow(value, gamma) * a)
            if value > 255:
                value = 255
            corrected.append(value)

        return corrected

    def _calculate_colored_brush(self):
        if self._type == 'light':
            color = self.data()['color']
            if color == [0, 0, 0]:
                # shortcut for black
                return BRUSH_BLACK
            color = self._calculate_color_gamma_correction(color)

{'fraction_non_alphanumeric': 0.10594249201277955, 'fraction_numerical': 0.014185303514376997, 'mean_word_length': 2.23121387283237, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 10, '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': '6509002', 'n_tokens_mistral': 2517, 'n_tokens_neox': 2314, 'n_words': 562}