Repository: tefra/xsdata
Pull request #986 (2024-03-22 07:48:46)

feat: Add codegen debug messages with performance stats
## 📒 Description

> Write a brief description of your PR.

Resolves #xxxx

## 🔗 What I've Done

> Write a description of the steps taken to resolve the issue

## 💬 Comments

> A place to write any comments to the reviewer.

## 🛫 Checklist

- [ ] Updated docs
- [ ] Added unit-tests
- [ ] [Sample tests](https://github.com/tefra/xsdata-samples) pass
- [ ] [W3C tests](https://github.com/tefra/xsdata-w3c-tests) pass


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=986) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=986&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=986&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=986&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=986&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=986)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/tefra/xsdata/pull/986?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 99.84%. Comparing base [(`059c607`)](https://app.codecov.io/gh/tefra/xsdata/commit/059c607ddbbff332edc3470c2ba979a458db681e?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou) to head [(`f642933`)](https://app.codecov.io/gh/tefra/xsdata/pull/986?dropdown=coverage&src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #986      +/-   ##
==========================================
- Coverage   99.98%   99.84%   -0.15%     
==========================================
  Files         116      117       +1     
  Lines        9116     9140      +24     
  Branches     2166     2174       +8     
==========================================
+ Hits         9115     9126      +11     
- Misses          0       12      +12     
- Partials        1        2       +1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/tefra/xsdata/pull/986?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Chris+Tsou).

sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=986) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=986&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=986&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=986&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=986&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=tefra_xsdata&pullRequest=986)



Patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 44042079..a43928f0 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -8,7 +8,7 @@ repos:
       - id: end-of-file-fixer
       - id: debug-statements
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    rev: v0.3.2
+    rev: v0.3.3
     hooks:
       - id: ruff
         args: [ --fix, --show-fixes ]
diff --git a/xsdata/codegen/container.py b/xsdata/codegen/container.py
index 2a4a8bb5..4207fee2 100644
--- a/xsdata/codegen/container.py
+++ b/xsdata/codegen/container.py
@@ -28,6 +28,7 @@ from xsdata.codegen.handlers import (
 )
 from xsdata.codegen.mixins import ContainerInterface
 from xsdata.codegen.models import Class, Status
+from xsdata.codegen.stopwatch import stopwatch
 from xsdata.codegen.utils import ClassUtils
 from xsdata.codegen.validator import ClassValidator
 from xsdata.models.config import GeneratorConfig
@@ -186,7 +187,8 @@ class ClassContainer(ContainerInterface):
 
     def validate_classes(self):
         """Merge redefined classes."""
-        ClassValidator(self).process()
+        with stopwatch("ClassValidator"):
+            ClassValidator(self).process()
 
     def process_classes(self, step: int):
         """Run the given step processors for all classes.
@@ -210,7 +212,8 @@ class ClassContainer(ContainerInterface):
         """
         target.status = Status(step)
         for processor in self.processors.get(step, []):
-            processor.process(target)
+            with stopwatch(processor.__class__.__name__):
+                processor.process(target)
 
         for inner in target.inner:
             if inner.status < step:
@@ -227,11 +230,13 @@ class ClassContainer(ContainerInterface):
         ]
 
         for designator in designators:
-            designator.run()
+            with stopwatch(designator.__class__.__name__):
+                designator.run()
 
     def filter_classes(self):
         """Filter the classes to be generated."""
-        FilterClasses(self).run()
+        with stopwatch(FilterClasses.__name__):
+            FilterClasses(self).run()
 
     def remove_groups(self):
         """Remove xs:groups and xs:attributeGroups from the container."""
diff --git a/xsdata/codegen/stopwatch.py b/xsdata/codegen/stopwatch.py
new file mode 100644
index 00000000..c28fe353
--- /dev/null
+++ b/xsdata/codegen/stopwatch.py
@@ -0,0 +1,16 @@
+from collections import defaultdict
+from contextlib import contextmanager
+from time import perf_counter_ns
+from typing import Dict, List
+
+
+@contextmanager
+def stopwatch(name: str):
+    """Simple context manager that logs elapsed times."""
+    start_time = perf_counter_ns()
+    yield
+    stop_time = perf_counter_ns()
+    stopwatches[name].append(stop_time - start_time)
+
+
+stopwatches: Dict[str, List[int]] = defaultdict(list)
diff --git a/xsdata/codegen/transformer.py b/xsdata/codegen/transformer.py
index 19c7a743..9e2db8bb 100644
--- a/xsdata/codegen/transformer.py
+++ b/xsdata/codegen/transformer.py
@@ -24,6 +24,7 @@ from xsdata.codegen.models import Class
 from xsdata.codegen.parsers import DtdParser
 from xsdata.codegen.parsers.definitions import DefinitionsParser
 from xsdata.codegen.parsers.schema import SchemaParser
+from xsdata.codegen.stopwatch import stopwatch, stopwatches
 from xsdata.codegen.utils import ClassUtils
 from xsdata.codegen.writer import CodeWriter
 from xsdata.formats.dataclass.models.generics import AnyElement
@@ -142,6 +143,9 @@ class ResourceTransformer:
                 help="Try a different structure style and enabling unnest classes.",
             )
 
+        for name, times in stopwatches.items():
+            logger.debug(f"{name} - {sum(times) / 1e9}s")
+
     def process_sources(self, uris: List[str]):
         """Process a list of resolved URI strings.
 
@@ -278,10 +282,11 @@ class ResourceTransformer:
             )
 
             writer = CodeWriter.from_config(self.config)
-            if self.print:
-                writer.print(classes)
-            else:
-                writer.write(classes)
+            with stopwatch(CodeWriter.__name__):
+                if self.print:
+                    writer.print(classes)
+                else:
+                    writer.write(classes)
 
     def convert_schema(self, schema: Schema):
         """Convert a schema instance to codegen classes.
diff --git a/xsdata/formats/dataclass/models/builders.py b/xsdata/formats/dataclass/models/builders.py
index 6d4a9a58..0e1a71f0 100644
--- a/xsdata/formats/dataclass/models/builders.py
+++ b/xsdata/formats/dataclass/models/builders.py
@@ -131,8 +131,8 @@ class XmlMetaBuilder:
                 attributes[var.qname] = var
             elif var.is_element:
                 elements[var.qname].append(var)
-                if var.wrapper:
-                    wrappers[var.wrapper] = var.qname
+                if var.wrapper_qname:
+                    wrappers[var.wrapper_qname] = var.qname
             elif var.is_elements:
                 choices.append(var)
             elif var.is_attributes:
@@ -403,10 +403,6 @@ class XmlVarBuilder:
         any_type = self.is_any_type(types, xml_type)
         clazz = first(tp for tp in types if self.class_type.is_model(tp))
         namespaces = self.resolve_namespaces(xml_type, namespace, parent_namespace)
-        default_namespace = self.default_namespace(namespaces)
-        qname = build_qname(default_namespace, local_name)
-        if wrapper is not None:
-            wrapper = build_qname(default_namespace, wrapper)
 
         elements = {}
         wildcards = []
@@ -423,7 +419,8 @@ class XmlVarBuilder:
         return XmlVar(
             index=cur_index,
             name=name,
-            qname=qname,
+            local_name=local_name,
+            wrapper=wrapper,
             init=init,
             mixed=mixed,
             format=format_str,
@@ -441,7 +438,6 @@ class XmlVarBuilder:
             wildcards=wildcards,
             namespaces=namespaces,
             xml_type=xml_type,
-            wrapper=wrapper,
         )
 
     def build_choices(
diff --git a/xsdata/formats/dataclass/models/elements.py b/xsdata/formats/dataclass/models/elements.py
index 43919396..4d4284e1 100644
--- a/xsdata/formats/dataclass/models/elements.py
+++ b/xsdata/formats/dataclass/models/elements.py
@@ -18,7 +18,7 @@ from typing import (
 from xsdata.formats.converter import converter
 from xsdata.models.enums import NamespaceType
 from xsdata.utils import collections
-from xsdata.utils.namespaces import local_name, target_uri
+from xsdata.utils.namespaces import build_qname, local_name, target_uri
 
 NoneType = type(None)
 
@@ -55,13 +55,32 @@ class MetaMixin:
         return f"{self.__class__.__qualname__}({', '.join(params)})"
 
 
+def default_namespace(namespaces: Sequence[str]) -> Optional[str]:
+    """Return the first valid namespace uri or None.
+
+    Args:
+        namespaces: A list of namespace options which may include
+            valid uri(s) or a placeholder e.g. ##any, ##other,
+            ##targetNamespace, ##local
+
+    Returns:
+        A namespace uri or None if there isn't any.
+    """
+    for namespace in namespaces:
+        if namespace and not namespace.startswith("#"):
+            return namespace
+
+    return None
+
+
 class XmlVar(MetaMixin):
     """Class field binding metadata.
 
     Args:
         index: Position index of the variable
         name: Name of the variable
-        qname: Namespace-qualified name of the variable
+        local_name: Local name of the variable
+        wrapper: The element wrapper name
         types: Supported types for the variable
         clazz: Target class type
         init: Indicates if the field should be included in the constructor
@@ -79,14 +98,14 @@ class XmlVar(MetaMixin):
         namespaces: List of supported namespaces
         elements: Mapping of qualified name-repeatable elements
         wildcards: List of repeatable wildcards
-        wrapper: Name for the wrapper (applies for list types only)
 
     Attributes:
+        qname: Namespace-qualified name of the variable
+        wrapper_qname: Namespace-qualified name of the variable wrapper
         tokens: Indicates if the field has associated tokens
         list_element: Indicates if the field is a list or tuple element
         namespace_matches: Matching namespaces information
         is_clazz_union: Indicates if the field is a union of multiple types
-        local_name: Local name extracted from the qualified name
         is_text: Indicates if the field represents text content
         is_element: Indicates if the field represents an XML element
         is_elements: Indicates if the field represents a sequence of XML elements
@@ -98,7 +117,8 @@ class XmlVar(MetaMixin):
     __slots__ = (
         "index",
         "name",
-        "qname",
+        "local_name",
+        "wrapper",
         "types",
         "clazz",
         "init",
@@ -115,8 +135,9 @@ class XmlVar(MetaMixin):
         "namespaces",
         "elements",
         "wildcards",
-        "wrapper",
         # Calculated
+        "qname",
+        "wrapper_qname",
         "tokens",
         "list_element",
         "is_text",
@@ -127,15 +148,14 @@ class XmlVar(MetaMixin):
         "is_attributes",
         "namespace_matches",
         "is_clazz_union",
-        "local_name",
-        "wrapper_local_name",
     )
 
     def __init__(
         self,
         index: int,
         name: str,
-        qname: str,
+        local_name: str,
+        wrapper: Optional[str],
         types: Sequence[Type],
         clazz: Optional[Type],
         init: bool,
@@ -153,12 +173,12 @@ class XmlVar(MetaMixin):
         namespaces: Sequence[str],
         elements: Mapping[str, "XmlVar"],
         wildcards: Sequence["XmlVar"],
-        wrapper: Optional[str] = None,
         **kwargs: Any,
     ):
         self.index = index
         self.name = name
-        self.qname = qname
+        self.local_name = local_name
+        self.wrapper = wrapper
         self.types = types
         self.clazz = clazz
         self.init = init
@@ -176,18 +196,18 @@ class XmlVar(MetaMixin):
         self.elements = elements
         self.wildcards = wildcards
         self.wrapper = wrapper
-
         self.factory = factory
         self.tokens_factory = tokens_factory
 
         self.namespace_matches: Optional[Dict[str, bool]] = None
-
         self.is_clazz_union = self.clazz and len(types) > 1
-        self.local_name = local_name(qname)
 
-        self.wrapper_local_name = None
+        namespace = default_namespace(namespaces)
+
+        self.qname = build_qname(namespace, local_name)
+        self.wrapper_qname = None
         if wrapper:
-            self.wrapper_local_name = local_name(wrapper)
+            self.wrapper_qname = build_qname(namespace, wrapper)
 
         self.is_text = False
         self.is_element = False
diff --git a/xsdata/formats/dataclass/parsers/dict.py b/xsdata/formats/dataclass/parsers/dict.py
index 3ef83b1f..7f6f6d37 100644
--- a/xsdata/formats/dataclass/parsers/dict.py
+++ b/xsdata/formats/dataclass/parsers/dict.py
@@ -431,7 +431,7 @@ class DictDecoder:
                 is_array = collections.is_array(value)
                 if is_array == var_is_list:
                     return var
-            elif var.wrapper_local_name == key:
+            elif var.wrapper == key:
                 if isinstance(value, dict) and var.local_name in value:
                     val = value[var.local_name]
                     var_is_list = var.list_element or var.tokens
diff --git a/xsdata/formats/dataclass/parsers/tree.py b/xsdata/formats/dataclass/parsers/tree.py
index b8541b7e..72132f01 100644
--- a/xsdata/formats/dataclass/parsers/tree.py
+++ b/xsdata/formats/dataclass/parsers/tree.py
@@ -6,6 +6,7 @@ from xsdata.formats.dataclass.parsers.bases import NodeParser, Parsed
 from xsdata.formats.dataclass.parsers.handlers import default_handler
 from xsdata.formats.dataclass.parsers.mixins import XmlHandler, XmlNode
 from xsdata.formats.dataclass.parsers.nodes.wildcard import WildcardNode
+from xsdata.utils import namespaces
 
 
 @dataclass
@@ -37,9 +38,11 @@ class TreeParser(NodeParser):
             item = queue[-1]
             child = item.child(qname, attrs, ns_map, len(objects))
         except IndexError:
+            namespace, name = namespaces.split_qname(qname)
             var = XmlVar(
-                name=qname,
-                qname=qname,
+                name=name,
+                local_name=name,
+                wrapper=None,
                 xml_type=XmlType.WILDCARD,
                 index=0,
                 types=(object,),
@@ -56,7 +59,7 @@ class TreeParser(NodeParser):
                 nillable=False,
                 sequence=None,
                 default=None,
-                namespaces=(),
+                namespaces=(namespace,),
                 elements={},
                 wildcards=(),
             )
diff --git a/xsdata/formats/dataclass/serializers/dict.py b/xsdata/formats/dataclass/serializers/dict.py
index ec611dc9..0996cde2 100644
--- a/xsdata/formats/dataclass/serializers/dict.py
+++ b/xsdata/formats/dataclass/serializers/dict.py
@@ -100,7 +100,6 @@ class DictEncoder:
                 or not var.is_optional(value)
             ):
                 if var.wrapper:
-                    assert var.wrapper_local_name is not None
-                    yield var.wrapper_local_name, self.encode(value, var)
+                    yield var.wrapper, self.encode(value, var)
                 else:
                     yield var.local_name, self.encode(value, var)
diff --git a/xsdata/formats/dataclass/serializers/mixins.py b/xsdata/formats/dataclass/serializers/mixins.py
index bbdeb7c7..5adede3c 100644
--- a/xsdata/formats/dataclass/serializers/mixins.py
+++ b/xsdata/formats/dataclass/serializers/mixins.py
@@ -413,13 +413,13 @@ class EventGenerator:
             yield XmlWriterEvent.ATTR, key, value
 
         for var, value in self.next_value(obj, meta):
-            if var.wrapper:
-                yield XmlWriterEvent.START, var.wrapper
+            if var.wrapper_qname:
+                yield XmlWriterEvent.START, var.wrapper_qname
 
             yield from self.convert_value(value, var, namespace)
 
-            if var.wrapper:
-                yield XmlWriterEvent.END, var.wrapper
+            if var.wrapper_qname:
+                yield XmlWriterEvent.END, var.wrapper_qname
 
         yield XmlWriterEvent.END, qname
 


Test patch:
diff --git a/tests/formats/dataclass/models/test_builders.py b/tests/formats/dataclass/models/test_builders.py
index bcdba9bc..df539dc0 100644
--- a/tests/formats/dataclass/models/test_builders.py
+++ b/tests/formats/dataclass/models/test_builders.py
@@ -43,7 +43,7 @@ class XmlMetaBuilderTests(FactoryTestCase):
     @mock.patch.object(XmlMetaBuilder, "build_vars")
     def test_build(self, mock_build_vars):
         var = XmlVarFactory.create(
-            xml_type=XmlType.ELEMENT, name="foo", qname="{foo}bar", types=(int,)
+            xml_type=XmlType.ELEMENT, name="foo", namespaces=("foo",), types=(int,)
         )
         mock_build_vars.return_value = [var]
 
@@ -146,7 +146,7 @@ class XmlMetaBuilderTests(FactoryTestCase):
                 xml_type=XmlType.ELEMENT,
                 index=1,
                 name="author",
-                qname="Author",
+                local_name="Author",
                 types=(str,),
                 required=True,
             ),
@@ -154,7 +154,7 @@ class XmlMetaBuilderTests(FactoryTestCase):
                 xml_type=XmlType.ELEMENT,
                 index=2,
                 name="title",
-                qname="Title",
+                local_name="Title",
                 types=(str,),
                 required=True,
             ),
@@ -162,7 +162,7 @@ class XmlMetaBuilderTests(FactoryTestCase):
                 xml_type=XmlType.ELEMENT,
                 index=3,
                 name="genre",
-                qname="Genre",
+                local_name="Genre",
                 types=(str,),
                 required=True,
             ),
@@ -170,7 +170,7 @@ class XmlMetaBuilderTests(FactoryTestCase):
                 xml_type=XmlType.ELEMENT,
                 index=4,
                 name="price",
-                qname="Price",
+                local_name="Price",
                 types=(float,),
                 required=True,
             ),
@@ -178,7 +178,7 @@ class XmlMetaBuilderTests(FactoryTestCase):
                 xml_type=XmlType.ELEMENT,
                 index=5,
                 name="pub_date",
-                qname="PubDate",
+                local_name="PubDate",
                 types=(XmlDate,),
                 required=True,
             ),
@@ -186,18 +186,22 @@ class XmlMetaBuilderTests(FactoryTestCase):
                 xml_type=XmlType.ELEMENT,
                 index=6,
                 name="review",
-                qname="Review",
+                local_name="Review",
                 types=(str,),
                 required=True,
             ),
             XmlVarFactory.create(
-                xml_type=XmlType.ATTRIBUTE, index=7, name="id", qname="ID", types=(str,)
+                xml_type=XmlType.ATTRIBUTE,
+                index=7,
+                name="id",
+                local_name="ID",
+                types=(str,),
             ),
             XmlVarFactory.create(
                 xml_type=XmlType.ATTRIBUTE,
                 index=8,
                 name="lang",
-                qname="LANG",
+                local_name="LANG",
                 types=(str,),
                 init=False,
                 default="en",
@@ -288,7 +292,7 @@ class XmlVarBuilderTests(TestCase):
                 "{bar}a": XmlVarFactory.create(
                     index=2,
                     name="choice",
-                    qname="{bar}a",
+                    local_name="a",
                     types=(TypeA,),
                     clazz=TypeA,
                     factory=list,
@@ -297,7 +301,7 @@ class XmlVarBuilderTests(TestCase):
                 "{bar}b": XmlVarFactory.create(
                     index=3,
                     name="choice",
-                    qname="{bar}b",
+                    local_name="b",
                     types=(TypeB,),
                     clazz=TypeB,
                     factory=list,
@@ -306,7 +310,7 @@ class XmlVarBuilderTests(TestCase):
                 "{bar}int": XmlVarFactory.create(
                     index=4,
                     name="choice",
-                    qname="{bar}int",
+                    local_name="int",
                     types=(int,),
                     factory=list,
                     namespaces=("bar",),
@@ -314,7 +318,7 @@ class XmlVarBuilderTests(TestCase):
                 "{bar}float": XmlVarFactory.create(
                     index=5,
                     name="choice",
-                    qname="{bar}float",
+                    local_name="float",
                     types=(float,),
                     factory=list,
                     namespaces=("bar",),
@@ -322,7 +326,7 @@ class XmlVarBuilderTests(TestCase):
                 "{bar}qname": XmlVarFactory.create(
                     index=6,
                     name="choice",
-                    qname="{bar}qname",
+                    local_name="qname",
                     types=(QName,),
                     factory=list,
                     namespaces=("bar",),
@@ -330,7 +334,7 @@ class XmlVarBuilderTests(TestCase):
                 "{foo}union": XmlVarFactory.create(
                     index=7,
                     name="choice",
-                    qname="{foo}union",
+                    local_name="union",
                     types=(UnionType,),
                     clazz=UnionType,
                     factory=list,
@@ -339,7 +343,7 @@ class XmlVarBuilderTests(TestCase):
                 "{bar}tokens": XmlVarFactory.create(
                     index=8,
                     name="choice",
-                    qname="{bar}tokens",
+                    local_name="tokens",
                     types=(Decimal,),
                     tokens_factory=list,
                     derived=True,
@@ -353,7 +357,7 @@ class XmlVarBuilderTests(TestCase):
                     index=9,
                     name="choice",
                     xml_type=XmlType.WILDCARD,
-                    qname="{http://www.w3.org/1999/xhtml}any",
+                    local_name="any",
                     types=(object,),
                     factory=list,
                     default=None,
diff --git a/tests/formats/dataclass/parsers/nodes/test_element.py b/tests/formats/dataclass/parsers/nodes/test_element.py
index 6aaa0bea..750c21d5 100644
--- a/tests/formats/dataclass/parsers/nodes/test_element.py
+++ b/tests/formats/dataclass/parsers/nodes/test_element.py
@@ -291,7 +291,7 @@ class ElementNodeTests(FactoryTestCase):
         self.assertEqual(fixture("foo"), actual)
 
     def test_child(self):
-        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, qname="a", types=(TypeC,))
+        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="a", types=(TypeC,))
         attrs = {"a": "b"}
         ns_map = {"ns0": "xsdata"}
         position = 1
@@ -305,10 +305,10 @@ class ElementNodeTests(FactoryTestCase):
 
     def test_child_with_unique_element(self):
         single = XmlVarFactory.create(
-            index=1, xml_type=XmlType.ELEMENT, qname="cc", types=(TypeC,)
+            index=1, xml_type=XmlType.ELEMENT, name="cc", types=(TypeC,)
         )
         wildcard = XmlVarFactory.create(
-            index=2, xml_type=XmlType.WILDCARD, qname="cc", types=(object,)
+            index=2, xml_type=XmlType.WILDCARD, name="cc", types=(object,)
         )
         self.meta.elements[single.qname] = [single]
         self.meta.wildcards.append(wildcard)
@@ -328,8 +328,8 @@ class ElementNodeTests(FactoryTestCase):
     @mock.patch.object(ElementNode, "build_node")
     def test_child_when_failed_to_build_next_node(self, mock_build_node):
         mock_build_node.return_value = None
-        element = XmlVarFactory.create(xml_type=XmlType.ELEMENT, qname="a")
-        wildcard = XmlVarFactory.create(xml_type=XmlType.WILDCARD, qname="a")
+        element = XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="a")
+        wildcard = XmlVarFactory.create(xml_type=XmlType.WILDCARD, name="a")
 
         self.meta.elements[element.qname] = [element]
         self.meta.wildcards.append(wildcard)
@@ -348,7 +348,6 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="a",
             types=(TypeC, TypeB),
         )
         attrs = {"a": "b"}
@@ -369,7 +368,6 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="a",
             types=(TypeC,),
         )
         xsi_type = "foo"
@@ -396,7 +394,6 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="a",
             types=(TypeB,),
             derived=False,
         )
@@ -419,7 +416,7 @@ class ElementNodeTests(FactoryTestCase):
 
     @mock.patch.object(XmlContext, "fetch")
     def test_build_node_with_dataclass_var_validates_nillable(self, mock_ctx_fetch):
-        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, qname="a", types=(TypeC,))
+        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="a", types=(TypeC,))
         ns_map = {}
         nillable_meta = copy.deepcopy(self.meta)
         nillable_meta.nillable = True
@@ -438,7 +435,6 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="a",
             types=(object,),
             any_type=True,
         )
@@ -457,7 +453,6 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="a",
             types=(object,),
             any_type=True,
         )
@@ -474,7 +469,7 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="aaa",
+            local_name="aaa",
             types=(object,),
             any_type=True,
         )
@@ -491,7 +486,7 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="aaaa",
+            local_name="aaaa",
             types=(object,),
             any_type=True,
         )
@@ -508,7 +503,7 @@ class ElementNodeTests(FactoryTestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
             name="a",
-            qname="a",
+            local_name="a",
             types=(object,),
             any_type=True,
         )
@@ -524,7 +519,7 @@ class ElementNodeTests(FactoryTestCase):
         self.assertFalse(actual.mixed)
 
     def test_build_node_with_wildcard_var(self):
-        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, qname="aaaaa")
+        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, local_name="aaaaa")
         var.process_contents = "skip"
 
         actual = self.node.build_node(var.qname, var, {}, {}, 10)
@@ -535,7 +530,7 @@ class ElementNodeTests(FactoryTestCase):
 
     def test_build_node_with_primitive_var(self):
         var = XmlVarFactory.create(
-            xml_type=XmlType.TEXT, qname="a", types=(int,), default=100
+            xml_type=XmlType.TEXT, name="a", types=(int,), default=100
         )
         attrs = {"a": "b"}
         ns_map = {"ns0": "xsdata"}
diff --git a/tests/formats/dataclass/parsers/nodes/test_primitive.py b/tests/formats/dataclass/parsers/nodes/test_primitive.py
index a644789f..5e8f76d0 100644
--- a/tests/formats/dataclass/parsers/nodes/test_primitive.py
+++ b/tests/formats/dataclass/parsers/nodes/test_primitive.py
@@ -12,7 +12,7 @@ class PrimitiveNodeTests(TestCase):
     def test_bind(self, mock_parse_value):
         mock_parse_value.return_value = 13
         var = XmlVarFactory.create(
-            xml_type=XmlType.TEXT, name="foo", qname="foo", types=(int,), format="Nope"
+            xml_type=XmlType.TEXT, name="foo", types=(int,), format="Nope"
         )
         ns_map = {"foo": "bar"}
         node = PrimitiveNode(var, ns_map, False)
@@ -32,7 +32,7 @@ class PrimitiveNodeTests(TestCase):
 
     def test_bind_nillable_content(self):
         var = XmlVarFactory.create(
-            xml_type=XmlType.TEXT, name="foo", qname="foo", types=(str,), nillable=False
+            xml_type=XmlType.TEXT, name="foo", types=(str,), nillable=False
         )
         ns_map = {"foo": "bar"}
         node = PrimitiveNode(var, ns_map, False)
@@ -49,7 +49,6 @@ class PrimitiveNodeTests(TestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.TEXT,
             name="foo",
-            qname="foo",
             types=(bytes,),
             nillable=False,
         )
@@ -82,7 +81,7 @@ class PrimitiveNodeTests(TestCase):
         self.assertEqual(13, objects[-1][1])
 
     def test_child(self):
-        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo", qname="foo")
+        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo")
         node = PrimitiveNode(var, {}, False)
 
         with self.assertRaises(XmlContextError):
diff --git a/tests/formats/dataclass/parsers/nodes/test_union.py b/tests/formats/dataclass/parsers/nodes/test_union.py
index 5c233d7f..2bb8c2df 100644
--- a/tests/formats/dataclass/parsers/nodes/test_union.py
+++ b/tests/formats/dataclass/parsers/nodes/test_union.py
@@ -22,7 +22,7 @@ class UnionNodeTests(TestCase):
     def test_child(self):
         attrs = {"id": "1"}
         ns_map = {"ns0": "xsdata"}
-        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo", qname="foo")
+        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo")
         node = UnionNode(
             position=0,
             var=var,
@@ -38,7 +38,7 @@ class UnionNodeTests(TestCase):
         self.assertIsNot(attrs, node.events[0][2])
 
     def test_bind_appends_end_event_when_level_not_zero(self):
-        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo", qname="foo")
+        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo")
         node = UnionNode(
             position=0,
             var=var,
diff --git a/tests/formats/dataclass/parsers/nodes/test_wildcard.py b/tests/formats/dataclass/parsers/nodes/test_wildcard.py
index ba8653d1..c0698ef4 100644
--- a/tests/formats/dataclass/parsers/nodes/test_wildcard.py
+++ b/tests/formats/dataclass/parsers/nodes/test_wildcard.py
@@ -21,7 +21,7 @@ class WildcardNodeTests(TestCase):
             children=[1, 2, 3],
         )
 
-        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo", qname="a")
+        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo", local_name="a")
         node = WildcardNode(
             position=0, var=var, attrs=attrs, ns_map=ns_map, factory=AnyElement
         )
@@ -49,7 +49,7 @@ class WildcardNodeTests(TestCase):
     def test_child(self):
         attrs = {"id": "1"}
         ns_map = {"ns0": "xsdata"}
-        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo", qname="foo")
+        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo")
         node = WildcardNode(
             position=0, var=var, attrs={}, ns_map={}, factory=AnyElement
         )
diff --git a/tests/formats/dataclass/parsers/test_node.py b/tests/formats/dataclass/parsers/test_node.py
index f9e3dc52..0b7452e1 100644
--- a/tests/formats/dataclass/parsers/test_node.py
+++ b/tests/formats/dataclass/parsers/test_node.py
@@ -181,7 +181,7 @@ class NodeParserTests(TestCase):
         parser = NodeParser()
         objects = [("q", "result")]
         queue = []
-        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo", qname="foo")
+        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="foo")
         queue.append(PrimitiveNode(var, {}, False))
 
         self.assertTrue(parser.end(queue, objects, "author", "foobar", None))
diff --git a/tests/formats/dataclass/serializers/test_mixins.py b/tests/formats/dataclass/serializers/test_mixins.py
index 424948ce..2eb2e828 100644
--- a/tests/formats/dataclass/serializers/test_mixins.py
+++ b/tests/formats/dataclass/serializers/test_mixins.py
@@ -373,7 +373,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual("Type '<class 'int'>' is not a dataclass.", str(cm.exception))
 
     def test_convert_mixed_content(self):
-        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, qname="a", mixed=True)
+        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, name="a", mixed=True)
         book = BookForm(id="123")
         ebook = DerivedElement("ebook", BookForm(id="123"))
         value = ["text", AnyElement(qname="br"), book, ebook, "tail"]
@@ -399,7 +399,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
     def test_convert_data(self):
-        var = XmlVarFactory.create(xml_type=XmlType.TEXT, qname="a")
+        var = XmlVarFactory.create(xml_type=XmlType.TEXT, name="a")
         expected = [("data", "123")]
 
         result = self.generator.convert_value("123", var, "xsdata")
@@ -408,7 +408,7 @@ class EventGeneratorTests(TestCase):
 
     def test_convert_tokens(self):
         var = XmlVarFactory.create(
-            xml_type=XmlType.ELEMENT, qname="a", tokens_factory=list
+            xml_type=XmlType.ELEMENT, local_name="a", tokens_factory=list
         )
 
         result = self.generator.convert_value(None, var, "xsdata")
@@ -450,7 +450,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
         var = XmlVarFactory.create(
-            xml_type=XmlType.ELEMENT, qname="a", tokens=True, nillable=True
+            xml_type=XmlType.ELEMENT, name="a", tokens=True, nillable=True
         )
         expected = [
             ("start", "a"),
@@ -463,7 +463,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
     def test_convert_any_type_with_primitive(self):
-        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, qname="a")
+        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, name="a")
         expected = [("data", "str")]
 
         result = self.generator.convert_value("str", var, "xsdata")
@@ -471,7 +471,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
     def test_convert_any_type_with_primitive_element(self):
-        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, qname="a", types=(object,))
+        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="a", types=(object,))
         expected = [
             ("start", "a"),
             ("data", "str"),
@@ -483,7 +483,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
     def test_convert_any_type_with_any_element(self):
-        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, qname="a")
+        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, name="a")
         value = AnyElement(
             qname="a",
             text="b",
@@ -507,7 +507,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
     def test_convert_any_type_with_derived_element_primitive(self):
-        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, qname="a")
+        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, name="a")
         value = DerivedElement(qname="a", value=1)
         expected = [
             ("start", "a"),
@@ -521,7 +521,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
     def test_convert_any_type_with_derived_element_dataclass(self):
-        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, qname="a")
+        var = XmlVarFactory.create(xml_type=XmlType.WILDCARD, name="a")
         value = DerivedElement(
             qname="a", value=BookForm(title="def"), type="{urn:books}BookForm"
         )
@@ -542,7 +542,6 @@ class EventGeneratorTests(TestCase):
     def test_convert_xsi_type(self):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
-            qname="a",
             name="a",
             types=(BookForm,),
         )
@@ -561,7 +560,6 @@ class EventGeneratorTests(TestCase):
     def test_convert_xsi_type_with_derived_class(self):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
-            qname="a",
             name="a",
             types=(BookForm,),
         )
@@ -581,7 +579,6 @@ class EventGeneratorTests(TestCase):
     def test_convert_xsi_type_with_illegal_derived_class(self):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
-            qname="a",
             name="a",
             types=(BookForm,),
         )
@@ -594,7 +591,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual("TypeA is not derived from BookForm", str(cm.exception))
 
     def test_convert_element(self):
-        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, qname="a")
+        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="a")
         expected = [
             ("start", "a"),
             ("data", "123"),
@@ -606,7 +603,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(expected, list(result))
 
     def test_convert_element_with_nillable_true(self):
-        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, qname="a", nillable=True)
+        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="a", nillable=True)
         expected = [
             ("start", "a"),
             ("attr", QNames.XSI_NIL, "true"),
@@ -621,7 +618,6 @@ class EventGeneratorTests(TestCase):
     def test_convert_element_with_any_type_var(self):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
-            qname="a",
             name="a",
             types=(object,),
             any_type=True,
@@ -640,7 +636,6 @@ class EventGeneratorTests(TestCase):
     def test_convert_element_with_any_type_var_ignore_xs_string(self):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENT,
-            qname="a",
             name="a",
             types=(object,),
             any_type=True,
@@ -667,10 +662,9 @@ class EventGeneratorTests(TestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENTS,
             name="compound",
-            qname="compound",
             elements={
                 "a": XmlVarFactory.create(
-                    xml_type=XmlType.ELEMENT, qname="a", types=(int,)
+                    xml_type=XmlType.ELEMENT, name="a", types=(int,)
                 )
             },
         )
@@ -691,7 +685,7 @@ class EventGeneratorTests(TestCase):
             name="compound",
             elements={
                 "a": XmlVarFactory.create(
-                    xml_type=XmlType.ELEMENT, qname="a", types=(SequentialType,)
+                    xml_type=XmlType.ELEMENT, name="a", types=(SequentialType,)
                 )
             },
         )
@@ -710,10 +704,9 @@ class EventGeneratorTests(TestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENTS,
             name="compound",
-            qname="compound",
             elements={
                 "a": XmlVarFactory.create(
-                    xml_type=XmlType.ELEMENT, qname="a", types=(int,)
+                    xml_type=XmlType.ELEMENT, name="a", types=(int,)
                 )
             },
         )
@@ -732,14 +725,12 @@ class EventGeneratorTests(TestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENTS,
             name="compound",
-            qname="compound",
             elements={
                 "a": XmlVarFactory.create(
-                    xml_type=XmlType.ELEMENT, qname="a", types=(int,)
+                    xml_type=XmlType.ELEMENT, name="a", types=(int,)
                 ),
                 "b": XmlVarFactory.create(
                     xml_type=XmlType.ELEMENT,
-                    qname="b",
                     name="b",
                     types=(int,),
                     tokens_factory=list,
@@ -763,10 +754,9 @@ class EventGeneratorTests(TestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENTS,
             name="compound",
-            qname="compound",
             elements={
                 "a": XmlVarFactory.create(
-                    xml_type=XmlType.WILDCARD, qname="a", types=(object,)
+                    xml_type=XmlType.WILDCARD, name="a", types=(object,)
                 )
             },
         )
@@ -786,10 +776,9 @@ class EventGeneratorTests(TestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENTS,
             name="compound",
-            qname="compound",
             elements={
                 "a": XmlVarFactory.create(
-                    xml_type=XmlType.ELEMENT, qname="a", types=(float,)
+                    xml_type=XmlType.ELEMENT, name="a", types=(float,)
                 )
             },
         )
@@ -802,7 +791,7 @@ class EventGeneratorTests(TestCase):
         self.assertEqual(msg, str(cm.exception))
 
     def test_convert_value_with_list_value(self):
-        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, qname="a", factory=list)
+        var = XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="a", factory=list)
         value = [True, False]
         expected = [
             ("start", "a"),
diff --git a/tests/formats/dataclass/test_elements.py b/tests/formats/dataclass/test_elements.py
index b51d23d1..428def91 100644
--- a/tests/formats/dataclass/test_elements.py
+++ b/tests/formats/dataclass/test_elements.py
@@ -24,9 +24,15 @@ class XmlValTests(TestCase):
     def setUp(self) -> None:
         self.context = XmlContext()
 
-    def test_property_local_name(self):
-        var = XmlVarFactory.create(name="a", qname="{B}A")
-        self.assertEqual("A", var.local_name)
+    def test_property_qname(self):
+        var = XmlVarFactory.create(name="a", local_name="A", namespaces=("B",))
+        self.assertEqual("{B}A", var.qname)
+
+    def test_property_wrapper_qname(self):
+        var = XmlVarFactory.create(
+            name="a", local_name="A", wrapper="AA", namespaces=("B",)
+        )
+        self.assertEqual("{B}AA", var.wrapper_qname)
 
     def test_property_clazz(self):
         var = XmlVarFactory.create(name="foo")
@@ -53,14 +59,11 @@ class XmlValTests(TestCase):
         var = XmlVarFactory.create(
             xml_type=XmlType.ELEMENTS,
             name="foo",
-            qname="foo",
             elements={
                 "{a}a": XmlVarFactory.create(
-                    xml_type=XmlType.ELEMENT, name="a", qname="{a}a"
-                ),
-                "b": XmlVarFactory.create(
-                    xml_type=XmlType.ELEMENT, name="b", qname="b"
+                    xml_type=XmlType.ELEMENT, name="a", namespaces=("a",)
                 ),
+                "b": XmlVarFactory.create(xml_type=XmlType.ELEMENT, name="b"),
             },
         )
 
@@ -192,9 +195,9 @@ class XmlMetaTests(TestCase):
         mock_match_namespace.side_effect = [False, False, False, True]
 
         attributes = [
-            XmlVarFactory.create(xml_type=XmlType.ATTRIBUTES, qname="any", name="any"),
+            XmlVarFactory.create(xml_type=XmlType.ATTRIBUTES, name="any"),
             XmlVarFactory.create(
-                xml_type=XmlType.ATTRIBUTES, qname="other", name="any"
+                xml_type=XmlType.ATTRIBUTES, local_name="other", name="any"
             ),
         ]
         self.meta.any_attributes = attributes
@@ -213,7 +216,7 @@ class XmlMetaTests(TestCase):
                 namespaces=["##any"],
                 elements={
                     "{c}root": XmlVarFactory.create(
-                        xml_type=XmlType.ELEMENT, name="root", qname="{c}root"
+                        xml_type=XmlType.ELEMENT, name="root", namespaces=("c",)
                     ),
                 },
             ),
diff --git a/xsdata/utils/testing.py b/xsdata/utils/testing.py
index 6c272846..086a7ed7 100644
--- a/xsdata/utils/testing.py
+++ b/xsdata/utils/testing.py
@@ -379,7 +379,8 @@ class XmlVarFactory(Factory):
     def create(
         cls,
         name: Optional[str] = None,
-        qname: Optional[str] = None,
+        local_name: Optional[str] = None,
+        wrapper: Optional[str] = None,
         index: int = 0,
         types: Optional[Sequence[Type]] = None,
         clazz: Optional[Type] = None,
@@ -403,8 +404,8 @@ class XmlVarFactory(Factory):
     ) -> XmlVar:
         name = name or f"{prefix}{cls.next_letter()}"
 
-        if qname is None:
-            qname = name
+        if local_name is None:
+            local_name = name
 
         if types is None:
             types = ()
@@ -418,7 +419,8 @@ class XmlVarFactory(Factory):
         return XmlVar(
             index=index,
             name=name,
-            qname=qname,
+            local_name=local_name,
+            wrapper=wrapper,
             types=types,
             clazz=clazz or first(tp for tp in types if is_dataclass(tp)),
             init=init,
@@ -437,7 +439,6 @@ class XmlVarFactory(Factory):
             namespaces=namespaces,
             elements=elements,
             wildcards=wildcards,
-            wrapper=None,
         )