[pygobject] Move doc string generator into separate module



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]