[pygobject] Move doc string generator into separate module
- From: Simon Feltman <sfeltman src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pygobject] Move doc string generator into separate module
- Date: Fri, 26 Jul 2013 23:42:42 +0000 (UTC)
commit 6fdde256e840600c84a648ab21da2fe5c212e5bc
Author: Simon Feltman <sfeltman src gnome org>
Date: Fri Jul 12 12:21:54 2013 -0700
Move doc string generator into separate module
Move the doc string generator for creating function signatures
into "gi.docstring". This includes a new API for getting and
setting the doc string creation functions:
gi.docstring.get_doc_string_generator
gi.docstring.set_doc_string_generator
gi.docstring.generate_doc_string
Beyond adding the ability for custom doc string generators,
this API is a necessary step for adding lazy __doc__
attribute access for optimization.
https://bugzilla.gnome.org/show_bug.cgi?id=704037
gi/Makefile.am | 3 +-
gi/docstring.py | 106 +++++++++++++++++++++++++++++++++++++++++++++++
gi/types.py | 55 +-----------------------
tests/Makefile.am | 1 +
tests/test_docstring.py | 49 ++++++++++++++++++++++
tests/test_gi.py | 30 -------------
6 files changed, 161 insertions(+), 83 deletions(-)
---
diff --git a/gi/Makefile.am b/gi/Makefile.am
index c687d31..fc11ff8 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -31,7 +31,8 @@ pygi_PYTHON = \
types.py \
module.py \
importer.py \
- pygtkcompat.py
+ pygtkcompat.py \
+ docstring.py
pygi_LTLIBRARIES = _gi.la
diff --git a/gi/docstring.py b/gi/docstring.py
new file mode 100644
index 0000000..713bb6e
--- /dev/null
+++ b/gi/docstring.py
@@ -0,0 +1,106 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2013 Simon Feltman <sfeltman gnome org>
+#
+# docstring.py: documentation string generator for gi.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from ._gi import \
+ VFuncInfo, \
+ FunctionInfo, \
+ DIRECTION_IN, \
+ DIRECTION_OUT, \
+ DIRECTION_INOUT
+
+
+#: Module storage for currently registered doc string generator function.
+_generate_doc_string_func = None
+
+
+def set_doc_string_generator(func):
+ """Set doc string generator function
+
+ :Parameters:
+ func : callable
+ Function which takes a GIInfoStruct and returns
+ documentation for it.
+ """
+ global _generate_doc_string_func
+ _generate_doc_string_func = func
+
+
+def get_doc_string_generator():
+ return _generate_doc_string_func
+
+
+def generate_doc_string(info):
+ """Generator a doc string given a GIInfoStruct
+
+ This passes the info struct to the currently registered doc string
+ generator and returns the result.
+ """
+ return _generate_doc_string_func(info)
+
+
+def split_function_info_args(info):
+ """Split a functions args into a tuple of two lists.
+
+ Note that args marked as DIRECTION_INOUT will be in both lists.
+
+ :Returns:
+ Tuple of (in_args, out_args)
+ """
+ in_args = []
+ out_args = []
+ for arg in info.get_arguments():
+ direction = arg.get_direction()
+ if direction in (DIRECTION_IN, DIRECTION_INOUT):
+ in_args.append(arg)
+ if direction in (DIRECTION_OUT, DIRECTION_INOUT):
+ out_args.append(arg)
+ return (in_args, out_args)
+
+
+def _generate_callable_info_function_signature(info):
+ """Default doc string generator"""
+ in_args, out_args = split_function_info_args(info)
+ in_args_strs = []
+ if isinstance(info, VFuncInfo):
+ in_args_strs = ['self']
+ elif isinstance(info, FunctionInfo):
+ if info.is_method():
+ in_args_strs = ['self']
+ elif info.is_constructor():
+ in_args_strs = ['cls']
+
+ for arg in in_args:
+ argstr = arg.get_name() + ':' + arg.get_pytype_hint()
+ if arg.is_optional():
+ argstr += '=<optional>'
+ in_args_strs.append(argstr)
+ in_args_str = ', '.join(in_args_strs)
+
+ if out_args:
+ out_args_str = ', '.join(arg.get_name() + ':' + arg.get_pytype_hint()
+ for arg in out_args)
+ return '%s(%s) -> %s' % (info.get_name(), in_args_str, out_args_str)
+ else:
+ return '%s(%s)' % (info.get_name(), in_args_str)
+
+
+set_doc_string_generator(_generate_callable_info_function_signature)
diff --git a/gi/types.py b/gi/types.py
index 69bb494..b9c0e37 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -28,18 +28,15 @@ import warnings
from . import _gobject
from ._gobject._gobject import GInterface
from ._gobject.constants import TYPE_INVALID
+from .docstring import generate_doc_string
from ._gi import \
InterfaceInfo, \
ObjectInfo, \
StructInfo, \
VFuncInfo, \
- FunctionInfo, \
register_interface_info, \
- hook_up_vfunc_implementation, \
- DIRECTION_IN, \
- DIRECTION_OUT, \
- DIRECTION_INOUT
+ hook_up_vfunc_implementation
StructInfo # pyflakes
@@ -50,59 +47,13 @@ if (3, 0) <= sys.version_info < (3, 3):
return hasattr(obj, '__call__')
-def split_function_info_args(info):
- """Split a functions args into a tuple of two lists.
-
- Note that args marked as DIRECTION_INOUT will be in both lists.
-
- :Returns:
- Tuple of (in_args, out_args)
- """
- in_args = []
- out_args = []
- for arg in info.get_arguments():
- direction = arg.get_direction()
- if direction in (DIRECTION_IN, DIRECTION_INOUT):
- in_args.append(arg)
- if direction in (DIRECTION_OUT, DIRECTION_INOUT):
- out_args.append(arg)
- return (in_args, out_args)
-
-
-def get_callable_info_doc_string(info):
- """Build a signature string which can be used for documentation."""
- in_args, out_args = split_function_info_args(info)
- in_args_strs = []
- if isinstance(info, VFuncInfo):
- in_args_strs = ['self']
- elif isinstance(info, FunctionInfo):
- if info.is_method():
- in_args_strs = ['self']
- elif info.is_constructor():
- in_args_strs = ['cls']
-
- for arg in in_args:
- argstr = arg.get_name() + ':' + arg.get_pytype_hint()
- if arg.is_optional():
- argstr += '=<optional>'
- in_args_strs.append(argstr)
- in_args_str = ', '.join(in_args_strs)
-
- if out_args:
- out_args_str = ', '.join(arg.get_name() + ':' + arg.get_pytype_hint()
- for arg in out_args)
- return '%s(%s) -> %s' % (info.get_name(), in_args_str, out_args_str)
- else:
- return '%s(%s)' % (info.get_name(), in_args_str)
-
-
def wraps_callable_info(info):
"""Similar to functools.wraps but with specific GICallableInfo support."""
def update_func(func):
func.__info__ = info
func.__name__ = info.get_name()
func.__module__ = 'gi.repository.' + info.get_namespace()
- func.__doc__ = get_callable_info_doc_string(info)
+ func.__doc__ = generate_doc_string(info)
return func
return update_func
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7062aa7..b845e4b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -109,6 +109,7 @@ EXTRA_DIST = \
test_overrides_gtk.py \
test_atoms.py \
test_generictreemodel.py \
+ test_docstring.py \
compat_test_pygtk.py \
gi/__init__.py \
gi/overrides/__init__.py \
diff --git a/tests/test_docstring.py b/tests/test_docstring.py
new file mode 100644
index 0000000..853f39d
--- /dev/null
+++ b/tests/test_docstring.py
@@ -0,0 +1,49 @@
+import unittest
+
+import gi.docstring
+from gi.repository import GIMarshallingTests
+
+
+class Test(unittest.TestCase):
+ def test_api(self):
+ new_func = lambda info: 'docstring test'
+ old_func = gi.docstring.get_doc_string_generator()
+
+ gi.docstring.set_doc_string_generator(new_func)
+ self.assertEqual(gi.docstring.get_doc_string_generator(),
+ new_func)
+ self.assertEqual(gi.docstring.generate_doc_string(None),
+ 'docstring test')
+
+ # Set back to original generator
+ gi.docstring.set_doc_string_generator(old_func)
+ self.assertEqual(gi.docstring.get_doc_string_generator(),
+ old_func)
+
+ def test_split_args_multi_out(self):
+ in_args, out_args = gi.docstring.split_function_info_args(GIMarshallingTests.int_out_out.__info__)
+ self.assertEqual(len(in_args), 0)
+ self.assertEqual(len(out_args), 2)
+ self.assertEqual(out_args[0].get_pytype_hint(), 'int')
+ self.assertEqual(out_args[1].get_pytype_hint(), 'int')
+
+ def test_split_args_inout(self):
+ in_args, out_args =
gi.docstring.split_function_info_args(GIMarshallingTests.long_inout_max_min.__info__)
+ self.assertEqual(len(in_args), 1)
+ self.assertEqual(len(out_args), 1)
+ self.assertEqual(in_args[0].get_name(), out_args[0].get_name())
+ self.assertEqual(in_args[0].get_pytype_hint(), out_args[0].get_pytype_hint())
+
+ def test_split_args_none(self):
+ obj = GIMarshallingTests.Object(int=33)
+ in_args, out_args = gi.docstring.split_function_info_args(obj.none_inout.__info__)
+ self.assertEqual(len(in_args), 1)
+ self.assertEqual(len(out_args), 1)
+
+ def test_final_signature_with_full_inout(self):
+ self.assertEqual(GIMarshallingTests.Object.full_inout.__doc__,
+ 'full_inout(object:GIMarshallingTests.Object) -> object:GIMarshallingTests.Object')
+
+ def test_overridden_doc_is_not_clobbered(self):
+ self.assertEqual(GIMarshallingTests.OverridesObject.method.__doc__,
+ 'Overridden doc string.')
diff --git a/tests/test_gi.py b/tests/test_gi.py
index 16e51a4..60c2333 100644
--- a/tests/test_gi.py
+++ b/tests/test_gi.py
@@ -2951,36 +2951,6 @@ class TestObjectInfo(unittest.TestCase):
GObject.ObjectClass.__info__)
-class TestSignatureArgs(unittest.TestCase):
- def test_split_args_multi_out(self):
- in_args, out_args = gi.types.split_function_info_args(GIMarshallingTests.int_out_out.__info__)
- self.assertEqual(len(in_args), 0)
- self.assertEqual(len(out_args), 2)
- self.assertEqual(out_args[0].get_pytype_hint(), 'int')
- self.assertEqual(out_args[1].get_pytype_hint(), 'int')
-
- def test_split_args_inout(self):
- in_args, out_args = gi.types.split_function_info_args(GIMarshallingTests.long_inout_max_min.__info__)
- self.assertEqual(len(in_args), 1)
- self.assertEqual(len(out_args), 1)
- self.assertEqual(in_args[0].get_name(), out_args[0].get_name())
- self.assertEqual(in_args[0].get_pytype_hint(), out_args[0].get_pytype_hint())
-
- def test_split_args_none(self):
- obj = GIMarshallingTests.Object(int=33)
- in_args, out_args = gi.types.split_function_info_args(obj.none_inout.__info__)
- self.assertEqual(len(in_args), 1)
- self.assertEqual(len(out_args), 1)
-
- def test_final_signature_with_full_inout(self):
- self.assertEqual(GIMarshallingTests.Object.full_inout.__doc__,
- 'full_inout(object:GIMarshallingTests.Object) -> object:GIMarshallingTests.Object')
-
- def test_overridden_doc_is_not_clobbered(self):
- self.assertEqual(GIMarshallingTests.OverridesObject.method.__doc__,
- 'Overridden doc string.')
-
-
class TestDeprecation(unittest.TestCase):
def test_method(self):
d = GLib.Date.new()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]