Support type annotations
MShekow opened this issue · 3 comments
There are type annotations such as PEP-484 or PEP-526 which allow to statically type your Python code. Unfortunately, pynsource does not support those. Would it be possible to support them? In the current state, pynsource's use is somewhat limited for me, because it won't detect even simple associations, such as shown in this example:
class Restaurant:
pass
class Customer:
def __init__(self, restaurant: Restaurant):
self.restaurant = restaurant
Best regards!
Thanks for raising this important enhancement proposal. I've been meaning to add this to Pynsource for a while, just waiting for someone to ask for it I guess.
I've just now added support for detecting type annotations on parameters to methods of classes which looks after the use case you have given.
Aside: Ironically, prior to the new commit, declaring the Restaurant
class ahead of the Customer
class would trigger Pynsource to already treat self.restaurant
as a implicit reference to the Restaurant class - without needing type annotations - simply due to the convention that it is the same name with the first letter in uppercase. But with the new commit, you don't need to rely on this dubious convention I had in place, and the correct association is created, due to the restaurant: Restaurant
type annotation.
I've also added type annotation detection to attribute assignments e.g.
class Customer:
def __init__(self, restaurant):
self.restaurant: Restaurant = restaurant
self.fred: Fred
Please let me know if there are any other important use cases where type annotations need to be detected. Bear in mind that Pynsource skips as much Python code (that is being reverse engineered into UML) in its parsing as it can, because traditionally, it has only been interested in 'structure' and there was no need to parse deeply into expressions and bodies of code - saving complexity and time. I'm prepared to start parsing more of the incoming Python code if the use cases are strong enough.
Thanks for getting back to me about this so quickly.
There a few things I find sub-optimal.
First: types are not shown in the diagrams (neither in the "UML" view, nor in the "PlantUML" view. For instance, I would expect the diagram to show the attribute restaurant: Restaurant
and not just restaurant
.
Second: the association arrows (e.g. composition) seem to not have labels in the UML view at all, but they do have the label of the type (rather than the name of the variable) in the PlantUML view (I would expect attributes of this type to not even be part of the class-box, e.g. I would have expected that the Customer
box has only the __init__
method, and no attributes, with a composition-arrow labelled restaurant
that goes from Customer
to the Restaurant
class box.)
Third: consider the following example:
class Mammal:
def __init__(self):
self.some_prop = 1
class Dog(Mammal):
def __init__(self, can_bark: bool):
super().__init__()
self.can_bark = can_bark
class SomeClass:
def __init__(self, other: Dog):
self.other = other
The PlantUML markup is less than optimal:
__init__()
is missing arguments (and their types)- There is a funny
bool
class :) - pynsource could have inferred that the type of
Mammal.some_prop
isint
First: types are not shown in the diagrams (neither in the "UML" view, nor in the "PlantUML" view. For instance, I would expect the diagram to show the attribute restaurant: Restaurant and not just restaurant.
Agreed, this would be a nice feature, have created #77.
Second: the association arrows (e.g. composition) seem to not have labels in the UML view at all, but they do have the label of the type (rather than the name of the variable) in the PlantUML view
Agreed this is not right, have created #78 and disabled line labels in PlantUML view for now, till this is resolved.
Adding labels to lines in UML view would be good too, have created #76.
(I would expect attributes of this type to not even be part of the class-box, e.g. I would have expected that the Customer box has only the init method, and no attributes, with a composition-arrow labelled restaurant that goes from Customer to the Restaurant class box.)
Just because an attribute is visualised as a line, doesn't mean it should disappear from being listed as an attribute of a class. Perhaps your way could be an option at some time in the future.
init() is missing arguments (and their types)
There is a funny bool class :)
pynsource could have inferred that the type of Mammal.some_prop is int
The latest commit fixes the 'funny bool class' issue, and the following built in classes are no longer visualised:
BUILT_IN_TYPES = ('int', 'float', 'bool', 'str', 'bytes', 'List', 'Set', 'Dict', 'Tuple', 'Optional',
'Callable', 'Iterator', 'Union', 'Any', 'Mapping', 'MutableMapping', 'Sequence', 'Iterable', 'Set',
'Match', 'AnyStr', 'IO', 'Callable', 'TypeVar') # I think I identified them all!
As this issue is initially about type annotations, which has been addressed, I am closing this particular issue.
Thanks for the feedback!