Scripted objects saving attributes/fr: Difference between revisions
(Updating to match new version of source page) |
(Created page with "* [https://forum.freecadweb.org/viewtopic.php?f=18&t=44009 obj.Proxy.Type est un dict, pas une chaîne de caractères], explication de {{incode|__getstate__}} et {{incode|__se...") |
||
(25 intermediate revisions by 2 users not shown) | |||
Line 5: | Line 5: | ||
== Introduction == |
== Introduction == |
||
[[Scripted_objects| |
Les [[Scripted_objects/fr|Objets créés par script]] sont reconstruits à chaque fois qu'un [[File_Format_FCStd/fr|document au format FCStd]] est ouvert. Pour ce faire, le document conserve une référence au module et à la classe Python qui ont été utilisés pour créer l'objet, ainsi que ses propriétés. |
||
Les attributs de la classe utilisée pour créer l'objet peuvent également être enregistrés, c'est-à-dire "sérialisés". Ceci peut être contrôlé par les méthodes {{incode|__getstate__}} et {{incode|__setstate__}} de la classe. |
|||
== |
== Sauvegarde de tous les attributs == |
||
Par défaut, les attributs enregistrés dans une classe d'objets sont ceux du dictionnaire {{incode|__dict__}} de la classe. |
|||
{{Code|code= |
{{Code|code= |
||
Line 36: | Line 36: | ||
}} |
}} |
||
Un objet peut être créé à l'aide de cette classe et il peut être enregistré dans {{FileName|my_document.FCstd}}. Si aucun [[viewprovider/fr|viewprovider]] particulier n'est attribué au nouvel objet, sa classe proxy est simplement définie sur une valeur différente de {{incode|None}}, dans ce cas, sur {{incode|1}}. |
|||
{{Code|code= |
{{Code|code= |
||
import FreeCAD as App |
import FreeCAD as App |
||
Line 54: | Line 54: | ||
}} |
}} |
||
Lorsque nous rouvrons le fichier, nous pouvons inspecter le dictionnaire de la classe de l'objet. |
|||
When we re-open the file we can inspect the dictionary of the object's class. |
|||
{{Code|code= |
{{Code|code= |
||
>>> obj = App.ActiveDocument.Custom |
>>> obj = App.ActiveDocument.Custom |
||
Line 63: | Line 63: | ||
}} |
}} |
||
Nous voyons que tous les attributs qui commencent par {{incode|self}} dans la classe ont été sauvegardés. Ceux-ci peuvent être de différents types, notamment chaîne de caractères, liste, flottant et dictionnaire. Le tuple original pour {{incode|self.color}} a été converti en liste, mais sinon tous les attributs ont été chargés de la même manière. |
|||
== Sauvegarde d'attributs spécifiques == |
|||
== Saving specific attributes == |
|||
Nous pouvons définir une classe similaire à la première, qui implémente des attributs spécifiques à sauvegarder. |
|||
We can define a class similar to the first one, that implements specific attributes to save. |
|||
{{Code|code= |
{{Code|code= |
||
# various_states.py |
# various_states.py |
||
Line 97: | Line 97: | ||
}} |
}} |
||
La valeur de retour de {{incode|__getstate__}} est l'objet qui sera sérialisé. Il peut s'agir d'une valeur unique ou d'un tuple de valeurs. Lorsque l'objet est restauré, la classe appelle la méthode {{incode|__setstate__}}, en passant la variable {{incode|state}} avec le contenu sérialisé. Dans ce cas, {{incode|state}} est un tuple qui est décomposé dans les variables respectives pour reconstruire l'"état" qui existait à l'origine. |
|||
{{Code|code= |
{{Code|code= |
||
state = (self.color, self.width) |
state = (self.color, self.width) |
||
Line 103: | Line 103: | ||
}} |
}} |
||
Nous pouvons créer un objet avec cette classe et enregistrer le document, comme dans l'exemple précédent. Lorsque nous rouvrons le fichier, nous pouvons inspecter le dictionnaire de la classe de l'objet. |
|||
We can create an object with this class, and save the document, just like in the previous example. When we re-open the file we can inspect the dictionary of the object's class. |
|||
{{Code|code= |
{{Code|code= |
||
>>> obj2 = App.ActiveDocument.Custom2 |
>>> obj2 = App.ActiveDocument.Custom2 |
||
Line 112: | Line 112: | ||
}} |
}} |
||
Le tuple original de {{incode|self.color}} a été converti en liste, mais les autres informations ont été récupérées sans problème. Au lieu de restaurer tous les attributs comme dans le cas précédent, seuls les attributs que nous avons spécifiés dans {{incode|__getstate__}} et {{incode|__setstate__}} ont été restaurés. |
|||
== |
== Utilisation == |
||
=== |
=== Identifier le type === |
||
Normalement, les [[scripted_objects/fr|objets créés par script]] devraient utiliser des [[property/fr|propriétés]] pour stocker des informations, car celles-ci sont automatiquement restaurées à l'ouverture du document. |
|||
Cependant, il arrive que la classe restitue des informations internes qui ne sont pas destinées à être modifiées, mais qu'il est utile d'inspecter. |
|||
However, sometimes the class restore internal information which is not intended to be modified, but which is helpful to inspect. |
|||
Par exemple, la plupart des objets de l'[[Draft_Workbench/fr|atelier Draft]] configurent un attribut {{incode|Type}} qui peut être utilisé pour déterminer le type d'objet utilisé. |
|||
{{Code|code= |
{{Code|code= |
||
Line 137: | Line 137: | ||
}} |
}} |
||
Tous les objets ont une propriété {{incode|TypeId}}, mais pour les [[scripted_objects/fr|objets créés par script]], cette propriété n'est pas utile car elle fait toujours référence à la classe C++ parente, par exemple, [[Part_Part2DObject/fr|{{incode|Part::Part2DObjectPython}}]] ou [[Part_Feature/fr|{{incode|Part::FeaturePython}}]]. Par conséquent, le fait d'avoir cet attribut supplémentaire {{incode|Proxy.Type}} dans la classe est utile pour traiter chaque objet d'une manière particulière. |
|||
=== |
=== Migration de l'objet === |
||
Les informations de version peuvent être stockées à l'intérieur de la classe afin de vérifier l'origine d'un objet. |
|||
Version information can be stored inside the class in order to verify the origin of an object. |
|||
{{Code|code= |
{{Code|code= |
||
Line 158: | Line 158: | ||
}} |
}} |
||
Si la structure de la classe change, c'est-à-dire si ses propriétés ou méthodes changent, sont renommées ou supprimées, nous pourrions tester l'attribut version afin de faire migrer l'ancien objet vers un nouvel ensemble de propriétés ou vers une nouvelle classe. Ceci peut être fait en implémentant la méthode {{incode|onDocumentRestored}}, comme expliqué dans [[Scripted_objects_migration/fr|Migration d'objets créés par script]]. |
|||
{{Code|code= |
{{Code|code= |
||
Line 171: | Line 171: | ||
}} |
}} |
||
== |
== Liens == |
||
* [[Scripted_objects| |
* [[Scripted_objects/fr|Objets créés par script]] |
||
* [[Scripted_objects_migration| |
* [[Scripted_objects_migration/fr|Migration d'objets créés par script]] |
||
* [https://forum.freecadweb.org/viewtopic.php?f=10&t=49120 |
* [https://forum.freecadweb.org/viewtopic.php?f=10&t=49120 Discussion sur le forum FreeCAD : Sérialisation des objets scripts : json ou pickle ?] |
||
* [https://forum.freecadweb.org/viewtopic.php?f=18&t=44009 obj.Proxy.Type |
* [https://forum.freecadweb.org/viewtopic.php?f=18&t=44009 obj.Proxy.Type est un dict, pas une chaîne de caractères], explication de {{incode|__getstate__}} et {{incode|__setstate__}} dans le forum. |
||
* [https://docs.python.org/3/library/pickle.html#object.__getstate__ |
* [https://docs.python.org/3/library/pickle.html#object.__getstate__ Le module Pickle] dans la documentation Python. |
||
{{Powerdocnavi{{#translation:}}}} |
{{Powerdocnavi{{#translation:}}}} |
Revision as of 10:18, 5 December 2021
Introduction
Les Objets créés par script sont reconstruits à chaque fois qu'un document au format FCStd est ouvert. Pour ce faire, le document conserve une référence au module et à la classe Python qui ont été utilisés pour créer l'objet, ainsi que ses propriétés.
Les attributs de la classe utilisée pour créer l'objet peuvent également être enregistrés, c'est-à-dire "sérialisés". Ceci peut être contrôlé par les méthodes __getstate__
et __setstate__
de la classe.
Sauvegarde de tous les attributs
Par défaut, les attributs enregistrés dans une classe d'objets sont ceux du dictionnaire __dict__
de la classe.
# various_states.py
class VariousStates:
def __init__(self, obj):
obj.addProperty("App::PropertyLength", "Length")
obj.addProperty("App::PropertyArea", "Area")
obj.Length = 15
obj.Area = 300
obj.Proxy = self
Type = dict()
Type["Version"] = "Custom"
Type["Release"] = "production"
self.Type = Type
self.Type = "Custom"
self.ver = "0.18"
self.color = (0, 0, 1)
self.width = 2.5
def execute(self, obj):
pass
Un objet peut être créé à l'aide de cette classe et il peut être enregistré dans my_document.FCstd. Si aucun viewprovider particulier n'est attribué au nouvel objet, sa classe proxy est simplement définie sur une valeur différente de None
, dans ce cas, sur 1
.
import FreeCAD as App
import various_states
doc = App.newDocument()
doc.FileName = "my_document.FCStd"
obj = doc.addObject("Part::FeaturePython", "Custom")
various_states.VariousStates(obj)
if App.GuiUp:
obj.ViewObject.Proxy = 1
doc.recompute()
doc.save()
Lorsque nous rouvrons le fichier, nous pouvons inspecter le dictionnaire de la classe de l'objet.
>>> obj = App.ActiveDocument.Custom
>>> print(obj.Proxy)
<various_states.VariousStates object at 0x7f0a899bde10>
>>> print(obj.Proxy.__dict__)
{'Type': {'Version': 'Custom', 'Release': 'production'}, 'ver': '0.18', 'color': [0, 0, 1], 'width': 2.5}
Nous voyons que tous les attributs qui commencent par self
dans la classe ont été sauvegardés. Ceux-ci peuvent être de différents types, notamment chaîne de caractères, liste, flottant et dictionnaire. Le tuple original pour self.color
a été converti en liste, mais sinon tous les attributs ont été chargés de la même manière.
Sauvegarde d'attributs spécifiques
Nous pouvons définir une classe similaire à la première, qui implémente des attributs spécifiques à sauvegarder.
# various_states.py
class CustomStates:
def __init__(self, obj):
obj.addProperty("App::PropertyLength", "Length")
obj.addProperty("App::PropertyArea", "Area")
obj.Length = 15
obj.Area = 300
obj.Proxy = self
Type = dict()
Type["Version"] = "Custom"
Type["Release"] = "production"
self.Type = Type
self.ver = "0.18"
self.color = (0, 0, 1)
self.width = 2.5
def execute(self, obj):
pass
def __getstate__(self):
return self.color, self.width
def __setstate__(self, state):
self.color = state[0]
self.width = state[1]
La valeur de retour de __getstate__
est l'objet qui sera sérialisé. Il peut s'agir d'une valeur unique ou d'un tuple de valeurs. Lorsque l'objet est restauré, la classe appelle la méthode __setstate__
, en passant la variable state
avec le contenu sérialisé. Dans ce cas, state
est un tuple qui est décomposé dans les variables respectives pour reconstruire l'"état" qui existait à l'origine.
state = (self.color, self.width)
state = ((0, 0, 1), 2.5)
Nous pouvons créer un objet avec cette classe et enregistrer le document, comme dans l'exemple précédent. Lorsque nous rouvrons le fichier, nous pouvons inspecter le dictionnaire de la classe de l'objet.
>>> obj2 = App.ActiveDocument.Custom2
>>> print(obj2.Proxy)
<various_states.CustomStates object at 0x7fb399496630>
>>> print(obj2.Proxy.__dict__)
{'color': [0, 0, 1], 'width': 2.5}
Le tuple original de self.color
a été converti en liste, mais les autres informations ont été récupérées sans problème. Au lieu de restaurer tous les attributs comme dans le cas précédent, seuls les attributs que nous avons spécifiés dans __getstate__
et __setstate__
ont été restaurés.
Utilisation
Identifier le type
Normalement, les objets créés par script devraient utiliser des propriétés pour stocker des informations, car celles-ci sont automatiquement restaurées à l'ouverture du document.
Cependant, il arrive que la classe restitue des informations internes qui ne sont pas destinées à être modifiées, mais qu'il est utile d'inspecter.
Par exemple, la plupart des objets de l'atelier Draft configurent un attribut Type
qui peut être utilisé pour déterminer le type d'objet utilisé.
class DraftObject:
def __init__(self, obj, _type):
self.Type = _type
def __getstate__(self):
return self.Type
def __setstate__(self, state):
if state:
self.Type = state
Tous les objets ont une propriété TypeId
, mais pour les objets créés par script, cette propriété n'est pas utile car elle fait toujours référence à la classe C++ parente, par exemple, Part::Part2DObjectPython
ou Part::FeaturePython
. Par conséquent, le fait d'avoir cet attribut supplémentaire Proxy.Type
dans la classe est utile pour traiter chaque objet d'une manière particulière.
Migration de l'objet
Les informations de version peuvent être stockées à l'intérieur de la classe afin de vérifier l'origine d'un objet.
class CustomObject:
def __init__(self, obj, _type):
self.Type = _type
self.version = "0.18"
def __getstate__(self):
return self.Type, self.version
def __setstate__(self, state):
if state:
self.Type = state[0]
self.version = state[1]
Si la structure de la classe change, c'est-à-dire si ses propriétés ou méthodes changent, sont renommées ou supprimées, nous pourrions tester l'attribut version afin de faire migrer l'ancien objet vers un nouvel ensemble de propriétés ou vers une nouvelle classe. Ceci peut être fait en implémentant la méthode onDocumentRestored
, comme expliqué dans Migration d'objets créés par script.
class CustomObject:
def onDocumentRestored(self, obj):
if hasattr(obj.Proxy, "version") and obj.Proxy.version:
if obj.Proxy.version == "0.18":
self.migrate_from_018(obj)
def migrate_from_018(self, obj):
...
Liens
- Objets créés par script
- Migration d'objets créés par script
- Discussion sur le forum FreeCAD : Sérialisation des objets scripts : json ou pickle ?
- obj.Proxy.Type est un dict, pas une chaîne de caractères, explication de
__getstate__
et__setstate__
dans le forum. - Le module Pickle dans la documentation Python.
- Scripts FreeCAD : Python, Introduction à Python, Tutoriel sur les scripts Python, Débuter avec les scripts
- Modules : Modules intégrés, Unités, Quantity
- Ateliers : Création d'atelier, Commands Gui, Les commandes, Installer des ateliers supplémentaires
- Maillages et objets Parts : Scripts Mesh, Script de données topologiques, Conversion objet Mesh en Part, PythonOCC
- Objets paramétriques : Objets créés par script, Viewproviders (Icône personnalisée dans l'arborescence)
- Scénographie : Graphe de scène Coin (Inventor), Pivy
- Interface graphique : Création d'interface, Création d'une boite de dialogue (1, 2, 3, 4, 5), PySide, Exemples PySide débutant, intermédiaire, expérimenté
- Macros : Macros, Comment installer des macros
- Intégration : Intégrer FreeCAD, Intégration de FreeCADGui
- Autre : Expressions, Extraits de codes, Fonction - tracer une ligne, Bibliothèque mathématique vectorielle de FreeCAD (déprécié)