You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2022/11/14 23:33:38 UTC

[plc4x] branch plc4py-codegen updated: feat(plc4py/codegen): Started to fill out the complex type template.

This is an automated email from the ASF dual-hosted git repository.

hutcheb pushed a commit to branch plc4py-codegen
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/plc4py-codegen by this push:
     new ab3ecf0e27 feat(plc4py/codegen): Started to fill out the complex type template.
ab3ecf0e27 is described below

commit ab3ecf0e279098f21deebaa5cbb9518acdbd7d0d
Author: Ben Hutcheson <be...@gmail.com>
AuthorDate: Mon Nov 14 17:32:50 2022 -0600

    feat(plc4py/codegen): Started to fill out the complex type template.
---
 .../language/python/PythonLanguageOutput.java      |   2 +-
 .../python/PythonLanguageTemplateHelper.java       |   5 +-
 .../python/complex-type-template.python.ftlh       | 650 ++++++++++-----------
 .../templates/python/data-io-template.python.ftlh  |  38 +-
 .../templates/python/enum-template.python.ftlh     |  38 +-
 .../plc4py/drivers/modbus/ModbusConfiguration.py   |   3 +-
 sandbox/plc4py/pom.xml                             |  17 +
 sandbox/plc4py/setup.py                            |   1 +
 .../plc4py/spi/configuration/test_configuration.py |  20 +-
 sandbox/plc4py/tests/unit/plc4py/spi/tcp/server.py |   6 +-
 10 files changed, 382 insertions(+), 398 deletions(-)

diff --git a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageOutput.java b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageOutput.java
index bb48c9023a..6a0019524b 100644
--- a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageOutput.java
+++ b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageOutput.java
@@ -42,7 +42,7 @@ public class PythonLanguageOutput extends FreemarkerLanguageOutput {
 
     @Override
     public String getName() {
-        return "python";
+        return "Python";
     }
 
     @Override
diff --git a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
index b5ec041b41..5dc77675eb 100644
--- a/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
+++ b/code-generation/language-python/src/main/java/org/apache/plc4x/language/python/PythonLanguageTemplateHelper.java
@@ -55,11 +55,14 @@ public class PythonLanguageTemplateHelper extends BaseFreemarkerLanguageTemplate
 
     public String packageName(String protocolName, String languageName, String languageFlavorName) {
         return Optional.ofNullable(options.get("package")).orElseGet(() ->
-            "org.apache.plc4x." + String.join("", languageName.split("-")) + "." +
                 String.join("", protocolName.split("-")) + "." +
                 String.join("", languageFlavorName.split("-")));
     }
 
+    public String packageName(String languageFlavorName) {
+        return String.join("", languageFlavorName.split("\\-"));
+    }
+
     @Override
     public String getLanguageTypeNameForField(Field field) {
         // If the referenced type is a DataIo type, the value is of type PlcValue.
diff --git a/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh b/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
index c712b97723..d56a8d5ed3 100644
--- a/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
+++ b/code-generation/language-python/src/main/resources/templates/python/complex-type-template.python.ftlh
@@ -4,7 +4,7 @@
   distributed with this work for additional information
   regarding copyright ownership.  The ASF licenses this file
   to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
+  "License") you may not use this file except in compliance
   with the License.  You may obtain a copy of the License at
 
       https://www.apache.org/licenses/LICENSE-2.0
@@ -26,49 +26,63 @@
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
 <#-- Declare the name and type of variables declared locally inside the template -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.java
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package ${helper.packageName(protocolName, languageName, outputFlavor)};
-
-import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
-import static org.apache.plc4x.java.spi.codegen.io.DataReaderFactory.*;
-import static org.apache.plc4x.java.spi.codegen.io.DataWriterFactory.*;
-import static org.apache.plc4x.java.spi.codegen.fields.FieldReaderFactory.*;
-import static org.apache.plc4x.java.spi.codegen.fields.FieldWriterFactory.*;
-
-import org.apache.plc4x.java.spi.codegen.*;
-import org.apache.plc4x.java.spi.codegen.io.*;
-import org.apache.plc4x.java.spi.codegen.fields.*;
-import org.apache.plc4x.java.api.exceptions.*;
-import org.apache.plc4x.java.spi.generation.*;
-import org.apache.plc4x.java.api.value.*;
-
-import java.time.*;
-import java.util.*;
-import java.math.BigInteger;
-
-// Code generated by code-generation. DO NOT EDIT.
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.py
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License") you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   https:#www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Code generated by code-generation. DO NOT EDIT.
+
+from dataclasses import dataclass
 
 <#-- TODO: the code below implies that parserArguments will be null if not present... not pretty  -->
 <#if type.parserArguments.isPresent()><#assign parserArguments=type.allParserArguments.orElseThrow()></#if>
-public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${type.name}<#if type.isDiscriminatedParentTypeDefinition()></#if><#if type.parentType.isPresent()> extends ${type.parentType.orElseThrow().name}</#if> implements Message {
+<#if type.isDiscriminatedParentTypeDefinition()>@abc.abstractmethod</#if>
+@dataclass
+class ${type.name}<#if type.isDiscriminatedParentTypeDefinition()></#if>(PlcMessage<#if type.parentType.isPresent()>,${type.parentType.orElseThrow().name}</#if>):
+    <#if parserArguments?has_content>
+        <#assign filteredParserArguments=parserArguments?filter(arg -> !type.isDiscriminatorField(arg.name) && !type.getPropertyFieldFromThisOrParentByName(arg.name).isPresent())>
+    </#if>
+    <#-- Property fields are fields that require a property in the pojo -->
+    <#if type.propertyFields?has_content>
+        <#list type.propertyFields as field>
+            ${field.name}: ${helper.getLanguageTypeNameForTypeReference(field.type, !field.isOptionalField())}
+        </#list>
+    </#if>
+    <#if filteredParserArguments?has_content>
+        # Arguments.
+        <#list filteredParserArguments as parserArgument>
+            ${parserArgument.name}: ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)}
+        </#list>
+    </#if>
+    <#assign reservedFields=type.getFields()?filter(f->f.isReservedField())>
+    <#if reservedFields?has_content>
+        # Reserved Fields
+        <#list reservedFields as reservedField>
+            reservedField${reservedField?index}: ${helper.getLanguageTypeNameForTypeReference(reservedField.asReservedField().orElseThrow().type, false)}
+        </#list>
+    </#if>
+    <#-- If the current type contains "const" fields, generate some Python constants for holing their values -->
+    <#if type.constFields?has_content>
+        <#list type.constFields as field>
+            ${field.name?upper_case}: ${helper.getLanguageTypeNameForTypeReference(field.type)} = ${helper.toParseExpression(field, field.type, field.referenceValue, parserArguments)}
+        </#list>
+    </#if>
 
 <#--
     If this is a discriminated child type, we need to generate methods for accessing it's discriminator
@@ -76,172 +90,119 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
 -->
 <#if type.isDiscriminatedChildTypeDefinition()>
     <#assign discriminatedChildType = type.asDiscriminatedComplexTypeDefinition().orElseThrow()>
-    // Accessors for discriminator values.
+    # Accessors for discriminator values.
     <#list discriminatedChildType.getDiscriminatorMap() as discriminatorName, discriminatorValue>
         <#-- If the discriminator name matches that of another field, suppress the methods generation -->
         <#if !discriminatedChildType.isNonDiscriminatorField(discriminatorName)><#--&& !discriminatedChildType.isParserArgument(discriminatorName)-->
             <#assign discriminatorType = helper.getDiscriminatorTypes()[discriminatorName]>
-    public ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} get${discriminatorName?cap_first}() {
+    def ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} get${discriminatorName?cap_first}() {
             <#if discriminatorValue?? && !helper.isWildcard(discriminatorValue)>
                 <#if discriminatorType.isEnumTypeReference()>
-        return ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)};
+        return ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}.${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)}
                 <#else>
-        return (${helper.getLanguageTypeNameForTypeReference(discriminatorType, true)}) ${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)};
+        return (${helper.getLanguageTypeNameForTypeReference(discriminatorType, true)}) ${helper.toParseExpression(null, discriminatorType, discriminatorValue, parserArguments)}
                 </#if>
             <#else>
-        return ${helper.getNullValueForTypeReference(discriminatorType)};
+        return ${helper.getNullValueForTypeReference(discriminatorType)}
             </#if>
     }
         </#if>
     </#list>
 </#if>
+
+
+    <#-- getAllPropertyFields() returns not only the property fields of this type but also of it's parents -->
+    def __post_init__():
+        <@compress single_line=true>
+            super.__init__(
+            <#if type.parentPropertyFields?has_content>
+                <#list type.parentPropertyFields as field>
+                    self.${field.name}
+                    <#sep>, </#sep>
+                </#list>
+            </#if>
+            <#if type.parentType.isPresent() && type.parentType.orElseThrow().allParserArguments.isPresent()>
+                <#assign filteredParentParserArguments = type.parentType.orElseThrow().allParserArguments.orElseThrow()?filter(arg -> !type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().isDiscriminatorField(arg.name))>
+                <#if filteredParentParserArguments?has_content>
+                    <#if type.parentPropertyFields?has_content>, </#if>
+                    <#list filteredParentParserArguments as parserArgument>
+                        self.${parserArgument.name}
+                        <#sep>, </#sep>
+                    </#list>
+                </#if>
+            </#if>
+            )
+        </...@compress>
+
+
 <#--
     If this is a discriminated parent type, we need to generate the abstract methods for accessing it's
     discriminator values instead.
 -->
-<#if type.isDiscriminatedParentTypeDefinition()>
-    <#assign discriminatedParentType = type>
+    <#if type.isDiscriminatedParentTypeDefinition()>
+        <#assign discriminatedParentType = type>
     <#-- @ftlvariable name="discriminatedParentType" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-    // Abstract accessors for discriminator values.
-    <#list helper.discriminatorTypes as discriminatorName, discriminatorType>
+    # Abstract accessors for discriminator values.
+        <#list helper.discriminatorTypes as discriminatorName, discriminatorType>
         <#-- If the discriminator name matches that of another field, suppress the methods generation -->
-        <#if !type.isNonDiscriminatorField(discriminatorName)><#-- && !type.isParserArgument(discriminatorName)-->
-    public abstract ${helper.getLanguageTypeNameForTypeReference(discriminatorType)} get${discriminatorName?cap_first}();
-        </#if>
-    </#list>
-</#if>
-<#-- If the current type contains "const" fields, generate some java constants for holing their values -->
-<#if type.constFields?has_content>
-
-    // Constant values.
-    <#list type.constFields as field>
-    public static final ${helper.getLanguageTypeNameForTypeReference(field.type)} ${field.name?upper_case} = ${helper.toParseExpression(field, field.type, field.referenceValue, parserArguments)};
-    </#list>
-</#if>
-<#-- Property fields are fields that require a property in the pojo -->
-<#if type.propertyFields?has_content>
-
-    // Properties.
-    <#list type.propertyFields as field>
-    protected final ${helper.getLanguageTypeNameForTypeReference(field.type, !field.isOptionalField())} ${field.name};
-    </#list>
-</#if>
-<#if parserArguments?has_content>
-  <#assign filteredParserArguments=parserArguments?filter(arg -> !type.isDiscriminatorField(arg.name) && !type.getPropertyFieldFromThisOrParentByName(arg.name).isPresent())>
-</#if>
-<#if filteredParserArguments?has_content>
-
-    // Arguments.
-    <#list filteredParserArguments as parserArgument>
-    protected final ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name};
-    </#list>
-</#if>
-<#assign reservedFields=type.getFields()?filter(f->f.isReservedField())>
-<#if reservedFields?has_content>
-    // Reserved Fields
-    <#list reservedFields as reservedField>
-    private ${helper.getLanguageTypeNameForTypeReference(reservedField.asReservedField().orElseThrow().type, false)} reservedField${reservedField?index};
-    </#list>
-</#if>
-
-    <#-- getAllPropertyFields() returns not only the property fields of this type but also of it's parents -->
-    <@compress single_line=true>
-    public ${type.name}(
-        <#list type.getAllPropertyFields() as field>
-            ${helper.getLanguageTypeNameForField(field)} ${field.name}
-            <#sep>, </#sep>
-        </#list>
-        <#if filteredParserArguments?has_content>
-            <#if type.getAllPropertyFields()?has_content>, </#if>
-            <#list filteredParserArguments as parserArgument>
-                ${helper.getLanguageTypeNameForTypeReference(parserArgument.type)} ${parserArgument.name}
-                <#sep>, </#sep>
-            </#list>
-        </#if>
-        ) {
-    </...@compress>
-
-    <@compress single_line=true>
-        super(
-        <#if type.parentPropertyFields?has_content>
-            <#list type.parentPropertyFields as field>
-                ${field.name}
-                <#sep>, </#sep>
-            </#list>
-        </#if>
-        <#if type.parentType.isPresent() && type.parentType.orElseThrow().allParserArguments.isPresent()>
-            <#assign filteredParentParserArguments = type.parentType.orElseThrow().allParserArguments.orElseThrow()?filter(arg -> !type.parentType.orElseThrow().asComplexTypeDefinition().orElseThrow().isDiscriminatorField(arg.name))>
-            <#if filteredParentParserArguments?has_content>
-                <#if type.parentPropertyFields?has_content>, </#if>
-                <#list filteredParentParserArguments as parserArgument>
-                    ${parserArgument.name}
-                    <#sep>, </#sep>
-                </#list>
+            <#if !type.isNonDiscriminatorField(discriminatorName)><#-- && !type.isParserArgument(discriminatorName)-->
+    @abstractmethod
+    def get${discriminatorName?cap_first}() -> ${helper.getLanguageTypeNameForTypeReference(discriminatorType)}:
             </#if>
-        </#if>
-        );
-    </...@compress>
+        </#list>
+    </#if>
 
-<#list type.propertyFields as field>
-        this.${field.name} = ${field.name};
-</#list>
-<#if filteredParserArguments?has_content>
-    <#list filteredParserArguments as parserArgument>
-        this.${parserArgument.name} = ${parserArgument.name};
-    </#list>
-</#if>
-    }
 
 <#list type.abstractFields as field>
-    public abstract ${helper.getLanguageTypeNameForField(field)} get${field.asNamedField().orElseThrow().name?cap_first}();
+    @abstractmethod
+    def get${field.asNamedField().orElseThrow().name?cap_first}() -> ${helper.getLanguageTypeNameForField(field)}:
 
 </#list>
 <#list type.propertyFields as field>
-    public ${helper.getLanguageTypeNameForField(field)} get${field.name?cap_first}() {
-        return ${field.name};
-    }
+    def get${field.name?cap_first}() -> ${helper.getLanguageTypeNameForField(field)}:
+        return ${field.name}
 
 </#list>
 <#list type.virtualFields as field>
-    public ${helper.getLanguageTypeNameForField(field)} get${field.name?cap_first}() {
+    def get${field.name?cap_first}() -> ${helper.getLanguageTypeNameForField(field)}:
         <#if helper.getLanguageTypeNameForField(field) = 'String'>
-        return ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toSerializationExpression(field, field.type, field.valueExpression, parserArguments)});
+        return ${helper.getLanguageTypeNameForField(field)}.valueOf(${helper.toSerializationExpression(field, field.type, field.valueExpression, parserArguments)})
         <#--elseif helper.getLanguageTypeNameForField(field) = 'BigInteger' && !helper.isBigIntegerSource(field.valueExpression)-->
         <#elseif helper.getLanguageTypeNameForField(field) = 'BigInteger'>
-        Object o = ${helper.toSerializationExpression(field, field.type, field.valueExpression, parserArguments)};
-        if (o instanceof BigInteger)
-            return (BigInteger) o;
-        return BigInteger.valueOf(((Number)o).longValue());
+        o = ${helper.toSerializationExpression(field, field.type, field.valueExpression, parserArguments)}
+        if isinstance(o, bignum):
+            return o
+        return bignum(o)
         <#else>
-        return (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(field, field.type, field.valueExpression, parserArguments)});
+        return ${helper.getLanguageTypeNameForField(field)}(${helper.toSerializationExpression(field, field.type, field.valueExpression, parserArguments)})
         </#if>
-    }
+
 
 </#list>
 <#list type.constFields as field>
-    public ${helper.getLanguageTypeNameForField(field)} get${field.name?cap_first}() {
-        return ${field.name?upper_case};
-    }
+    def get${field.name?cap_first}() -> ${helper.getLanguageTypeNameForField(field)}:
+        return ${field.name?upper_case}
 
 </#list>
 
     <#if outputFlavor != "passive">
 <#if type.isDiscriminatedChildTypeDefinition()>
-    @Override
-    protected void serialize${type.parentType.orElseThrow().name}Child(WriteBuffer writeBuffer) throws SerializationException {
+    def serialize${type.parentType.orElseThrow().name}Child(writeBuffer: WriteBuffer):
 <#else>
     <#if type.isDiscriminatedParentTypeDefinition()>
-    abstract protected void serialize${type.name?cap_first}Child(WriteBuffer writeBuffer) throws SerializationException;
+    @abstractmethod
+    abstract protected void serialize${type.name?cap_first}Child(writeBuffer: WriteBuffer):
+        pass
 
     </#if>
-    public void serialize(WriteBuffer writeBuffer) throws SerializationException {
+    def serialize(writeBuffer: WriteBuffer):
 </#if>
-        PositionAware positionAware = writeBuffer;
+        positionAware: PositionAware = writeBuffer
         <#if helper.hasFieldOfType("unknown")>
-            throw new SerializationException("Unknown field not serializable");
+            raise SerializationException("Unknown field not serializable")
         <#else>
-            int startPos = positionAware.getPos();
-            writeBuffer.pushContext("${type.name}");
+            startPos: int = positionAware.getPos()
+            writeBuffer.pushContext("${type.name}")
             <#assign reservedFieldIndex=0>
             <#list type.fields as field>
                 <#switch field.typeName>
@@ -250,13 +211,13 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Array Field (${arrayField.name})
+                        # Array Field (${arrayField.name})
                         <#if arrayField.type.elementTypeReference.isByteBased()>
-                        writeByteArrayField("${namedField.name}", ${namedField.name}, writeByteArray(writeBuffer, 8));
+                        writeByteArrayField("${namedField.name}", ${namedField.name}, writeByteArray(writeBuffer, 8))
                         <#elseif arrayField.type.elementTypeReference.isSimpleTypeReference()>
-                        writeSimpleTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getDataWriterCall(arrayField.type.elementTypeReference, namedField.name)});
+                        writeSimpleTypeArrayField("${namedField.name}", ${namedField.name}, ${helper.getDataWriterCall(arrayField.type.elementTypeReference, namedField.name)})
                         <#else>
-                        writeComplexTypeArrayField("${namedField.name}", ${namedField.name}, writeBuffer);
+                        writeComplexTypeArrayField("${namedField.name}", ${namedField.name}, writeBuffer)
                         </#if>
                         <#break>
                     <#case "checksum">
@@ -264,338 +225,335 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Checksum Field (checksum) (Calculated)
-                        writeChecksumField("${namedField.name}", (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.type, checksumField.checksumExpression, parserArguments)}), ${helper.getDataWriterCall(typedField.type, namedField.name)});
+                        # Checksum Field (checksum) (Calculated)
+                        writeChecksumField("${namedField.name}", (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.type, checksumField.checksumExpression, parserArguments)}), ${helper.getDataWriterCall(typedField.type, namedField.name)})
                         <#break>
                     <#case "const">
                         <#assign constField = field.asConstField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Const Field (${constField.name})
-                        <#if typedField.type.isEnumTypeReference()>writeConstField("${constField.name}", ${namedField.name?upper_case}.getValue(), ${helper.getDataWriterCall(helper.getEnumBaseTypeReference(typedField.type), namedField.name)});<#else>writeConstField("${constField.name}", ${namedField.name?upper_case}, ${helper.getDataWriterCall(typedField.type, namedField.name)});</#if>
+                        # Const Field (${constField.name})
+                        <#if typedField.type.isEnumTypeReference()>writeConstField("${constField.name}", ${namedField.name?upper_case}.getValue(), ${helper.getDataWriterCall(helper.getEnumBaseTypeReference(typedField.type), namedField.name)})<#else>writeConstField("${constField.name}", ${namedField.name?upper_case}, ${helper.getDataWriterCall(typedField.type, namedField.name)})</#if>
                         <#break>
                     <#case "discriminator">
                         <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
-                        <#if typedField.type.isEnumTypeReference()>writeDiscriminatorEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", get${discriminatorField.name?cap_first}(), ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")});<#else>writeDiscriminatorField("${namedField.name}", get${discriminatorField.name?cap_first}(), ${helper.getDataWriterCall(typedField.type, namedField.name)});</#if>
+                        # Discriminator Field (${discriminatorField.name}) (Used as input to a switch field)
+                        <#if typedField.type.isEnumTypeReference()>writeDiscriminatorEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", get${discriminatorField.name?cap_first}(), ${helper.getEnumDataWriterCall(typedField.type, namedField.name, "value")})<#else>writeDiscriminatorField("${namedField.name}", get${discriminatorField.name?cap_first}(), ${helper.getDataWriterCall(typedField.type, namedField.name)})</#if>
                         <#break>
                     <#case "enum">
                         <#assign enumField = field.asEnumField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Enum field (${namedField.name})
-                        writeEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, enumField.fieldName)});
+                        # Enum field (${namedField.name})
+                        writeEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${namedField.name}, ${helper.getEnumDataWriterCall(typedField.type, namedField.name, enumField.fieldName)})
                         <#break>
                     <#case "implicit">
                         <#assign implicitField = field.asImplicitField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Implicit Field (${implicitField.name}) (Used for parsing, but its value is not stored as it's implicitly given by the objects content)
+                        # Implicit Field (${implicitField.name}) (Used for parsing, but its value is not stored as it's implicitly given by the objects content)
                         <#-- Implicit field values might be used in expressions, in order to avoid problems, we generate a temporary variable with the given name. -->
-                        ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.type, implicitField.serializeExpression, parserArguments)});
-                        writeImplicitField("${namedField.name}", ${implicitField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)});
+                        ${helper.getLanguageTypeNameForField(field)} ${implicitField.name} = (${helper.getLanguageTypeNameForField(field)}) (${helper.toSerializationExpression(implicitField, implicitField.type, implicitField.serializeExpression, parserArguments)})
+                        writeImplicitField("${namedField.name}", ${implicitField.name}, ${helper.getDataWriterCall(typedField.type, namedField.name)})
                         <#break>
                     <#case "manualArray">
                         <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Manual Array Field (${manualArrayField.name})
-                        writeManualArrayField("${namedField.name}", ${namedField.name}, (${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)} _value) -> ${helper.toParseExpression(manualArrayField, manualArrayField.type.elementTypeReference, manualArrayField.serializeExpression, parserArguments)}, writeBuffer);
+                        # Manual Array Field (${manualArrayField.name})
+                        writeManualArrayField("${namedField.name}", ${namedField.name}, (${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)} _value) -> ${helper.toParseExpression(manualArrayField, manualArrayField.type.elementTypeReference, manualArrayField.serializeExpression, parserArguments)}, writeBuffer)
                         <#break>
                     <#case "manual">
                         <#assign manualField = field.asManualField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Manual Field (${manualField.name})
-                        writeManualField("${namedField.name}", () -> ${helper.toParseExpression(manualField, manualField.type, manualField.serializeExpression, parserArguments)}, writeBuffer);
+                        # Manual Field (${manualField.name})
+                        writeManualField("${namedField.name}", () -> ${helper.toParseExpression(manualField, manualField.type, manualField.serializeExpression, parserArguments)}, writeBuffer)
                         <#break>
                     <#case "optional">
                         <#assign optionalField = field.asOptionalField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Optional Field (${optionalField.name}) (Can be skipped, if the value is null)
+                        # Optional Field (${optionalField.name}) (Can be skipped, if the value is null)
                         <#if optionalField.type.isEnumTypeReference()>
-                            writeOptionalEnumField("${optionalField.name}", "${helper.getLanguageTypeNameForField(field)}", ${optionalField.name}, ${helper.getEnumDataWriterCall(optionalField.type, optionalField.name, "value")}<#if optionalField.conditionExpression.present>, ${helper.toSerializationExpression(optionalField, helper.boolTypeReference, optionalField.conditionExpression.get(), parserArguments)}</#if>);
+                            writeOptionalEnumField("${optionalField.name}", "${helper.getLanguageTypeNameForField(field)}", ${optionalField.name}, ${helper.getEnumDataWriterCall(optionalField.type, optionalField.name, "value")}<#if optionalField.conditionExpression.present>, ${helper.toSerializationExpression(optionalField, helper.boolTypeReference, optionalField.conditionExpression.get(), parserArguments)}</#if>)
                         <#elseif optionalField.type.isDataIoTypeReference()>
-                            writeOptionalField("${optionalField.name}", ${optionalField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> ${optionalField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb, val<#if optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, param, p [...]
+                            writeOptionalField("${optionalField.name}", ${optionalField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> ${optionalField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb, val<#if optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, param, p [...]
                         <#else>
-                            writeOptionalField("${optionalField.name}", ${optionalField.name}, ${helper.getDataWriterCall(typedField.type, optionalField.name)}<#if optionalField.conditionExpression.present>, ${helper.toSerializationExpression(optionalField, helper.boolTypeReference, optionalField.conditionExpression.get(), parserArguments)}</#if>);
+                            writeOptionalField("${optionalField.name}", ${optionalField.name}, ${helper.getDataWriterCall(typedField.type, optionalField.name)}<#if optionalField.conditionExpression.present>, ${helper.toSerializationExpression(optionalField, helper.boolTypeReference, optionalField.conditionExpression.get(), parserArguments)}</#if>)
                         </#if>
                         <#break>
                     <#case "padding">
                         <#assign paddingField = field.asPaddingField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
 
-                        // Padding Field (padding)
-                        writePaddingField("padding", (int) (${helper.toParseExpression(paddingField, helper.intTypeReference, paddingField.paddingCondition, parserArguments)}), (${helper.getLanguageTypeNameForField(field)}) ${helper.toSerializationExpression(paddingField, paddingField.type, paddingField.paddingValue, parserArguments)}, ${helper.getDataWriterCall(typedField.type, "padding")});
+                        # Padding Field (padding)
+                        writePaddingField("padding", (int) (${helper.toParseExpression(paddingField, helper.intTypeReference, paddingField.paddingCondition, parserArguments)}), (${helper.getLanguageTypeNameForField(field)}) ${helper.toSerializationExpression(paddingField, paddingField.type, paddingField.paddingValue, parserArguments)}, ${helper.getDataWriterCall(typedField.type, "padding")})
                         <#break>
                     <#case "reserved">
                         <#assign reservedField = field.asReservedField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
 
-                        // Reserved Field (reserved)
-                        writeReservedField("reserved", reservedField${reservedFieldIndex}!=null?reservedField${reservedFieldIndex}:${helper.getReservedValue(reservedField)}, ${helper.getDataWriterCall(typedField.type, "reserved")});<#assign reservedFieldIndex=reservedFieldIndex+1>
+                        # Reserved Field (reserved)
+                        writeReservedField("reserved", reservedField${reservedFieldIndex}!=null?reservedField${reservedFieldIndex}:${helper.getReservedValue(reservedField)}, ${helper.getDataWriterCall(typedField.type, "reserved")})<#assign reservedFieldIndex=reservedFieldIndex+1>
                         <#break>
                     <#case "simple">
                         <#assign simpleField = field.asSimpleField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Simple Field (${namedField.name})
+                        # Simple Field (${namedField.name})
                         <#if typedField.type.isEnumTypeReference()>
-                            writeSimpleEnumField("${simpleField.name}", "${helper.getLanguageTypeNameForField(field)}", ${simpleField.name}, ${helper.getEnumDataWriterCall(simpleField.type, simpleField.name, "value")});
+                            writeSimpleEnumField("${simpleField.name}", "${helper.getLanguageTypeNameForField(field)}", ${simpleField.name}, ${helper.getEnumDataWriterCall(simpleField.type, simpleField.name, "value")})
                         <#elseif simpleField.type.isDataIoTypeReference()>
-                            writeSimpleField("${simpleField.name}", ${simpleField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> ${simpleField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb, val<#if simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, parserArguments [...]
+                            writeSimpleField("${simpleField.name}", ${simpleField.name}, new DataWriterDataIoDefault(writeBuffer, (wb, val) -> ${simpleField.type.asComplexTypeReference().orElseThrow().name}.staticSerialize(wb, val<#if simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, parserArguments [...]
                         <#else>
-                            writeSimpleField("${simpleField.name}", ${simpleField.name}, ${helper.getDataWriterCall(typedField.type, simpleField.name)}${helper.getFieldOptions(typedField, parserArguments)});</#if>
+                            writeSimpleField("${simpleField.name}", ${simpleField.name}, ${helper.getDataWriterCall(typedField.type, simpleField.name)}${helper.getFieldOptions(typedField, parserArguments)})</#if>
                         <#break>
                     <#case "switch">
                         <#assign switchField = field.asSwitchField().orElseThrow()>
 
-                        // Switch field (Serialize the sub-type)
-                        serialize${type.name?cap_first}Child(writeBuffer);
+                        # Switch field (Serialize the sub-type)
+                        serialize${type.name?cap_first}Child(writeBuffer)
                         <#break>
                     <#case "virtual">
                         <#assign virtualField = field.asVirtualField().orElseThrow()>
                         <#assign typedField = field.asTypedField().orElseThrow()>
                         <#assign namedField = field.asNamedField().orElseThrow()>
 
-                        // Virtual field (doesn't actually serialize anything, just makes the value available)
-                        ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = get${namedField.name?cap_first}();
-                        writeBuffer.writeVirtual("${namedField.name}", ${namedField.name});
+                        # Virtual field (doesn't actually serialize anything, just makes the value available)
+                        ${namedField.name}: ${helper.getLanguageTypeNameForField(field)}  = get${namedField.name?cap_first}()
+                        writeBuffer.writeVirtual("${namedField.name}", ${namedField.name})
                         <#break>
                 </#switch>
             </#list>
 
-            writeBuffer.popContext("${type.name}");
+            writeBuffer.popContext("${type.name}")
         </#if>
-        }
+
     </#if>
 
-    @Override
-    public int getLengthInBytes() {
-        return (int) Math.ceil((float) getLengthInBits() / 8.0);
-    }
+    def getLengthInBytes() -> int:
+        return (int) Math.ceil((float) getLengthInBits() / 8.0)
 
-    @Override
-    public int getLengthInBits() {
-        int lengthInBits = <#if type.parentType.isPresent()>super.getLengthInBits()<#else>0</#if>;
-        ${type.name} _value  = this;
+    def getLengthInBits() -> int:
+        lengthInBits: int = <#if type.parentType.isPresent()>super.getLengthInBits()<#else>0</#if>
+        _value: ${type.name}  = this
 <#list type.fields as field>
 <#switch field.typeName>
     <#case "array">
         <#assign arrayField = field.asArrayField().orElseThrow()>
         <#assign arrayElementTypeReference = arrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
 
-        // Array field
+        # Array field
         if(${arrayField.name} != null) {
         <#if arrayElementTypeReference.isSimpleTypeReference()>
             <#assign simpleTypeReference = arrayElementTypeReference.asSimpleTypeReference().orElseThrow()>
-            lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.<#if arrayElementTypeReference.isByteBased()>length<#else>size()</#if>;
+            lengthInBits += ${simpleTypeReference.sizeInBits} * ${arrayField.name}.<#if arrayElementTypeReference.isByteBased()>length<#else>size()</#if>
         <#elseif arrayField.isCountArrayField()>
-            int i=0;
+            i: int = 0
             <#assign nonSimpleTypeReference = arrayElementTypeReference.asNonSimpleTypeReference().orElseThrow()>
-            for(${nonSimpleTypeReference.name} element : ${arrayField.name}) {
-                boolean last = ++i >= ${arrayField.name}.size();
-                lengthInBits += element.getLengthInBits();
-            }
+            for element in ${arrayField.name}:
+                last: boolean = ++i >= ${arrayField.name}.size()
+                lengthInBits += element.getLengthInBits()
+
         <#else>
-            for(Message element : ${arrayField.name}) {
-                lengthInBits += element.getLengthInBits();
-            }
+            for element in ${arrayField.name}:
+                lengthInBits += element.getLengthInBits()
+
         </#if>
-        }
+
         <#break>
     <#case "checksum">
         <#assign checksumField = field.asChecksumField().orElseThrow()>
         <#assign typedField = field.asTypedField().orElseThrow()>
         <#assign simpleTypeReference = typedField.type.asSimpleTypeReference().orElseThrow()>
 
-        // Checksum Field (checksum)
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        # Checksum Field (checksum)
+        lengthInBits += ${simpleTypeReference.sizeInBits}
         <#break>
     <#case "const">
         <#assign constField = field.asConstField().orElseThrow()>
         <#assign typedField = field.asTypedField().orElseThrow()>
 
-        // Const Field (${constField.name})
+        # Const Field (${constField.name})
         <#if typedField.type.isSimpleTypeReference()>
         <#assign simpleTypeReference = typedField.type.asSimpleTypeReference().orElseThrow()>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        lengthInBits += ${simpleTypeReference.sizeInBits}
         <#else>
-        lengthInBits += ${helper.getEnumBaseTypeReference(typedField.type).sizeInBits};
+        lengthInBits += ${helper.getEnumBaseTypeReference(typedField.type).sizeInBits}
         </#if>
         <#break>
     <#case "discriminator">
         <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
 
-        // Discriminator Field (${discriminatorField.name})
+        # Discriminator Field (${discriminatorField.name})
         <#if discriminatorField.type.isSimpleTypeReference()>
             <#assign simpleTypeReference = discriminatorField.type.asSimpleTypeReference().orElseThrow()>
             <#if simpleTypeReference.isVstringTypeReference()>
                 <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
-        lengthInBits += ${helper.toSerializationExpression(discriminatorField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+        lengthInBits += ${helper.toSerializationExpression(discriminatorField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)}
             <#else>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        lengthInBits += ${simpleTypeReference.sizeInBits}
             </#if>
         <#elseif helper.isEnumField(field)>
-            lengthInBits += ${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits};
+            lengthInBits += ${helper.getEnumBaseTypeReference(discriminatorField.type).sizeInBits}
         <#else>
-            lengthInBits += ${discriminatorField.name}.getLengthInBits();
+            lengthInBits += ${discriminatorField.name}.getLengthInBits()
         </#if>
         <#break>
     <#case "enum">
         <#assign enumField = field.asEnumField().orElseThrow()>
 
-        // Enum Field (${enumField.name})
-        lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits};
+        # Enum Field (${enumField.name})
+        lengthInBits += ${helper.getEnumBaseTypeReference(enumField.type).sizeInBits}
         <#break>
     <#case "implicit">
         <#assign implicitField = field.asImplicitField().orElseThrow()>
         <#assign simpleTypeReference = implicitField.type.asSimpleTypeReference().orElseThrow()>
 
-        // Implicit Field (${implicitField.name})
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        # Implicit Field (${implicitField.name})
+        lengthInBits += ${simpleTypeReference.sizeInBits}
         <#break>
     <#case "manualArray">
         <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
         <#assign arrayElementTypeReference = manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
 
-        // Manual Array Field (${manualArrayField.name})
-        lengthInBits += ${helper.toParseExpression(manualArrayField, helper.intTypeReference, manualArrayField.lengthExpression, parserArguments)} * 8;
+        # Manual Array Field (${manualArrayField.name})
+        lengthInBits += ${helper.toParseExpression(manualArrayField, helper.intTypeReference, manualArrayField.lengthExpression, parserArguments)} * 8
         <#break>
     <#case "manual">
         <#assign manualField = field.asManualField().orElseThrow()>
 
-        // Manual Field (${manualField.name})
-        lengthInBits += ${helper.toParseExpression(manualField, helper.intTypeReference, manualField.lengthExpression, parserArguments)};
+        # Manual Field (${manualField.name})
+        lengthInBits += ${helper.toParseExpression(manualField, helper.intTypeReference, manualField.lengthExpression, parserArguments)}
         <#break>
     <#case "optional">
         <#assign optionalField = field.asOptionalField().orElseThrow()>
 
-        // Optional Field (${optionalField.name})
-        if(${optionalField.name} != null) {
+        # Optional Field (${optionalField.name})
+        if ${optionalField.name} is not None:
         <#if optionalField.type.isSimpleTypeReference()>
             <#assign simpleTypeReference = optionalField.type.asSimpleTypeReference().orElseThrow()>
             <#if simpleTypeReference.isVstringTypeReference()>
                 <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
-            lengthInBits += ${helper.toSerializationExpression(optionalField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+            lengthInBits += ${helper.toSerializationExpression(optionalField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)}
             <#else>
-            lengthInBits += ${simpleTypeReference.sizeInBits};
+            lengthInBits += ${simpleTypeReference.sizeInBits}
             </#if>
         <#elseif helper.isEnumField(field)>
-            lengthInBits += ${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits};
+            lengthInBits += ${helper.getEnumBaseTypeReference(optionalField.type).sizeInBits}
         <#elseif optionalField.type.isDataIoTypeReference()>
-            lengthInBits += ${optionalField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${optionalField.name}<#if optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, param, parserArguments)}<#sep>, </#sep></#list></#if>);
+            lengthInBits += ${optionalField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${optionalField.name}<#if optionalField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list optionalField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(optionalField, helper.anyTypeReference, param, parserArguments)}<#sep>, </#sep></#list></#if>)
         <#else>
-            lengthInBits += ${optionalField.name}.getLengthInBits();
+            lengthInBits += ${optionalField.name}.getLengthInBits()
         </#if>
-        }
+
         <#break>
     <#case "padding">
         <#assign paddingField = field.asPaddingField().orElseThrow()>
         <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
-        // Padding Field (padding)
+        # Padding Field (padding)
         <#-- We're replacing the "lastItem" with 'false' here as the item itself can't know if it is the last -->
-        int _timesPadding = (int) (${helper.toParseExpression(paddingField, helper.intTypeReference, paddingField.paddingCondition, parserArguments)});
-        while (_timesPadding-- > 0) {
-            lengthInBits += ${simpleTypeReference.sizeInBits};
-        }
+        int _timesPadding = int(${helper.toParseExpression(paddingField, helper.intTypeReference, paddingField.paddingCondition, parserArguments)})
+        while _timesPadding-- > 0:
+            lengthInBits += ${simpleTypeReference.sizeInBits}
+
         <#break>
     <#case "reserved">
         <#assign reservedField = field.asReservedField().orElseThrow()>
         <#assign simpleTypeReference = reservedField.type.asSimpleTypeReference().orElseThrow()>
 
-        // Reserved Field (reserved)
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        # Reserved Field (reserved)
+        lengthInBits += ${simpleTypeReference.sizeInBits}
         <#break>
     <#case "simple">
         <#assign simpleField = field.asSimpleField().orElseThrow()>
 
-        // Simple field (${simpleField.name})
+        # Simple field (${simpleField.name})
         <#if simpleField.type.isSimpleTypeReference()>
             <#assign simpleTypeReference = simpleField.type.asSimpleTypeReference().orElseThrow()>
             <#if simpleTypeReference.isVstringTypeReference()>
                 <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
-        lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
+        lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)}
             <#else>
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        lengthInBits += ${simpleTypeReference.sizeInBits}
             </#if>
         <#elseif helper.isEnumField(field)>
-        lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
+        lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits}
         <#elseif simpleField.type.isDataIoTypeReference()>
-        lengthInBits += ${simpleField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${simpleField.name}<#if simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, parserArguments)}<#sep>, </#sep></#list></#if>);
+        lengthInBits += ${simpleField.type.asComplexTypeReference().orElseThrow().name}.getLengthInBits(${simpleField.name}<#if simpleField.type.asComplexTypeReference().orElseThrow().params?has_content>, <#list simpleField.type.asComplexTypeReference().orElseThrow().params.orElseThrow() as param>${helper.toParseExpression(simpleField, helper.anyTypeReference, param, parserArguments)}<#sep>, </#sep></#list></#if>)
         <#else>
-        lengthInBits += ${simpleField.name}.getLengthInBits();
+        lengthInBits += ${simpleField.name}.getLengthInBits()
         </#if>
         <#break>
     <#case "switch">
         <#assign switchField = field.asSwitchField().orElseThrow()>
 
-        // Length of sub-type elements will be added by sub-type...
+        # Length of sub-type elements will be added by sub-type...
         <#break>
     <#case "unknown">
         <#assign unknownField = field.asUnknownField().orElseThrow()>
         <#assign simpleTypeReference = unknownField.type.asSimpleTypeReference().orElseThrow()>
 
-        // Unknown field
-        lengthInBits += ${simpleTypeReference.sizeInBits};
+        # Unknown field
+        lengthInBits += ${simpleTypeReference.sizeInBits}
         <#break>
     <#case "virtual">
         <#assign virtualField = field.asVirtualField().orElseThrow()>
 
-        // A virtual field doesn't have any in- or output.
+        # A virtual field doesn't have any in- or output.
         <#break>
 </#switch>
 </#list>
 
-        return lengthInBits;
-    }
+        return lengthInBits
+
 
 <#-- The parse and serialize methods here are just proxies for forwardning the requests to static counterparts -->
     <#if !type.isDiscriminatedChildTypeDefinition()>
-    public static ${type.name} staticParse(ReadBuffer readBuffer, Object... args) throws ParseException {
-        PositionAware positionAware = readBuffer;
+    def staticParse(readBuffer: ReadBuffer , args) -> ${type.name}:
+        positionAware: PositionAware = readBuffer
         <#if parserArguments?has_content>
-        if((args == null) || (args.length != ${parserArguments?size})) {
-            throw new PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length);
-        }
+        if (args == null) or (args.length != ${parserArguments?size}):
+            raise PlcRuntimeException("Wrong number of arguments, expected ${parserArguments?size}, but got " + args.length)
+
             <#list parserArguments as parserArgument>
                 <#assign languageName=helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)>
-        ${languageName} ${parserArgument.name};
-        if(args[${parserArgument?index}] instanceof ${languageName}) {
-            ${parserArgument.name} = (${languageName}) args[${parserArgument?index}];
+        ${languageName} ${parserArgument.name}
+        if isinstance(args[${parserArgument?index}], ${languageName}):
+            ${parserArgument.name} = (${languageName}) args[${parserArgument?index}]
                 <#if parserArgument.type.isSimpleTypeReference() || parserArgument.type.isEnumTypeReference()>
-        } else if (args[${parserArgument?index}] instanceof String) {
-            ${parserArgument.name} = ${languageName}.valueOf((String) args[${parserArgument?index}]);
+        elif isinstance(args[${parserArgument?index}], String):
+            ${parserArgument.name} = ${languageName}.valueOf((String) args[${parserArgument?index}])
                 </#if>
-        } else {
-            throw new PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${languageName} or a string which is parseable but was " + args[${parserArgument?index}].getClass().getName());
-        }
+        else:
+            raise PlcRuntimeException("Argument ${parserArgument?index} expected to be of type ${languageName} or a string which is parseable but was " + args[${parserArgument?index}].getClass().getName())
+
             </#list>
         </#if>
-        return staticParse(readBuffer<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>);
+        return staticParse(readBuffer<#if parserArguments?has_content>, <#list parserArguments as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if>)
     }
 
     </#if>
 <#-- Here come the actual parse and serialize methods that actually do the parsing and serlaizing -->
     <#assign hasParserArguments=parserArguments?has_content/>
     <#assign parserArgumentList><#if hasParserArguments><#list parserArguments as parserArgument>${helper.getLanguageTypeNameForTypeReference(parserArgument.type, false)} ${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-    public static ${type.name}<#if type.isDiscriminatedChildTypeDefinition()>Builder staticParseBuilder<#else> staticParse</#if>(ReadBuffer readBuffer<#if hasParserArguments>, ${parserArgumentList}</#if>) throws ParseException {
-        readBuffer.pullContext("${type.name}");
-        PositionAware positionAware = readBuffer;
-        int startPos = positionAware.getPos();
-        int curPos;
+    def <#if type.isDiscriminatedChildTypeDefinition()>Builder staticParseBuilder<#else> staticParse</#if>(readBuffer: ReadBuffer<#if hasParserArguments>, ${parserArgumentList}</#if>) -> ${type.name}:
+        readBuffer.pullContext("${type.name}")
+        positionAware: PositionAware = readBuffer
+        startPos: int = positionAware.getPos()
+        curPos: int = 0
     <#assign reservedFieldIndex=0>
     <#list type.fields as field>
         <#switch field.typeName>
@@ -607,21 +565,21 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
 
                 <#if arrayElementTypeReference.isByteBased()>
                     <#if !field.isCountArrayField() && !field.isLengthArrayField()>
-                        throw new ParseException("array fields of type byte only support 'count' and 'length' loop-types.");
+                        raise ParseException("array fields of type byte only support 'count' and 'length' loop-types.")
                     </#if>
-                    byte[] ${namedField.name} = readBuffer.readByteArray("${namedField.name}", Math.toIntExact(${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+                    ${namedField.name}: byte[] = readBuffer.readByteArray("${namedField.name}", Math.toIntExact(${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)})
                 <#else>
                 <#-- If this is a count array, we can directly initialize an array with the given size -->
                     <#if field.isCountArrayField()>
-                        ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} ${arrayField.name} = readCountArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+                        ${arrayField.name}: ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} = readCountArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)})
                     <#-- In all other cases do we have to work with a list, that is later converted to an array -->
                     <#else>
                     <#-- For a length array, we read data till the read position of the buffer reaches a given position -->
                         <#if field.isLengthArrayField()>
-                            ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} ${arrayField.name} = readLengthArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+                            ${arrayField.name}: ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} = readLengthArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, ${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)})
                         <#-- A terminated array keeps on reading data as long as the termination expression evaluates to false -->
                         <#elseif field.isTerminatedArrayField()>
-                            ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} ${arrayField.name} = readTerminatedArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) (${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}))${helper.getFieldOptions(typedField, parserArguments)});
+                            ${arrayField.name}: ${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)} = readTerminatedArrayField("${arrayField.name}", ${helper.getDataReaderCall(arrayField.type)}, () -> ((boolean) (${helper.toParseExpression(arrayField, helper.intTypeReference, arrayField.loopExpression, parserArguments)}))${helper.getFieldOptions(typedField, parserArguments)})
                         </#if>
                     </#if>
                 </#if>
@@ -631,42 +589,42 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(assertField, assertField.type, assertField.conditionExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(assertField, assertField.type, assertField.conditionExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "checksum">
                 <#assign checksumField = field.asChecksumField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.type, checksumField.checksumExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, (${helper.getLanguageTypeNameForField(field)}) (${helper.toParseExpression(checksumField, checksumField.type, checksumField.checksumExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "const">
                 <#assign constField = field.asConstField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${type.name}.${namedField.name?upper_case}${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}, ${type.name}.${namedField.name?upper_case}${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "discriminator">
                 <#assign discriminatorField = field.asDiscriminatorField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "enum">
                 <#assign enumField = field.asEnumField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", "${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}", readEnum(${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}::firstEnumForField${enumField.fieldName?cap_first}, ${helper.getDataReaderCall(helper.getEnumFieldTypeReference(enumField.type, enumField.fieldName))})${helper.getFieldOptions(typed [...]
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", "${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}", readEnum(${enumField.type.asNonSimpleTypeReference().orElseThrow().typeDefinition.name}::firstEnumForField${enumField.fieldName?cap_first}, ${helper.getDataReaderCall(helper.getEnumFieldTypeReference(enumField.type, enumField.fieldName))})${helper.getFieldOptions(type [...]
                 <#break>
             <#case "implicit">
                 <#assign implicitField = field.asImplicitField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "manualArray">
                 <#assign manualArrayField = field.asManualArrayField().orElseThrow()>
@@ -675,9 +633,9 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#assign arrayElementTypeReference = manualArrayField.type.asArrayTypeReference().orElseThrow().getElementTypeReference()>
 
                 <#if arrayElementTypeReference.isByteBased()>
-                    byte[] ${namedField.name} = readManualByteArrayField("${namedField.name}", readBuffer, (byte[] _values) -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (byte) (${helper.toParseExpression(manualArrayField, manualArrayField.type, manualArrayField.parseExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+                    ${namedField.name}: byte[] = readManualByteArrayField("${namedField.name}", readBuffer, (byte[] _values) -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (byte) (${helper.toParseExpression(manualArrayField, manualArrayField.type, manualArrayField.parseExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)})
                 <#else>
-                    ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} ${namedField.name} = readManualArrayField("${namedField.name}", readBuffer, (${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} _values) -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)}) (${helper.toPa [...]
+                    ${namedField.name}: ${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} = readManualArrayField("${namedField.name}", readBuffer, (${helper.getNonPrimitiveLanguageTypeNameForField(manualArrayField)} _values) -> (boolean) (${helper.toParseExpression(manualArrayField, helper.boolTypeReference, manualArrayField.loopExpression, parserArguments)}), () -> (${helper.getLanguageTypeNameForTypeReference(manualArrayField.type.elementTypeReference)}) (${helper.toP [...]
                 </#if>
                 <#break>
             <#case "manual">
@@ -685,44 +643,44 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${manualField.name} = readManualField("${namedField.name}", readBuffer, () -> (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(manualField, manualField.type, manualField.parseExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+                ${manualField.name}: ${helper.getLanguageTypeNameForField(field)} = readManualField("${namedField.name}", readBuffer, () -> (${helper.getLanguageTypeNameForField(manualField)}) (${helper.toParseExpression(manualField, manualField.type, manualField.parseExpression, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "optional">
                 <#assign optionalField = field.asOptionalField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}<#if optionalField.conditionExpression.present>, ${helper.toParseExpression(optionalField, helper.boolTypeReference, optionalField.conditionExpression.get(), parserArguments)}</#if>${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}<#if optionalField.conditionExpression.present>, ${helper.toParseExpression(optionalField, helper.boolTypeReference, optionalField.conditionExpression.get(), parserArguments)}</#if>${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "padding">
                 <#assign paddingField = field.asPaddingField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign simpleTypeReference = paddingField.type.asSimpleTypeReference().orElseThrow()>
 
-                read${field.typeName?cap_first}Field(${helper.getDataReaderCall(typedField.type)}, (int) (${helper.toParseExpression(paddingField, paddingField.type, paddingField.paddingCondition, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)});
+                read${field.typeName?cap_first}Field(${helper.getDataReaderCall(typedField.type)}, (int) (${helper.toParseExpression(paddingField, paddingField.type, paddingField.paddingCondition, parserArguments)})${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "reserved">
                 <#assign reservedField = field.asReservedField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForTypeReference(reservedField.type, false)} reservedField${reservedFieldIndex}<#assign reservedFieldIndex=reservedFieldIndex+1> = read${field.typeName?cap_first}Field("reserved", ${helper.getDataReaderCall(typedField.type)}, ${helper.getReservedValue(reservedField)}${helper.getFieldOptions(typedField, parserArguments)});
+                ${helper.getLanguageTypeNameForTypeReference(reservedField.type, false)} reservedField${reservedFieldIndex}<#assign reservedFieldIndex=reservedFieldIndex+1> = read${field.typeName?cap_first}Field("reserved", ${helper.getDataReaderCall(typedField.type)}, ${helper.getReservedValue(reservedField)}${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "simple">
                 <#assign simpleField = field.asSimpleField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = <#if typedField.type.isEnumTypeReference()>readEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});<#else>read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});</#if>
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = <#if typedField.type.isEnumTypeReference()>readEnumField("${namedField.name}", "${helper.getLanguageTypeNameForField(field)}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)})<#else>read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)})</#if>
                 <#break>
             <#case "switch">
                 <#assign switchField = field.asSwitchField().orElseThrow()>
 
-                // Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
-                ${type.name}Builder builder = null;
+                # Switch Field (Depending on the discriminator values, passes the instantiation to a sub-type)
+                builder: ${type.name}Builder = None
                 <#list switchField.cases as case>
                     <@compress single_line=true>
                         <#if case.discriminatorValueTerms?has_content>
-                            if(
+                            if<#sep>
                             <#list case.discriminatorValueTerms as discriminatorValueTerm>
                                 <#if helper.isWildcard(discriminatorValueTerm)>
                                     true
@@ -738,57 +696,57 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                                     </#if>
                                     )
                                 </#if>
-                                <#sep> && </#sep>
+                                <#sep> and </#sep>
                             </#list>
                             )
-                        </#if>{
+                        </#if>:
                     </...@compress>
                     <@compress single_line=true>
                         <#assign hasCaseParseArguments=case.allParserArguments.isPresent() && case.allParserArguments.orElseThrow()?has_content>
                         <#assign caseParseArguments><#if hasCaseParseArguments><#list case.allParserArguments.orElseThrow() as parserArgument>${parserArgument.name}<#sep>, </#sep></#list></#if></#assign>
-                        builder = ${case.name}.staticParseBuilder(readBuffer<#if hasCaseParseArguments>, ${tracer.dive("case parse arguments")} ${caseParseArguments}</#if>);
+                        builder = ${case.name}.staticParseBuilder(readBuffer<#if hasCaseParseArguments>, ${tracer.dive("case parse arguments")} ${caseParseArguments}</#if>)
                     </...@compress>
-                    }<#sep> else </#sep>
+                    <#sep> else:</#sep>
                 </#list>
-                if (builder == null) {
-                    throw new ParseException("Unsupported case for discriminated type"<#if switchField.getDiscriminatorExpressions()?has_content>+" parameters ["<#list switchField.getDiscriminatorExpressions() as discriminatorExpression>+"${discriminatorExpression.stringRepresentation()}="+${helper.toParseExpression(null, null, discriminatorExpression, parserArguments)}<#sep>+" "</#sep></#list>+"]"</#if>);
-                }
+                if builder is None:
+                    raise ParseException("Unsupported case for discriminated type"<#if switchField.getDiscriminatorExpressions()?has_content>+" parameters ["<#list switchField.getDiscriminatorExpressions() as discriminatorExpression>+"${discriminatorExpression.stringRepresentation()}="+${helper.toParseExpression(null, null, discriminatorExpression, parserArguments)}<#sep>+" "</#sep></#list>+"]"</#if>)
+
                 <#break>
             <#case "unknown">
                 <#assign unknownField = field.asUnknownField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
 
-                read${field.typeName?cap_first}Field("unknown", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)});
+                read${field.typeName?cap_first}Field("unknown", ${helper.getDataReaderCall(typedField.type)}${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "virtual">
                 <#assign virtualField = field.asVirtualField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getLanguageTypeNameForField(field)}.class, ${helper.toParseExpression(virtualField, virtualField.type, virtualField.valueExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getLanguageTypeNameForField(field)}.class, ${helper.toParseExpression(virtualField, virtualField.type, virtualField.valueExpression, parserArguments)}${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
             <#case "validation">
                 <#assign validationField = field.asValidationField().orElseThrow()>
-                // Validation
-                if (!(${helper.toParseExpression(validationField, helper.boolTypeReference, validationField.getValidationExpression(), null)})) {
+                # Validation
+                if not ${helper.toParseExpression(validationField, helper.boolTypeReference, validationField.getValidationExpression(), null)}):
                     <#assign errorType="ParseValidationException">
                     <#if !validationField.shouldFail()><#assign errorType="ParseAssertException"></#if>
-                    throw new ${errorType}(${validationField.getDescription().orElse("\"Validation failed\"")});
-                }
+                    raise ${errorType}(${validationField.getDescription().orElse("\"Validation failed\"")})
+
                 <#break>
             <#case "peek">
                 <#assign peekField = field.asPeekField().orElseThrow()>
                 <#assign typedField = field.asTypedField().orElseThrow()>
                 <#assign namedField = field.asNamedField().orElseThrow()>
 
-                ${helper.getLanguageTypeNameForField(field)} ${namedField.name} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}<#if peekField.offsetExpression.present>, ${helper.toParseExpression(peekField, helper.boolTypeReference, peekField.offsetExpression.get(), parserArguments)}</#if>${helper.getFieldOptions(typedField, parserArguments)});
+                ${namedField.name}: ${helper.getLanguageTypeNameForField(field)} = read${field.typeName?cap_first}Field("${namedField.name}", ${helper.getDataReaderCall(typedField.type)}<#if peekField.offsetExpression.present>, ${helper.toParseExpression(peekField, helper.boolTypeReference, peekField.offsetExpression.get(), parserArguments)}</#if>${helper.getFieldOptions(typedField, parserArguments)})
                 <#break>
         </#switch>
     </#list>
 
-    readBuffer.closeContext("${type.name}");
-    // Create the instance
+    readBuffer.closeContext("${type.name}")
+    # Create the instance
     <#if type.isDiscriminatedChildTypeDefinition()>
-        return new ${type.name}Builder(
+        return ${type.name}Builder(
         <#list type.propertyFields as field>
             ${field.name}<#sep>, </#sep>
         </#list>
@@ -801,9 +759,9 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
         <#list reservedFields as reservedField>
             reservedField${reservedField?index}<#sep>, </#sep>
         </#list>
-        );
+        )
     <#elseif type.isDiscriminatedParentTypeDefinition()>
-        ${type.name} _${type.name?uncap_first} = builder.build(
+        _${type.name?uncap_first}: ${type.name} = builder.build(
         <#list type.propertyFields as field>
             ${field.name}<#sep>, </#sep>
         </#list>
@@ -813,14 +771,13 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 ${arg.name}<#sep>, </#sep>
             </#list>
         </#if>
-        );
+        )
         <#list reservedFields as reservedField>
-        _${type.name?uncap_first}.reservedField${reservedField?index} = reservedField${reservedField?index};
+        _${type.name?uncap_first}.reservedField${reservedField?index} = reservedField${reservedField?index}
         </#list>
-        return _${type.name?uncap_first};
+        return _${type.name?uncap_first}
     <#else>
-        ${type.name} _${type.name?uncap_first};
-        _${type.name?uncap_first} = new ${type.name}(
+        _${type.name?uncap_first}: ${type.name} = ${type.name}(
         <#list type.propertyFields as field>
             ${field.name}<#sep>, </#sep>
         </#list>
@@ -830,16 +787,15 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 ${arg.name}<#sep>, </#sep>
             </#list>
         </#if>
-        );
+        )
         <#list reservedFields as reservedField>
-            _${type.name?uncap_first}.reservedField${reservedField?index} = reservedField${reservedField?index};
+            _${type.name?uncap_first}.reservedField${reservedField?index} = reservedField${reservedField?index}
         </#list>
-        return _${type.name?uncap_first};
+        return _${type.name?uncap_first}
     </#if>
-    }
 
     <#if type.isDiscriminatedParentTypeDefinition()>
-        public static interface ${type.name}Builder {
+        def interface ${type.name}Builder {
             ${type.name} build(
         <#list type.propertyFields as field>
             ${helper.getLanguageTypeNameForField(field)} ${field.name}<#sep>, </#sep>
@@ -850,7 +806,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 ${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}<#sep>, </#sep>
             </#list>
         </#if>
-        );
+        )
         }
 
     </#if>
@@ -858,16 +814,16 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
         public static class ${type.name}Builder implements ${type.parentType.orElseThrow().name}.${type.parentType.orElseThrow().name}Builder {
         <#if type.propertyFields?has_content>
             <#list type.propertyFields as field>
-        private final ${helper.getLanguageTypeNameForField(field)} ${field.name};
+        private final ${helper.getLanguageTypeNameForField(field)} ${field.name}
             </#list>
         </#if>
         <#if filteredParserArguments?has_content>
             <#list filteredParserArguments as arg>
-        private final ${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name};
+        private final ${helper.getLanguageTypeNameForTypeReference(arg.type)} ${arg.name}
             </#list>
         </#if>
         <#list reservedFields as reservedField>
-        private final ${helper.getLanguageTypeNameForTypeReference(reservedField.type, false)} reservedField${reservedField?index};
+        private final ${helper.getLanguageTypeNameForTypeReference(reservedField.type, false)} reservedField${reservedField?index}
         </#list>
 
         public ${type.name}Builder(
@@ -886,15 +842,15 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
         </#list>
         ) {
         <#list type.propertyFields as field>
-            this.${field.name} = ${field.name};
+            this.${field.name} = ${field.name}
         </#list>
         <#if filteredParserArguments?has_content>
             <#list filteredParserArguments as arg>
-            this.${arg.name} = ${arg.name};
+            this.${arg.name} = ${arg.name}
             </#list>
         </#if>
         <#list reservedFields as reservedField>
-            this.reservedField${reservedField?index} = reservedField${reservedField?index};
+            this.reservedField${reservedField?index} = reservedField${reservedField?index}
         </#list>
         }
 
@@ -918,11 +874,11 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
             <#list filteredParserArguments as arg>
                 ${arg.name}<#sep>, </#sep>
             </#list>
-        </#if>);
+        </#if>)
         <#list reservedFields as reservedField>
-            ${type.name?uncap_first}.reservedField${reservedField?index} = reservedField${reservedField?index};
+            ${type.name?uncap_first}.reservedField${reservedField?index} = reservedField${reservedField?index}
         </#list>
-            return ${type.name?uncap_first};
+            return ${type.name?uncap_first}
         }
     }
 
@@ -931,12 +887,12 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
     @Override
     public boolean equals(Object o) {
         if (this == o) {
-            return true;
+            return true
         }
         if (!(o instanceof ${type.name})) {
-            return false;
+            return false
         }
-        ${type.name} that = (${type.name}) o;
+        ${type.name} that = (${type.name}) o
         return
             <#if type.propertyFields?has_content>
             <#list type.propertyFields as field>
@@ -946,7 +902,7 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
             <#if type.parentType.isPresent()>
             super.equals(that) &&
             </#if>
-            true;
+            true
     }
 
     @Override
@@ -960,18 +916,18 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
             get${field.name?cap_first}()<#sep>,</#sep>
             </#list>
             </#if>
-        );
+        )
     }
 
     @Override
     public String toString() {
-        WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true);
+        WriteBufferBoxBased writeBufferBoxBased = new WriteBufferBoxBased(true, true)
         try {
-            writeBufferBoxBased.writeSerializable(this);
+            writeBufferBoxBased.writeSerializable(this)
         } catch (SerializationException e) {
-            throw new RuntimeException(e);
+            throw new RuntimeException(e)
         }
-        return "\n" + writeBufferBoxBased.getBox().toString()+ "\n";
+        return "\n" + writeBufferBoxBased.getBox().toString()+ "\n"
     }
 }
 </#outputformat>
\ No newline at end of file
diff --git a/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh b/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
index 7779e6e266..1bb4576d87 100644
--- a/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
+++ b/code-generation/language-python/src/main/resources/templates/python/data-io-template.python.ftlh
@@ -25,25 +25,25 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.ComplexTypeDefinition" -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.java
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.py
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
 package ${helper.packageName(protocolName, languageName, outputFlavor)};
 
 import static org.apache.plc4x.java.spi.generation.StaticHelper.*;
diff --git a/code-generation/language-python/src/main/resources/templates/python/enum-template.python.ftlh b/code-generation/language-python/src/main/resources/templates/python/enum-template.python.ftlh
index 24da7f185b..64a44d5b73 100644
--- a/code-generation/language-python/src/main/resources/templates/python/enum-template.python.ftlh
+++ b/code-generation/language-python/src/main/resources/templates/python/enum-template.python.ftlh
@@ -26,25 +26,25 @@
 <#-- @ftlvariable name="helper" type="org.apache.plc4x.language.java.JavaLanguageTemplateHelper" -->
 <#-- @ftlvariable name="tracer" type="org.apache.plc4x.plugins.codegenerator.protocol.freemarker.Tracer" -->
 <#-- @ftlvariable name="type" type="org.apache.plc4x.plugins.codegenerator.types.definitions.EnumTypeDefinition" -->
-${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.java
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
+${helper.packageName(protocolName, languageName, outputFlavor)?replace(".", "/")}/${type.name}.py
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
 package ${helper.packageName(protocolName, languageName, outputFlavor)};
 
 import org.apache.plc4x.java.spi.generation.Message;
diff --git a/sandbox/plc4py/plc4py/drivers/modbus/ModbusConfiguration.py b/sandbox/plc4py/plc4py/drivers/modbus/ModbusConfiguration.py
index acf4ed2bcd..3ef7b97331 100644
--- a/sandbox/plc4py/plc4py/drivers/modbus/ModbusConfiguration.py
+++ b/sandbox/plc4py/plc4py/drivers/modbus/ModbusConfiguration.py
@@ -20,7 +20,6 @@ from plc4py.spi.configuration.PlcConfiguration import PlcConfiguration
 
 
 class ModbusConfiguration(PlcConfiguration):
-
     def __init__(self, url):
         super().__init__(url)
 
@@ -28,4 +27,4 @@ class ModbusConfiguration(PlcConfiguration):
             self.transport = "tcp"
 
         if self.port is None:
-            self.port = 502
\ No newline at end of file
+            self.port = 502
diff --git a/sandbox/plc4py/pom.xml b/sandbox/plc4py/pom.xml
index db0587c3e8..bba9d1c285 100644
--- a/sandbox/plc4py/pom.xml
+++ b/sandbox/plc4py/pom.xml
@@ -79,6 +79,7 @@
               <protocolName>modbus</protocolName>
               <languageName>python</languageName>
               <outputFlavor>read-write</outputFlavor>
+              <outputDir>${project.basedir}/plc4py/protocols</outputDir>
             </configuration>
           </execution>
         </executions>
@@ -112,6 +113,22 @@
             </configuration>
           </execution>
 
+          <execution>
+            <id>python-black</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <executable>${python.venv.bin}python3</executable>
+              <arguments>
+                <argument>-m</argument>
+                <argument>black</argument>
+                <argument>.</argument>
+              </arguments>
+            </configuration>
+          </execution>
+
           <execution>
             <id>python-install</id>
             <phase>compile</phase>
diff --git a/sandbox/plc4py/setup.py b/sandbox/plc4py/setup.py
index ddec35e7ea..1c4a04e3fa 100644
--- a/sandbox/plc4py/setup.py
+++ b/sandbox/plc4py/setup.py
@@ -41,6 +41,7 @@ setup(
     install_requires=[
         "pytest-asyncio>=0.18.3",
         "pip-tools",
+        "black",
     ],
     extras_require={
         "dev": [
diff --git a/sandbox/plc4py/tests/unit/plc4py/spi/configuration/test_configuration.py b/sandbox/plc4py/tests/unit/plc4py/spi/configuration/test_configuration.py
index 08893561f1..c89e40a1b8 100644
--- a/sandbox/plc4py/tests/unit/plc4py/spi/configuration/test_configuration.py
+++ b/sandbox/plc4py/tests/unit/plc4py/spi/configuration/test_configuration.py
@@ -20,7 +20,9 @@ from plc4py.spi.configuration.PlcConfiguration import PlcConfiguration
 
 
 def test_configuration_standard_raw_ip():
-    config = PlcConfiguration("profibus:raw://127.0.0.1:4664&host=localhost&mac=01:02:03:04:05:06")
+    config = PlcConfiguration(
+        "profibus:raw://127.0.0.1:4664&host=localhost&mac=01:02:03:04:05:06"
+    )
     assert config.protocol == "profibus"
     assert config.transport == "raw"
     assert config.host == "127.0.0.1"
@@ -29,7 +31,9 @@ def test_configuration_standard_raw_ip():
 
 
 def test_configuration_standard_tcp_localhost():
-    config = PlcConfiguration("profibus:tcp://localhost:4664&host=localhost&mac=01:02:03:04:05:06")
+    config = PlcConfiguration(
+        "profibus:tcp://localhost:4664&host=localhost&mac=01:02:03:04:05:06"
+    )
     assert config.protocol == "profibus"
     assert config.transport == "tcp"
     assert config.host == "localhost"
@@ -38,7 +42,9 @@ def test_configuration_standard_tcp_localhost():
 
 
 def test_configuration_standard_no_transport():
-    config = PlcConfiguration("profibus://localhost:4664&host=localhost&mac=01:02:03:04:05:06")
+    config = PlcConfiguration(
+        "profibus://localhost:4664&host=localhost&mac=01:02:03:04:05:06"
+    )
     assert config.protocol == "profibus"
     assert config.transport == None
     assert config.host == "localhost"
@@ -47,7 +53,9 @@ def test_configuration_standard_no_transport():
 
 
 def test_configuration_standard_second_parameter():
-    config = PlcConfiguration("profibus://localhost:4664&host=localhost&mac=01:02:03:04:05:06")
+    config = PlcConfiguration(
+        "profibus://localhost:4664&host=localhost&mac=01:02:03:04:05:06"
+    )
     assert config.protocol == "profibus"
     assert config.transport == None
     assert config.host == "localhost"
@@ -57,7 +65,9 @@ def test_configuration_standard_second_parameter():
 
 
 def test_configuration_standard_no_port():
-    config = PlcConfiguration("profibus://localhost&host=localhost&mac=01:02:03:04:05:06")
+    config = PlcConfiguration(
+        "profibus://localhost&host=localhost&mac=01:02:03:04:05:06"
+    )
     assert config.protocol == "profibus"
     assert config.transport == None
     assert config.host == "localhost"
diff --git a/sandbox/plc4py/tests/unit/plc4py/spi/tcp/server.py b/sandbox/plc4py/tests/unit/plc4py/spi/tcp/server.py
index 7f92a178ad..6aee4a2645 100644
--- a/sandbox/plc4py/tests/unit/plc4py/spi/tcp/server.py
+++ b/sandbox/plc4py/tests/unit/plc4py/spi/tcp/server.py
@@ -28,10 +28,8 @@ class Server:
     port: int
 
     def __post_init__(self):
-        self._sock = socket.socket(socket.AF_INET,
-                                   socket.SOCK_STREAM)
-        self._sock.setsockopt(socket.SOL_SOCKET,
-                              socket.SO_REUSEADDR, 1)
+        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 
     def __enter__(self):
         self._sock.bind((self.host, self.port))