Skip to content

Commit 823a7ca

Browse files
committed
draft implementation of methods support.
1 parent 4787c5d commit 823a7ca

File tree

5 files changed

+74
-27
lines changed

5 files changed

+74
-27
lines changed

py2puml/domain/umlclass.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
from inspect import signature
12
from typing import List
2-
from dataclasses import dataclass
3+
from dataclasses import dataclass, field
34

45
from py2puml.domain.umlitem import UmlItem
56

@@ -9,7 +10,15 @@ class UmlAttribute(object):
910
type: str
1011
static: bool
1112

13+
14+
@dataclass
15+
class UmlMethod(object):
16+
name: str
17+
signature: str
18+
19+
1220
@dataclass
1321
class UmlClass(UmlItem):
1422
attributes: List[UmlAttribute]
23+
methods: List[UmlMethod]
1524
is_abstract: bool = False

py2puml/exportpuml.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from inspect import signature
12
from typing import List, Iterable
23

34
from py2puml.domain.umlitem import UmlItem
@@ -9,6 +10,7 @@
910
PUML_FILE_END = '@enduml\n'
1011
PUML_ITEM_START_TPL = '{item_type} {item_fqn} {{\n'
1112
PUML_ATTR_TPL = ' {attr_name}: {attr_type}{staticity}\n'
13+
PUML_METHOD_TPL = ' {name}{signature}\n'
1214
PUML_ITEM_END = '}\n'
1315
PUML_COMPOSITION_TPL = '{source_fqn} {rel_type}-- {target_fqn}\n'
1416

@@ -31,6 +33,8 @@ def to_puml_content(uml_items: List[UmlItem], uml_relations: List[UmlRelation])
3133
yield PUML_ITEM_START_TPL.format(item_type='abstract class' if uml_item.is_abstract else 'class', item_fqn=uml_class.fqn)
3234
for uml_attr in uml_class.attributes:
3335
yield PUML_ATTR_TPL.format(attr_name=uml_attr.name, attr_type=uml_attr.type, staticity=FEATURE_STATIC if uml_attr.static else FEATURE_INSTANCE)
36+
for uml_method in uml_class.methods:
37+
yield PUML_METHOD_TPL.format(name=uml_method.name, signature=uml_method.signature)
3438
yield PUML_ITEM_END
3539
else:
3640
raise TypeError(f'cannot process uml_item of type {uml_item.__class__}')

py2puml/inspection/inspectclass.py

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11

2-
from inspect import isabstract
2+
from inspect import isabstract, signature
3+
import inspect
34
from typing import Type, List, Dict
45

56
from re import compile
67
from dataclasses import dataclass
78

89
from py2puml.domain.umlitem import UmlItem
9-
from py2puml.domain.umlclass import UmlClass, UmlAttribute
10+
from py2puml.domain.umlclass import UmlClass, UmlAttribute, UmlMethod
1011
from py2puml.domain.umlrelation import UmlRelation, RelType
1112
from py2puml.parsing.parseclassconstructor import parse_class_constructor
12-
from py2puml.utils import inspect_domain_definition
1313

1414
CONCRETE_TYPE_PATTERN = compile("^<(?:class|enum) '([\\.|\\w]+)'>$")
1515

@@ -33,20 +33,12 @@ def handle_inheritance_relation(
3333
)
3434

3535
def inspect_static_attributes(
36-
class_type: Type,
3736
class_type_fqn: str,
37+
definition_attrs: List[UmlAttribute],
38+
class_type: Type,
3839
root_module_name: str,
39-
domain_items_by_fqn: Dict[str, UmlItem],
4040
domain_relations: List[UmlRelation]
4141
) -> List[UmlAttribute]:
42-
definition_attrs: List[UmlAttribute] = []
43-
uml_class = UmlClass(
44-
name=class_type.__name__,
45-
fqn=class_type_fqn,
46-
attributes=definition_attrs,
47-
is_abstract=isabstract(class_type)
48-
)
49-
domain_items_by_fqn[class_type_fqn] = uml_class
5042
# inspect_domain_definition(class_type)
5143
type_annotations = getattr(class_type, '__annotations__', None)
5244
if type_annotations is not None:
@@ -58,7 +50,7 @@ def inspect_static_attributes(
5850
if attr_class.__module__.startswith(root_module_name):
5951
attr_type = attr_class.__name__
6052
domain_relations.append(
61-
UmlRelation(uml_class.fqn, f'{attr_class.__module__}.{attr_class.__name__}', RelType.COMPOSITION)
53+
UmlRelation(class_type_fqn, f'{attr_class.__module__}.{attr_class.__name__}', RelType.COMPOSITION)
6254
)
6355
else:
6456
attr_type = concrete_type
@@ -73,7 +65,7 @@ def inspect_static_attributes(
7365
if getattr(component_class, '__name__', None) is not None
7466
]
7567
domain_relations.extend([
76-
UmlRelation(uml_class.fqn, f'{component_class.__module__}.{component_class.__name__}', RelType.COMPOSITION)
68+
UmlRelation(class_type_fqn, f'{component_class.__module__}.{component_class.__name__}', RelType.COMPOSITION)
7769
for component_class in component_classes
7870
if component_class.__module__.startswith(root_module_name)
7971
])
@@ -85,16 +77,50 @@ def inspect_static_attributes(
8577

8678
return definition_attrs
8779

80+
def inspect_methods(
81+
definition_methods, class_type,
82+
):
83+
no_dunder = lambda x: not (x[0].startswith('__') or x[0].endswith('__'))
84+
methods = filter(no_dunder, inspect.getmembers(class_type, callable))
85+
for name, method in methods:
86+
signature = inspect.signature(method)
87+
uml_method = UmlMethod(
88+
name=name,
89+
signature=str(signature),
90+
)
91+
definition_methods.append(uml_method)
92+
93+
94+
def handle_class_type(
95+
class_type: Type,
96+
class_type_fqn: str,
97+
domain_items_by_fqn: Dict[str, UmlItem],
98+
) -> UmlClass:
99+
definition_attrs: List[UmlAttribute] = []
100+
definition_methods: List[UmlMethod] = []
101+
uml_class = UmlClass(
102+
name=class_type.__name__,
103+
fqn=class_type_fqn,
104+
attributes=definition_attrs,
105+
methods=definition_methods,
106+
is_abstract=isabstract(class_type)
107+
)
108+
domain_items_by_fqn[class_type_fqn] = uml_class
109+
return uml_class
110+
88111
def inspect_class_type(
89112
class_type: Type,
90113
class_type_fqn: str,
91114
root_module_name: str,
92115
domain_items_by_fqn: Dict[str, UmlItem],
93116
domain_relations: List[UmlRelation]
94117
):
118+
uml_class = handle_class_type(class_type, class_type_fqn, domain_items_by_fqn)
95119
attributes = inspect_static_attributes(
96-
class_type, class_type_fqn, root_module_name,
97-
domain_items_by_fqn, domain_relations
120+
class_type_fqn, uml_class.attributes, class_type, root_module_name, domain_relations
121+
)
122+
inspect_methods(
123+
uml_class.methods, class_type
98124
)
99125
instance_attributes, compositions = parse_class_constructor(class_type, class_type_fqn, root_module_name)
100126
attributes.extend(instance_attributes)
@@ -103,19 +129,20 @@ def inspect_class_type(
103129
handle_inheritance_relation(class_type, class_type_fqn, root_module_name, domain_relations)
104130

105131
def inspect_dataclass_type(
106-
class_type: Type[dataclass],
132+
class_type: Type,
107133
class_type_fqn: str,
108134
root_module_name: str,
109135
domain_items_by_fqn: Dict[str, UmlItem],
110136
domain_relations: List[UmlRelation]
111137
):
112-
for attribute in inspect_static_attributes(
113-
class_type,
114-
class_type_fqn,
115-
root_module_name,
116-
domain_items_by_fqn,
117-
domain_relations
118-
):
138+
uml_class = handle_class_type(class_type, class_type_fqn, domain_items_by_fqn)
139+
attributes = inspect_static_attributes(
140+
class_type_fqn, uml_class.attributes, class_type, root_module_name, domain_relations
141+
)
142+
inspect_methods(
143+
uml_class.methods, class_type
144+
)
145+
for attribute in attributes:
119146
attribute.static = False
120147

121148
handle_inheritance_relation(class_type, class_type_fqn, root_module_name, domain_relations)

py2puml/inspection/inspectnamedtuple.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ def inspect_namedtuple_type(
1616
attributes=[
1717
UmlAttribute(tuple_field, 'Any', False)
1818
for tuple_field in namedtuple_type._fields
19-
]
19+
],
20+
methods=[],
2021
)

py2puml/py2puml.domain.puml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ class py2puml.domain.umlclass.UmlAttribute {
66
}
77
class py2puml.domain.umlclass.UmlClass {
88
attributes: List[UmlAttribute]
9+
methods: List[UmlMethod]
910
is_abstract: bool
1011
}
1112
class py2puml.domain.umlitem.UmlItem {
1213
name: str
1314
fqn: str
1415
}
16+
class py2puml.domain.umlclass.UmlMethod {
17+
name: str
18+
signature: str
19+
}
1520
class py2puml.domain.umlenum.Member {
1621
name: str
1722
value: str
@@ -29,6 +34,7 @@ class py2puml.domain.umlrelation.UmlRelation {
2934
type: RelType
3035
}
3136
py2puml.domain.umlclass.UmlClass *-- py2puml.domain.umlclass.UmlAttribute
37+
py2puml.domain.umlclass.UmlClass *-- py2puml.domain.umlclass.UmlMethod
3238
py2puml.domain.umlitem.UmlItem <|-- py2puml.domain.umlclass.UmlClass
3339
py2puml.domain.umlenum.UmlEnum *-- py2puml.domain.umlenum.Member
3440
py2puml.domain.umlitem.UmlItem <|-- py2puml.domain.umlenum.UmlEnum

0 commit comments

Comments
 (0)