-
-
Notifications
You must be signed in to change notification settings - Fork 216
Align with UML Specification: Literals #3749
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There are some issues: * I cannot set default values for attributes in Gaphor
I merge the main branch into this PR. In the process it looks like I introduced an issue: I cannot set a default value on an attribute anymore. |
Thanks @amolenaar - I couldn't figure out the git incantation to do this merge on my machine. I'll take a look and fix the problem. |
In also want to make another attempt. It's a bit of a pity though that all changes are in one commit. If it were multiple smaller commits, merge conflicts are easier to resolve. |
@@ -4,6 +4,8 @@ | |||
|
|||
from __future__ import annotations | |||
|
|||
from decimal import Decimal as UnlimitedNatural |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use Decimal as UnlimitedNatural?
A natural number is whole number right? If so, we can use int
: integers in Python grow and do not overflow, similar to BigInteger
in Java.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The int type can't handle "*". I used Decimal with conversions in and out. Can't see any other way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I could create a type as something like "int | math.inf", that would do the trick, but math.inf is not a type. The only types in Python that can handle infinite values are Decimal and Float. I chose Decimal. Of course, this requires constraining the Decimal input values to int or math.inf, and constraining the Decimal values to str(int(value)) or "*" when converting back to a string. I don't really see any alternatives - do you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use a union type int | typing.Literal["*"]
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. Let me try that.
if self.type is decimal.Decimal and isinstance(value, str): | ||
if value == "*" or value == "inf" or value == "Infinity": | ||
value = decimal.Decimal(math.inf) | ||
else: | ||
value = decimal.Decimal(int(value)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why we need decimal
here. We deal with natural (whole, positive) numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See earlier comment abut UnlimitedNatural. The issue is handling infinite values.
This is bizarre. The test that failed on windows (in the teardown) passes when I run it in the debugger in my development environment (which is where and how I usually run the tests), but it fails when I run it without the debugger! I'm looking at it now. |
gaphor/core/modeling/properties.py
Outdated
if opposite is not None: | ||
self.original.opposite = opposite |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably not change the original opposite relation when a relation is redefined.
I assume the opposite relation should wither point to the original opposite end, or a redefined one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this code, and instead make the relation Property.class_
<-> Class.ownedAttribute
redefined Property.structuredClassifier
<-> StructuredClassifier.ownedAttribute
.
Property.class_
did not redefine Property.structuredClassifier
, but was a subset, whereas Class.ownedAttribute
redefined StructuredClassifier.ownedAttribute
. Both ends should redefine their "super parts" for this to work.
See 3dc4747.
gaphor/UML/recipes.py
Outdated
assoc.ownedEnd = end_a | ||
assoc.ownedEnd = end_b |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why has this changed to ownedEnd
? Shouldn't an association end be at least a memberEnd
of an association? Otherwise Property.association
is not set, which should be set always if a property belongs to an association, if I understand correctly.
Setting ownedEnd
has no effect, since the change is undone by set_navigability
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this: Association.ownedEnd
is set by the set_navigability
function. To my understanding, Property.association
should referenjce the association.
See 3dc4747
Redefined properties should not overwrite opposite end of original Property.class_ pointer to Class.ownedAttribute, but Class.ownedAttribute pointed to Property.structuredClassifier. In case an association is birections, both ends should be redefined.
It's still used for expressions. This reverts commit 56619b6.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can merge this.
The use of decimal.Decimal
is internal, so we can factor that out in a later PR.
@pbrown12303 Thanks again for your help on making Gaphor the best modeling tool out there :) |
@amolenaar You are quite welcome. I hope to add more. Starting my research now... |
This change brings the core structure of Gaphor UML into alignment with the UML 2.5 specification. It does not implement all of the UML specification. There are two significant areas of modification:
<<simpleAttribute>>
stereotype was removed from ValueSpecification. This required implementing the Literal subclasses of ValueSpecification, with the exception of LiteralReal. Attributes that previously referenced ValueSpecifications as simple values have been converted to references to ValueSpecifications. This required updating all code that accessed these references. Recipes have been added to facilitate accessing and updating these references. The scope of this change was fairly broad.StructuredClassifier <--> Property
andProperty <--> Association
are two examples. In both cases, one of the relationships had to be renamed as Gaphor treats the role names as class property names, which led to ambiguity.The storage.py file has been updated to make these changes backwards compatible.
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: #3720, #3517,
What is the new behavior?
Does this PR introduce a breaking change?
Other information