Skip to content

Commit b39dee9

Browse files
doyou89doyou89.junglucsorel
authored
Inspect sub-folders recursively (#8)
* fixed sub-folders recursive inspection, unit tests * skips imports that are not classes * upgraded pytest version, properly separated project and poetry configurations * add __init__.py in tests folder to run pytest in vscode Co-authored-by: doyou89.jung <doyou89.jung@samsung.com> Co-authored-by: Luc Sorel-Giffo <luc.sorel@gmail.com>
1 parent e2270c6 commit b39dee9

File tree

15 files changed

+190
-118
lines changed

15 files changed

+190
-118
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ __pycache__/
44
*.egg-info/
55
*.puml
66
dist/
7+
.vscode/

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ From a given path corresponding to a folder containing python code, `py2puml` lo
3030
3131
* complex type hints with more than one level of genericity are not properly handled for the moment: `List[MyClass]` or `Dict[str, MyClass]` are handled properly, `Dict[str, List[MyClass]]` is not. If your domain classes (also called business objects or DTOs) have attributes with complex type hints, it may be a code smell indicating that you should write a class which would better represent the business logic. But I may improve this part of the library as well 😀
3232

33-
* `py2puml` does not inspect sub-folders recursively, but it is planned
34-
3533
* `py2puml` outputs diagrams in PlantUML syntax, which can be saved in text files along your python code and versioned with them. To generate image files, use the PlantUML runtime or a docker image (see [think/plantuml](https://hub.docker.com/r/think/plantuml))
3634

3735
* `py2puml` uses features of python 3 (generators for example) and thus won't work with python 2 runtimes. It relies on native python modules and uses no 3rd-party library, except [pytest](https://docs.pytest.org/en/latest/) as a development dependency for running the unit-tests
@@ -123,11 +121,16 @@ Which renders like this:
123121
# Tests
124122

125123
```sh
124+
# directly with poetry
125+
poetry run python -m pytest -v
126+
127+
# in a virtual environment
126128
python3 -m pytest -v
127129
```
128130

129131
# Changelog
130132

133+
* `0.3.1`: inspect sub-folders recursively
131134
* `0.3.0`: handle classes derived from namedtuples (attribute types are `any`)
132135
* `0.2.0`: handle inheritance relationships and enums. Unit tested
133136
* `0.1.3`: first release, handle all module of a folder and compositions of domain classes
@@ -139,6 +142,7 @@ Unless stated otherwise all works are licensed under the [MIT license](http://sp
139142
# Contributions
140143

141144
* [Luc Sorel-Giffo](https://github.com/lucsorel)
145+
* [Doyou Jung](https://github.com/doyou89)
142146

143147
Pull-requests are welcome and will be processed on a best-effort basis.
144148

poetry.lock

Lines changed: 86 additions & 94 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

poetry.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[virtualenvs]
2+
create = true
3+
in-project = true

py2puml/parser.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Iterable, Type, List, Dict
22
from types import ModuleType
33
from enum import Enum
4-
from inspect import getmembers
4+
from inspect import getmembers, isclass
55
from re import compile
66

77
from py2puml.domain.umlitem import UmlItem
@@ -11,17 +11,18 @@
1111
from py2puml.utils import inspect_type
1212

1313
CONCRETE_TYPE_PATTERN = compile("^<(?:class|enum) '([\\.|\\w]+)'>$")
14-
1514
def filter_domain_definitions(module: ModuleType, root_module_name: str) -> Iterable[Type]:
1615
for definition_key in dir(module):
1716
definition_type = getattr(module, definition_key)
18-
definition_members = getmembers(definition_type)
19-
definition_module_member = next(
20-
(member for member in definition_members if member[0] == '__module__' and member[1].startswith(root_module_name)),
21-
None
22-
)
23-
if definition_module_member is not None:
24-
yield definition_type
17+
if isclass(definition_type):
18+
definition_members = getmembers(definition_type)
19+
definition_module_member = next((
20+
member for member in definition_members
21+
# ensures that the type belongs to the module being parsed
22+
if member[0] == '__module__' and member[1].startswith(root_module_name)
23+
), None)
24+
if definition_module_member is not None:
25+
yield definition_type
2526

2627
def get_type_name(type: Type, root_module_name: str):
2728
if type.__module__.startswith(root_module_name):

py2puml/py2puml.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@
1212
def py2puml(domain_path: str, domain_module: str) -> Iterable[str]:
1313
domain_items_by_fqdn: Dict[str, UmlItem] = {}
1414
domain_relations: List[UmlRelation] = []
15-
for _, name, is_pkg in walk_packages([domain_path]):
15+
for _, name, is_pkg in walk_packages([domain_path], f'{domain_module}.'):
1616
if not is_pkg:
17-
domain_item_module: ModuleType = import_module(
18-
f'{domain_module}.{name}'
19-
)
17+
domain_item_module: ModuleType = import_module(name)
2018
parse_item_module(
2119
domain_item_module,
2220
domain_module,

0 commit comments

Comments
 (0)