Merge lp:~spud/spud/get-set-manager into lp:spud

Proposed by Patrick Farrell
Status: Merged
Merged at revision: 437
Proposed branch: lp:~spud/spud/get-set-manager
Merge into: lp:spud
Diff against target: 309 lines (+79/-48)
6 files modified
diamond/diamond/interface.py (+29/-41)
diamond/diamond/tree.py (+11/-6)
include/spud (+12/-0)
include/spud.h (+2/-0)
src/spud.cpp (+16/-1)
src/spud_interfaces.cpp (+9/-0)
To merge this branch: bzr merge lp:~spud/spud/get-set-manager
Reviewer Review Type Date Requested Status
Stephan Kramer Approve
Review via email: mp+69652@code.launchpad.net

Description of the change

Changes to support accessing spud data inside python diagnostic fields in Fluidity.

This commit adds two new semi-public functions. I don't want to make these fully public (i.e. documented in the manual etc.) because they are a bit of a hack.

The two functions are spud_get_manager and spud_set_manager. These get and set the core internal data structure of libspud, the manager.options of the OptionManager class.

Why is this necessary? Here's what happens chronologically when we have python code that imports libspud:

* Before the fluidity main, the spud constructor is called on the OptionManager object. It allocates options.manager.
* Fluidity calls load_options and that populates the options.manager.
* We use it happily.
* When we import libspud, it calls the spud constructor *on the same OptionManager object*. It allocates options.manager AGAIN, losing the pointer to where we had our data stored.
* That options.manager has no data, and fluidity soon dies because of a want of options.
* At exit, the destructor gets called TWICE on the same fecking OptionManager.

Now, we modify this sequence of events to:

* Before the fluidity main, the spud constructor is called on the OptionManager object. It allocates options.manager.
* Fluidity calls load_options and that populates the options.manager.
* We use it happily.
* Before we load the Python interpreter, we take a pointer to the current good options.manager via spud_get_manager. We store that pointer in a capsule as fluidity_api._spud_manager.
* When we import libspud, it calls the spud constructor *on the same OptionManager object*. It allocates options.manager AGAIN.
* In the libspud python binding constructor, we fetch the old pointer to the good options manager from the capsule, and set it using spud_set_manager.
* Now we can happily access options from Python, and we haven't lost them from Fortran either.
* At exit, the destructor is called twice, but Patrick has been clever and added a "deallocated" flag so that we only deallocate things once.

Once this is accepted, I will propose the libspud C python bindings for addition, to replace/compliment the ctypes python binding. Once that's done, I will propose the merging of the editions on the fluidity side.

To post a comment you must log in.
Revision history for this message
Stephan Kramer (s-kramer) wrote :

If I understand the story above correctly, and I'm sure that I don't :), "import libspud" will still create a new options manager, except that we use this work around in the libspud python binding to swap it out with the manager we actually want to use. What will then happen with the new manager we're not using? Does it ever get deallocated? Will we not end up with a new unused options manager for every "import spud" that gets evaluated?

lp:~spud/spud/get-set-manager updated
429. By Patrick Farrell

Clean up the previously leaked options.manager.

Revision history for this message
Patrick Farrell (pefarrell) wrote :

That old manager is leaked. If desired, we could make the spud_set_manager free the old one. However, I wasn't worried about it because it is very small, and more importantly does not grow; even if
multiple scripts call import libspud many times, it only actually gets imported by python once (and so the Spud object constructor only gets called twice, no matter how much the python binding is used).

However, I added the call to delete options.manager, so even that one instance is no longer leaked.

Revision history for this message
Stephan Kramer (s-kramer) wrote :

Very good - just thought about it because, afaik we trash the python environment for every python evaluation. Looks good to me

review: Approve
lp:~spud/spud/get-set-manager updated
430. By Patrick Farrell

Merge from the trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'diamond/diamond/interface.py'
2--- diamond/diamond/interface.py 2011-07-28 14:52:55 +0000
3+++ diamond/diamond/interface.py 2011-07-29 09:21:43 +0000
4@@ -283,6 +283,9 @@
5 # if we have a relative path, make it absolute
6 filename = os.path.abspath(filename)
7
8+ if filename == self.filename:
9+ return
10+
11 try:
12 os.stat(filename)
13 except OSError:
14@@ -635,19 +638,12 @@
15 else:
16 return self._get_focus_widget(focus)
17
18- def _handle_clipboard(self, widget, signal):
19- if isinstance(widget, gtk.MenuItem):
20- return False
21- else:
22- widget = self._get_focus_widget(self.main_window)
23- if widget is not self.treeview and gobject.signal_lookup(signal + "-clipboard", widget):
24- widget.emit(signal + "-clipboard")
25- return True
26- return False
27-
28 def on_copy(self, widget=None):
29- if self._handle_clipboard(widget, "copy"):
30- return
31+ if not isinstance(widget, gtk.MenuItem):
32+ widget = self._get_focus_widget(self.main_window)
33+ if widget is not self.treeview and gobject.signal_lookup("copy-clipboard", widget):
34+ widget.emit("copy-clipboard")
35+ return
36
37 if isinstance(self.selected_node, mixedtree.MixedTree):
38 node = self.selected_node.parent
39@@ -666,39 +662,28 @@
40 return
41
42 def on_paste(self, widget=None):
43- if self._handle_clipboard(widget, "paste"):
44- return
45+ if not isinstance(widget, gtk.MenuItem):
46+ widget = self._get_focus_widget(self.main_window)
47+ if widget is not self.treeview and gobject.signal_lookup("paste-clipboard", widget):
48+ widget.emit("paste-clipboard")
49+ return
50
51 clipboard = gtk.clipboard_get()
52 ios = StringIO.StringIO(clipboard.wait_for_text())
53
54 if self.selected_iter is not None:
55- node = self.treestore.get_value(self.selected_iter, 0)
56+ node = self.treestore.get_value(self.selected_iter, 1)
57
58 if node != None:
59-
60- expand = not node.active
61- if expand:
62- self.expand_tree(self.selected_iter)
63
64 newnode = self.s.read(ios, node)
65
66 if newnode is None:
67- if expand:
68- self.collapse_tree(self.selected_iter, False)
69 self.statusbar.set_statusbar("Trying to paste invalid XML.")
70 return
71
72- if node.parent is not None:
73- newnode.set_parent(node.parent)
74- children = node.parent.get_children()
75- children.insert(children.index(node), newnode)
76- children.remove(node)
77-
78- self.set_treestore(self.selected_iter, [newnode], True, True)
79-
80- newnode.recompute_validity()
81- self.treeview.queue_draw()
82+ if not node.active:
83+ self.expand_tree(self.selected_iter)
84
85 # Extract and display validation errors
86 lost_eles, added_eles, lost_attrs, added_attrs = self.s.read_errors()
87@@ -725,6 +710,12 @@
88 dialogs.long_message(self.main_window, msg)
89
90 self.set_saved(False)
91+
92+ self.treeview.freeze_child_notify()
93+ iter = self.set_treestore(self.selected_iter, [newnode], True, True)
94+ self.treeview.thaw_child_notify()
95+
96+ self.treeview.get_selection().select_iter(iter)
97
98 return
99
100@@ -918,7 +909,7 @@
101 if replace:
102 replacediter = iter
103 iter = self.treestore.iter_parent(replacediter)
104- else:
105+ else:
106 self.remove_children(iter)
107
108 for t in new_tree:
109@@ -1130,7 +1121,7 @@
110
111 return
112
113- def collapse_tree(self, iter, confirm = True):
114+ def collapse_tree(self, iter):
115 """
116 Collapses part of the tree.
117 """
118@@ -1158,7 +1149,7 @@
119 self.set_saved(False)
120 self.remove_children(iter)
121 else:
122- self.delete_tree(iter, confirm)
123+ self.delete_tree(iter)
124
125 elif choice_or_tree.cardinality == "+":
126 count = parent_tree.count_children_by_schemaname(choice_or_tree.schemaname)
127@@ -1166,23 +1157,20 @@
128 # do nothing
129 return
130 else: # count > 2
131- self.delete_tree(iter, confirm)
132+ self.delete_tree(iter)
133
134 parent_tree.recompute_validity()
135 self.treeview.queue_draw()
136 return
137
138- def delete_tree(self, iter, confirm):
139+ def delete_tree(self, iter):
140 choice_or_tree, = self.treestore.get(iter, 0)
141 parent_tree = choice_or_tree.parent
142 isSelected = self.treeview.get_selection().iter_is_selected(iter)
143 sibling = self.treestore.iter_next(iter)
144
145- if confirm:
146- response = dialogs.prompt(self.main_window, "Are you sure you want to delete this node?")
147-
148- # not A or B == A implies B
149- if not confirm or response == gtk.RESPONSE_YES:
150+ confirm = dialogs.prompt(self.main_window, "Are you sure you want to delete this node?")
151+ if confirm == gtk.RESPONSE_YES:
152 parent_tree.delete_child_by_ref(choice_or_tree)
153 self.remove_children(iter)
154 self.treestore.remove(iter)
155
156=== modified file 'diamond/diamond/tree.py'
157--- diamond/diamond/tree.py 2011-07-27 13:53:35 +0000
158+++ diamond/diamond/tree.py 2011-07-29 09:21:43 +0000
159@@ -266,7 +266,7 @@
160
161 sub_tree=etree.Element(self.name)
162
163- for key in self.attrs:
164+ for key in self.attrs.keys():
165 val = self.attrs[key]
166 output_val = val[1]
167 if output_val is not None:
168@@ -275,9 +275,17 @@
169 for child in self.children:
170 if child.active is True:
171 child.write_core(sub_tree)
172+# else:
173+# if child.cardinality == '?':
174+# root=etree.Element(self.name)
175+# child.write_core(root)
176+# comment_buffer = StringIO.StringIO(etree.tostring(root))
177+# comment_text = ("DIAMOND MAGIC COMMENT (inactive optional subtree %s):\n" % child.schemaname)
178+# comment_text = comment_text + base64.b64encode(bz2.compress(comment_buffer.getvalue()))
179+# sub_tree.append(etree.Comment(unicode(comment_text)))
180
181 if self.data is not None:
182- sub_tree.text = unicode(self.data)
183+ sub_tree.text=(unicode(self.data))
184
185 if parent is not None:
186 parent.append(sub_tree)
187@@ -533,9 +541,6 @@
188
189 def __str__(self):
190 return self.get_display_name()
191-
192- def __repr__(self):
193- return self.get_name_path()
194-
195+
196 gobject.type_register(Tree)
197
198
199=== modified file 'include/spud'
200--- include/spud 2011-07-11 15:25:35 +0000
201+++ include/spud 2011-07-29 09:21:43 +0000
202@@ -52,6 +52,8 @@
203 public:
204
205 static void clear_options();
206+ static void* get_manager();
207+ static void set_manager(void* m);
208
209 static OptionError load_options(const std::string& filename);
210 static OptionError write_options(const std::string& filename);
211@@ -404,6 +406,7 @@
212
213 };
214
215+ bool deallocated;
216 Option* options;
217
218 };
219@@ -412,6 +415,15 @@
220 OptionManager::clear_options();
221 }
222
223+ inline void* get_manager(){
224+ return OptionManager::get_manager();
225+ }
226+
227+ inline void set_manager(void* m){
228+ OptionManager::set_manager(m);
229+ return;
230+ }
231+
232 inline OptionError load_options(const std::string& filename){
233 return OptionManager::load_options(filename);
234 }
235
236=== modified file 'include/spud.h'
237--- include/spud.h 2011-07-11 15:25:35 +0000
238+++ include/spud.h 2011-07-29 09:21:43 +0000
239@@ -36,6 +36,8 @@
240 #endif
241
242 void spud_clear_options();
243+ void* spud_get_manager();
244+ void spud_set_manager(void* m);
245
246 int spud_load_options(const char* filename, const int filename_len);
247 int spud_write_options(const char* filename, const int filename_len);
248
249=== modified file 'src/spud.cpp'
250--- src/spud.cpp 2011-07-11 15:25:35 +0000
251+++ src/spud.cpp 2011-07-29 09:21:43 +0000
252@@ -41,6 +41,16 @@
253 return;
254 }
255
256+ void* OptionManager::get_manager() {
257+ return (void*) manager.options;
258+ }
259+
260+ void OptionManager::set_manager(void* m) {
261+ delete manager.options;
262+ manager.options = (Spud::OptionManager::Option*) m;
263+ return;
264+ }
265+
266 OptionError OptionManager::load_options(const string& filename){
267 return manager.options->load_options(filename);
268 }
269@@ -543,6 +553,7 @@
270
271 OptionManager::OptionManager(){
272 options = new Option();
273+ deallocated = false;
274
275 return;
276 }
277@@ -553,7 +564,11 @@
278 }
279
280 OptionManager::~OptionManager(){
281- delete options;
282+ if (!deallocated)
283+ {
284+ delete options;
285+ deallocated = true;
286+ }
287
288 return;
289 }
290
291=== modified file 'src/spud_interfaces.cpp'
292--- src/spud_interfaces.cpp 2011-07-11 15:25:35 +0000
293+++ src/spud_interfaces.cpp 2011-07-29 09:21:43 +0000
294@@ -40,6 +40,15 @@
295 return;
296 }
297
298+ void* spud_get_manager(){
299+ return get_manager();
300+ }
301+
302+ void spud_set_manager(void* m){
303+ set_manager(m);
304+ return;
305+ }
306+
307 int spud_load_options(const char* filename, const int filename_len)
308 {
309 return load_options(string(filename, filename_len));

Subscribers

People subscribed via source and target branches