Skip to content

Commit

Permalink
Merge pull request #951 from tefra/revert-945-avoid-flattening-elements
Browse files Browse the repository at this point in the history
Revert "Avoid flattening elements"
  • Loading branch information
tefra authored Feb 19, 2024
2 parents 853bb04 + 29bb389 commit ebc5a87
Show file tree
Hide file tree
Showing 15 changed files with 264 additions and 180 deletions.
15 changes: 15 additions & 0 deletions docs/codegen/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,21 @@ The style of docstrings to create.
**CLI Option:**
`-ds, --docstring-style [reStructuredText|NumPy|Google|Accessible|Blank]`

### FilterStrategy

When the class analyzer runs, a lot of types, base classes are flattened, leaving a lot
of orphan classes. The filter strategy can be used to remove unused classes.

| Style | Description |
| ----------------- | --------------------------------------------------------------------------- |
| `all` | Generate all simple and complex types. |
| `allGlobals` | Generate global elements and complex types and all referenced simple types. |
| `referredGlobals` | Generate global elements and all referenced simple and complex types. |

**Default Value:** `allGlobals`

**CLI Option:** `-fs, --filter-strategy [all|allGlobals|referredGlobals]`

### RelativeImports

Generate relative instead of absolute imports.
Expand Down
36 changes: 31 additions & 5 deletions tests/codegen/handlers/test_filter_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from xsdata.codegen.container import ClassContainer
from xsdata.codegen.handlers import FilterClasses
from xsdata.models.config import GeneratorConfig
from xsdata.models.config import ClassFilterStrategy, GeneratorConfig
from xsdata.models.enums import Tag
from xsdata.utils.testing import ClassFactory, FactoryTestCase
from xsdata.utils.testing import AttrFactory, ClassFactory, FactoryTestCase


class FilterClassesTests(FactoryTestCase):
Expand All @@ -27,18 +27,44 @@ def test_filter_all_globals(self):

element = ClassFactory.create(tag=Tag.ELEMENT, abstract=True)

expected = [complex_type, enum_1, element]
expected = [complex_type, enum_1]
self.container.extend([complex_type, enum_1, simple_type, enum_2, element])
self.handler.run()
self.assertEqual(expected, list(self.container))

def test_filter_referred_globals(self):
self.container.config.output.filter_strategy = (
ClassFilterStrategy.REFERRED_GLOBALS
)

element_1 = ClassFactory.create(tag=Tag.ELEMENT, attrs=AttrFactory.list(2))
element_2 = ClassFactory.create(tag=Tag.ELEMENT, attrs=AttrFactory.list(2))
enum_1 = ClassFactory.enumeration(2)
element_2.attrs[0].types[0].reference = enum_1.ref

expected = [element_2, enum_1]
self.container.extend([element_1, element_2, enum_1])
self.handler.run()
self.assertEqual(expected, list(self.container))

def test_filter_all(self):
simple_type = ClassFactory.simple_type()
enumeration = ClassFactory.enumeration(2)
complex_type = ClassFactory.elements(2)
self.container.extend([simple_type, enumeration, complex_type])
self.container.config.output.filter_strategy = ClassFilterStrategy.ALL

self.handler.run()
self.assertEqual(3, len(list(self.container)))

@mock.patch("xsdata.codegen.handlers.filter_classes.logger.warning")
def test_run_with_no_global_types(self, mock_warning):
def test_run_with_strategy_not_all_with_no_classes(self, mock_warning):
classes = [ClassFactory.enumeration(2), ClassFactory.simple_type()]
self.container.extend(classes)
self.handler.run()
self.assertEqual(classes, list(self.container))

mock_warning.assert_called_once_with(
"No global types exist, will generate all types.",
"The filter strategy '%s' returned no classes, will generate all types.",
"allGlobals",
)
6 changes: 3 additions & 3 deletions tests/codegen/handlers/test_flatten_class_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ def test_should_remove_extension(self):
self.assertTrue(callback(source, target, extension))

def test_should_flatten_extension(self):
source = ClassFactory.create(tag=Tag.COMPLEX_TYPE)
target = ClassFactory.create(tag=Tag.ELEMENT)
source = ClassFactory.create()
target = ClassFactory.create()

self.assertFalse(self.processor.should_flatten_extension(source, target))

Expand All @@ -407,7 +407,7 @@ def test_should_flatten_extension(self):
self.assertTrue(self.processor.should_flatten_extension(source, target))

# Source is a simple type
source = ClassFactory.simple_type()
source = ClassFactory.create(attrs=[AttrFactory.create(tag=Tag.SIMPLE_TYPE)])
target = ClassFactory.elements(1)
self.assertTrue(self.processor.should_flatten_extension(source, target))

Expand Down
41 changes: 41 additions & 0 deletions tests/codegen/models/test_class.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys

from xsdata.codegen.models import SIMPLE_TYPES
from xsdata.exceptions import CodeGenerationError
from xsdata.models.enums import DataType, Namespace, Tag
from xsdata.utils.namespaces import build_qname
Expand Down Expand Up @@ -101,6 +102,16 @@ def test_property_has_suffix_attr(self):
obj.attrs[1].index = sys.maxsize
self.assertTrue(obj.has_suffix_attr)

def test_property_is_complex(self):
obj = ClassFactory.create(tag=Tag.ELEMENT)
self.assertTrue(obj.is_complex)

obj = ClassFactory.create(tag=Tag.COMPLEX_TYPE)
self.assertTrue(obj.is_complex)

obj = ClassFactory.create(tag=Tag.SIMPLE_TYPE)
self.assertFalse(obj.is_complex)

def test_property_is_element(self):
obj = ClassFactory.create(tag=Tag.ELEMENT)
self.assertTrue(obj.is_element)
Expand All @@ -118,6 +129,21 @@ def test_property_is_enumeration(self):
obj.attrs.clear()
self.assertFalse(obj.is_enumeration)

def test_property_is_global_type(self):
obj = ClassFactory.create(abstract=True, tag=Tag.ELEMENT)
self.assertFalse(obj.is_global_type)

obj = ClassFactory.create(tag=Tag.ELEMENT)
self.assertTrue(obj.is_global_type)

obj = ClassFactory.create(tag=Tag.COMPLEX_TYPE)
obj.extensions.append(ExtensionFactory.create())
self.assertTrue(obj.is_global_type)

obj.extensions.clear()
obj.attrs.append(AttrFactory.create(tag=Tag.EXTENSION))
self.assertFalse(obj.is_global_type)

def test_property_is_restricted(self):
obj = ClassFactory.create()
ext = ExtensionFactory.create(tag=Tag.EXTENSION)
Expand All @@ -128,6 +154,21 @@ def test_property_is_restricted(self):
ext.tag = Tag.RESTRICTION
self.assertTrue(obj.is_restricted)

def test_property_is_simple_type(self):
obj = ClassFactory.elements(2)

self.assertFalse(obj.is_simple_type)

obj.attrs.pop()
self.assertFalse(obj.is_simple_type)

for tag in SIMPLE_TYPES:
obj.attrs[0].tag = tag
self.assertTrue(obj.is_simple_type)

obj.extensions.append(ExtensionFactory.create())
self.assertFalse(obj.is_simple_type)

def test_property_is_group(self):
self.assertTrue(ClassFactory.create(tag=Tag.GROUP).is_group)
self.assertTrue(ClassFactory.create(tag=Tag.ATTRIBUTE_GROUP).is_group)
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen/test_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def test_filter_classes(self):
container = ClassContainer(config=GeneratorConfig())
container.extend([complex_type, enum_1, enum_2, simple_type, element])

expected = [complex_type, enum_1, element]
expected = [complex_type, enum_1]
container.filter_classes()
self.assertEqual(expected, list(container))

Expand Down
10 changes: 0 additions & 10 deletions tests/fixtures/dtd/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
from tests.fixtures.dtd.models.complete_example import (
Blog,
Body,
Origin,
Post,
PostStatus,
Source,
Tag,
Tags,
Title,
)

__all__ = [
"Blog",
"Body",
"Origin",
"Post",
"PostStatus",
"Source",
"Tag",
"Tags",
"Title",
]
60 changes: 5 additions & 55 deletions tests/fixtures/dtd/models/complete_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,64 +3,14 @@
from typing import List, Optional


@dataclass
class Body:
value: str = field(
default="",
metadata={
"required": True,
},
)


@dataclass
class Origin:
value: str = field(
default="",
metadata={
"required": True,
},
)


class PostStatus(Enum):
DRAFT = "draft"
PUBLISHED = "published"


@dataclass
class Source:
value: str = field(
default="",
metadata={
"required": True,
},
)


@dataclass
class Tag:
value: str = field(
default="",
metadata={
"required": True,
},
)


@dataclass
class Title:
value: str = field(
default="",
metadata={
"required": True,
},
)


@dataclass
class Tags:
tag: List[Tag] = field(
tag: List[str] = field(
default_factory=list,
metadata={
"name": "Tag",
Expand Down Expand Up @@ -100,29 +50,29 @@ class Post:
"required": True,
},
)
origin: List[Origin] = field(
origin: List[str] = field(
default_factory=list,
metadata={
"name": "Origin",
"type": "Element",
},
)
source: List[Source] = field(
source: List[str] = field(
default_factory=list,
metadata={
"name": "Source",
"type": "Element",
},
)
title: Optional[Title] = field(
title: Optional[str] = field(
default=None,
metadata={
"name": "Title",
"type": "Element",
"required": True,
},
)
body: Optional[Body] = field(
body: Optional[str] = field(
default=None,
metadata={
"name": "Body",
Expand Down
Loading

0 comments on commit ebc5a87

Please sign in to comment.