diff --git a/README.md b/README.md
index a4d13ad..17d82db 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@
-
-
+
+
Python to PlantUML
@@ -94,18 +94,8 @@ This outputs the following PlantUML content:
```plantuml
@startuml py2puml.domain
-namespace py2puml.domain {
- namespace package {}
- namespace umlclass {}
- namespace umlitem {}
- namespace umlenum {}
- namespace umlrelation {}
-}
-class py2puml.domain.package.Package {
- name: str
- children: List[Package]
- items_number: int
-}
+!pragma useIntermediatePackages false
+
class py2puml.domain.umlclass.UmlAttribute {
name: str
type: str
@@ -135,7 +125,6 @@ class py2puml.domain.umlrelation.UmlRelation {
target_fqn: str
type: RelType
}
-py2puml.domain.package.Package *-- py2puml.domain.package.Package
py2puml.domain.umlclass.UmlClass *-- py2puml.domain.umlclass.UmlAttribute
py2puml.domain.umlitem.UmlItem <|-- py2puml.domain.umlclass.UmlClass
py2puml.domain.umlenum.UmlEnum *-- py2puml.domain.umlenum.Member
@@ -147,7 +136,7 @@ footer Generated by //py2puml//
Using PlantUML, this content is rendered as in this diagram:
-![py2puml domain UML Diagram](https://www.plantuml.com/plantuml/png/ZPD1Yzim48Nl-XLpNbWRUZHxs2M4rj1DbZGzbIN8zcmgAikkD2wO9F-zigqWEw1L3i6HPgJlFUdfsH3NrDKIslvBQxz9rTHSAAPuZQRb9TuKuCG0PaLU_k5776S1IicDkLcGk9RaRT4wRPA18Ut6vMyXAuqgW-_2q2_N_kwgWh0s1zNL1UeCXA9n_iAcdnTamQEApnHTUvAVjNmXqgBeAAoB-dOnDiH9b1aKJIETYBj8gvai07xb6kTtfiMRDWTUM38loV62feVpYNWUMWOXkVq6tNxyLMuO8g7g8gIn9Nd5uQw2e7zSTZX7HJUqqjUU3L2FWElvJRZti6wDafDeb5i_shWb-QvaXtBVjpuMg-ths_P7li-tcmmUu3J5uEAg-URRUfVlNpQhTGPFPr-EUlD4ws-tr0XWcawNU5ZS2W1nVKJoi_EWEjspSxYmo8jyU7oCF5eMoxNV8_BCM2INJsUxKOp68WdnOWAfl5j56CBkl4cd9H8pzj4qX1g-eaBD2IieUaXJjp1DsJEgolvZ_m40)
+![py2puml domain UML Diagram](https://www.plantuml.com/plantuml/png/ZPBFwzf04CNl-rTChu89z1WyA29jeFx0sbCHcIIZBDtTfBkJWgZ_UyUeuSitO7BQnwxpUSzvcGP6pxKrK9s_Ld96HMbHE_MbydYo27MWr35vIuL6fWtcV_140Ove0YcL6mpXqsmaihcFVbapO_OwgvdWeW0SMaeWi1VDvwhLae9rda1MbaRT-gdpksY8-EA717xemBy_UkuLW0u7pCG5S-xbQoPxnwToTl8U_xf6lfadLzjeIJOZtnd_XwQcGG09i92p8TW6zlfl3_HU07J_GNVUaq7MfOksP7QotuOnNoytwv_fBbsl4XZ1vR7icxoag--BRRgRhUQB12RNzgcRiEiWARTFtRY4ilOv7Tej0J3w4t5xqrR-p2OclGsFnkD17vVgwN9o5L2Vc-hfGyAyxtneYZScQk369Sk0-jMnB9ayV2D77faAoCuGny_1E5PJSeMe_m00)
For a full overview of the CLI, run:
@@ -213,6 +202,7 @@ poetry run pytest -v --cov=py2puml --cov-branch --cov-report term-missing --cov-
# Changelog
+* `0.8.1`: delegated the grouping of nested namespaces (see `0.7.0`) to the PlantUML binary, which handles it natively
* `0.8.0`: added support for union types, and github actions (pre-commit hooks + automated tests)
* `0.7.2`: added the current working directory to the import path to make py2puml work in any directory or in native virtual environment (not handled by poetry)
* `0.7.1`: removed obsolete part of documentation: deeply compound types are now well handled (by version `0.7.0`)
diff --git a/py2puml/asserts.py b/py2puml/asserts.py
index 039d774..7bbce4a 100644
--- a/py2puml/asserts.py
+++ b/py2puml/asserts.py
@@ -11,16 +11,29 @@ def assert_py2puml_is_file_content(domain_path: str, domain_module: str, diagram
assert_py2puml_is_stringio(domain_path, domain_module, expected_puml_file)
+def normalize_lines_with_returns(lines_with_returns: Iterable[str]) -> List[str]:
+ '''
+ When comparing contents, each piece of contents can either be:
+ - a formatted string block output by the py2puml command containg line returns
+ - a single line of contents read from a file, each line ending with a line return
+
+ This function normalizes each sequence of contents as a list of string lines,
+ each one finishing without a line return to ease comparison.
+ '''
+ return ''.join(lines_with_returns).split('\n')
+
+
def assert_py2puml_is_stringio(domain_path: str, domain_module: str, expected_content_stream: StringIO):
- # generates the PlantUML documentation
- puml_content = list(py2puml(domain_path, domain_module))
+ puml_content_lines = normalize_lines_with_returns(py2puml(domain_path, domain_module))
+ expected_content_lines = normalize_lines_with_returns(expected_content_stream)
- assert_multilines(puml_content, expected_content_stream)
+ assert_multilines(puml_content_lines, expected_content_lines)
-def assert_multilines(actual_multilines: List[str], expected_multilines: Iterable[str]):
+def assert_multilines(actual_multilines: List[str], expected_multilines: List[str]):
line_index = 0
for line_index, (actual_line, expected_line) in enumerate(zip(actual_multilines, expected_multilines)):
+ # print(f'{actual_line=}\n{expected_line=}')
assert actual_line == expected_line, f'actual and expected contents have changed at line {line_index + 1}: {actual_line=}, {expected_line=}'
assert line_index + 1 == len(actual_multilines), f'actual and expected diagrams have {line_index + 1} lines'
diff --git a/py2puml/cli.py b/py2puml/cli.py
index 21c2450..776a872 100644
--- a/py2puml/cli.py
+++ b/py2puml/cli.py
@@ -16,7 +16,7 @@ def run():
argparser = ArgumentParser(description='Generate PlantUML class diagrams to document your Python application.')
- argparser.add_argument('-v', '--version', action='version', version='py2puml 0.8.0')
+ argparser.add_argument('-v', '--version', action='version', version='py2puml 0.8.1')
argparser.add_argument('path', metavar='path', type=str, help='the filepath to the domain')
argparser.add_argument('module', metavar='module', type=str, help='the module name of the domain', default=None)
diff --git a/py2puml/domain/package.py b/py2puml/domain/package.py
deleted file mode 100644
index 8b5cbd4..0000000
--- a/py2puml/domain/package.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from dataclasses import dataclass, field
-from typing import List
-
-
-@dataclass
-class Package:
- '''A folder or a python module'''
- name: str
- children: List['Package'] = field(default_factory=list)
- items_number: int = 0
diff --git a/py2puml/export/namespace.py b/py2puml/export/namespace.py
deleted file mode 100644
index 3261cd0..0000000
--- a/py2puml/export/namespace.py
+++ /dev/null
@@ -1,98 +0,0 @@
-from typing import Iterable, List, Tuple
-
-from py2puml.domain.package import Package
-from py2puml.domain.umlitem import UmlItem
-
-# templating constants
-INDENT = ' '
-PUML_NAMESPACE_START_TPL = '{indentation}namespace {namespace_name} {{'
-PUML_NAMESPACE_END_TPL = '{indentation}}}\n'
-
-
-def get_or_create_module_package(root_package: Package, domain_parts: List[str]) -> Package:
- '''Returns or create the package containing the tail domain part'''
- package = root_package
- for domain_part in domain_parts:
- domain_package = next(
- (sub_package for sub_package in package.children if sub_package.name == domain_part), None
- )
- if domain_package is None:
- domain_package = Package(domain_part)
- package.children.append(domain_package)
- package = domain_package
- return package
-
-
-def visit_package(package: Package, parent_namespace_names: Tuple[str], indentation_level: int) -> Iterable[str]:
- '''
- Recursively visits the package and its subpackages to produce the PlantUML documentation about the namespace
- '''
- package_with_items = package.items_number > 0
- # prints the namespace if:
- # - it has inner uml_items
- # - OR it has more than one sub-package (if no item and only 1 subpackage, they can be concatenated)
- print_namespace = package_with_items or len(package.children) > 1
- # the indentation for the inner namespace is incremented if the current namespace is printed (because it has uml_items in it)
- # otherwise its package name will be used as a prefix for the inner namespaces
- next_indentation = indentation_level + 1 if print_namespace else indentation_level
- package_with_name = package.name is not None
- namespace_names = parent_namespace_names
-
- # concatenates the package name with the ones of the empty parent parent names
- if package_with_name:
- namespace_names += (package.name, )
-
- # starts the namespace declaration (without an end-of-line line return, we don't know yet whether there is inner content)
- start_of_namespace_line = None
- if print_namespace:
- # initializes the namespace decalaration but not yield yet: we don't know if it should be closed now or if there is inner content
- start_of_namespace_line = PUML_NAMESPACE_START_TPL.format(
- indentation=INDENT * indentation_level, namespace_name='.'.join(namespace_names)
- )
-
- parent_names = () if print_namespace else namespace_names
- has_inner_namespace = False
- for sub_package in package.children:
- for sub_package_line in visit_package(sub_package, parent_names, next_indentation):
- if not has_inner_namespace:
- has_inner_namespace = True
- # ends the start-of-namespace with a line return because some inner namespace is about to be documented
- if print_namespace:
- yield f'{start_of_namespace_line}\n'
- yield sub_package_line
-
- # yields the end-of-namespace brace:
- # - with an indentation if it had sub-packages
- # - right after the opening brace otherwise
- if print_namespace:
- if has_inner_namespace:
- yield PUML_NAMESPACE_END_TPL.format(indentation=INDENT * indentation_level)
- else:
- yield PUML_NAMESPACE_END_TPL.format(indentation=start_of_namespace_line)
-
-
-def build_packages_structure(uml_items: List[UmlItem]) -> Package:
- '''
- Creates the Package arborescent structure with the given UML items with their fully-qualified module names
- '''
- root_package = Package(None)
- for uml_item in uml_items:
- module_package = get_or_create_module_package(root_package, uml_item.fqn.split('.')[:-1])
- module_package.items_number += 1
-
- return root_package
-
-
-def puml_namespace_content(uml_items: List[UmlItem]) -> Iterable[str]:
- '''
- Yields the documentation about the packages structure in the PlantUML syntax
- '''
- root_package = Package(None)
- # creates the Package arborescent structure with the given UML items with their fully-qualified module names
- for uml_item in uml_items:
- class_package = get_or_create_module_package(root_package, uml_item.fqn.split('.')[:-1])
- class_package.items_number += 1
-
- # yields the documentation using a visitor pattern approach
- for namespace_line in visit_package(root_package, (), 0):
- yield namespace_line
diff --git a/py2puml/export/puml.py b/py2puml/export/puml.py
index 21e0a85..bedaecd 100644
--- a/py2puml/export/puml.py
+++ b/py2puml/export/puml.py
@@ -4,15 +4,23 @@
from py2puml.domain.umlenum import UmlEnum
from py2puml.domain.umlitem import UmlItem
from py2puml.domain.umlrelation import UmlRelation
-from py2puml.export.namespace import puml_namespace_content
-PUML_FILE_START = '@startuml {diagram_name}\n'
-PUML_FILE_FOOTER = 'footer Generated by //py2puml//\n'
-PUML_FILE_END = '@enduml\n'
-PUML_ITEM_START_TPL = '{item_type} {item_fqn} {{\n'
-PUML_ATTR_TPL = ' {attr_name}: {attr_type}{staticity}\n'
-PUML_ITEM_END = '}\n'
-PUML_RELATION_TPL = '{source_fqn} {rel_type}-- {target_fqn}\n'
+PUML_FILE_START = '''@startuml {diagram_name}
+!pragma useIntermediatePackages false
+
+'''
+PUML_FILE_FOOTER = '''footer Generated by //py2puml//
+'''
+PUML_FILE_END = '''@enduml
+'''
+PUML_ITEM_START_TPL = '''{item_type} {item_fqn} {{
+'''
+PUML_ATTR_TPL = ''' {attr_name}: {attr_type}{staticity}
+'''
+PUML_ITEM_END = '''}
+'''
+PUML_RELATION_TPL = '''{source_fqn} {rel_type}-- {target_fqn}
+'''
FEATURE_STATIC = ' {static}'
FEATURE_INSTANCE = ''
@@ -21,10 +29,6 @@
def to_puml_content(diagram_name: str, uml_items: List[UmlItem], uml_relations: List[UmlRelation]) -> Iterable[str]:
yield PUML_FILE_START.format(diagram_name=diagram_name)
- # exports the namespaces
- for namespace_line in puml_namespace_content(uml_items):
- yield namespace_line
-
# exports the domain classes and enums
for uml_item in uml_items:
if isinstance(uml_item, UmlEnum):
diff --git a/py2puml/py2puml.domain.puml b/py2puml/py2puml.domain.puml
index 5eeece8..4f1b120 100644
--- a/py2puml/py2puml.domain.puml
+++ b/py2puml/py2puml.domain.puml
@@ -1,16 +1,6 @@
@startuml py2puml.domain
-namespace py2puml.domain {
- namespace package {}
- namespace umlclass {}
- namespace umlitem {}
- namespace umlenum {}
- namespace umlrelation {}
-}
-class py2puml.domain.package.Package {
- name: str
- children: List[Package]
- items_number: int
-}
+!pragma useIntermediatePackages false
+
class py2puml.domain.umlclass.UmlAttribute {
name: str
type: str
@@ -40,7 +30,6 @@ class py2puml.domain.umlrelation.UmlRelation {
target_fqn: str
type: RelType
}
-py2puml.domain.package.Package *-- py2puml.domain.package.Package
py2puml.domain.umlclass.UmlClass *-- py2puml.domain.umlclass.UmlAttribute
py2puml.domain.umlitem.UmlItem <|-- py2puml.domain.umlclass.UmlClass
py2puml.domain.umlenum.UmlEnum *-- py2puml.domain.umlenum.Member
diff --git a/pyproject.toml b/pyproject.toml
index cd4c426..bea4578 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "py2puml"
-version = "0.8.0"
+version = "0.8.1"
description = "Generate PlantUML class diagrams to document your Python application."
keywords = ["class diagram", "PlantUML", "documentation", "inspection", "AST"]
readme = "README.md"
diff --git a/tests/modules/withnestednamespace/plantuml_namespace.txt b/tests/modules/withnestednamespace/plantuml_namespace.txt
deleted file mode 100644
index 745e723..0000000
--- a/tests/modules/withnestednamespace/plantuml_namespace.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace tests.modules.withnestednamespace {
- namespace nomoduleroot.modulechild.leaf {}
- namespace tree {}
- namespace branches.branch {}
- namespace withonlyonesubpackage.underground {
- namespace roots.roots {}
- }
- namespace trunks.trunk {}
-}
diff --git a/tests/modules/withnestednamespace/tests.modules.withnestednamespace.puml b/tests/modules/withnestednamespace/tests.modules.withnestednamespace.puml
index fd02e9f..01569d1 100644
--- a/tests/modules/withnestednamespace/tests.modules.withnestednamespace.puml
+++ b/tests/modules/withnestednamespace/tests.modules.withnestednamespace.puml
@@ -1,13 +1,6 @@
@startuml tests.modules.withnestednamespace
-namespace tests.modules.withnestednamespace {
- namespace nomoduleroot.modulechild.leaf {}
- namespace tree {}
- namespace branches.branch {}
- namespace withonlyonesubpackage.underground {
- namespace roots.roots {}
- }
- namespace trunks.trunk {}
-}
+!pragma useIntermediatePackages false
+
class tests.modules.withnestednamespace.nomoduleroot.modulechild.leaf.CommownLeaf {
color: int
area: float
diff --git a/tests/puml_files/withrootnotincwd.puml b/tests/puml_files/withrootnotincwd.puml
index 8df89bc..8d97c9b 100644
--- a/tests/puml_files/withrootnotincwd.puml
+++ b/tests/puml_files/withrootnotincwd.puml
@@ -1,8 +1,6 @@
@startuml withrootnotincwd
-namespace withrootnotincwd {
- namespace point {}
- namespace segment {}
-}
+!pragma useIntermediatePackages false
+
class withrootnotincwd.point.Point {
x: float
y: float
diff --git a/tests/py2puml/export/test_namespace.py b/tests/py2puml/export/test_namespace.py
deleted file mode 100644
index 6ded9eb..0000000
--- a/tests/py2puml/export/test_namespace.py
+++ /dev/null
@@ -1,144 +0,0 @@
-from typing import Dict, List, Tuple
-
-from pytest import mark
-
-from py2puml.domain.package import Package
-from py2puml.domain.umlitem import UmlItem
-from py2puml.domain.umlrelation import UmlRelation
-from py2puml.export.namespace import build_packages_structure, get_or_create_module_package, visit_package
-from py2puml.inspection.inspectpackage import inspect_package
-
-
-@mark.parametrize(
- ['root_package', 'module_qualified_name'], [
- (Package(None), 'py2puml'),
- (Package(None, [Package('py2puml')]), 'py2puml'),
- (Package(None), 'py2puml.export.namespace'),
- ]
-)
-def test_get_or_create_module_package(root_package: Package, module_qualified_name: str):
- module_parts = module_qualified_name.split('.')
- module_package = get_or_create_module_package(root_package, module_parts)
- assert module_package.name == module_parts[-1], 'the module package has the expected name'
-
- # checks that the hierarchy of intermediary nested packages has been created if necessary
- inner_package = root_package
- for module_name in module_parts:
- inner_package = next(
- child_package for child_package in inner_package.children if child_package.name == module_name
- )
-
- assert inner_package == module_package, f'the module package is contained in the {module_qualified_name} hierarchy'
-
-
-@mark.parametrize(
- ['uml_items', 'items_number_by_package_name'], [
- ([UmlItem('Package', 'py2puml.export.namespace.Package')], {
- 'namespace': 1
- }),
- (
- [
- UmlItem('UmlClass', 'py2puml.domain.umlclass.UmlClass'),
- UmlItem('UmlAttribute', 'py2puml.domain.umlclass.UmlAttribute')
- ], {
- 'umlclass': 2
- }
- ),
- (
- [
- UmlItem('Package', 'py2puml.export.namespace.Package'),
- UmlItem('ImaginaryClass', 'py2puml.domain.ImaginaryClass'),
- UmlItem('UmlClass', 'py2puml.domain.umlclass.UmlClass'),
- UmlItem('UmlAttribute', 'py2puml.domain.umlclass.UmlAttribute')
- ], {
- 'domain': 1,
- 'namespace': 1,
- 'umlclass': 2
- }
- ),
- ]
-)
-def test_build_packages_structure(uml_items: List[UmlItem], items_number_by_package_name: Dict[str, int]):
- root_package = build_packages_structure(uml_items)
-
- # ensures that:
- # - each uml_item has a package for its module
- # - each nested package either has module items or child packages
- for uml_item in uml_items:
- inner_package = root_package
- module_parts = uml_item.fqn.split('.')[:-1]
- for module_name in module_parts:
- inner_package = next(
- child_package for child_package in inner_package.children if child_package.name == module_name
- )
-
- expected_items_number = items_number_by_package_name.get(module_name, 0)
- assert expected_items_number == inner_package.items_number, f'package {module_name} must have {expected_items_number} items, found {inner_package.items_number}'
-
- has_children_packages = len(inner_package.children) > 0
- has_module_items = inner_package.items_number > 0
- assert has_children_packages or has_module_items, f'package {inner_package.name} in hierarchy of {module_parts} has items or children packages'
-
-
-NO_CHILDREN_PACKAGES = []
-
-SAMPLE_ROOT_PACKAGE = Package(
- None, [
- Package(
- 'py2puml', [
- Package(
- 'domain',
- [Package('package', NO_CHILDREN_PACKAGES, 1),
- Package('umlclass', NO_CHILDREN_PACKAGES, 1)]
- ),
- Package('inspection', [Package('inspectclass', NO_CHILDREN_PACKAGES, 1)])
- ]
- )
- ]
-)
-SAMPLE_NAMESPACE_LINES = '''namespace py2puml {
- namespace domain {
- namespace package {}
- namespace umlclass {}
- }
- namespace inspection.inspectclass {}
-}'''
-
-
-@mark.parametrize(
- ['package_to_visit', 'parent_namespace_names', 'indentation_level', 'expected_namespace_lines'],
- [
- (Package(None), (), 0, []), # the root package yields no namespace documentation
- (Package(None, NO_CHILDREN_PACKAGES, 1),
- (), 0, ['namespace {}\n']), # the root package yields namespace documentation if it has uml items
- (Package(None, NO_CHILDREN_PACKAGES, 1), (), 1, [' namespace {}\n']), # indentation level of 1 -> 2 spaces
- (Package(None, NO_CHILDREN_PACKAGES, 1),
- (), 3, [' namespace {}\n']), # indentation level of 3 -> 6 spaces
- (
- Package('umlclass', NO_CHILDREN_PACKAGES, 2),
- ('py2puml', 'domain'), 0, ['namespace py2puml.domain.umlclass {}\n']
- ),
- (SAMPLE_ROOT_PACKAGE, (), 0, (f'{line}\n' for line in SAMPLE_NAMESPACE_LINES.split('\n'))),
- ]
-)
-def test_visit_package(
- package_to_visit: Package, parent_namespace_names: Tuple[str], indentation_level: int,
- expected_namespace_lines: List[str]
-):
- for expected_namespace_line, namespace_line in zip(expected_namespace_lines, visit_package(
- package_to_visit, parent_namespace_names, indentation_level)):
- assert expected_namespace_line == namespace_line
-
-
-def test_build_packages_structure_visit_package_from_tree_package(
- domain_items_by_fqn: Dict[str, UmlItem], domain_relations: List[UmlRelation]
-):
- domain_path = 'tests/modules/withnestednamespace'
- domain_module = 'tests.modules.withnestednamespace'
- inspect_package(domain_path, domain_module, domain_items_by_fqn, domain_relations)
- package = build_packages_structure(domain_items_by_fqn.values())
-
- with open(f'{domain_path}/plantuml_namespace.txt', encoding='utf8') as tree_namespace_file:
- for line_index, (namespace_line, expected_namespace_line) in enumerate(zip(visit_package(package, (), 0),
- tree_namespace_file)):
- assert namespace_line == expected_namespace_line, f'{line_index}: namespace content'
diff --git a/tests/py2puml/test__init__.py b/tests/py2puml/test__init__.py
index 799886b..045ea99 100644
--- a/tests/py2puml/test__init__.py
+++ b/tests/py2puml/test__init__.py
@@ -3,7 +3,7 @@
# Ensures the library version is modified in the pyproject.toml file when upgrading it (pull request)
def test_version():
- assert __version__ == '0.8.0'
+ assert __version__ == '0.8.1'
# Description also output in the CLI
diff --git a/tests/py2puml/test_asserts.py b/tests/py2puml/test_asserts.py
new file mode 100644
index 0000000..f15693e
--- /dev/null
+++ b/tests/py2puml/test_asserts.py
@@ -0,0 +1,22 @@
+from io import StringIO
+from typing import Iterable, List
+
+from pytest import mark
+
+from py2puml.asserts import normalize_lines_with_returns
+
+PY2PUML_HEADER = '''@startuml py2puml.domain
+!pragma useIntermediatePackages false
+'''
+
+
+@mark.parametrize(
+ ['input_lines_with_returns', 'expected_lines'], [
+ (['line'], ['line']),
+ (['line\n'], ['line', '']),
+ ([PY2PUML_HEADER], ['@startuml py2puml.domain', '!pragma useIntermediatePackages false', '']),
+ (StringIO(PY2PUML_HEADER), ['@startuml py2puml.domain', '!pragma useIntermediatePackages false', '']),
+ ]
+)
+def test_normalize_lines_with_returns(input_lines_with_returns: Iterable[str], expected_lines: List[str]):
+ assert normalize_lines_with_returns(input_lines_with_returns) == expected_lines
diff --git a/tests/py2puml/test_py2puml.py b/tests/py2puml/test_py2puml.py
index f4bec28..5621cf0 100644
--- a/tests/py2puml/test_py2puml.py
+++ b/tests/py2puml/test_py2puml.py
@@ -24,10 +24,8 @@ def test_py2puml_with_heavily_nested_model():
def test_py2puml_with_subdomain():
expected = """@startuml tests.modules.withsubdomain
-namespace tests.modules.withsubdomain {
- namespace subdomain.insubdomain {}
- namespace withsubdomain {}
-}
+!pragma useIntermediatePackages false
+
class tests.modules.withsubdomain.subdomain.insubdomain.Engine {
horsepower: int
}