def setValue(self, value): """ Verändert den Wert der Eigenschaft. """ if self.__value != value: self.__value = value Debug.debug("Ändere Eigenschaft {} zu {}".format(self.name, self.__value), level=3) self.valueChanged.emit(self.__value) self.traitChanged.emit(self)
def setValue(self, value): """ Verändert den Wert der Eigenschaft. """ if self.__value != value: self.__value = value Debug.debug("Ändere Eigenschaft {} zu {}".format( self.name, self.__value), level=3) self.valueChanged.emit(self.__value) self.traitChanged.emit(self)
def read(self): """ Diese Methode startet den Lesevorgang. Es wird kontrolliert, ob es sich um eine Zuässige Template-Datei für dieses Programm handelt \exception ErrXmlTooOldVersion Die XML-Datei hat die falsche Version. \exception ErrXmlOldVersion Die XML-Datei hat die falsche Version. \exception ErrXmlParsing Beim Parsen der XML-Datei ist ein Fehler aufgetreten. """ #dbgStart = Debug.timehook() for item in self.__templateFiles: Debug.debug("Reading from file \"{}\".".format(item), level=2) file_content = None with open(item, mode="rb") as fi: file_content = fi.read() ## Erzeuge eine temporäre Datei, mit der etree umgehen kann und schreibe den Inhalt aus der Qt-Resource in selbige hinein. file_like = tempfile.SpooledTemporaryFile() ## Dank dieser Einstellung kann ich zlib verwenden um Dateien zu dekomprimieren, welche mittels des gzip-Moduls komprimiert wurden. decompressed_object = zlib.decompressobj(16 + zlib.MAX_WBITS) file_like.write(decompressed_object.decompress(file_content)) file_like.seek(0) xml_content = etree.parse(file_like) file_like.close() xml_root_element = xml_content.getroot() version_source = xml_root_element.attrib["version"] required_source = False if "required" in xml_root_element.attrib: required_source = xml_root_element.attrib["required"].lower( ) == "true" #Debug.debug(versionSource) try: self.checkXmlVersion(xml_root_element.tag, version_source, item, required=required_source) except ErrXmlOldVersion as e: text_description = self.tr( "{} Loading of template will be continued but errors may occur." .format(str(e))) self.exception_raised.emit(text_description, "warning") result = self.readSpecies(xml_content) self.readTemplate(xml_content, result[0], result[1])
def checkXmlVersion(self, name, version, filename=None, required=False ): """ Überprüft die Version der XML-Datei. Damit ist die SoulCreator-Version gemeint. \param required Für den Betrieb des Programms erfordelriche Dateien sorgen dafür, daß das Programm einen entsprechend ernsten Fehler ausgibt. """ Debug.debug( "Version of file \"{name_file}\": {name} {version}".format( name_file=filename, name=name, version=version, ), level=3 ) if name == Config.PROGRAM_NAME: if version == Config.version(): return else: # Unterschiede in der Minor-Version sind ignorierbar, Unterschiede in der Major-Version allerdings nicht. version_split = version.split(".") version_split = [ int(item) for item in version_split ] if filename is not None: filename = os.path.basename(filename) if version_split[0] < Config.PROGRAM_VERSION["major"]: raise Error.ErrXmlVersion( "XML-file \"{filename}\" was created with {program_name} {file_version} and is incompatible with {program_name} {program_version}.\nLoading of file aborted.".format( filename=filename, file_version=version, program_name=Config.PROGRAM_NAME, program_version=Config.version() ), got=version, critical=required ) else: raise Error.ErrXmlOldVersion( "XML-file \"{filename}\" was created with {program_name} {file_version} and may be compatible with {program_name} {program_version}.".format( filename=filename, file_version=version, program_name=Config.PROGRAM_NAME, program_version=Config.version() ), got=version, critical=required ) else: raise Error.ErrXmlVersion( got="{} {}".format(name, version), expected="{} {}".format(Config.PROGRAM_NAME, Config.version()), critical=required )
def readCharacterIdentity(self, tree): """ Lese die Identitäten des Charkaters aus. \note Derzeit gibt es nur eine. forenames="" surname="" honorname="" nickname="" supername="" gender="Male" """ identity = tree.find("identities/identity") if identity is not None: self.__character.identity.forenames = self.getElementAttribute(identity, "forenames").split(" ") self.__character.identity.surname = self.getElementAttribute(identity, "surname") self.__character.identity.honorname = self.getElementAttribute(identity, "honorname") self.__character.identity.nickname = self.getElementAttribute(identity, "nickname") self.__character.identity.supername = self.getElementAttribute(identity, "supername") self.__character.identity.gender = self.getElementAttribute(identity, "gender") else: Debug.debug( "No identity of the character found.", level=3 )
def read(self): """ Diese Methode startet den Lesevorgang. Es wird kontrolliert, ob es sich um eine Zuässige Template-Datei für dieses Programm handelt \exception ErrXmlTooOldVersion Die XML-Datei hat die falsche Version. \exception ErrXmlOldVersion Die XML-Datei hat die falsche Version. \exception ErrXmlParsing Beim Parsen der XML-Datei ist ein Fehler aufgetreten. """ #dbgStart = Debug.timehook() for item in self.__templateFiles: Debug.debug( "Reading from file \"{}\".".format(item), level=2 ) file_content = None with open(item, mode="rb") as fi: file_content = fi.read() ## Erzeuge eine temporäre Datei, mit der etree umgehen kann und schreibe den Inhalt aus der Qt-Resource in selbige hinein. file_like = tempfile.SpooledTemporaryFile() ## Dank dieser Einstellung kann ich zlib verwenden um Dateien zu dekomprimieren, welche mittels des gzip-Moduls komprimiert wurden. decompressed_object = zlib.decompressobj(16 + zlib.MAX_WBITS) file_like.write(decompressed_object.decompress(file_content)) file_like.seek(0) xml_content = etree.parse(file_like) file_like.close() xml_root_element = xml_content.getroot() version_source = xml_root_element.attrib["version"] required_source = False if "required" in xml_root_element.attrib: required_source = xml_root_element.attrib["required"].lower() == "true" #Debug.debug(versionSource) try: self.checkXmlVersion( xml_root_element.tag, version_source, item, required=required_source ) except ErrXmlOldVersion as e: text_description = self.tr( "{} Loading of template will be continued but errors may occur.".format( str( e ) ) ) self.exception_raised.emit( text_description, "warning" ) result = self.readSpecies(xml_content) self.readTemplate(xml_content, result[0], result[1])
def read( self, file_name ): """ Startet den Lesevorgang. \note Diese Funktion kann sowohl normale xml-Dateien als auch mittels gzip komprimierte xml-Dateien laden. """ Debug.debug( "Loading Character out of {}.".format(file_name) ) ## Mittels lxml kann diese Funktion normale XML-Dateien und offenbar auch mittels gzip komprimierte XML-Dateien laden. ## Das normale ElementTree-Modul kann das aber nicht. xml_content = None try: xml_content = etree.parse(file_name) except etree.ParseError: ## Möglicherweise eine komprimierte Datei und lxml wurde nicht verwendet? xml_content = etree.parse(gzip.GzipFile(file_name)) xmlRootElement = xml_content.getroot() versionSource = xmlRootElement.attrib["version"] try: self.checkXmlVersion( xmlRootElement.tag, versionSource, file_name ) except ErrXmlOldVersion as e: text_description = self.tr( "{} Loading will be continued but errors may occur.".format( str( e ) ) ) self.exception_raised.emit( text_description, "warning" ) ## Die Daten müssen zuerst geladen werden, damit schon beim Laden die Unterschiedung zwischen Kindern und Erwachsenen erfolgen kann. self.readDates(xml_content) self.readCharacterInfo(xml_content) self.readCharacterIdentity(xml_content) self.readDerangements(xml_content) self.readTraits(xml_content) self.readItems(xml_content) self.readSpeciesSpecials(xml_content) self.readPicture(xml_content)
def _do_connect(trait, storage, character): """ Durchsucht alle existierenden Eigenschaften und kontrolliert, ob sie als Voraussetzung für <trait> in Frage kommen. """ trait_prerequisites = trait.prerequisitesText Debug.debug( "Voraussetzungen von {trait}: {prerequisite}".format(trait=trait.name, prerequisite=trait_prerequisites), level=4, ) stop_loop = False for prerequisite_typ in storage.traits.keys(): ## Angabe in den Ressourcen: <typ>.<trait>[.<specialty>] typ_resource = "{}.".format(prerequisite_typ) ## Ist eine Eigenschaft diesen Typs eine Voraussetzung der Eigenschaft? if typ_resource in trait_prerequisites: #Debug.debug("{trait} hat {typ} als Voraussetzung!".format(trait=trait.name, typ=item)) for prerequisite_category in storage.categories(prerequisite_typ): for prerequisite_trait in character.traits[prerequisite_typ][prerequisite_category].values(): ## Überprüfen ob die Eigenschaft im Anforderungstext des Merits vorkommt. trait_resource = "{}.{}".format(prerequisite_typ, prerequisite_trait.identifier) if trait_resource in trait_prerequisites: # Überprüfen ob diese Eigenschaft tatsächlich in den Voraussetzungen enthalten ist. Bei dieser Überprüfung ist es wichtig, auf den ganuen Namen zu prüfen: "Status" != "Status: Camarilla" # Diese Überprüfung wird aber nur durchgeführt, wenn die Chance besteht, daß dieser String identisch ist. match_list = re.findall(r"(\w+\.[\w]+[:\s]*[\w]+)(?=[\s]*[><=.]+)", trait_prerequisites, re.UNICODE) if trait_resource in match_list: stop_loop = _create_connection( trait, prerequisite_trait, trait_prerequisites, trait_resource ) if stop_loop: return if not stop_loop: ## Es kann auch die Supereigenschaft als Voraussetzung vorkommen ... if Config.POWERSTAT_IDENTIFIER in trait_prerequisites: character.powerstatChanged.connect(trait.checkPrerequisites) ## ... oder die Moral if Config.MORALITY_IDENTIFIER in trait_prerequisites: character.moralityChanged.connect(trait.checkPrerequisites)
def checkPrerequisites(trait, storage, character): if not isinstance(trait, BasicTrait): Debug.debug("Error!") else: if trait.hasPrerequisites and trait.prerequisiteTraits: ## Angabe in den Ressourcen: <typ>.<trait>[.<specialty>] >|<|== ? and|or ... ## Diese werden aufgeteilt in [[ <typ>, <trait>, <specialty> ] >|<|== ? and|or ... ] traitPrerequisites = trait.prerequisitesText #Debug.debug("{trait} hat Voraussetzungen? {truth}".format(trait=trait.name, truth=trait.hasPrerequisites)) for item in trait.prerequisiteTraits: # Überprüfen, ob die Eigenschaft im Anforderungstext des Merits vorkommt. literalReference = "ptr{}".format(id(item)) if literalReference in traitPrerequisites: ## Spezialisierungen literalReferencePlusSpecial = "{}.".format(literalReference) if literalReferencePlusSpecial in traitPrerequisites: idx = traitPrerequisites.index(literalReferencePlusSpecial) #traitWithSpecial = re.search(r"\w+\.{1}(\w+)", traitPrerequisites[idx:]) #special = traitWithSpecial.group(1) specialties = re.findall(r"\w+\.{1}(\w+)", traitPrerequisites[idx:]) for special in specialties: if special in item.specialties: traitPrerequisites = traitPrerequisites.replace(".{}".format(special), "") else: traitPrerequisites = traitPrerequisites.replace("{}.{}".format(literalReference, special), "0") traitPrerequisites = traitPrerequisites.replace(literalReference, str(item.value)) # Es kann auch die Supereigenschaft als Voraussetzung vorkommen ... if Config.POWERSTAT_IDENTIFIER in traitPrerequisites: traitPrerequisites = traitPrerequisites.replace(Config.POWERSTAT_IDENTIFIER, str(character.powerstat)) # ... oder die Moral if Config.MORALITY_IDENTIFIER in traitPrerequisites: traitPrerequisites = traitPrerequisites.replace(Config.MORALITY_IDENTIFIER, str(character.morality)) # Die Voraussetzungen sollten jetzt nurnoch aus Zahlen und logischen Operatoren bestehen. ## eval() is dangerous ## Aber ast.literal_eval() erlaubt nicht das Auswerten von "a < b" etc. ## Es werden ausschließlich Zahlen, Klammern "(" und ")" und die Zeichen "<" "<=" ">" ">=" "==" und "!=" sowie den logischen Verknüpfungen "and" und "or" erlaubt. #traitPrerequisites = "1 < 2 and 2 < 3" if re.match( r"^(\(*\d+\s*[<>=!]+\s*\d+\)*\s*(and|or)?\s*)+$", traitPrerequisites ): try: result = eval(traitPrerequisites) #Debug.debug("Eigenschaft {} ({} = {})".format(trait.name, traitPrerequisites, result)) except (NameError, SyntaxError): Debug.debug("Error bei {}: {}".format(trait.name, traitPrerequisites)) result = False else: raise ValueError("Only digits, spaces and the symbols \"<\", \">\", \"=\", \"!\", \"(\" and \")\" are allowed at this point.") Debug.debug( "Eigenschaft \"{}\" wird verfügbar? {}!".format(trait.name, result), level=4 ) trait.setAvailable(result)
def writeFile(self, tree, file_name): """ Schreibt den Elementbaum in eine Datei. Die Charaktere können als komprimierte Datei gespeichert werden, wenn dies in den Einstellungen so festgelegt wird. """ _character_data = None if lxmlLoadad: Debug.debug( "Using the advanced lxml-module to write the XML-tree." ) _character_data = etree.tostring(tree, pretty_print=True, encoding="UTF-8", xml_declaration=True) else: Debug.debug( "Using the basic xml.etree.ElementTree-module to write the XML-tree." ) _character_data = etree.tostring(tree, encoding="unicode") ## In die Datei schreiben. if Config.compress_saves: Debug.debug( "Writing character into {} (compressed).".format(file_name) ) with gzip.open(file_name, "w") as file_object: file_object.write(bytes(_character_data, "UTF-8")) else: Debug.debug( "Writing character into {} (uncompressed).".format(file_name) ) with open(file_name, "w") as file_object: file_object.write(_character_data)