<commit_before># Copyright (c) 2016 <NAME>.
# Uranium is released under the terms of the AGPLv3 or higher.

import configparser
import io
import copy

from UM.Signal import Signal, signalemitter
from UM.PluginObject import PluginObject
from UM.Logger import Logger
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType

import UM.Settings.ContainerRegistry

from . import ContainerInterface
from . import SettingInstance
from . import SettingRelation

class InvalidInstanceError(Exception):
    pass

class IncorrectInstanceVersionError(Exception):
    pass

class DefinitionNotFoundError(Exception):
    pass

MimeTypeDatabase.addMimeType(
    MimeType(
        name = "application/x-uranium-instancecontainer",
        comment = "Uranium Instance Container",
        suffixes = [ "inst.cfg" ]
    )
)

##  A container for SettingInstance objects.
#
#
@signalemitter
class InstanceContainer(ContainerInterface.ContainerInterface, PluginObject):
    Version = 2

    ##  Constructor
    #
    #   \param container_id A unique, machine readable/writable ID for this container.
    def __init__(self, container_id, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._id = str(container_id)
        self._name = container_id
        self._definition = None
        self._metadata = {}
        self._instances = {}
        self._read_only = False
        self._dirty = False

    ##  \copydoc ContainerInterface::getId
    #
    #   Reimplemented from ContainerInterface
    def getId(self):
        return self._id

    id = property(getId)

    ##  \copydoc ContainerInterface::getName
    #
    #   Reimplemented from ContainerInterface
    def getName(self):
        return self._name

    name = property(getName)

    nameChanged = Signal()

    def setName(self, name):
        if name != self._name:
            self._name = name
            self._dirty = True
            self.nameChanged.emit()

    ##  \copydoc ContainerInterface::isReadOnly
    #
    #   Reimplemented from ContainerInterface
    def isReadOnly(self):
        return self._read_only

    def setReadOnly(self, read_only):
        self._read_only = read_only

    ##  \copydoc ContainerInterface::getMetaData
    #
    #   Reimplemented from ContainerInterface
    def getMetaData(self):
        return self._metadata

    metaData = property(getMetaData)
    metaDataChanged = Signal()

    def setMetaData(self, metadata):
        if metadata != self._metadata:
            self._metadata = metadata
            self._dirty = True
            self.metaDataChanged.emit(self)

    ##  \copydoc ContainerInterface::getMetaDataEntry
    #
    #   Reimplemented from ContainerInterface
    def getMetaDataEntry(self, entry, default = None):
        return self._metadata.get(entry, default)

    ##  Add a new entry to the metadata of this container.
    #
    #   \param key \type{str} The key of the new entry.
    #   \param value The value of the new entry.
    #
    #   \note This does nothing if the key already exists.
    def addMetaDataEntry(self, key, value):
        if key not in self._metadata:
            self._metadata[key] = value
            self._dirty = True
            self.metaDataChanged.emit(self)
        else:
            Logger.log("w", "Meta data with key %s was already added.", key)

    ##  Set a metadata entry to a certain value.
    #
    #   \param key The key of the metadata entry to set.
    #   \param value The new value of the metadata.
    #
    #   \note This does nothing if the key is not already added to the metadata.
    def setMetaDataEntry(self, key, value):
        if key in self._metadata:
            self._metadata[key] = value
            self._dirty = True
            self.metaDataChanged.emit(self)
        else:
            Logger.log("w", "Meta data with key %s was not found. Unable to change.", key)

    ##  Check if this container is dirty, that is, if it changed from deserialization.
    def isDirty(self):
        return self._dirty

    ##  \copydoc ContainerInterface::getProperty
    #
    #   Reimplemented from ContainerInterface
    def getProperty(self, key, property_name):
        if key in self._instances:
            try:
                return getattr(self._instances[key], property_name)
            except AttributeError:
                pass

        return None

    ##  \copydoc ContainerInterface::hasProperty
    #
    #   Reimplemented from ContainerInterface.
    def hasProperty(self, key, property_name):
        return key in self._instances and hasattr(self._instances[key], property_name)

    ##  Set the value of a property of a SettingInstance.
    #
    #   This will set the value of the specified property on the SettingInstance corresponding to key.
    #   If no instance has been created for the specified key, a new one will be created and inserted
    #   into this instance.
    #
    #   \param key \type{string} The key of the setting to set a property of.
    #   \param property_name \type{string} The name of the property to set.
    #   \param property_value The new value of the property.
    #   \param container The container to use for retrieving values when changing the property triggers property updates. Defaults to None, which means use the current container.
    #
    #   \note If no definition container is set for this container, new instances cannot be created and this method will do nothing.
    def setProperty(self, key, property_name, property_value, container = None):
        if key not in self._instances:
            if not self._definition:
                Logger.log("w", "Tried to set value of setting %s that has no instance in container %s and unable to create a new instance (1)", key, repr(self))
                return

            setting_definition = self._definition.findDefinitions(key = key)
            if not setting_definition:
                Logger.log("w", "Tried to set value of setting %s that has no instance in container %s and unable to create a new instance (2)", key, repr(self))
                return

            instance = SettingInstance.SettingInstance(setting_definition[0], self)
            instance.propertyChanged.connect(self.propertyChanged)
            self._instances[instance.definition.key] = instance

        #Logger.log("d", "Set property '%s' of '%s' in '%s' to '%s'", property_name, key, self._id, property_value)
        self._instances[key].setProperty(property_name, property_value, container)

        self._dirty = True

    propertyChanged = Signal()

    ##  Remove all instances from this container.<commit_msg>Clarify log output and remove commented-out code<commit_after># Copyright (c) 2016 Ultimaker B.V.
# Uranium is released under the terms of the AGPLv3 or higher.

import configparser
import io
import copy

from UM.Signal import Signal, signalemitter
from UM.PluginObject import PluginObject
from UM.Logger import Logger
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType

import UM.Settings.ContainerRegistry

from . import ContainerInterface
from . import SettingInstance
from . import SettingRelation

class InvalidInstanceError(Exception):
    pass

class IncorrectInstanceVersionError(Exception):
    pass

class DefinitionNotFoundError(Exception):
    pass

MimeTypeDatabase.addMimeType(
    MimeType(
        name = "application/x-uranium-instancecontainer",
        comment = "Uranium Instance Container",
        suffixes = [ "inst.cfg" ]
    )
)

##  A container for SettingInstance objects.
#
#
@signalemitter
class InstanceContainer(ContainerInterface.ContainerInterface, PluginObject):
    Version = 2

    ##  Constructor
    #
    #   \param container_id A unique, machine readable/writable ID for this container.
    def __init__(self, container_id, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._id = str(container_id)
        self._name = container_id
        self._definition = None
        self._metadata = {}
        self._instances = {}
        self._read_only = False
        self._dirty = False

    ##  \copydoc ContainerInterface::getId
    #
    #   Reimplemented from ContainerInterface
    def getId(self):
        return self._id

    id = property(getId)

    ##  \copydoc ContainerInterface::getName
    #
    #   Reimplemented from ContainerInterface
    def getName(self):
        return self._name

    name = property(getName)

    nameChanged = Signal()

    def setName(self, name):
        if name != self._name:
            self._name = name
            self._dirty = True
            self.nameChanged.emit()

    ##  \copydoc ContainerInterface::isReadOnly
    #
    #   Reimplemented from ContainerInterface
    def isReadOnly(self):
        return self._read_only

    def setReadOnly(self, read_only):
        self._read_only = read_only

    ##  \copydoc ContainerInterface::getMetaData
    #
    #   Reimplemented from ContainerInterface
    def getMetaData(self):
        return self._metadata

    metaData = property(getMetaData)
    metaDataChanged = Signal()

    def setMetaData(self, metadata):
        if metadata != self._metadata:
            self._metadata = metadata
            self._dirty = True
            self.metaDataChanged.emit(self)

    ##  \copydoc ContainerInterface::getMetaDataEntry
    #
    #   Reimplemented from ContainerInterface
    def getMetaDataEntry(self, entry, default = None):
        return self._metadata.get(entry, default)

    ##  Add a new entry to the metadata of this container.
    #
    #   \param key \type{str} The key of the new entry.
    #   \param value The value of the new entry.
    #
    #   \note This does nothing if the key already exists.
    def addMetaDataEntry(self, key, value):
        if key not in self._metadata:
            self._metadata[key] = value
            self._dirty = True
            self.metaDataChanged.emit(self)
        else:
            Logger.log("w", "Meta data with key %s was already added.", key)

    ##  Set a metadata entry to a certain value.
    #
    #   \param key The key of the metadata entry to set.
    #   \param value The new value of the metadata.
    #
    #   \note This does nothing if the key is not already added to the metadata.
    def setMetaDataEntry(self, key, value):
        if key in self._metadata:
            self._metadata[key] = value
            self._dirty = True
            self.metaDataChanged.emit(self)
        else:
            Logger.log("w", "Meta data with key %s was not found. Unable to change.", key)

    ##  Check if this container is dirty, that is, if it changed from deserialization.
    def isDirty(self):
        return self._dirty

    ##  \copydoc ContainerInterface::getProperty
    #
    #   Reimplemented from ContainerInterface
    def getProperty(self, key, property_name):
        if key in self._instances:
            try:
                return getattr(self._instances[key], property_name)
            except AttributeError:
                pass

        return None

    ##  \copydoc ContainerInterface::hasProperty
    #
    #   Reimplemented from ContainerInterface.
    def hasProperty(self, key, property_name):
        return key in self._instances and hasattr(self._instances[key], property_name)

    ##  Set the value of a property of a SettingInstance.
    #
    #   This will set the value of the specified property on the SettingInstance corresponding to key.
    #   If no instance has been created for the specified key, a new one will be created and inserted
    #   into this instance.
    #
    #   \param key \type{string} The key of the setting to set a property of.
    #   \param property_name \type{string} The name of the property to set.
    #   \param property_value The new value of the property.
    #   \param container The container to use for retrieving values when changing the property triggers property updates. Defaults to None, which means use the current container.
    #
    #   \note If no definition container is set for this container, new instances cannot be created and this method will do nothing.
    def setProperty(self, key, property_name, property_value, container = None):
        if key not in self._instances:
            if not self._definition:
                Logger.log("w", "Tried to set value of setting %s that has no instance in container %s and the container has no definition", key, self._name)
                return

            setting_definition = self._definition.findDefinitions(key = key)
            if not setting_definition:
                Logger.log("w", "Tried to set value of setting %s that has no instance in container %s or its definition %s", key, self._name, self._definition.getName())
                return

            instance = SettingInstance.SettingInstance(setting_definition[0], self)
            instance.propertyChanged.connect(self.propertyChanged)
            self._instances[instance.definition.key] = instance

        self._instances[key].setProperty(property_name, property_value, container)

        self._dirty = True

    propertyChanged = Signal()

    ##  Remove all instances from this container.
{'fraction_non_alphanumeric': 0.0762383017575896, 'fraction_numerical': 0.0012173780719774785, 'mean_word_length': 2.5863574351978174, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, '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': '1187923', 'n_tokens_mistral': 3502, 'n_tokens_neox': 3418, 'n_words': 1205}