Skip to content

Commit

Permalink
Bug 342948 – Add exception handling to GOption
Browse files Browse the repository at this point in the history
svn path=/trunk/; revision=681
  • Loading branch information
Gustavo J. A. M. Carneiro committed Jul 7, 2007
1 parent fe3966c commit 4dcda65
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 18 deletions.
9 changes: 9 additions & 0 deletions ChangeLog
@@ -1,3 +1,12 @@
2007-04-30 Johannes Hölzl <johannes.hoelzl@gmx.de>

* gobject/gobjectmodule.c (init_gobjectmodule),
* gobject/pygoptiongroup.c (arg_func),
* gobject/option.py (OptionParser._parse_args, OptionGroup._to_goptiongroup),
* tests/test_option.py: OptParse-Exceptions in GOption-callbacks
are now convertet into an GError. GError from the
GOptionGroup.run is convertet into an OptParse-Exception.

2007-07-06 Ed Catmur <ed@catmur.co.uk>

* gobject/pygtype.c (pyg_param_gvalue_from_pyobject),
Expand Down
4 changes: 3 additions & 1 deletion gobject/gobjectmodule.c
Expand Up @@ -3028,7 +3028,7 @@ pyg_error_check(GError **error)
* Returns: 0 if no exception has been raised, -1 if it is a
* valid gobject.GError, -2 otherwise.
*/
static gboolean
gboolean
pyg_gerror_exception_check(GError **error)
{
PyObject *type, *value, *traceback;
Expand Down Expand Up @@ -3634,6 +3634,8 @@ init_gobject(void)

PyModule_AddStringConstant(m, "OPTION_REMAINING", G_OPTION_REMAINING);

PyModule_AddStringConstant(m, "OPTION_ERROR", (char*) g_quark_to_string(G_OPTION_ERROR));

PyModule_AddIntConstant(m, "SPAWN_LEAVE_DESCRIPTORS_OPEN",
G_SPAWN_LEAVE_DESCRIPTORS_OPEN);
PyModule_AddIntConstant(m, "SPAWN_DO_NOT_REAP_CHILD",
Expand Down
31 changes: 29 additions & 2 deletions gobject/option.py
Expand Up @@ -31,11 +31,16 @@

import sys
import optparse
from optparse import OptionError
from optparse import OptParseError, OptionError, OptionValueError, \
BadOptionError, OptionConflictError
import _gobject as gobject

__all__ = [
"OptParseError",
"OptionError",
"OptionValueError",
"BadOptionError",
"OptionConflictError"
"Option",
"OptionGroup",
"OptionParser",
Expand Down Expand Up @@ -172,7 +177,15 @@ def callback(option_name, option_value, group):
opt = self._long_opt[option_name]
else:
opt = self._short_opt[option_name]
opt.process(option_name, option_value, self.values, parser)

try:
opt.process(option_name, option_value, self.values, parser)
except OptionValueError, error:
gerror = gobject.GError(str(error))
gerror.domain = gobject.OPTION_ERROR
gerror.code = gobject.OPTION_ERROR_BAD_VALUE
gerror.message = str(error)
raise gerror

group = gobject.OptionGroup(self.name, self.description,
self.help_description, callback)
Expand Down Expand Up @@ -301,5 +314,19 @@ def _process_args(self, largs, rargs, values):
context = self._to_goptioncontext(values)
largs.extend(context.parse([sys.argv[0]] + rargs))

def parse_args(self, args=None, values=None):
try:
return optparse.OptionParser.parse_args(self, args, values)
except gobject.GError, error:
if error.domain != gobject.OPTION_ERROR:
raise
if error.code == gobject.OPTION_ERROR_BAD_VALUE:
raise OptionValueError(error.message)
elif error.code == gobject.OPTION_ERROR_UNKNOWN_OPTION:
raise BadOptionError(error.message)
elif error.code == gobject.OPTION_ERROR_FAILED:
raise OptParseError(error.message)
else:
raise

make_option = Option
2 changes: 2 additions & 0 deletions gobject/pygobject-private.h
Expand Up @@ -101,6 +101,8 @@ PyObject *pyg_integer_richcompare(PyObject *v,
PyObject *w,
int op);

gboolean pyg_gerror_exception_check(GError **error);

/* from pygtype.h */
extern PyTypeObject PyGTypeWrapper_Type;

Expand Down
36 changes: 22 additions & 14 deletions gobject/pygoptiongroup.c
Expand Up @@ -25,6 +25,7 @@
#endif

#include "pygobject-private.h"
#include "pygobject.h"

static gboolean
check_if_owned(PyGOptionGroup *self)
Expand All @@ -38,8 +39,8 @@ check_if_owned(PyGOptionGroup *self)
return FALSE;
}


static void destroy_g_group(PyGOptionGroup *self)
static void
destroy_g_group(PyGOptionGroup *self)
{
PyGILState_STATE state;
state = pyg_gil_state_ensure();
Expand Down Expand Up @@ -100,30 +101,37 @@ static gboolean
arg_func(const gchar *option_name,
const gchar *value,
PyGOptionGroup *self,
GError *error)
GError **error)
{
PyObject *ret;
PyGILState_STATE state;

gboolean no_error;

state = pyg_gil_state_ensure();

if (value == NULL)
{
ret = PyObject_CallFunction(self->callback, "sOO",
option_name, Py_None, self);
}
else
{
ret = PyObject_CallFunction(self->callback, "ssO",
option_name, value, self);
}

if (ret == NULL)
PyErr_Print();

pyg_gil_state_release(state);

if (ret == NULL)
return FALSE;

Py_DECREF(ret);
return TRUE;
if (ret != NULL)
{
Py_DECREF(ret);
pyg_gil_state_release(state);
return TRUE;
}
else
{
no_error = pyg_gerror_exception_check(error) != -1;
pyg_gil_state_release(state);
return no_error;
}
}

static PyObject *
Expand Down
43 changes: 42 additions & 1 deletion tests/test_option.py
@@ -1,20 +1,35 @@
#!/usr/bin/env python

import unittest
import sys

from StringIO import StringIO
from common import gobject
from gobject import option

class TestOption(unittest.TestCase):
EXCEPTION_MESSAGE = "This callback fails"

def setup_group(self):
def option_callback(option, opt, value, parser):
raise StandardError(self.EXCEPTION_MESSAGE)

group = option.OptionGroup(
"unittest", "Unit test options", "Show all unittest options",
option_list = [
option.make_option("-f", "-u", "--file", "--unit-file",
type="filename",
dest="unit_file",
help="Unit test option"),
option.make_option("--test-integer",
type="int",
dest="test_integer",
help="Unit integer option"),
option.make_option("--callback-failure-test",
action="callback",
callback=option_callback,
dest="test_integer",
help="Unit integer option"),
])
group.add_option("-t", "--test",
action="store_false",
Expand All @@ -24,7 +39,8 @@ def setup_group(self):
return group

def setup_parser(self):
parser = option.OptionParser("NAMES...", description="Option unit test")
parser = option.OptionParser("NAMES...",
description="Option unit test")
parser.add_option("-t", "--test", help="Unit test option",
action="store_false", dest="test", default=True)
return parser
Expand All @@ -38,6 +54,31 @@ def testOption(self):
assert group.values.test
assert not parser.values.test
assert group.values.unit_file == "test"

try:
parser.parse_args(["test_option.py", "--test-integer=text"])
except option.OptionValueError:
pass
else:
assert False

sio = StringIO()
old_stderr = sys.stderr
sys.stderr = sio
try:
parser.parse_args(["test_option.py", "--callback-failure-test"])
finally:
sys.stderr = old_stderr
assert (sio.getvalue().split('\n')[-2] ==
"StandardError: " + self.EXCEPTION_MESSAGE)

try:
parser.parse_args(["test_option.py", "--unknwon-option"])
except option.BadOptionError:
pass
else:
assert False

def testBadConstructor(self):
self.assertRaises(TypeError, option.OptionGroup)

0 comments on commit 4dcda65

Please sign in to comment.