py2puml
py2puml copied to clipboard
feat: parse functions into objects
Mostly looking for feedback/thoughts as I don't think this is quite ready for use as-is.
Here is some example Python-3.8 code:
from dataclasses import dataclass
from enum import Enum
from typing import List, Union
class Foo(Enum):
SPAM: str = "SPAM"
HAM: str = "HAM"
@dataclass
class Bar(Enum):
EGGS: List[str]
def greeting(name: Union[Foo, None]) -> Bar:
if name is None:
return Bar([])
else:
return Bar([name])
which results in the following diagram:

My idea is to represent functions in such a way that the inputs/outputs are clear what class/datatype are being used in the functions. Again, not quite there yet, but motivated to explore this idea if anyone else is 😄
Perhaps the idea diverges too far from py2puml goals, but curious if this community had thoughts.
Thanks for reading!
hi @jakebrinkmann :smiley:
Thank you for your interest and contribution to the library. My original need was to document domain datastructures (dataclasses and namedtuples, mainly), but documenting domain logic seems also interesting (since it is your needs, someone else is likely to need it too).
I think the issue is to find a way to represent a function entity in UML, which I think do not include functions in its modelling approach. In your example we would have liked to find the greeting function in the same py2puml_example.example package, along with Foo and Bar.
Maybe we could use the plantuml Entity or Interface to document functions? What do you think?
What about producing this kind of plantuml code for functions: http://www.plantuml.com/plantuml/uml/LOz1Iu1048NlyoiUT2bGy2Q8Y0Mj7Ie2woGU5XjbGMTZTpr4-DyRFGHT7lCUZ-ynRKmsf7rRYMNVOBp73m7zs_rBTQcQf_DMeGD4qsfZn8CDL--nw_eApowc8QOmqa54JXA7sKwC9J0d9mlg6hSckp6cB8lY3lCkKt9Uq3GNvKFK3BgTuTKBltz_yLXXzfw0FCzLTUzaQqM3Fovf_C-tB9_wooy0
I used the interface type, customized with an F letter (see the Specific Spot section of https://plantuml.com/en/class-diagram):
@startuml
enum Foo {
SPAM: SPAM
HAM: HAM
}
class Bar {
EGGS: List[str]
}
interface greeting << (F,#FF7700) function >> {
Union[Foo, NoneType]: foo
---
Bar
}
Foo -- greeting
Bar -- greeting
@enduml
Oh Wow!! Your version is amazing! I love it!
Only change I could say is possibly wanting to clearly differentiate between inputs and outputs somehow, possibly:
http://www.plantuml.com/plantuml/uml/PT11ImCn40NW-_oA1ruKkajlXQMKAfWgg8Z5K-aXhDCIsCoKP0A2zB-Rhb8AlGnp-CXxcMKsdwp4WLXA17_xU1YuTQhu8M3zVl_QZPE0fzDU1nr1r0y-vxD_y6dqZwlLkiDBoBR9bhPq9A8WncddUpxhVMAs87lCvxXranldPhFfz0wx8hq55ImMusjjYsSv5Cjr8q1yv0wVKiN6gKxmfiBRF_V1LfBymzhcb7pvcQRHgtYwRAzDSmsMB5_rDhy0
slight changes:
- for better items alignment
- and composition arrows
Returninstead ofReturns
http://www.plantuml.com/plantuml/uml/POz1ImCn48NlyoiUUD7IBhqLbbAgOAgW8XPFfOUmJaiWcPHa0eBqlvkkKXRsChp3nxplhRFQf2LuOYa1_6t3oNDZOiGF0Tlt-zUslmGyNN8zT0PHvstEL_x1ffv_t6osBLvSrbtMjASp4JbHJWVRyPK-9cPrSiHoYLiplJ5ciPZFxt0eqgcBWjMg_zOqU9PJqLmJ0M83j_YKIkogu1HlKNZ_ntsmbYJ_OBMvD0_7p2QZTXhfJ6R3GRHc-Ih1_m80
What do you think? Would you be able to produce the code that generates that? And what PlantUML code would you yield for functions that:
- have no inputs?
- return nothing?
hi @jakebrinkmann, how are you?
I am wondering what the state of this PR is? Do you need any help?
I refactored the code base in a pull request that was merged. I can help you resolving the conflicts with this PR, if you want.
hi @jakebrinkmann , It's very interesting contribution.
I have some suggestion about UML representation. According to the definition of the UML relations, I would like to determine the type of relation depending on where the function is called. (This is a different example from above.)
- Passed in init as a parameter
class Foo:
def __init__(self, bar: Bar):
self.bar = bar
The type of relation may be aggregation. (bar may be instantiated at another class)
@startuml
Foo o-- Bar
@enduml
- Instantiated in init
class Foo:
def __init__(self):
self.bar = Bar()
The type of relation may be composition or aggregation. (When the object of Foo is deleted, self.bar deleted also)
@startuml
Foo *-- Bar
@enduml
- Instantiated in a method
class Foo:
def func1(self):
self.func2(Bar()) # instantiated in `func1`
def func2(self, bar: Bar): # passed in `func2` as a parameter
bar.run()
The type of relation is association. (It's temporary relations)
@startuml
Foo ..> Bar
@enduml
hi @doyou89
As far as I understand, @jakebrinkmann' s feature request is related to module functions (functions that take inputs and return outputs, detached from any class or instance), not to class or instance methods. The feature would include those functions alongside other data structures already handled by py2puml (classes, dataclasses, namedtuples, enums).
However, your suggestions could be the basis to improvements of py2puml about the ways associations are drawn between datastructures. I am not a big fan of instantiating components inside the constructor (use case 2.) because it makes unit testing harder.
hi @jakebrinkmann
What is the status of this PR? Do you need some help to finalize it?
hi @jakebrinkmann
I am wondering if you want some help to rebase and merge this PR?
I am interested in getting this done too. maybe we need to align these ideas with https://github.com/lucsorel/py2puml/issues/11 too?