Skip to content

Commit da53f1a

Browse files
committed
Refactor: Move object version checking and migration logic to check_version.py.
Uses the onDocumentRestored() callback to check and migrate object versions when a document is loaded, instead of doing this in the execute() method of each feature. Pros: - ensures that objects are updated as soon as they are loaded, and avoids unnecessary checks during execution. Cons: - Forces all objects from older workbenches to be migrated when a document is loaded, rather than only when modified. diff --git a/freecad/gridfinity_workbench/check_version.py b/freecad/gridfinity_workbench/check_version.py new file mode 100644 index 0000000..48ad36d --- /dev/null +++ b/freecad/gridfinity_workbench/check_version.py @@ -0,0 +1,98 @@ +"""Feature modules contain bins an baseplate objects.""" + +# ruff: noqa: D101, D102, D107 + +import FreeCAD as fc # noqa: N813 + +from . import const +from .version import __version__ + + +def check_object_version(obj: fc.DocumentObject) -> bool: + """Check if the object's version matches the current version of the Gridfinity Workbench. + + Returns False if the object's version is different from the current version, indicating that + the object needs to be updated. + """ + return str(getattr(obj, "version", "")) == __version__ + + +def migrate_object_version(obj: fc.DocumentObject) -> None: # noqa: C901 + """Update an object from an older version to the current version. + + This function will check the version of the object against the current + Gridfinity Workbench version. If they are different, it will update the + object to the current version. + """ + if check_object_version(obj): + return + + def versiontuple(v: str) -> tuple[int, ...]: + return tuple(map(int, (v.split(".")))) + + migrated = False + if versiontuple(obj.version) < versiontuple("0.11.9"): + migrated = True + # v0.11.9: Changes to the magnet properties. + if not hasattr(obj, "CrushRibsCount"): + obj.addProperty( + "App::PropertyInteger", + "CrushRibsCount", + "GridfinityNonStandard", + "Number of crush ribs <br><br> default = 12", + ).CrushRibsCount = const.CRUSH_RIB_N + if not hasattr(obj, "CrushRibsWaviness"): + obj.addProperty( + "App::PropertyFloatConstraint", + "CrushRibsWaviness", + "GridfinityNonStandard", + "Waviness of crush ribs, from range [0, 1]", + ).CrushRibsWaviness = (const.CRUSH_RIB_WAVINESS, 0, 1, 0.05) + + # v0.11.9: MagnetRelief property was renamed to MagnetRemoveChannel + if not hasattr(obj, "MagnetRemoveChannel"): + obj.addProperty( + "App::PropertyBool", + "MagnetRemoveChannel", + "GridfinityNonStandard", + "Toggle the magnet hole remove channel on or off, only used if magnet holes are on", + ).MagnetRemoveChannel = getattr(obj, "MagnetRelief", False) + if hasattr(obj, "MagnetRelief"): + obj.removeProperty("MagnetRelief") + + if versiontuple(obj.version) < versiontuple("0.12.0"): + migrated = True + # v0.12.0: calculation of UsableHeight was changed to use object Expressions. + obj.setExpression("UsableHeight", "TotalHeight - HeightUnitValue") + + # v0.12.0: xGridUnits and yGridUnits were changed from int to float properties. + xgridunits = getattr(obj, "xGridUnits", None) + if xgridunits is None or isinstance(xgridunits, int): + obj.removeProperty("xGridUnits") + obj.addProperty( + "App::PropertyFloat", + "xGridUnits", + "Gridfinity", + "Number of grid units in the x direction <br> <br> default = 2", + ).xGridUnits = float(xgridunits or const.X_GRID_UNITS) + + ygridunits = getattr(obj, "yGridUnits", None) + if ygridunits is None or isinstance(ygridunits, int): + obj.removeProperty("yGridUnits") + obj.addProperty( + "App::PropertyFloat", + "yGridUnits", + "Gridfinity", + "Number of grid units in the y direction <br> <br> default = 2", + ).yGridUnits = float(ygridunits or const.Y_GRID_UNITS) + + # Update the version property to the current version after updating the object. + obj.version = __version__ + + if migrated: + obj.recompute() # Force re-evaluation of expressions after updating properties. + fc.Console.PrintLog( + f"Gridfinity Workbench v{__version__}: " + f"updating '{obj.Name}' object properties from version v{obj.version}.\n" + f"'{obj.Name}' will be saved with v{__version__} properties.\n", + ) diff --git a/freecad/gridfinity_workbench/features.py b/freecad/gridfinity_workbench/features.py index 95087de..dd34974 100644 --- a/freecad/gridfinity_workbench/features.py +++ b/freecad/gridfinity_workbench/features.py @@ -8,7 +8,7 @@ import FreeCAD as fc # noqa: N813 import Part from . import baseplate_feature_construction as baseplate_feat -from . import const, grid_initial_layout, label_shelf, utils +from . import check_version, const, grid_initial_layout, label_shelf, utils from . import feature_construction as feat from .custom_shape_features import ( clean_up_layout, @@ -23,58 +23,6 @@ from .version import __version__ unitmm = fc.Units.Quantity("1 mm") -def update_object_properties_from_older_version(obj: fc.DocumentObject) -> None: - """Update an object from an older version to the current version. - - This function should be called in the execute method of each feature, and will check the - version of the object against the current Gridfinity Workbench version. If they are different, - it will update the object to the current version. - """ - def versiontuple(v: str) -> tuple[int, ...]: - return tuple(map(int, (v.split(".")))) - - if versiontuple(obj.version) < versiontuple("0.11.10"): - # v0.11.10: MagnetRelief property was renamed to MagnetRemoveChannel - if not hasattr(obj, "MagnetRemoveChannel"): - obj.addProperty( - "App::PropertyBool", - "MagnetRemoveChannel", - "GridfinityNonStandard", - "Toggle the magnet hole remove channel on or off, only used if magnet holes are on", - ).MagnetRemoveChannel = getattr(obj, "MagnetRelief", False) - if hasattr(obj, "MagnetRelief"): - obj.removeProperty("MagnetRelief") - - if versiontuple(obj.version) < versiontuple("0.12.0"): - # v0.12.0: calculation of UsableHeight was changed to use object Expressions. - obj.setExpression("UsableHeight", "TotalHeight - HeightUnitValue") - - # v0.12.0: xGridUnits and yGridUnits were changed from int to float properties. - xgridunits = getattr(obj, "xGridUnits", None) - if xgridunits is None or isinstance(xgridunits, int): - obj.removeProperty("xGridUnits") - obj.addProperty( - "App::PropertyFloat", - "xGridUnits", - "Gridfinity", - "Number of grid units in the x direction <br> <br> default = 2", - ).xGridUnits = float(xgridunits or const.X_GRID_UNITS) - - ygridunits = getattr(obj, "yGridUnits", None) - if ygridunits is None or isinstance(ygridunits, int): - obj.removeProperty("yGridUnits") - obj.addProperty( - "App::PropertyFloat", - "yGridUnits", - "Gridfinity", - "Number of grid units in the y direction <br> <br> default = 2", - ).yGridUnits = float(ygridunits or const.Y_GRID_UNITS) - - # Update the version property to the current version after updating the object. - obj.version = __version__ - obj.recompute() # ensure the object is recomputed after updating properties - - class FoundationGridfinity: def __init__(self, obj: fc.DocumentObject) -> None: obj.addProperty( @@ -87,15 +35,10 @@ class FoundationGridfinity: obj.Proxy = self - def execute(self, fp: Part.Feature) -> None: - if str(getattr(fp, "version", "")) != __version__: - fc.Console.PrintLog( - f"Gridfinity Workbench v{__version__}: " - f"updating '{fp.Name}' object properties from version v{fp.version}.\n" - f"'{fp.Name}' will be saved with v{__version__} properties.\n", - ) - update_object_properties_from_older_version(fp) + def onDocumentRestored(self, obj: fc.DocumentObject) -> None: # noqa: N802 + check_version.migrate_object_version(obj) + def execute(self, fp: Part.Feature) -> None: gridfinity_shape = self.generate_gridfinity_shape(fp) if hasattr(fp, "BaseFeature") and fp.BaseFeature is not None:
1 parent 6ecde77 commit da53f1a

2 files changed

Lines changed: 102 additions & 61 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""Feature modules contain bins an baseplate objects."""
2+
3+
# ruff: noqa: D101, D102, D107
4+
5+
import FreeCAD as fc # noqa: N813
6+
7+
from . import const
8+
from .version import __version__
9+
10+
11+
def check_object_version(obj: fc.DocumentObject) -> bool:
12+
"""Check if the object's version matches the current version of the Gridfinity Workbench.
13+
14+
Returns False if the object's version is different from the current version, indicating that
15+
the object needs to be updated.
16+
"""
17+
return str(getattr(obj, "version", "")) == __version__
18+
19+
20+
def migrate_object_version(obj: fc.DocumentObject) -> None: # noqa: C901
21+
"""Update an object from an older version to the current version.
22+
23+
This function will check the version of the object against the current
24+
Gridfinity Workbench version. If they are different, it will update the
25+
object to the current version.
26+
"""
27+
if check_object_version(obj):
28+
return
29+
30+
def versiontuple(v: str) -> tuple[int, ...]:
31+
return tuple(map(int, (v.split("."))))
32+
33+
migrated = False
34+
if versiontuple(obj.version) < versiontuple("0.11.9"):
35+
migrated = True
36+
# v0.11.9: Changes to the magnet properties.
37+
if not hasattr(obj, "CrushRibsCount"):
38+
obj.addProperty(
39+
"App::PropertyInteger",
40+
"CrushRibsCount",
41+
"GridfinityNonStandard",
42+
"Number of crush ribs <br><br> default = 12",
43+
).CrushRibsCount = const.CRUSH_RIB_N
44+
if not hasattr(obj, "CrushRibsWaviness"):
45+
obj.addProperty(
46+
"App::PropertyFloatConstraint",
47+
"CrushRibsWaviness",
48+
"GridfinityNonStandard",
49+
"Waviness of crush ribs, from range [0, 1]",
50+
).CrushRibsWaviness = (const.CRUSH_RIB_WAVINESS, 0, 1, 0.05)
51+
52+
# v0.11.9: MagnetRelief property was renamed to MagnetRemoveChannel
53+
if not hasattr(obj, "MagnetRemoveChannel"):
54+
obj.addProperty(
55+
"App::PropertyBool",
56+
"MagnetRemoveChannel",
57+
"GridfinityNonStandard",
58+
"Toggle the magnet hole remove channel on or off, only used if magnet holes are on",
59+
).MagnetRemoveChannel = getattr(obj, "MagnetRelief", False)
60+
if hasattr(obj, "MagnetRelief"):
61+
obj.removeProperty("MagnetRelief")
62+
63+
if versiontuple(obj.version) < versiontuple("0.12.0"):
64+
migrated = True
65+
# v0.12.0: calculation of UsableHeight was changed to use object Expressions.
66+
obj.setExpression("UsableHeight", "TotalHeight - HeightUnitValue")
67+
68+
# v0.12.0: xGridUnits and yGridUnits were changed from int to float properties.
69+
xgridunits = getattr(obj, "xGridUnits", None)
70+
if xgridunits is None or isinstance(xgridunits, int):
71+
obj.removeProperty("xGridUnits")
72+
obj.addProperty(
73+
"App::PropertyFloat",
74+
"xGridUnits",
75+
"Gridfinity",
76+
"Number of grid units in the x direction <br> <br> default = 2",
77+
).xGridUnits = float(xgridunits or const.X_GRID_UNITS)
78+
79+
ygridunits = getattr(obj, "yGridUnits", None)
80+
if ygridunits is None or isinstance(ygridunits, int):
81+
obj.removeProperty("yGridUnits")
82+
obj.addProperty(
83+
"App::PropertyFloat",
84+
"yGridUnits",
85+
"Gridfinity",
86+
"Number of grid units in the y direction <br> <br> default = 2",
87+
).yGridUnits = float(ygridunits or const.Y_GRID_UNITS)
88+
89+
# Update the version property to the current version after updating the object.
90+
obj.version = __version__
91+
92+
if migrated:
93+
obj.recompute() # Force re-evaluation of expressions after updating properties.
94+
fc.Console.PrintLog(
95+
f"Gridfinity Workbench v{__version__}: "
96+
f"updating '{obj.Name}' object properties from version v{obj.version}.\n"
97+
f"'{obj.Name}' will be saved with v{__version__} properties.\n",
98+
)

freecad/gridfinity_workbench/features.py

Lines changed: 4 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Part
99

1010
from . import baseplate_feature_construction as baseplate_feat
11-
from . import const, grid_initial_layout, label_shelf, utils
11+
from . import check_version, const, grid_initial_layout, label_shelf, utils
1212
from . import feature_construction as feat
1313
from .custom_shape_features import (
1414
clean_up_layout,
@@ -23,58 +23,6 @@
2323
unitmm = fc.Units.Quantity("1 mm")
2424

2525

26-
def update_object_properties_from_older_version(obj: fc.DocumentObject) -> None:
27-
"""Update an object from an older version to the current version.
28-
29-
This function should be called in the execute method of each feature, and will check the
30-
version of the object against the current Gridfinity Workbench version. If they are different,
31-
it will update the object to the current version.
32-
"""
33-
def versiontuple(v: str) -> tuple[int, ...]:
34-
return tuple(map(int, (v.split("."))))
35-
36-
if versiontuple(obj.version) < versiontuple("0.11.10"):
37-
# v0.11.10: MagnetRelief property was renamed to MagnetRemoveChannel
38-
if not hasattr(obj, "MagnetRemoveChannel"):
39-
obj.addProperty(
40-
"App::PropertyBool",
41-
"MagnetRemoveChannel",
42-
"GridfinityNonStandard",
43-
"Toggle the magnet hole remove channel on or off, only used if magnet holes are on",
44-
).MagnetRemoveChannel = getattr(obj, "MagnetRelief", False)
45-
if hasattr(obj, "MagnetRelief"):
46-
obj.removeProperty("MagnetRelief")
47-
48-
if versiontuple(obj.version) < versiontuple("0.12.0"):
49-
# v0.12.0: calculation of UsableHeight was changed to use object Expressions.
50-
obj.setExpression("UsableHeight", "TotalHeight - HeightUnitValue")
51-
52-
# v0.12.0: xGridUnits and yGridUnits were changed from int to float properties.
53-
xgridunits = getattr(obj, "xGridUnits", None)
54-
if xgridunits is None or isinstance(xgridunits, int):
55-
obj.removeProperty("xGridUnits")
56-
obj.addProperty(
57-
"App::PropertyFloat",
58-
"xGridUnits",
59-
"Gridfinity",
60-
"Number of grid units in the x direction <br> <br> default = 2",
61-
).xGridUnits = float(xgridunits or const.X_GRID_UNITS)
62-
63-
ygridunits = getattr(obj, "yGridUnits", None)
64-
if ygridunits is None or isinstance(ygridunits, int):
65-
obj.removeProperty("yGridUnits")
66-
obj.addProperty(
67-
"App::PropertyFloat",
68-
"yGridUnits",
69-
"Gridfinity",
70-
"Number of grid units in the y direction <br> <br> default = 2",
71-
).yGridUnits = float(ygridunits or const.Y_GRID_UNITS)
72-
73-
# Update the version property to the current version after updating the object.
74-
obj.version = __version__
75-
obj.recompute() # ensure the object is recomputed after updating properties
76-
77-
7826
class FoundationGridfinity:
7927
def __init__(self, obj: fc.DocumentObject) -> None:
8028
obj.addProperty(
@@ -87,15 +35,10 @@ def __init__(self, obj: fc.DocumentObject) -> None:
8735

8836
obj.Proxy = self
8937

90-
def execute(self, fp: Part.Feature) -> None:
91-
if str(getattr(fp, "version", "")) != __version__:
92-
fc.Console.PrintLog(
93-
f"Gridfinity Workbench v{__version__}: "
94-
f"updating '{fp.Name}' object properties from version v{fp.version}.\n"
95-
f"'{fp.Name}' will be saved with v{__version__} properties.\n",
96-
)
97-
update_object_properties_from_older_version(fp)
38+
def onDocumentRestored(self, obj: fc.DocumentObject) -> None: # noqa: N802
39+
check_version.migrate_object_version(obj)
9840

41+
def execute(self, fp: Part.Feature) -> None:
9942
gridfinity_shape = self.generate_gridfinity_shape(fp)
10043

10144
if hasattr(fp, "BaseFeature") and fp.BaseFeature is not None:

0 commit comments

Comments
 (0)