From 8c5bdc3e12947580e91c018b71adf9ad3128bb75 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 30 Jun 2011 10:14:33 +0100 Subject: [PATCH] python: Add explicit g.close() method (RHBZ#717786). --- generator/generator_python.ml | 26 +++++++++++++++++++ python/t/800-explicit-close.py | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 python/t/800-explicit-close.py diff --git a/generator/generator_python.ml b/generator/generator_python.ml index ffd63da..48dd24f 100644 --- a/generator/generator_python.ml +++ b/generator/generator_python.ml @@ -545,6 +545,9 @@ import libguestfsmod pr "\n"; pr "\ +class ClosedHandle(ValueError): + pass + class GuestFS: \"\"\"Instances of this class are libguestfs API handles.\"\"\" @@ -553,7 +556,27 @@ class GuestFS: self._o = libguestfsmod.create () def __del__ (self): + if self._o: + libguestfsmod.close (self._o) + + def _check_not_closed (self): + if not self._o: + raise ClosedHandle (\"GuestFS: method called on closed handle\") + + def close (self): + u\"\"\"Explicitly close the guestfs handle. + + The handle is closed implicitly when its reference count goes + to zero (eg. when it goes out of scope or the program ends). + + This call is only needed if you want to force the handle to + close now. After calling this, the program must not call + any method on the handle (except the implicit call to + __del__ which happens when the final reference is cleaned up). + \"\"\" + self._check_not_closed () libguestfsmod.close (self._o) + self._o = None def set_event_callback (self, cb, event_bitmask): u\"\"\"Register an event callback. @@ -577,10 +600,12 @@ class GuestFS: \"guestfs_set_event_callback\" in guestfs(3) before using this function. \"\"\" + self._check_not_closed () return libguestfsmod.set_event_callback (self._o, cb, event_bitmask) def delete_event_callback (self, event_handle): u\"\"\"Delete an event callback.\"\"\" + self._check_not_closed () libguestfsmod.delete_event_callback (self._o, event_handle) "; @@ -641,6 +666,7 @@ class GuestFS: | StringList n | DeviceList n -> pr " %s = list (%s)\n" n n ) args; + pr " self._check_not_closed ()\n"; pr " return libguestfsmod.%s (self._o" name; List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (args@optargs); pr ")\n\n"; diff --git a/python/t/800-explicit-close.py b/python/t/800-explicit-close.py new file mode 100644 index 0000000..291534d --- /dev/null +++ b/python/t/800-explicit-close.py @@ -0,0 +1,59 @@ +# libguestfs Python bindings +# Copyright (C) 2011 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# Test implicit vs explicit closes of the handle (RHBZ#717786). + +import os +import guestfs + +g = guestfs.GuestFS () + +g.close () # explicit close +del g # implicit close - should be no error/warning + +# Expect an exception if we call a method on a closed handle. +g = guestfs.GuestFS () +g.close () +try: + g.set_memsize (512) + raise Exception("expected an exception from previous statement") +except guestfs.ClosedHandle: + pass +del g + +# Verify that the handle is really being closed by g.close, by setting +# up a close event and testing that it happened. +g = guestfs.GuestFS () + +close_invoked = 0 + +def close_callback (ev, eh, buf, array): + global close_invoked + close_invoked += 1 + +g.set_event_callback (close_callback, guestfs.EVENT_CLOSE) + +if close_invoked != 0: + raise Exception("close_invoked should be 0") + +g.close () +if close_invoked != 1: + raise Exception("close_invoked should be 1") + +del g +if close_invoked != 1: + raise Exception("close_invoked should be 1") -- 1.8.3.1