New Upstream Release - pybindgen

Ready changes

Summary

Merged new upstream version: 0.22.1+dfsg1 (was: 0.20.0+dfsg1).

Resulting package

Built on 2022-11-19T18:10 (took 7m5s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases python-pybindgen-docapt install -t fresh-releases python3-pybindgen

Lintian Result

Diff

diff --git a/.travis.yml b/.travis.yml
index d96b950..f1979bf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,13 @@
 language: python
+arch:
+  - ppc64le
+  - amd64
 
 python:
   - 2.7
-  - 3.4
-  - 3.5
   - 3.6
+  - 3.7
+  - 3.8
 
 
 sudo: false
diff --git a/PKG-INFO b/PKG-INFO
index fc00b39..f716c57 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: PyBindGen
-Version: 0.20.0
+Version: 0.22.1
 Summary: Python Bindings Generator
-Home-page: https://launchpad.net/pybindgen
+Home-page: https://github.com/gjcarneiro/pybindgen
 Author: Gustavo Carneiro
 Author-email: gjcarneiro@gmail.com
 License: UNKNOWN
diff --git a/PyBindGen.egg-info/PKG-INFO b/PyBindGen.egg-info/PKG-INFO
index fc00b39..f716c57 100644
--- a/PyBindGen.egg-info/PKG-INFO
+++ b/PyBindGen.egg-info/PKG-INFO
@@ -1,8 +1,8 @@
 Metadata-Version: 1.1
 Name: PyBindGen
-Version: 0.20.0
+Version: 0.22.1
 Summary: Python Bindings Generator
-Home-page: https://launchpad.net/pybindgen
+Home-page: https://github.com/gjcarneiro/pybindgen
 Author: Gustavo Carneiro
 Author-email: gjcarneiro@gmail.com
 License: UNKNOWN
diff --git a/PyBindGen.egg-info/SOURCES.txt b/PyBindGen.egg-info/SOURCES.txt
index 477dab0..e226c31 100644
--- a/PyBindGen.egg-info/SOURCES.txt
+++ b/PyBindGen.egg-info/SOURCES.txt
@@ -30,6 +30,7 @@ benchmarks/wscript
 bzr-plugins/gnulog.py
 doc/Makefile
 doc/apiref.rst
+doc/castxmlparser.rst
 doc/codesink.rst
 doc/conf.py
 doc/container.rst
@@ -40,7 +41,6 @@ doc/cppexception.rst
 doc/cppmethod.rst
 doc/enum.rst
 doc/function.rst
-doc/gccxmlparser.rst
 doc/index.rst
 doc/make.bat
 doc/module.rst
@@ -138,7 +138,6 @@ pybindgen/cppexception.py
 pybindgen/cppmethod.py
 pybindgen/enum.py
 pybindgen/function.py
-pybindgen/gccxmlparser.py
 pybindgen/module.py
 pybindgen/overloading.py
 pybindgen/pytypeobject.py
@@ -187,5 +186,4 @@ waf-tools/boost.py
 waf-tools/cflags.py
 waf-tools/command.py
 waf-tools/pkgconfig.py
-waf-tools/python_patched.py
 waf-tools/shellcmd.py
\ No newline at end of file
diff --git a/debian/changelog b/debian/changelog
index 25fe7cc..83f40f3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+pybindgen (0.22.1+dfsg1-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Sat, 19 Nov 2022 18:04:04 -0000
+
 pybindgen (0.20.0+dfsg1-4) unstable; urgency=medium
 
   [ Debian Janitor ]
diff --git a/debian/patches/dont-change-version-in-setup.patch b/debian/patches/dont-change-version-in-setup.patch
index edc58f1..1f44167 100644
--- a/debian/patches/dont-change-version-in-setup.patch
+++ b/debian/patches/dont-change-version-in-setup.patch
@@ -9,10 +9,10 @@ the +dfsg1 suffix) dpkg-source fails because the source files changed.
  setup.py | 5 ++---
  1 file changed, 2 insertions(+), 3 deletions(-)
 
-diff --git a/setup.py b/setup.py
-index 8368acb..2fee052 100644
---- a/setup.py
-+++ b/setup.py
+Index: pybindgen.git/setup.py
+===================================================================
+--- pybindgen.git.orig/setup.py
++++ pybindgen.git/setup.py
 @@ -4,11 +4,10 @@ from setuptools import setup
  with open('README.rst') as file_:
      LONG_DESCRIPTION = file_.read()
diff --git a/doc/apiref.rst b/doc/apiref.rst
index d8dfa5e..1fd4dc1 100644
--- a/doc/apiref.rst
+++ b/doc/apiref.rst
@@ -18,10 +18,10 @@ Higher layers
    cppexception
    container
 
-   gccxmlparser
+   castxmlparser
    settings
-   
-   
+
+
 Lower layers
 -----------------------
 .. toctree::
diff --git a/doc/gccxmlparser.rst b/doc/castxmlparser.rst
similarity index 64%
rename from doc/gccxmlparser.rst
rename to doc/castxmlparser.rst
index c7488df..144239d 100644
--- a/doc/gccxmlparser.rst
+++ b/doc/castxmlparser.rst
@@ -1,10 +1,10 @@
 
 ==========================================================
-gccxmlparser: scan header files to extract API definitions
+castxmlparser: scan header files to extract API definitions
 ==========================================================
 
 
-.. automodule:: pybindgen.gccxmlparser
+.. automodule:: pybindgen.castxmlparser
     :members:
     :undoc-members:
     :show-inheritance:
diff --git a/doc/tutorial.rst b/doc/tutorial.rst
index 58aee96..558ec82 100644
--- a/doc/tutorial.rst
+++ b/doc/tutorial.rst
@@ -37,7 +37,7 @@ and, then, will proceed to show how to use the automatic binding generator.
 Supported Python versions
 =========================
 
-PyBindGen officially supports Python versions 2.6, 2.7, and >= 3.3[*] (tested in 3.3 and 3.4).
+PyBindGen officially supports Python versions 2.6, 2.7, and >= 3.3 (tested in 3.3 and 3.4).
 
 PyBindGen does not support Python versions 3.0, 3.1, and 3.2.
 
@@ -45,10 +45,6 @@ Note that C files generated by PyBindGen transparently support
 multiple Python versions.  In particular, the generated code can build
 in either Python 2.x or Python 3.x.
 
-[*] The automatic header file scanning feature of PyBindGen (submodule
-`pybindgen.gccxmlparser`) does not work in any Python 3.x version,
-since the pygccxml package has not been ported to Python 3.
-
 
 
 Work flows
@@ -77,7 +73,7 @@ are several ways that PyBindGen can be used:
 
 A simple example
 ================
-The best way to get a feel for what PyBindGen looks like is to go through a 
+The best way to get a feel for what PyBindGen looks like is to go through a
 simple example.
 
 Code generation script
@@ -90,7 +86,7 @@ declared in a header my-module.h:
 
     void MyModuleDoAction (void);
 
-What we want to do is call this C function from python and be able to write 
+What we want to do is call this C function from python and be able to write
 python code such as::
 
   import MyModule
@@ -188,13 +184,13 @@ should be self-explanatory::
  [...]
  $ export PYTHONPATH=build/lib.linux-x86_64-2.7/
  $ python
- Python 2.7.5+ (default, Sep 19 2013, 13:48:49) 
+ Python 2.7.5+ (default, Sep 19 2013, 13:48:49)
  [GCC 4.8.1] on linux2
  Type "help", "copyright", "credits" or "license" for more information.
  >>> import mymodule
  >>> mymodule.MyModuleDoAction ()
  You called MyModuleDoAction !
- >>> 
+ >>>
 
 
 Wrapping types by value
@@ -217,8 +213,8 @@ argument to add_function specifies that our function returns a value of type
 'int' and the third argument specifies that our function takes as a
 single argument an 'int' of name 'value'::
 
-  mod.add_function('MyModuleDoAction', 
-                    pybindgen.retval ('int'), 
+  mod.add_function('MyModuleDoAction',
+                    pybindgen.retval ('int'),
                    [pybindgen.param ('int', 'v1'),
                     pybindgen.param ('int', 'v2')])
 
@@ -241,7 +237,7 @@ using positional arguments.
 Of course, the above example could be rewritten to the more compact and readable::
 
   from pybindgen import *
-  mod.add_function('MyModuleDoAction', retval ('int'), 
+  mod.add_function('MyModuleDoAction', retval ('int'),
                    [param ('int', 'v1'),
                     param ('int', 'v2')])
 
@@ -427,7 +423,7 @@ Then, bind its inner enum::
 
 and, finally, bind its inner class::
 
-  mod.add_class('Inner', outer_class=outer)
+  inner = mod.add_class('Inner', outer_class=outer)
   inner.add_constructor([])
 
 The only slightly tricky part is binding the Do method of the Inner
@@ -459,11 +455,11 @@ no special challenge. Let's look at an example:
 
   namespace Outer {
     void Do (void);
-    class MyClass 
+    class MyClass
     {};
     namespace Inner {
       void Do (void);
-      class MyClass 
+      class MyClass
       {};
     } // namespace Inner
   } // namespace Outer
@@ -502,7 +498,7 @@ Memory management for pointer types
 
 Until then, we have shown how to pass back and forth data through C/C++ APIs
 only by value but, a large fraction of real-world APIs use raw pointers
-(and, in the case of C++, smart pointers) as arguments or return values 
+(and, in the case of C++, smart pointers) as arguments or return values
 of functions/methods.
 
 Rather than try to explain the detail of every option offered by PyBindGen
@@ -572,14 +568,14 @@ disappears.
 A reference-counted object
 --------------------------
 
-A nice way to avoid some of the ambiguities of the above-mentioned API bindings is to 
+A nice way to avoid some of the ambiguities of the above-mentioned API bindings is to
 use reference-counted C or C++ objects which must provide a pair of functions or methods
 to increase or decrease the reference count of the object. For example, a classic
 C++ reference-counted class:
 
 .. code-block:: c++
 
-  class MyClass 
+  class MyClass
   {
   public:
     void Ref (void);
@@ -597,9 +593,9 @@ To wrap this class, we first need to declare our class::
 
   from pybindgen import cppclass
   [...]
-  mod.add_class('MyClass', memory_policy=cppclass.ReferenceCountingMethodsPolicy( 
-                    incref_method='Ref', 
-                    decref_method='Unref', 
+  mod.add_class('MyClass', memory_policy=cppclass.ReferenceCountingMethodsPolicy(
+                    incref_method='Ref',
+                    decref_method='Unref',
                     peekref_method='PeekRef'))
 
 The above allows PyBindGen to maintain and track the reference count
@@ -621,7 +617,7 @@ method.  If transfer_ownership=True it would mean that the caller
 would keep the passed in reference to itself, and if the caller
 wants to keep the reference it must call the incref method first.
 
-A more interesting case is that of returning such a reference counted 
+A more interesting case is that of returning such a reference counted
 object from a function:
 
 .. code-block:: c++
@@ -640,6 +636,17 @@ case too::
 Which instructs PyBindGen that DoSomething is not to be trusted and that it should
 acquire ownership of the returned pointer if it needs to keep track of it.
 
+A Copied Object or String
+-------------------------
+
+Some C/C++ functions, and in particular those generated as bindings to other
+languages allocate storage in the C/C++ heap purely for transferring data
+to the python C bindings (consider python calling golang via C wrappers for
+example). In these cases, there is no language level mechanism to track and free
+this storage. The 'free_on_copy' parameter can be used to request that the
+python generated bindings free this storage after Py_BuildValue has been
+used to take a copy of it. This is most often needed for C strings (char *)
+but is also available for C++ classes using 'delete' rather than 'free'.
 
 A STL container
 ---------------
@@ -738,7 +745,7 @@ scan the API definitions directly from the header files::
 
   import pybindgen
   from pybindgen import FileCodeSink
-  from pybindgen.gccxmlparser import ModuleParser
+  from pybindgen.castxmlparser import ModuleParser
 
   def my_module_gen():
       module_parser = ModuleParser('a1', '::')
@@ -770,7 +777,7 @@ PyBindGen based Python script::
   import sys
 
   from pybindgen import FileCodeSink
-  from pybindgen.gccxmlparser import ModuleParser
+  from pybindgen.castxmlparser import ModuleParser
 
   def my_module_gen():
       module_parser = ModuleParser('a2', '::')
diff --git a/examples/a/module-autogen.py b/examples/a/module-autogen.py
index acbf31d..2cda006 100644
--- a/examples/a/module-autogen.py
+++ b/examples/a/module-autogen.py
@@ -4,7 +4,7 @@ import sys
 
 import pybindgen
 from pybindgen import FileCodeSink
-from pybindgen.gccxmlparser import ModuleParser
+from pybindgen.castxmlparser import ModuleParser
 
 def my_module_gen():
     module_parser = ModuleParser('a1', '::')
diff --git a/examples/a/module-autoscan.py b/examples/a/module-autoscan.py
index 6d4ddbd..f333de8 100644
--- a/examples/a/module-autoscan.py
+++ b/examples/a/module-autoscan.py
@@ -3,7 +3,7 @@
 import sys
 
 from pybindgen import FileCodeSink
-from pybindgen.gccxmlparser import ModuleParser
+from pybindgen.castxmlparser import ModuleParser
 
 def my_module_gen():
     module_parser = ModuleParser('a2', '::')
diff --git a/examples/std_shared_ptr/modulegen.py b/examples/std_shared_ptr/modulegen.py
index 41d41fb..8cfb6c6 100755
--- a/examples/std_shared_ptr/modulegen.py
+++ b/examples/std_shared_ptr/modulegen.py
@@ -12,6 +12,7 @@ from pybindgen import Module, FileCodeSink, param, retval
 #from pybindgen.function import CustomFunctionWrapper
 #from pybindgen.cppmethod import CustomCppMethodWrapper
 from pybindgen import cppclass
+from pybindgen.typehandlers.smart_ptr import StdSharedPtr
 
 #from pybindgen import param, retval
 
@@ -25,7 +26,7 @@ def my_module_gen(out_file):
 
     mod.add_include ('"sp.h"')
 
-    Foo = mod.add_class('Foo', memory_policy=cppclass.SharedPtr('::Foo'))
+    Foo = mod.add_class('Foo', memory_policy=StdSharedPtr('::Foo'))
 
     Foo.add_constructor([param('std::string', 'datum')])
     Foo.add_constructor([])
@@ -37,7 +38,7 @@ def my_module_gen(out_file):
                      [param('std::shared_ptr<Foo>', 'foo')])
 
     mod.add_function('function_that_returns_foo', retval('std::shared_ptr<Foo>'), [])
-    
+
     ## ---- finally, generate the whole thing ----
     mod.generate(FileCodeSink(out_file))
 
diff --git a/pybindgen/castxmlparser.py b/pybindgen/castxmlparser.py
index 9377f9c..e4e7d1d 100644
--- a/pybindgen/castxmlparser.py
+++ b/pybindgen/castxmlparser.py
@@ -19,6 +19,7 @@ import warnings
 import re
 import logging
 import time
+from operator import itemgetter
 
 import pygccxml
 from pygccxml import parser
@@ -43,6 +44,7 @@ from pygccxml.declarations import templates
 from pygccxml.declarations import container_traits, class_declaration
 from pygccxml.declarations.declaration import declaration_t
 from pygccxml.declarations.class_declaration import class_declaration_t, class_t
+from pygccxml.declarations import get_dependencies_from_decl
 from . import settings
 from . import utils
 from pygccxml.utils import find_xml_generator
@@ -242,7 +244,7 @@ def normalize_class_name(class_name, module_namespace):
 
 def _pygen_kwargs(kwargs):
     l = []
-    for key, val in kwargs.items():
+    for key, val in sorted(kwargs.items(), key=itemgetter(0)):
         if isinstance(val, (CppClass, CppException)):
             l.append("%s=root_module[%r]" % (key, utils.ascii(val.full_name)))
         else:
@@ -346,6 +348,8 @@ class GccXmlTypeRegistry(object):
         for name, value in annotations.items():
             if name == 'caller_owns_return':
                 kwargs['caller_owns_return'] = annotations_scanner.parse_boolean(value)
+            if name == 'free_after_copy':
+                kwargs['free_after_copy'] = annotations_scanner.parse_boolean(value)
             elif name == 'reference_existing_object':
                 kwargs['reference_existing_object'] = annotations_scanner.parse_boolean(value)
             elif name == 'return_internal_reference':
@@ -653,7 +657,9 @@ class ModuleParser(object):
         self._post_scan_hooks.append(hook)
 
     def __location_match(self, decl):
-        if decl.location.file_name in self.header_files:
+        # Make sure absolute paths are compared.
+        abspath = os.path.abspath(decl.location.file_name)
+        if abspath in self.header_files:
             return True
         for incdir in self.whitelist_paths:
             if os.path.abspath(decl.location.file_name).startswith(incdir):
@@ -1065,7 +1071,7 @@ pybindgen.settings.error_handler = ErrorHandler()
             # logger.debug("Saw free function: %s", fun)
             if fun.name.startswith('__'):
                 continue
-            for dependency in fun.i_depend_on_them(recursive=True):
+            for dependency in get_dependencies_from_decl(fun,recursive=True):
                 type_info = dependency.depend_on_it
                 if type_traits.is_pointer(type_info):
                     type_info = type_traits.remove_pointer(type_info)
@@ -1381,7 +1387,7 @@ pybindgen.settings.error_handler = ErrorHandler()
             for member in cls.get_members(access='public'):
                 if member.name.startswith('__'):
                     continue
-                for dependency in member.i_depend_on_them(recursive=True):
+                for dependency in get_dependencies_from_decl(member,recursive=True):
                     type_info = dependency.depend_on_it
                     if type_traits.is_pointer(type_info):
                         type_info = type_traits.remove_pointer(type_info)
@@ -1607,7 +1613,8 @@ pybindgen.settings.error_handler = ErrorHandler()
             container_type = 'hash_set'
         elif traits is container_traits.hash_multiset_traits:
             container_type = 'hash_multiset'
-        elif traits is container_traits.map_traits:
+        elif (traits is container_traits.map_traits
+              or traits is container_traits.unordered_map_traits):
             container_type = 'map'
             if hasattr(traits, "key_type"):
                 key_type = traits.key_type(definition)
@@ -1616,9 +1623,7 @@ pybindgen.settings.error_handler = ErrorHandler()
                               "so we don't support mapping types with this  pygccxml version (%r)"
                               % pygccxml.__version__)
                 return
-
-        elif (traits is container_traits.map_traits
-              or traits is container_traits.multimap_traits
+        elif (traits is container_traits.multimap_traits
               or traits is container_traits.hash_map_traits
               or traits is container_traits.hash_multimap_traits):
             return # maps not yet implemented
@@ -2316,6 +2321,8 @@ pybindgen.settings.error_handler = ErrorHandler()
                 if argnum == 0 and as_method is not None \
                         and isinstance(arg.decl_type, cpptypes.pointer_t):
                     annotations.setdefault("transfer_ownership", "false")
+                    annotations.setdefault("free_after_copy", "false")
+
 
                 spec = self.type_registry.lookup_parameter(arg.decl_type, arg.name,
                                                            annotations,
diff --git a/pybindgen/container.py b/pybindgen/container.py
index c2616aa..a7966db 100644
--- a/pybindgen/container.py
+++ b/pybindgen/container.py
@@ -91,6 +91,7 @@ container_traits_list = {
     'hash_set':		ContainerTraits(add_value_method='insert'),
     'hash_multiset':	ContainerTraits(add_value_method='insert'),
     'map':		ContainerTraits(add_value_method='insert', is_mapping=True),
+    'unordered_map':	ContainerTraits(add_value_method='insert', is_mapping=True),
 }
 
 # from wikipedia: """Deque is sometimes written dequeue, but this use
@@ -110,7 +111,7 @@ class Container(object):
         :param container_type: a string with the type of container,
             one of 'list', 'deque', 'queue', 'priority_queue',
             'vector', 'stack', 'set', 'multiset', 'hash_set',
-            'hash_multiset', 'map'
+            'hash_multiset', 'map', 'unordered_map'
 
         :param outer_class: if the type is defined inside a class, must be a reference to the outer class
         :type outer_class: None or L{CppClass}
diff --git a/pybindgen/cppclass.py b/pybindgen/cppclass.py
index c5583ff..9364adc 100644
--- a/pybindgen/cppclass.py
+++ b/pybindgen/cppclass.py
@@ -35,6 +35,13 @@ from . import function
 
 import collections
 
+# Prepare for python 3.9
+try:
+    collectionsCallable = collections.Callable
+except AttributeError:
+    import collections.abc
+    collectionsCallable = collections.abc.Callable
+
 try:
     set
 except NameError:
@@ -282,7 +289,7 @@ class CppHelperClass(object):
         for existing in self.virtual_methods:
             if method.matches_signature(existing):
                 return # don't re-add already existing method
-        
+
         if isinstance(method, CppDummyMethod):
             if method.is_pure_virtual:
                 self.cannot_be_constructed = True
@@ -303,8 +310,8 @@ class CppHelperClass(object):
             proxy = CppVirtualMethodProxy(method)
             proxy.main_wrapper = method # XXX: need to explain this
             self.add_virtual_proxy(proxy)
-        
-        
+
+
     def add_virtual_parent_caller(self, parent_caller):
         """Add a new CppVirtualMethodParentCaller object to this helper class"""
         assert isinstance(parent_caller, CppVirtualMethodParentCaller)
@@ -409,7 +416,7 @@ void set_pyobj(PyObject *pyobj)
         code_sink.writeln("Py_CLEAR(m_pyself);")
         code_sink.unindent()
         code_sink.writeln("}\n")
-            
+
         if not self.class_.import_from_module:
             ## write the parent callers (_name)
             for parent_caller in self.virtual_parent_callers.values():
@@ -495,7 +502,7 @@ void set_pyobj(PyObject *pyobj)
             else:
                 parent_caller_name = name
             method_defs.append(parent_caller.get_py_method_def(parent_caller_name))
-                
+
         ## write the virtual proxies
         for virtual_proxy in self.virtual_proxies:
             #virtual_proxy.class_ = self.class_
@@ -513,7 +520,7 @@ void set_pyobj(PyObject *pyobj)
         for dummy, custom_body in self.custom_methods:
             if custom_body:
                 code_sink.writeln(custom_body)
-        
+
         return method_defs
 
 
@@ -576,7 +583,7 @@ class CppClass(object):
             inherits from the parent class.  Only root classes can have a
             memory policy defined.
         :type memory_policy: L{MemoryPolicy}
-        
+
         :param foreign_cpp_namespace: if set, the class is assumed to
             belong to the given C++ namespace, regardless of the C++
             namespace of the python module it will be added to.  For
@@ -817,7 +824,7 @@ class CppClass(object):
 
         The binary operator is assumed to operate with both operands
         of the type of the class, either by reference or by value.
-        
+
         :param operator: string indicating the name of the operator to
             support, e.g. '=='
         """
@@ -1018,7 +1025,7 @@ class CppClass(object):
                         self._have_pure_virtual_methods = True
 
         return self._have_pure_virtual_methods
-                            
+
     have_pure_virtual_methods = property(get_have_pure_virtual_methods)
 
 
@@ -1036,10 +1043,10 @@ class CppClass(object):
         all subclasses.  The hook function is called like this::
           hook_function(helper_class)
         """
-        if not isinstance(hook, collections.Callable):
+        if not isinstance(hook, collectionsCallable):
             raise TypeError("hook function must be callable")
         self.helper_class_hooks.append(hook)
-        
+
     def _get_all_helper_class_hooks(self):
         """
         Returns a list of all helper class hook functions, including
@@ -1113,7 +1120,7 @@ class CppClass(object):
             raise CodeGenerationError("%s cannot be constructed (class has pure virtual methods)" % self.full_name)
         else:
             return self.full_name
-        
+
 
     def implicitly_converts_to(self, other):
         """
@@ -1151,7 +1158,7 @@ class CppClass(object):
 #         return classes
 
     def _update_names(self):
-        
+
         prefix = settings.name_prefix.capitalize()
 
         if self.outer_class is None:
@@ -1177,7 +1184,7 @@ class CppClass(object):
 
         def mangle(name):
             return mangle_name(name)
-        
+
         def flatten(name):
             "make a name like::This look LikeThis"
             return ''.join([make_upper(mangle(s)) for s in name.split('::')])
@@ -1216,12 +1223,12 @@ class CppClass(object):
         try:
             param_type_matcher.register(alias, self.ThisClassParameter)
         except ValueError: pass
-        
+
         self.ThisClassRefParameter.CTYPES.append(alias+'&')
         try:
             param_type_matcher.register(alias+'&', self.ThisClassRefParameter)
         except ValueError: pass
-        
+
         self.ThisClassReturn.CTYPES.append(alias)
         try:
             return_type_matcher.register(alias, self.ThisClassReturn)
@@ -1245,7 +1252,7 @@ class CppClass(object):
             return_type_matcher.register(alias+'&', self.ThisClassRefReturn)
         except ValueError: pass
 
-        
+
     def get_module(self):
         """Get the Module object this class belongs to"""
         return self._module
@@ -1285,7 +1292,7 @@ class CppClass(object):
                 self.helper_class = CppHelperClass(self)
                 self.module.add_include('<typeinfo>')
         return self.helper_class
-    
+
     def get_type_narrowing_root(self):
         """Find the root CppClass along the subtree of all parent classes that
         have automatic_type_narrowing=True Note: multiple inheritance
@@ -1409,7 +1416,7 @@ public:
 
 }
 ''')
-        
+
 
         if self.import_from_module:
             code_sink.writeln("\nextern pybindgen::TypeMap *_%s;\n" % self.typeid_map_name)
@@ -1440,7 +1447,7 @@ public:
             method.force_parse = method.PARSE_TUPLE_AND_KEYWORDS
         else:
             raise TypeError
-        
+
         method.class_ = self
 
         if method.visibility == 'protected' and not method.is_virtual:
@@ -1499,7 +1506,7 @@ public:
                                 new_method = parent_method.clone()
                                 new_method.class_ = self
                                 overload.add(new_method)
-            
+
         else:
             self.nonpublic_methods.append(method)
         if method.is_virtual:
@@ -1883,7 +1890,7 @@ typedef struct {
             error_retcode = "MOD_ERROR"
         else:
             error_retcode = "NULL"
-        
+
         # TODO: skip this step if the requested typestructure is never used
         if ' named ' in self.import_from_module:
             module_name, type_name = self.import_from_module.split(" named ")
@@ -1914,7 +1921,7 @@ typedef struct {
                                          "    _%s = reinterpret_cast<pybindgen::TypeMap*> (PyCObject_AsVoidPtr (_cobj));\n"
                                          "    Py_DECREF(_cobj);\n"
                                          "}"
-                                         % (self.typeid_map_name, self.typeid_map_name))        
+                                         % (self.typeid_map_name, self.typeid_map_name))
 
         if self.parent is None:
             self.wrapper_registry.generate_import(code_sink, module.after_init, "module")
@@ -2009,7 +2016,7 @@ typedef struct {
 
         if self.has_output_stream_operator:
             self._generate_str(code_sink)
-        
+
         #self._generate_tp_hash(code_sink)
         #self._generate_tp_compare(code_sink)
 
@@ -2079,10 +2086,10 @@ typedef struct {
 
                 code_sink.writeln("{")
                 code_sink.indent()
-                
+
                 code_sink.writeln("%s left;" % left_name)
                 code_sink.writeln("%s right;" % right_name)
-                
+
                 code_sink.writeln("if (%s(py_left, &left) && %s(py_right, &right)) {" % (left_converter, right_converter))
                 code_sink.indent()
                 code_sink.writeln("%s result = (left %s right);" % (retval_name, op_symbol))
@@ -2093,7 +2100,7 @@ typedef struct {
 
                 code_sink.unindent()
                 code_sink.writeln("}")
-                
+
             code_sink.writeln("Py_INCREF(Py_NotImplemented);")
             code_sink.writeln("return Py_NotImplemented;")
             code_sink.unindent()
@@ -2117,9 +2124,9 @@ typedef struct {
 
                 code_sink.writeln("{")
                 code_sink.indent()
-                
+
                 code_sink.writeln("%s self;" % left_name)
-                
+
                 code_sink.writeln("if (%s(py_self, &self)) {" % (left_converter))
                 code_sink.indent()
                 code_sink.writeln("%s result = %s(self);" % (retval_name, op_symbol))
@@ -2130,7 +2137,7 @@ typedef struct {
 
                 code_sink.unindent()
                 code_sink.writeln("}")
-                
+
             code_sink.writeln("Py_INCREF(Py_NotImplemented);")
             code_sink.writeln("return Py_NotImplemented;")
             code_sink.unindent()
@@ -2140,7 +2147,7 @@ typedef struct {
         try_wrap_operator('-', 'nb_subtract')
         try_wrap_operator('*', 'nb_multiply')
         try_wrap_operator('/', 'nb_divide')
-        
+
         try_wrap_operator('+=', 'nb_inplace_add')
         try_wrap_operator('-=', 'nb_inplace_subtract')
         try_wrap_operator('*=', 'nb_inplace_multiply')
@@ -2150,7 +2157,7 @@ typedef struct {
 
         pynumbermethods.generate(code_sink)
         return '&' + number_methods_var_name
-        
+
     def _generate_sequence_methods(self, code_sink):
         sequence_methods_var_name = "%s__py_sequence_methods" % (self.mangled_full_name,)
 
@@ -2182,7 +2189,7 @@ typedef struct {
 
         pysequencemethods.generate(code_sink)
         return '&' + sequence_methods_var_name
-        
+
     def have_sequence_methods(self):
         """Determine if this object has sequence methods registered."""
         for x in self.valid_sequence_methods:
@@ -2203,8 +2210,8 @@ typedef struct {
         else:
             self.slots.setdefault("tp_dictoffset", "0")
         if self.binary_numeric_operators:
-            tp_flags.add("Py_TPFLAGS_CHECKTYPES")            
-        self.slots.setdefault("tp_flags", '|'.join(tp_flags))
+            tp_flags.add("Py_TPFLAGS_CHECKTYPES")
+        self.slots.setdefault("tp_flags", '|'.join(sorted(tp_flags)))
 
         if docstring is None:
             docstring = self.generate_docstring()
@@ -2227,7 +2234,8 @@ typedef struct {
         except KeyError:
             pass
         else:
-            dict_.setdefault("tp_call", call_method.wrapper_actual_name)
+            if call_method.wrapper_actual_name:
+                dict_.setdefault("tp_call", call_method.wrapper_actual_name)
 
         self.pytype.generate(code_sink)
 
@@ -2269,7 +2277,7 @@ typedef struct {
             ## tp_init to prevent this type from inheriting a
             ## tp_init that will allocate an instance of the
             ## parent class instead of this class.
-            code_sink.writeln()            
+            code_sink.writeln()
             wrapper = CppNoConstructor(self.cannot_be_constructed)
             wrapper.generate(code_sink, self)
             constructor = wrapper.wrapper_actual_name
@@ -2284,7 +2292,7 @@ typedef struct {
         construct_name = self.get_construct_name()
         copy_wrapper_name = '_wrap_%s__copy__' % self.pystruct
         code_sink.writeln('''
-static PyObject*\n%s(%s *self)
+static PyObject*\n%s(%s *self, PyObject *PYBINDGEN_UNUSED(_args))
 {
 ''' % (copy_wrapper_name, self.pystruct))
         code_sink.indent()
@@ -2536,7 +2544,7 @@ static int
 }
 
 ''' % (tp_compare_function_name, self.pystruct, self.pystruct))
-        
+
 
     def _generate_destructor(self, code_sink, have_constructor):
         """Generate a tp_dealloc function and register it in the type"""
@@ -2567,7 +2575,7 @@ static void
         code_block.write_code('Py_TYPE(self)->tp_free((PyObject*)self);')
 
         code_block.write_cleanup()
-        
+
         code_block.declarations.get_code_sink().flush_to(code_sink)
         code_block.sink.flush_to(code_sink)
 
@@ -2608,7 +2616,7 @@ if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &%s)) {
                 code_sink.writeln("Py_INCREF(Py_NotImplemented);\n"
                                   "return Py_NotImplemented;")
             code_sink.unindent()
-        
+
         wrap_operator('<', 'Py_LT')
         wrap_operator('<=', 'Py_LE')
         wrap_operator('==', 'Py_EQ')
@@ -2634,7 +2642,7 @@ if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &%s)) {
         module.after_init.write_code(
             'PyModule_AddObject(m, (char *) \"%s\", (PyObject *) &%s);' % (
                 alias, self.pytypestruct))
-        
+
     def write_allocate_pystruct(self, code_block, lvalue, wrapper_type=None):
         """
         Generates code to allocate a python wrapper structure, using
@@ -2654,7 +2662,7 @@ if (!PyObject_IsInstance((PyObject*) other, (PyObject*) &%s)) {
                 "%s->inst_dict = NULL;" % (lvalue,))
         if self.memory_policy is not None:
             code_block.write_code(self.memory_policy.get_pystruct_init_code(self, lvalue))
-        
+
 
 # from pybindgen.cppclass_typehandlers import CppClassParameter, CppClassRefParameter, \
 #     CppClassReturnValue, CppClassRefReturnValue, CppClassPtrParameter, CppClassPtrReturnValue, CppClassParameterBase, \
@@ -2673,7 +2681,8 @@ from pybindgen.cppmethod import CppMethod, CppConstructor, CppNoConstructor, Cpp
 
 def common_shared_object_return(value, py_name, cpp_class, code_block,
                                 type_traits, caller_owns_return,
-                                reference_existing_object, type_is_pointer, caller_manages_return=True):
+                                reference_existing_object, type_is_pointer, caller_manages_return=True,
+                                free_after_copy=False):
 
     if type_is_pointer:
         value_value = '(*%s)' % value
@@ -2805,7 +2814,7 @@ def common_shared_object_return(value, py_name, cpp_class, code_block,
                 code_block.unindent()
                 code_block.write_code("}")
             else:
-                code_block.write_code("}")            
+                code_block.write_code("}")
     else:
         # since there is a helper class, check if this C++ object is an instance of that class
         # http://stackoverflow.com/questions/579887/how-expensive-is-rtti/1468564#1468564
@@ -2876,7 +2885,7 @@ def common_shared_object_return(value, py_name, cpp_class, code_block,
                 code_block.unindent()
                 code_block.write_code("}")
             else:
-                code_block.write_code("}")            
+                code_block.write_code("}")
 
         code_block.unindent()
         code_block.write_code("}") # closes: if (typeid(*(%s)) == typeid(%s)) { ... } else { ...
@@ -2926,7 +2935,7 @@ class CppClassParameter(CppClassParameterBase):
     CTYPES = []
     cpp_class = None #cppclass.CppClass('dummy') # CppClass instance
     DIRECTIONS = [Parameter.DIRECTION_IN]
-    
+
     def convert_python_to_c(self, wrapper):
         "parses python args to get C++ value"
         #assert isinstance(wrapper, ForwardWrapperBase)
@@ -3044,7 +3053,7 @@ class CppClassRefParameter(CppClassParameterBase):
         super(CppClassRefParameter, self).__init__(
             ctype, name, direction, is_const, default_value)
         self.default_value_type = default_value_type
-    
+
     def convert_python_to_c(self, wrapper):
         "parses python args to get C++ value"
         #assert isinstance(wrapper, ForwardWrapperBase)
@@ -3303,9 +3312,12 @@ class CppClassRefReturnValue(CppClassReturnValueBase):
 
     def get_c_error_return(self): # only used in reverse wrappers
         """See ReturnValue.get_c_error_return"""
-        if self.type_traits.type_is_reference:
-            raise NotSupportedError
-        return "return %s();" % (self.cpp_class.full_name,)
+        if (
+            self.type_traits.type_is_reference
+            and not self.type_traits.target_is_const
+        ):
+            raise NotSupportedError("non-const reference return not supported")
+        return "{static %s __err; return __err;}" % (self.cpp_class.full_name,)
 
     def convert_c_to_python(self, wrapper):
         """see ReturnValue.convert_c_to_python"""
@@ -3341,8 +3353,11 @@ class CppClassRefReturnValue(CppClassReturnValueBase):
 
     def convert_python_to_c(self, wrapper):
         """see ReturnValue.convert_python_to_c"""
-        if self.type_traits.type_is_reference:
-            raise NotSupportedError
+        if (
+            self.type_traits.type_is_reference
+            and not self.type_traits.target_is_const
+        ):
+            raise NotSupportedError("non-const reference return not supported")
         name = wrapper.declarations.declare_variable(
             self.cpp_class.pystruct+'*', "tmp_%s" % self.cpp_class.name)
         wrapper.parse_params.add_parameter(
@@ -3353,7 +3368,7 @@ class CppClassRefReturnValue(CppClassReturnValueBase):
         else:
             wrapper.after_call.write_code('%s = *%s->obj;' % (self.value, name))
 
-    
+
 class CppClassPtrParameter(CppClassParameterBase):
     "Class* handlers"
     CTYPES = []
@@ -3463,7 +3478,7 @@ class CppClassPtrParameter(CppClassParameterBase):
 
         value = self.transformation.transform(self, wrapper.declarations, wrapper.before_call, value_ptr)
         wrapper.call_params.append(value)
-        
+
         if self.transfer_ownership:
             if not isinstance(self.cpp_class.memory_policy, ReferenceCountingPolicy):
                 # if we transfer ownership, in the end we no longer own the object, so clear our pointer
@@ -3472,7 +3487,7 @@ class CppClassPtrParameter(CppClassParameterBase):
                 if self.cpp_class.memory_policy is not None:
                     self.cpp_class.wrapper_registry.write_unregister_wrapper(wrapper.after_call,
                                                                             '%s' % self.py_name,
-                                                                            self.memory_policy.get_pointer_to_void_name('%s->obj' % self.py_name))
+                                                                            self.cpp_class.memory_policy.get_pointer_to_void_name('%s->obj' % self.py_name))
                 else:
                     self.cpp_class.wrapper_registry.write_unregister_wrapper(wrapper.after_call,
                                                                             '%s' % self.py_name,
@@ -3659,7 +3674,7 @@ class CppClassPtrParameter(CppClassParameterBase):
             wrapper.before_call.unindent()
             wrapper.before_call.write_code("}") # closes if (typeid(*(%s)) == typeid(%s))\n{
             wrapper.build_params.add_parameter("N", [py_name])
-            
+
 
 
 class CppClassPtrReturnValue(CppClassReturnValueBase):
@@ -3670,11 +3685,13 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
 
     def __init__(self, ctype, caller_owns_return=None, custodian=None,
                  is_const=False, reference_existing_object=None,
-                 return_internal_reference=None, caller_manages_return=True):
+                 return_internal_reference=None, caller_manages_return=True, free_after_copy=False):
         """
         :param ctype: C type, normally 'MyClass*'
         :param caller_owns_return: if true, ownership of the object pointer
                               is transferred to the caller
+        :param free_after_copy: if true, the python wrapper must call delete on
+                              the returned pointer once it has taken a copy.
 
         :param custodian: bind the life cycle of the python wrapper
                for the return value object (ward) to that
@@ -3698,7 +3715,7 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
                   to an object that may have been deallocated in the
                   mean time.  Calling methods on such an object would
                   lead to a memory error.
-                  
+
         :param return_internal_reference: like
             reference_existing_object, but additionally adds
             custodian/ward to bind the lifetime of the 'self' object
@@ -3721,6 +3738,7 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
 
         self.caller_owns_return = caller_owns_return
         self.caller_manages_return = caller_manages_return
+        self.free_after_copy = free_after_copy
         self.reference_existing_object = reference_existing_object
         self.return_internal_reference = return_internal_reference
         if self.return_internal_reference:
@@ -3728,7 +3746,11 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
             self.reference_existing_object = True
         self.custodian = custodian
 
+        if self.caller_owns_return and self.free_after_copy:
+            raise TypeConfigurationError("only one of caller_owns_return or free_after_copy can be given")
+
         if self.caller_owns_return is None\
+                and self.free_after_copy is None \
                 and self.reference_existing_object is None:
             raise TypeConfigurationError("Either caller_owns_return or self.reference_existing_object must be given")
 
@@ -3743,7 +3765,7 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
         ## Value transformations
         value = self.transformation.untransform(
             self, wrapper.declarations, wrapper.after_call, self.value)
-        
+
         # if value is NULL, return None
         wrapper.after_call.write_code("if (!(%s)) {\n"
                                       "    Py_INCREF(Py_None);\n"
@@ -3759,11 +3781,15 @@ class CppClassPtrReturnValue(CppClassReturnValueBase):
                                     self.type_traits, self.caller_owns_return,
                                     self.reference_existing_object,
                                     type_is_pointer=True,
-                                    caller_manages_return=self.caller_manages_return)
+                                    caller_manages_return=self.caller_manages_return,
+                                    free_after_copy=self.free_after_copy)
 
         # return the value
         wrapper.build_params.add_parameter("N", [py_name], prepend=True)
-    
+        if self.free_after_copy:
+            wrapper.after_call.add_cleanup_code("delete retval;")
+            wrapper.after_call.add_cleanup_code("// free_after_copy for %s* %ss" % (self.cpp_class.name,wrapper.function_name))
+
 
     def convert_python_to_c(self, wrapper):
         """See ReturnValue.convert_python_to_c"""
@@ -3863,7 +3889,7 @@ def _add_ward(code_block, custodian, ward):
         "if (%(ward)s && !PySequence_Contains(%(wards)s, %(ward)s))\n"
         "    PyList_Append(%(wards)s, %(ward)s);" % dict(wards=wards, ward=ward))
     code_block.add_cleanup_code("Py_DECREF(%s);" % wards)
-            
+
 
 def _get_custodian_or_ward(wrapper, num):
     if num == -1:
diff --git a/pybindgen/cppmethod.py b/pybindgen/cppmethod.py
index 9d29e2f..06263fa 100644
--- a/pybindgen/cppmethod.py
+++ b/pybindgen/cppmethod.py
@@ -84,7 +84,7 @@ class CppMethod(ForwardWrapperBase):
         # bug 399870
         if is_virtual is None:
             is_virtual = is_pure_virtual
-            
+
         if return_value is None:
             return_value = ReturnValue.new('void')
 
@@ -291,7 +291,7 @@ class CppMethod(ForwardWrapperBase):
 
                            self.method_name, template_params,
                            ", ".join(self.call_params),
-                           
+
                            class_.full_name, self.method_name, template_params,
                            ", ".join(self.call_params)
                            )))
@@ -354,14 +354,23 @@ class CppMethod(ForwardWrapperBase):
                     "extra_wrapper_params can only be used with"\
                     " full varargs/kwargs wrappers"
                 self.wrapper_args = ["%s *%s" % (self._get_pystruct(), _self_name),
-                                     "PyObject *args"]
+                                     "PyObject *args",
+                                     "PyObject *PYBINDGEN_UNUSED(_kwargs)"]
         else:
             assert not extra_wrapper_params, \
                 "extra_wrapper_params can only be used with full varargs/kwargs wrappers"
             if 'METH_STATIC' in flags:
-                self.wrapper_args = ['void']
+                self.wrapper_args = [
+                    'PyObject *PYBINDGEN_UNUSED(_self)',
+                    "PyObject *PYBINDGEN_UNUSED(_args)",
+                    "PyObject *PYBINDGEN_UNUSED(_kwargs)",
+                ]
             else:
-                self.wrapper_args = ["%s *%s" % (self._get_pystruct(), _self_name)]
+                self.wrapper_args = [
+                    "%s *%s" % (self._get_pystruct(), _self_name),
+                    "PyObject *PYBINDGEN_UNUSED(_args)",
+                    "PyObject *PYBINDGEN_UNUSED(_kwargs)",
+                ]
         self.wrapper_args.extend(extra_wrapper_params)
 
         return self.wrapper_return, "%s(%s)" % (self.wrapper_actual_name, ', '.join(self.wrapper_args))
@@ -411,7 +420,7 @@ class CppMethod(ForwardWrapperBase):
             self.docstring = self.generate_docstring(method_name)
 
         return "{(char *) \"%s\", (PyCFunction) %s, %s, %s }," % \
-               (method_name, self.wrapper_actual_name, '|'.join(flags),
+               (method_name, self.wrapper_actual_name, '|'.join(sorted(flags)),
                 (self.docstring is None and "NULL" or ('"'+self.docstring+'"')))
 
     def generate_docstring(self, name):
@@ -439,7 +448,7 @@ class CppMethod(ForwardWrapperBase):
             pure_virtual = " = 0"
         else:
             pure_virtual = ''
-        
+
         if self.return_value is None:
             retval = "retval?"
         else:
@@ -631,7 +640,7 @@ class CppConstructor(ForwardWrapperBase):
         "Get the class wrapper object (CppClass)"
         return self._class
     class_ = property(get_class, set_class)
-    
+
     def generate_call(self, class_=None):
         "virtual method implementation; do not call"
         if class_ is None:
@@ -758,7 +767,7 @@ class CppConstructor(ForwardWrapperBase):
             cls_name = "???"
         else:
             cls_name = self._class.full_name
-        
+
         if self.return_value is None:
             retval = "retval?"
         else:
@@ -839,7 +848,7 @@ class CppNoConstructor(ForwardWrapperBase):
     def generate_call(self):
         "dummy method, not really called"
         pass
-    
+
     def generate(self, code_sink, class_):
         """
         Generates the wrapper code
@@ -922,7 +931,7 @@ class CppVirtualMethodParentCaller(CppMethod):
                                                    ', '.join([param.name for param in self.parameters])))
         else:
             code_sink.writeln('{ return %s::%s(%s); }' % (self.method.class_.full_name, self.method_name,
-                                                          ', '.join([param.name for param in self.parameters])))        
+                                                          ', '.join([param.name for param in self.parameters])))
 
 
     def generate_call(self, class_=None):
@@ -937,7 +946,7 @@ class CppVirtualMethodParentCaller(CppMethod):
             "%s == NULL" % helper,
             'PyErr_SetString(PyExc_TypeError, "Method %s of class %s is protected and can only be called by a subclass");'
             % (self.method_name, self.class_.name))
-        
+
         if self.return_value.ctype == 'void':
             self.before_call.write_code(
                 '%s(%s);' %
@@ -965,7 +974,7 @@ class CppVirtualMethodParentCaller(CppMethod):
         return "{(char *) \"%s\", (PyCFunction) %s, %s, %s }," % \
                (method_name,
                 self.wrapper_actual_name,#'::'.join((self._helper_class.name, self.wrapper_actual_name)),
-                '|'.join(flags),
+                '|'.join(sorted(flags)),
                 (self.docstring is None and "NULL" or ('"'+self.docstring+'"')))
 
     def clone(self):
@@ -1066,7 +1075,7 @@ class CppVirtualMethodProxy(ReverseWrapperBase):
             self.before_call.write_code('%s = PyObject_GetAttrString(m_pyself, (char *) "%s"); PyErr_Clear();'
                                         % (py_method, self.method_name))
         self.before_call.add_cleanup_code('Py_XDECREF(%s);' % py_method)
-        
+
         self.before_call.write_code(
             r'if (%s == NULL || Py_TYPE(%s) == &PyCFunction_Type) {' % (py_method, py_method))
         if self.return_value.ctype == 'void':
@@ -1111,7 +1120,7 @@ Py_FatalError("Error detected, but parent virtual is pure virtual or private vir
                                     (self.class_.pystruct, this_expression))
         self.before_call.add_cleanup_code("reinterpret_cast< %s* >(m_pyself)->obj = %s;" %
                                           (self.class_.pystruct, self_obj_before))
-        
+
         super(CppVirtualMethodProxy, self).generate(
             code_sink, '::'.join((self._helper_class.name, self.method_name)),
             decl_modifiers=[],
diff --git a/pybindgen/function.py b/pybindgen/function.py
index 19b0883..6d4069b 100644
--- a/pybindgen/function.py
+++ b/pybindgen/function.py
@@ -60,13 +60,13 @@ class Function(ForwardWrapperBase):
 
         if unblock_threads is None:
             unblock_threads = settings.unblock_threads
-        
+
         ## backward compatibility check
         if isinstance(return_value, string_types) and isinstance(function_name, ReturnValue):
             warnings.warn("Function has changed API; see the API documentation (but trying to correct...)",
                           DeprecationWarning, stacklevel=2)
             function_name, return_value = return_value, function_name
-            
+
         if return_value is None:
             return_value = ReturnValue.new('void')
 
@@ -175,7 +175,7 @@ class Function(ForwardWrapperBase):
         self.wrapper_base_name = "_wrap_%s_%s" % (
             module.prefix, self.mangled_name)
     module = property(get_module, set_module)
-    
+
     def generate_call(self):
         "virtual method implementation; do not call"
         if self.foreign_cpp_namespace:
@@ -189,7 +189,7 @@ class Function(ForwardWrapperBase):
             template_params = '< %s >' % ', '.join(self.template_parameters)
         else:
             template_params = ''
- 
+
         if self.throw:
             self.before_call.write_code('try\n{')
             self.before_call.indent()
@@ -260,12 +260,17 @@ class Function(ForwardWrapperBase):
             self.wrapper_args.append("PyObject *args")
             if 'METH_KEYWORDS' in flags:
                 self.wrapper_args.append("PyObject *kwargs")
+            else:
+                self.wrapper_args.append("PyObject *PYBINDGEN_UNUSED(_kwargs)")
+        else:
+                self.wrapper_args.append("PyObject *PYBINDGEN_UNUSED(_args)")
+                self.wrapper_args.append("PyObject *PYBINDGEN_UNUSED(_kwargs)")
         self.wrapper_args.extend(extra_wrapper_params)
         self.wrapper_return = "PyObject *"
         self.write_open_wrapper(code_sink)
         tmp_sink.flush_to(code_sink)
         self.write_close_wrapper(code_sink)
-        
+
 
     def generate_declaration(self, code_sink, extra_wrapper_parameters=()):
         ## We need to fake generate the code (and throw away the
@@ -294,7 +299,7 @@ class Function(ForwardWrapperBase):
             self.docstring = self.generate_docstring(name)
 
         return "{(char *) \"%s\", (PyCFunction) %s, %s, %s }," % \
-               (name, self.wrapper_actual_name, '|'.join(flags),
+               (name, self.wrapper_actual_name, '|'.join(sorted(flags)),
                 (self.docstring is None and "NULL" or ('"'+self.docstring+'"')))
 
     def generate_docstring(self, name):
diff --git a/pybindgen/gccxmlparser.py b/pybindgen/gccxmlparser.py
deleted file mode 100644
index 39ab0ee..0000000
--- a/pybindgen/gccxmlparser.py
+++ /dev/null
@@ -1,2301 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals, print_function, absolute_import
-
-DEBUG = False
-
-
-import sys
-
-PY3 = (sys.version_info[0] >= 3)
-if PY3:
-    string_types = str,
-else:
-    string_types = basestring,
-
-
-import os.path
-import warnings
-import re
-import pygccxml
-from pygccxml import parser
-from pygccxml import declarations
-from .module import Module
-from .typehandlers.codesink import FileCodeSink, CodeSink, NullCodeSink
-from .typehandlers import base
-from . import typehandlers
-from .typehandlers.base import ctypeparser
-from .typehandlers.base import ReturnValue, Parameter, TypeLookupError, TypeConfigurationError, NotSupportedError
-from pygccxml.declarations.enumeration import enumeration_t
-from .cppclass import CppClass, ReferenceCountingMethodsPolicy, FreeFunctionPolicy, ReferenceCountingFunctionsPolicy
-from .cppexception import CppException
-from pygccxml.declarations import type_traits
-from pygccxml.declarations import cpptypes
-from pygccxml.declarations import calldef
-from pygccxml.declarations import templates
-from pygccxml.declarations import container_traits
-from pygccxml.declarations.declaration import declaration_t
-from pygccxml.declarations.class_declaration import class_declaration_t, class_t
-from . import settings
-from . import utils
-
-#from pygccxml.declarations.calldef import \
-#    destructor_t, constructor_t, member_function_t
-from pygccxml.declarations.variable import variable_t
-import collections
-
-
-###
-### some patched pygccxml functions, from the type_traits module
-###
-def remove_pointer(type):
-    """removes pointer from the type definition
-
-    If type is not pointer type, it will be returned as is.
-    """
-    #nake_type = remove_alias( type )
-    nake_type = type
-    if not type_traits.is_pointer( nake_type ):
-        return type
-    elif isinstance( nake_type, cpptypes.volatile_t ) and isinstance( nake_type.base, cpptypes.pointer_t ):
-        return cpptypes.volatile_t( nake_type.base.base )
-    elif isinstance( nake_type, cpptypes.const_t ) and isinstance( nake_type.base, cpptypes.pointer_t ):
-        return cpptypes.const_t( nake_type.base.base )
-    elif isinstance(nake_type, cpptypes.compound_t) and isinstance( nake_type.base, cpptypes.calldef_type_t ):
-        return type
-    else:
-        if isinstance(nake_type, cpptypes.compound_t):
-            return nake_type.base
-        else:
-            return nake_type
-
-def remove_reference(type):
-    """removes reference from the type definition
-
-    If type is not reference type, it will be returned as is.
-    """
-    #nake_type = remove_alias( type )
-    nake_type = type
-    if not type_traits.is_reference( nake_type ):
-        return type
-    else:
-        if isinstance(nake_type, cpptypes.compound_t):
-            return nake_type.base
-        else:
-            return nake_type
-
-def remove_const(type):
-    """removes const from the type definition
-
-    If type is not const type, it will be returned as is
-    """
-
-    #nake_type = remove_alias( type )
-    nake_type = type
-    if not type_traits.is_const( nake_type ):
-        return type
-    else:
-        if isinstance(nake_type, cpptypes.compound_t):
-            return nake_type.base
-        else:
-            return nake_type
-###
-### end of patched pygccxml functions
-###
-
-
-## --- utility ---
-
-import pygccxml.declarations.type_traits
-def find_declaration_from_name(global_ns, declaration_name):
-    decl = pygccxml.declarations.type_traits.impl_details.find_value_type(global_ns, declaration_name)
-    return decl
-
-
-class ModuleParserWarning(Warning):
-    """
-    Base class for all warnings reported here.
-    """
-class NotSupportedWarning(ModuleParserWarning):
-    """
-    Warning for pybindgen GccxmlParser, to report something pybindgen does not support.
-    """
-class WrapperWarning(ModuleParserWarning):
-    """
-    Warning for pybindgen GccxmlParser, to be used when a C++
-    definition cannot be converted to a pybindgen wrapper.
-    """
-class AnnotationsWarning(ModuleParserWarning):
-    """
-    Warning for pybindgen GccxmlParser to report a problem in annotations.
-    """
-
-## ------------------------
-
-class ErrorHandler(settings.ErrorHandler):
-    def handle_error(self, wrapper, exception, traceback_):
-        if hasattr(wrapper, "gccxml_definition"):
-            definition = wrapper.gccxml_definition
-        elif hasattr(wrapper, "main_wrapper"):
-            try:
-                definition = wrapper.main_wrapper.gccxml_definition
-            except AttributeError:
-                definition = None
-        else:
-            definition = None
-
-        if definition is None:
-            print("exception %r in wrapper %s" % (exception, wrapper), file=sys.stderr)
-        else:
-            warnings.warn_explicit("exception %r in wrapper for %s"
-                                   % (exception, definition),
-                                   WrapperWarning, definition.location.file_name,
-                                   definition.location.line)
-        return True
-settings.error_handler = ErrorHandler()
-
-def normalize_name(decl_string):
-    return ctypeparser.normalize_type_string(decl_string)
-
-def normalize_class_name(class_name, module_namespace):
-    class_name = utils.ascii(class_name)
-    if not class_name.startswith(module_namespace):
-        class_name = module_namespace + class_name
-    class_name = normalize_name(class_name)
-    return class_name
-
-
-def _pygen_kwargs(kwargs):
-    l = []
-    for key, val in kwargs.items():
-        if isinstance(val, (CppClass, CppException)):
-            l.append("%s=root_module[%r]" % (key, utils.ascii(val.full_name)))
-        else:
-            if key == 'throw':
-                l.append("throw=[%s]" % (', '.join(["root_module[%r]" % utils.ascii(t.full_name) for t in val])))
-            elif key == 'parent' and isinstance(val, list):
-                l.append("parent=[%s]" % (', '.join(["root_module[%r]" % utils.ascii(cls.full_name) for cls in val])))
-            else:
-                l.append("%s=%r" % (key, val))
-    return l
-
-def _pygen_args_kwargs(args, kwargs):
-    return ", ".join([repr(arg) for arg in args] + _pygen_kwargs(kwargs))
-
-def _pygen_args_kwargs_dict(args, kwargs):
-    l = [repr(arg) for arg in args]
-    if kwargs:
-        l.append("dict(%s)" % ', '.join(_pygen_kwargs(kwargs)))
-    return ", ".join(l)
-
-def _pygen_retval(args, kwargs):
-    if len(args) == 1 and len(kwargs) == 0:
-        return repr(args[0])
-    return "retval(%s)" % _pygen_args_kwargs(args, kwargs)
-
-def _pygen_param(args, kwargs):
-    return "param(%s)" % _pygen_args_kwargs(args, kwargs)
-
-
-class GccXmlTypeRegistry(object):
-    def __init__(self, root_module):
-        """
-        :param root_module: the root L{Module} object
-        """
-        assert isinstance(root_module, Module)
-        assert root_module.parent is None
-        self.root_module = root_module
-        self.ordered_classes = [] # registered classes list, by registration order
-        self._root_ns_rx = re.compile(r"(^|\s)(::)")
-
-    def class_registered(self, cpp_class):
-        assert isinstance(cpp_class, (CppClass, CppException))
-        self.ordered_classes.append(cpp_class)
-
-#     def get_type_traits(self, type_info):
-#         #assert isinstance(type_info, cpptypes.type_t)
-
-#         debug = False #('int64_t' in type_info.decl_string)
-#         if debug:
-#             print >> sys.stderr, "***** type traits for %r" % (type_info.decl_string, )
-
-#         is_const = False
-#         is_reference = False
-#         is_pointer = 0
-#         pointer_or_ref_count = 0
-#         inner_const = False
-#         while 1:
-#             prev_type_info = type_info
-#             if type_traits.is_pointer(type_info):
-#                 is_pointer += 1
-#                 type_info = remove_pointer(type_info)
-#                 pointer_or_ref_count += 1
-#             elif type_traits.is_const(type_info):
-#                 type_info = remove_const(type_info)
-#                 if pointer_or_ref_count == 0:
-#                     is_const = True
-#                 elif pointer_or_ref_count == 1:
-#                     inner_const = True
-#                 else:
-#                     warnings.warn("multiple consts not handled")
-#             elif type_traits.is_reference(type_info):
-#                 warnings.warn("multiple &'s not handled")
-#                 is_reference = True
-#                 type_info = remove_reference(type_info)
-#                 pointer_or_ref_count += 1
-#             else:
-#                 break
-#             if type_info is prev_type_info:
-#                 break
-
-#         type_name = normalize_name(type_info.partial_decl_string)
-#         try:
-#             cpp_type = self.root_module[type_name]
-#         except KeyError:
-#             cpp_type = type_name
-
-#         if not isinstance(cpp_type, CppClass):
-#             cpp_type = type_name
-
-#         if debug:
-#             print >> sys.stderr, "*** > return ", repr((cpp_type, is_const, is_pointer, is_reference))
-#         return (cpp_type, is_const, inner_const, is_pointer, is_reference)
-
-    def _fixed_std_type_name(self, type_name):
-        type_name = utils.ascii(type_name)
-        decl = self._root_ns_rx.sub('', type_name)
-        return decl
-
-    def lookup_return(self, type_info, annotations={}):
-        kwargs = {}
-        for name, value in annotations.items():
-            if name == 'caller_owns_return':
-                kwargs['caller_owns_return'] = annotations_scanner.parse_boolean(value)
-            elif name == 'reference_existing_object':
-                kwargs['reference_existing_object'] = annotations_scanner.parse_boolean(value)
-            elif name == 'return_internal_reference':
-                kwargs['return_internal_reference'] = annotations_scanner.parse_boolean(value)
-            elif name == 'custodian':
-                kwargs['custodian'] = int(value)
-            else:
-                warnings.warn("invalid annotation name %r" % name, AnnotationsWarning)
-
-        cpp_type = normalize_name(type_info.partial_decl_string)
-        return (cpp_type,), kwargs
-
-
-    def lookup_parameter(self, type_info, param_name, annotations={}, default_value=None):
-        kwargs = {}
-        for name, value in annotations.items():
-            if name == 'transfer_ownership':
-                kwargs['transfer_ownership'] = annotations_scanner.parse_boolean(value)
-            elif name == 'direction':
-                if value.lower() == 'in':
-                    kwargs['direction'] = Parameter.DIRECTION_IN
-                elif value.lower() == 'out':
-                    kwargs['direction'] = Parameter.DIRECTION_OUT
-                elif value.lower() == 'inout':
-                    kwargs['direction'] = Parameter.DIRECTION_INOUT
-                else:
-                    warnings.warn("invalid direction direction %r" % value, AnnotationsWarning)
-            elif name == 'custodian':
-                kwargs['custodian'] = int(value)
-            elif name == 'array_length':
-                kwargs['array_length'] = int(value)
-            elif name == 'default_value':
-                kwargs['default_value'] = value
-            elif name == 'null_ok':
-                kwargs['null_ok'] = annotations_scanner.parse_boolean(value)
-            else:
-                warnings.warn("invalid annotation name %r" % name, AnnotationsWarning)
-
-        if default_value:
-            kwargs['default_value'] = utils.ascii(default_value)
-
-        cpp_type = normalize_name(type_info.partial_decl_string)
-
-        return (cpp_type, param_name), kwargs
-
-
-class AnnotationsScanner(object):
-    def __init__(self):
-        self.files = {} # file name -> list(lines)
-        self.used_annotations = {} # file name -> list(line_numbers)
-        self._comment_rx = re.compile(
-            r"^\s*(?://\s+-#-(?P<annotation1>.*)-#-\s*)|(?:/\*\s+-#-(?P<annotation2>.*)-#-\s*\*/)")
-        self._global_annotation_rx = re.compile(r"(\w+)(?:=([^\s;]+))?")
-        self._param_annotation_rx = re.compile(r"@(\w+)\(([^;]+)\)")
-
-    def _declare_used_annotation(self, file_name, line_number):
-        try:
-            l = self.used_annotations[file_name]
-        except KeyError:
-            l = []
-            self.used_annotations[file_name] = l
-        l.append(line_number)
-
-    def get_annotations(self, decl):
-        """
-        :param decl: pygccxml declaration_t object
-        """
-        assert isinstance(decl, declaration_t)
-
-        if isinstance(decl, calldef.calldef_t) \
-                and decl.is_artificial:
-            #print >> sys.stderr, "********** ARTIFICIAL:", decl
-            return {}, {}
-
-        file_name = decl.location.file_name
-        line_number = decl.location.line
-
-        try:
-            lines = self.files[file_name]
-        except KeyError:
-            with open(file_name, "rt") as f:
-                lines = f.readlines()
-            self.files[file_name] = lines
-
-        line_number -= 2
-        global_annotations = {}
-        parameter_annotations = {}
-        while 1:
-            line = lines[line_number]
-            line_number -= 1
-            m = self._comment_rx.match(line)
-            if m is None:
-                break
-            s = m.group('annotation1')
-            if s is None:
-                s = m.group('annotation2')
-            line = s.strip()
-            self._declare_used_annotation(file_name, line_number + 2)
-            for annotation_str in line.split(';'):
-                annotation_str = annotation_str.strip()
-                m = self._global_annotation_rx.match(annotation_str)
-                if m is not None:
-                    global_annotations[m.group(1)] = m.group(2)
-                    continue
-
-                m = self._param_annotation_rx.match(annotation_str)
-                if m is not None:
-                    param_annotation = {}
-                    parameter_annotations[m.group(1)] = param_annotation
-                    for param in m.group(2).split(','):
-                        m = self._global_annotation_rx.match(param.strip())
-                        if m is not None:
-                            param_annotation[m.group(1)] = m.group(2)
-                        else:
-                            warnings.warn_explicit("could not parse %r as parameter annotation element" %
-                                                   (param.strip()),
-                                                   AnnotationsWarning, file_name, line_number)
-                    continue
-                warnings.warn_explicit("could not parse %r" % (annotation_str),
-                                       AnnotationsWarning, file_name, line_number)
-        return global_annotations, parameter_annotations
-
-    def parse_boolean(self, value):
-        if isinstance(value, int):
-            return bool(value)
-        if value.lower() in ['false', 'off']:
-            return False
-        elif value.lower() in ['true', 'on']:
-            return True
-        else:
-            raise ValueError("bad boolean value %r" % value)
-
-    def warn_unused_annotations(self):
-        for file_name, lines in self.files.items():
-            try:
-                used_annotations = self.used_annotations[file_name]
-            except KeyError:
-                used_annotations = []
-            for line_number, line in enumerate(lines):
-                m = self._comment_rx.match(line)
-                if m is None:
-                    continue
-                #print >> sys.stderr, (line_number+1), used_annotations
-                if (line_number + 1) not in used_annotations:
-                    warnings.warn_explicit("unused annotation",
-                                           AnnotationsWarning, file_name, line_number+1)
-
-
-
-annotations_scanner = AnnotationsScanner()
-
-## ------------------------
-
-class PygenSection(object):
-    "Class to hold information about a python generation section"
-    def __init__(self, name, code_sink, local_customizations_module=None):
-        """
-        :param name: section name; this name should be a valid python
-            module name; the special name '__main__' is used to denote the
-            main section, which comprises the main script itself
-        :type name: str
-
-        :param code_sink: code sink that will receive the generated
-           code for the section.  Normally the code sink should write to
-           a file with the name of the section and a .py extension, to
-           allow importing it as module.
-        :type code_sink: L{CodeSink}
-
-        :param local_customizations_module: name of the python module
-          that may contain local customizations for the section, or
-          None.  If not None, PyBindGen will generate code that tries to
-          import that module in the respective section and call
-          functions on it, or ignore it if the module does not exist.
-        :type local_customizations_module: str
-        """
-        assert isinstance(name, string_types)
-        self.name = name
-        assert isinstance(code_sink, CodeSink)
-        self.code_sink = code_sink
-        assert local_customizations_module is None or isinstance(local_customizations_module, string_types)
-        self.local_customizations_module = local_customizations_module
-
-
-class PygenClassifier(object):
-    def classify(self, pygccxml_definition):
-        """
-        This is a pure virtual method that must be implemented by
-        subclasses.  It will be called by PyBindGen for every API
-        definition, and should return a section name.
-
-        :param pygccxml_definition: gccxml definition object
-        :returns: section name
-        """
-        raise NotImplementedError
-
-    def get_section_precedence(self, section_name):
-        """
-        This is a pure virtual method that may (or not) be implemented by
-        subclasses.  It will be called by PyBindGen for every API
-        definition, and should return the precedence of a section.
-        This is used when sections reflect 'modules' whose types must be
-        registered in a certain order.
-
-        :param section_name: the name of the section
-
-        :returns: order of precedence of the section.  The lower the
-          number, the sooner the section is to be registered.
-        """
-        raise NotImplementedError
-
-
-class ModuleParser(object):
-    """
-    :attr enable_anonymous_containers: if True, pybindgen will attempt
-        to scan for all std containers, even the ones that have no
-        typedef'ed name.  Enabled by default.
-
-    """
-
-    def __init__(self, module_name, module_namespace_name='::'):
-        """
-        Creates an object that will be able parse header files and
-        create a pybindgen module definition.
-
-        :param module_name: name of the Python module
-        :param module_namespace_name: optional C++ namespace name; if
-                                 given, only definitions of this
-                                 namespace will be included in the
-                                 python module
-        """
-        self.module_name = module_name
-        self.module_namespace_name = module_namespace_name
-        self.location_filter = None
-        self.header_files = None
-        self.gccxml_config = None
-        self.whitelist_paths = []
-        self.module_namespace = None # pygccxml module C++ namespace
-        self.module = None # the toplevel pybindgen.module.Module instance (module being generated)
-        self.declarations = None # (as returned by pygccxml.parser.parse)
-        self.global_ns = None
-        self._types_scanned = False
-        self._pre_scan_hooks = []
-        self._post_scan_hooks = []
-        self.type_registry = None
-        self._stage = None
-        self._pygen_sink = None
-        self._pygen_factory = None
-        self._anonymous_structs = [] # list of (pygccxml_anonymous_class, outer_pybindgen_class)
-        self._containers_to_register = []
-        self._containers_registered = {}
-        self.enable_anonymous_containers = True
-
-    def add_pre_scan_hook(self, hook):
-        """
-        Add a function to be called right before converting a gccxml
-        definition to a PyBindGen wrapper object.  This hook function
-        will be called for every scanned type, function, or method,
-        and given the a chance to modify the annotations for that
-        definition.  It will be called like this:::
-
-          pre_scan_hook(module_parser, pygccxml_definition, global_annotations,
-                        parameter_annotations)
-
-        where:
-
-           - module_parser -- the ModuleParser (this class) instance
-           - pygccxml_definition -- the definition reported by pygccxml
-           - global_annotations -- a dicionary containing the "global annotations"
-                                 for the definition, i.e. a set of key=value
-                                 pairs not associated with any particular
-                                 parameter
-           - parameter_annotations -- a dicionary containing the "parameter
-                                    annotations" for the definition.  It is a
-                                    dict whose keys are parameter names and
-                                    whose values are dicts containing the
-                                    annotations for that parameter.  Annotations
-                                    pertaining the return value of functions or
-                                    methods are denoted by a annotation for a
-                                    parameter named 'return'.
-        """
-        if not isinstance(hook, collections.Callable):
-            raise TypeError("hook must be callable")
-        self._pre_scan_hooks.append(hook)
-
-    def add_post_scan_hook(self, hook):
-        """
-        Add a function to be called right after converting a gccxml definition
-        to a PyBindGen wrapper object.  This hook function will be called for
-        every scanned type, function, or method.  It will be called like this::
-
-          post_scan_hook(module_parser, pygccxml_definition, pybindgen_wrapper)
-
-        where:
-
-           - module_parser -- the ModuleParser (this class) instance
-           - pygccxml_definition -- the definition reported by pygccxml
-           - pybindgen_wrapper -- a pybindgen object that generates a wrapper,
-                                such as CppClass, Function, or CppMethod.
-        """
-        if not isinstance(hook, collections.Callable):
-            raise TypeError("hook must be callable")
-        self._post_scan_hooks.append(hook)
-
-    def __location_match(self, decl):
-        if decl.location.file_name in self.header_files:
-            return True
-        for incdir in self.whitelist_paths:
-            if os.path.abspath(decl.location.file_name).startswith(incdir):
-                return True
-        return False
-
-    def parse(self, header_files, include_paths=None, whitelist_paths=None, includes=(),
-              pygen_sink=None, pygen_classifier=None, gccxml_options=None):
-        """
-        parses a set of header files and returns a pybindgen Module instance.
-        It is equivalent to calling the following methods:
-         1. parse_init(header_files, include_paths, whitelist_paths)
-         2. scan_types()
-         3. scan_methods()
-         4. scan_functions()
-         5. parse_finalize()
-
-         The documentation for L{ModuleParser.parse_init} explains the parameters.
-        """
-        self.parse_init(header_files, include_paths, whitelist_paths, includes, pygen_sink,
-                        pygen_classifier, gccxml_options)
-        self.scan_types()
-        self.scan_methods()
-        self.scan_functions()
-        self.parse_finalize()
-        return self.module
-
-    def parse_init(self, header_files, include_paths=None,
-                   whitelist_paths=None, includes=(), pygen_sink=None, pygen_classifier=None,
-                   gccxml_options=None):
-        """
-        Prepares to parse a set of header files.  The following
-        methods should then be called in order to finish the rest of
-        scanning process:
-
-          #. scan_types()
-          #. scan_methods()
-          #. scan_functions()
-          #. parse_finalize()
-
-        :param header_files: header files to parse
-        :type header_files: list of string
-
-        :param include_paths: (deprecated, use the parameter gccxml_options) list of include paths
-        :type include_paths: list of string
-
-        :param whitelist_paths: additional directories for definitions to be included
-           Normally the module parser filters out API definitions that
-           have been defined outside one of the header files indicated
-           for parsing.  The parameter whitelist_paths instructs the
-           module parser to accept definitions defined in another
-           header file if such header file is inside one of the
-           directories listed by whitelist_paths.
-        :type whitelist_paths: list of string
-
-        :param pygen_sink: code sink for python script generation.
-
-           This parameter activates a mode wherein ModuleParser, in
-           addition to building in memory API definitions, creates a
-           python script that will generate the module, when executed.
-           The generated Python script can be human editable and does
-           not require pygccxml or gccxml to run, only PyBindGen to be
-           installed.
-
-           The pygen parameter can be either:
-             #. A single code sink: this will become the main and only script file to be generated
-             #. A list of L{PygenSection} objects.  This option
-                requires the pygen_classifier to be given.
-
-        :type pygen_sink: L{CodeSink} or list of L{PygenSection} objects
-
-        :param pygen_classifier: the classifier to use when pygen is given and is a dict
-
-        :param gccxml_options: extra options to pass into the
-            :class:`pygccxml.parser.config.gccxml_configuration_t` object as keyword
-            arguments for more information).
-
-        :type gccxml_options: dict
-
-        """
-        assert isinstance(header_files, list)
-        assert isinstance(includes, (list, tuple))
-        self._pygen = pygen_sink
-        self._pygen_classifier = pygen_classifier
-        if isinstance(pygen_sink, list):
-            assert isinstance(pygen_classifier, PygenClassifier)
-            has_main = False
-            for sect in self._pygen:
-                if not isinstance(sect, PygenSection):
-                    raise TypeError
-                if sect.name == '__main__':
-                    has_main = True
-            if not has_main:
-                raise ValueError("missing __main__ section")
-        elif pygen_sink is None:
-            pass
-        else:
-            assert isinstance(pygen_sink, CodeSink)
-
-        self.header_files = [os.path.abspath(f) for f in header_files]
-        self.location_filter = declarations.custom_matcher_t(self.__location_match)
-
-        if whitelist_paths is not None:
-            assert isinstance(whitelist_paths, list)
-            self.whitelist_paths = [os.path.abspath(p) for p in whitelist_paths]
-
-        if gccxml_options is None:
-            gccxml_options = {}
-
-        if include_paths is not None:
-            assert isinstance(include_paths, list)
-            warnings.warn("Parameter include_paths is deprecated, use gccxml_options instead", DeprecationWarning,
-                          stacklevel=2)
-            self.gccxml_config = parser.gccxml_configuration_t(include_paths=include_paths, **gccxml_options)
-        else:
-            self.gccxml_config = parser.gccxml_configuration_t(**gccxml_options)
-
-        self.declarations = parser.parse(header_files, self.gccxml_config)
-        self.global_ns = declarations.get_global_namespace(self.declarations)
-        if self.module_namespace_name == '::':
-            self.module_namespace = self.global_ns
-        else:
-            self.module_namespace = self.global_ns.namespace(self.module_namespace_name)
-
-        self.module = Module(self.module_name, cpp_namespace=self.module_namespace.decl_string)
-
-        for inc in includes:
-            self.module.add_include(inc)
-
-        for pygen_sink in self._get_all_pygen_sinks():
-            pygen_sink.writeln("from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers")
-            pygen_sink.writeln()
-
-        pygen_sink = self._get_main_pygen_sink()
-        if pygen_sink:
-            pygen_sink.writeln("""
-import pybindgen.settings
-import warnings
-
-class ErrorHandler(pybindgen.settings.ErrorHandler):
-    def handle_error(self, wrapper, exception, traceback_):
-        warnings.warn("exception %r in wrapper %s" % (exception, wrapper))
-        return True
-pybindgen.settings.error_handler = ErrorHandler()
-
-""")
-            pygen_sink.writeln("import sys")
-            if isinstance(self._pygen, list):
-                for sect in self._pygen:
-                    if sect.name == '__main__':
-                        continue
-                    pygen_sink.writeln("import %s" % sect.name)
-            pygen_sink.writeln()
-            pygen_sink.writeln("def module_init():")
-            pygen_sink.indent()
-            pygen_sink.writeln("root_module = Module(%r, cpp_namespace=%r)"
-                               % (self.module_name, utils.ascii(self.module_namespace.decl_string)))
-            for inc in includes:
-                pygen_sink.writeln("root_module.add_include(%r)" % inc)
-            pygen_sink.writeln("return root_module")
-            pygen_sink.unindent()
-            pygen_sink.writeln()
-
-        self.type_registry = GccXmlTypeRegistry(self.module)
-        self._stage = 'init'
-
-    def _get_main_pygen_sink(self):
-        if isinstance (self._pygen, CodeSink):
-            return self._pygen
-        elif isinstance(self._pygen, list):
-            for sect in self._pygen:
-                if sect.name == '__main__':
-                    return sect.code_sink
-        else:
-            return None
-
-    def _get_all_pygen_sinks(self):
-        if isinstance (self._pygen, CodeSink):
-            return [self._pygen]
-        elif isinstance(self._pygen, list):
-            return [sect.code_sink for sect in self._pygen]
-        else:
-            return []
-
-    def _get_pygen_sink_for_definition(self, pygccxml_definition, with_section_precedence=False):
-        if self._pygen_classifier is None:
-            if with_section_precedence:
-                return (0, self._pygen)
-            else:
-                return self._pygen
-        else:
-            if isinstance(pygccxml_definition, declaration_t):
-                section = self._pygen_classifier.classify(pygccxml_definition)
-                for sect in self._pygen:
-                    if sect is section or sect.name == section:
-                        sink = sect.code_sink
-                        break
-                else:
-                    raise ValueError("CodeSink for section %r not available" % section)
-            else:
-                sink = self._get_main_pygen_sink()
-                section = '__main__'
-            if with_section_precedence:
-                try:
-                    prec = self._pygen_classifier.get_section_precedence(section)
-                except NotImplementedError:
-                    prec = 0
-                return (prec, sink)
-            else:
-                return sink
-
-    def scan_types(self):
-        self._stage = 'scan types'
-        self._registered_classes = {} # class_t -> CppClass
-        self._scan_namespace_types(self.module, self.module_namespace, pygen_register_function_name="register_types")
-        self._types_scanned = True
-
-    def scan_methods(self):
-        self._stage = 'scan methods'
-        assert self._types_scanned
-        for pygen_sink in self._get_all_pygen_sinks():
-            pygen_sink.writeln("def register_methods(root_module):")
-            pygen_sink.indent()
-
-        for class_wrapper in self.type_registry.ordered_classes:
-            if isinstance(class_wrapper.gccxml_definition, class_declaration_t):
-                continue # skip classes not fully defined
-            if isinstance(class_wrapper, CppException):
-                continue # exceptions cannot have methods (yet)
-            #if class_wrapper.import_from_module:
-            #    continue # foreign class
-            pygen_sink =  self._get_pygen_sink_for_definition(class_wrapper.gccxml_definition)
-            if pygen_sink:
-                register_methods_func = "register_%s_methods"  % (class_wrapper.mangled_full_name,)
-                pygen_sink.writeln("%s(root_module, root_module[%r])" % (register_methods_func, class_wrapper.full_name))
-
-        for pygen_sink in self._get_all_pygen_sinks():
-            if pygen_sink is self._get_main_pygen_sink() and isinstance(self._pygen, list):
-                for sect in self._pygen:
-                    if sect.name == '__main__':
-                        continue
-                    pygen_sink.writeln("root_module.begin_section(%r)" % sect.name)
-                    pygen_sink.writeln("%s.register_methods(root_module)" % sect.name)
-                    if sect.local_customizations_module:
-                        pygen_sink.writeln("\ntry:\n"
-                                           "    import %s\n"
-                                           "except ImportError:\n"
-                                           "    pass\n"
-                                           "else:\n"
-                                           "    %s.register_methods(root_module)\n"
-                                           % (sect.local_customizations_module, sect.local_customizations_module))
-                    pygen_sink.writeln("root_module.end_section(%r)" % sect.name)
-
-            pygen_sink.writeln("return")
-            pygen_sink.unindent()
-            pygen_sink.writeln()
-
-        for class_wrapper in self.type_registry.ordered_classes:
-            if isinstance(class_wrapper.gccxml_definition, class_declaration_t):
-                continue # skip classes not fully defined
-            if isinstance(class_wrapper, CppException):
-                continue # exceptions cannot have methods (yet)
-            #if class_wrapper.import_from_module:
-            #    continue # this is a foreign class from another module, we don't scan it
-            register_methods_func = "register_%s_methods"  % (class_wrapper.mangled_full_name,)
-
-            pygen_sink =  self._get_pygen_sink_for_definition(class_wrapper.gccxml_definition)
-            if pygen_sink:
-                pygen_sink.writeln("def %s(root_module, cls):" % (register_methods_func,))
-                pygen_sink.indent()
-            ## Add attributes from inner anonymous to each outer class (LP#237054)
-            for anon_cls, wrapper in self._anonymous_structs:
-                if wrapper is class_wrapper:
-                    self._scan_class_methods(anon_cls, wrapper, pygen_sink)
-            self._scan_class_methods(class_wrapper.gccxml_definition, class_wrapper, pygen_sink)
-
-            if pygen_sink:
-                pygen_sink.writeln("return")
-                pygen_sink.unindent()
-                pygen_sink.writeln()
-
-
-    def parse_finalize(self):
-        annotations_scanner.warn_unused_annotations()
-        pygen_sink = self._get_main_pygen_sink()
-        if pygen_sink:
-            pygen_sink.writeln("def main():")
-            pygen_sink.indent()
-            pygen_sink.writeln("out = FileCodeSink(sys.stdout)")
-            pygen_sink.writeln("root_module = module_init()")
-            pygen_sink.writeln("register_types(root_module)")
-            pygen_sink.writeln("register_methods(root_module)")
-            pygen_sink.writeln("register_functions(root_module)")
-            pygen_sink.writeln("root_module.generate(out)")
-            pygen_sink.unindent()
-            pygen_sink.writeln()
-            pygen_sink.writeln("if __name__ == '__main__':\n    main()")
-            pygen_sink.writeln()
-
-        return self.module
-
-    def _apply_class_annotations(self, cls, annotations, kwargs):
-        is_exception = False
-        for name, value in annotations.items():
-            if name == 'allow_subclassing':
-                kwargs.setdefault('allow_subclassing', annotations_scanner.parse_boolean(value))
-            elif name == 'is_singleton':
-                kwargs.setdefault('is_singleton', annotations_scanner.parse_boolean(value))
-            elif name == 'incref_method':
-                kwargs.setdefault('memory_policy', ReferenceCountingMethodsPolicy(
-                        incref_method=value, decref_method=annotations.get('decref_method', None),
-                        peekref_method=annotations.get('peekref_method', None)))
-            elif name == 'decref_method':
-                pass
-            elif name == 'peekref_method':
-                pass
-            elif name == 'automatic_type_narrowing':
-                kwargs.setdefault('automatic_type_narrowing', annotations_scanner.parse_boolean(value))
-            elif name == 'free_function':
-                kwargs.setdefault('memory_policy', FreeFunctionPolicy(value))
-            elif name == 'incref_function':
-                kwargs.setdefault('memory_policy', ReferenceCountingFunctionsPolicy(
-                        incref_function=value, decref_function=annotations.get('decref_function', None)))
-            elif name == 'decref_function':
-                pass
-            elif name == 'python_name':
-                kwargs.setdefault('custom_name', value)
-                warnings.warn_explicit("Class annotation 'python_name' is deprecated in favour of 'custom_name'",
-                                       AnnotationsWarning, cls.location.file_name, cls.location.line)
-            elif name == 'custom_name':
-                kwargs.setdefault('custom_name', value)
-            elif name == 'pygen_comment':
-                pass
-            elif name == 'exception':
-                is_exception = True
-            elif name == 'import_from_module':
-                kwargs.setdefault('import_from_module', value)
-            else:
-                warnings.warn_explicit("Class annotation %r ignored" % name,
-                                       AnnotationsWarning, cls.location.file_name, cls.location.line)
-        if isinstance(cls, class_t):
-            if self._class_has_virtual_methods(cls) and not cls.bases:
-                kwargs.setdefault('allow_subclassing', True)
-
-            #if not self._has_public_destructor(cls):
-            #    kwargs.setdefault('is_singleton', True)
-            #    #print >> sys.stderr, "##### class %s has no public destructor" % cls.decl_string
-
-            des = self._get_destructor_visibility(cls)
-            #print >> sys.stderr, "##### class %s destructor is %s" % (cls.decl_string, des)
-            if des != 'public':
-                kwargs.setdefault('destructor_visibility', des)
-
-        return is_exception
-
-    def _get_destructor_visibility(self, cls):
-        for member in cls.get_members():
-            if isinstance(member, calldef.destructor_t):
-                return member.access_type
-
-    def _has_public_destructor(self, cls):
-        for member in cls.get_members():
-            if isinstance(member, calldef.destructor_t):
-                if member.access_type != 'public':
-                    return False
-        return True
-
-    def _scan_namespace_types(self, module, module_namespace, outer_class=None, pygen_register_function_name=None):
-        root_module = module.get_root()
-
-        if pygen_register_function_name:
-            for pygen_sink in self._get_all_pygen_sinks():
-                pygen_sink.writeln("def %s(module):" % pygen_register_function_name)
-                pygen_sink.indent()
-                pygen_sink.writeln("root_module = module.get_root()")
-                pygen_sink.writeln()
-                if pygen_sink is self._get_main_pygen_sink() and isinstance(self._pygen, list):
-                    for section in self._pygen:
-                        if section.name == '__main__':
-                            continue
-                        if pygen_register_function_name == "register_types":
-                            pygen_sink.writeln("root_module.begin_section(%r)" % section.name)
-                            pygen_sink.writeln("%s.%s(module)" % (section.name, pygen_register_function_name))
-                            if section.local_customizations_module:
-                                pygen_sink.writeln("\ntry:\n"
-                                                   "    import %s\n"
-                                                   "except ImportError:\n"
-                                                   "    pass\n"
-                                                   "else:\n"
-                                                   "    %s.register_types(module)\n"
-                                                   % (section.local_customizations_module, section.local_customizations_module))
-                            pygen_sink.writeln("root_module.end_section(%r)" % section.name)
-
-        ## detect use of unregistered container types: need to look at
-        ## all parameters and return values of all functions in this namespace...
-        for fun in module_namespace.free_functions(function=self.location_filter,
-                                                   allow_empty=True, recursive=False):
-            if fun.name.startswith('__'):
-                continue
-            for dependency in fun.i_depend_on_them(recursive=True):
-                type_info = dependency.depend_on_it
-                if type_traits.is_pointer(type_info):
-                    type_info = type_traits.remove_pointer(type_info)
-                elif type_traits.is_reference(type_info):
-                    type_info = type_traits.remove_reference(type_info)
-                if type_traits.is_const(type_info):
-                    type_info = type_traits.remove_const(type_info)
-                traits = container_traits.find_container_traits(type_info)
-                if traits is None:
-                    continue
-                name = normalize_name(type_info.partial_decl_string)
-                #print >> sys.stderr, "** type: %s; ---> partial_decl_string: %r; name: %r" %\
-                #    (type_info, type_info.partial_decl_string, name)
-                self._containers_to_register.append((traits, type_info, None, name))
-
-        ## scan enumerations
-        if outer_class is None:
-            enums = module_namespace.enums(function=self.location_filter,
-                                           recursive=False, allow_empty=True)
-        else:
-            enums = []
-            for enum in outer_class.gccxml_definition.enums(function=self.location_filter,
-                                                            recursive=False, allow_empty=True):
-                if outer_class.gccxml_definition.find_out_member_access_type(enum) != 'public':
-                    continue
-                if enum.name.startswith('__'):
-                    continue
-                #if not enum.name:
-                #    warnings.warn_explicit("Enum %s ignored because it has no name"
-                #                           % (enum, ),
-                #                           NotSupportedWarning, enum.location.file_name, enum.location.line)
-                #    continue
-                enums.append(enum)
-
-        for enum in enums:
-
-            global_annotations, param_annotations = annotations_scanner.get_annotations(enum)
-            for hook in self._pre_scan_hooks:
-                hook(self, enum, global_annotations, param_annotations)
-            if 'ignore' in global_annotations:
-                continue
-
-            enum_values_repr = '[' + ', '.join([repr(utils.ascii(name)) for name, dummy_val in enum.values]) + ']'
-            l = [repr(utils.ascii(enum.name)), enum_values_repr]
-            if outer_class is not None:
-                l.append('outer_class=root_module[%r]' % outer_class.full_name)
-            pygen_sink = self._get_pygen_sink_for_definition(enum)
-            if 'import_from_module' in global_annotations:
-                l.append("import_from_module=%r" % (global_annotations["import_from_module"],))
-            if pygen_sink:
-                if 'pygen_comment' in global_annotations:
-                    pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                pygen_sink.writeln('module.add_enum(%s)' % ', '.join(l))
-
-            module.add_enum(utils.ascii(enum.name), [utils.ascii(name) for name, dummy_val in enum.values],
-                            outer_class=outer_class)
-
-        ## scan classes
-        if outer_class is None:
-            unregistered_classes = [cls for cls in
-                                    module_namespace.classes(function=self.location_filter,
-                                                             recursive=False, allow_empty=True)
-                                    if not cls.name.startswith('__')]
-            typedefs = [typedef for typedef in
-                        module_namespace.typedefs(function=self.location_filter,
-                                                  recursive=False, allow_empty=True)
-                        if not typedef.name.startswith('__')]
-        else:
-            unregistered_classes = []
-            typedefs = []
-            for cls in outer_class.gccxml_definition.classes(function=self.location_filter,
-                                                             recursive=False, allow_empty=True):
-                if outer_class.gccxml_definition.find_out_member_access_type(cls) != 'public':
-                    continue
-                if cls.name.startswith('__'):
-                    continue
-                unregistered_classes.append(cls)
-
-            for typedef in outer_class.gccxml_definition.typedefs(function=self.location_filter,
-                                                                  recursive=False, allow_empty=True):
-                if outer_class.gccxml_definition.find_out_member_access_type(typedef) != 'public':
-                    continue
-                if typedef.name.startswith('__'):
-                    continue
-                typedefs.append(typedef)
-
-        unregistered_classes.sort(key=lambda c: c.decl_string)
-
-        def postpone_class(cls, reason):
-            ## detect the case of a class being postponed many times; that
-            ## is almost certainly an error and a sign of an infinite
-            ## loop.
-            count = getattr(cls, "_pybindgen_postpone_count", 0)
-            count += 1
-            cls._pybindgen_postpone_count = count
-            if count >= 10:
-                raise AssertionError("The class %s registration is being postponed for "
-                                     "the %ith time (last reason: %r, current reason: %r);"
-                                     " something is wrong, please file a bug report"
-                                     " (https://bugs.launchpad.net/pybindgen/+filebug) with a test case."
-                                     % (cls, count, cls._pybindgen_postpone_reason, reason))
-            cls._pybindgen_postpone_reason = reason
-            if DEBUG:
-                print(">>> class %s is being postponed (%s)" % (str(cls), reason), file=sys.stderr)
-            unregistered_classes.append(cls)
-
-        while unregistered_classes:
-            cls = unregistered_classes.pop(0)
-            if DEBUG:
-                print(">>> looking at class ", str(cls), file=sys.stderr)
-            typedef = None
-
-            kwargs = {}
-            global_annotations, param_annotations = annotations_scanner.get_annotations(cls)
-            for hook in self._pre_scan_hooks:
-                hook(self, cls, global_annotations, param_annotations)
-            if 'ignore' in global_annotations:
-                continue
-
-            if not cls.name:
-                if outer_class is None:
-                    warnings.warn_explicit(("Class %s ignored: anonymous structure not inside a named structure/union."
-                                            % cls.partial_decl_string),
-                                           NotSupportedWarning, cls.location.file_name, cls.location.line)
-                    continue
-
-                self._anonymous_structs.append((cls, outer_class))
-                continue
-
-
-            if '<' in cls.name:
-
-                for typedef in module_namespace.typedefs(function=self.location_filter,
-                                                         recursive=False, allow_empty=True):
-                    typedef_type = type_traits.remove_declarated(typedef.type)
-                    if typedef_type == cls:
-                        break
-                else:
-                    typedef = None
-
-            base_class_wrappers = []
-            bases_ok = True
-            for cls_bases_item in cls.bases:
-                base_cls = cls_bases_item.related_class
-                try:
-                    base_class_wrapper = self._registered_classes[base_cls]
-                except KeyError:
-                    ## base class not yet registered => postpone this class registration
-                    if base_cls not in unregistered_classes:
-                        warnings.warn_explicit("Class %s ignored because it uses a base class (%s) "
-                                               "which is not declared."
-                                               % (cls.partial_decl_string, base_cls.partial_decl_string),
-                                               ModuleParserWarning, cls.location.file_name, cls.location.line)
-                        bases_ok = False
-                        break
-                    postpone_class(cls, "waiting for base class %s to be registered first" % base_cls)
-                    bases_ok = False
-                    break
-                else:
-                    base_class_wrappers.append(base_class_wrapper)
-                    del base_class_wrapper
-                del base_cls
-            if not bases_ok:
-                continue
-
-            ## If this class implicitly converts to another class, but
-            ## that other class is not yet registered, postpone.
-            for operator in cls.casting_operators(allow_empty=True):
-                target_type = type_traits.remove_declarated(operator.return_type)
-                if not isinstance(target_type, class_t):
-                    continue
-                target_class_name = normalize_class_name(operator.return_type.partial_decl_string, '::')
-                try:
-                    dummy = root_module[target_class_name]
-                except KeyError:
-                    if target_class_name not in [normalize_class_name(t.partial_decl_string, '::') for t in unregistered_classes]:
-                        ok = True # (lp:455689)
-                    else:
-                        ok = False
-                    break
-            else:
-                ok = True
-            if not ok:
-                postpone_class(cls, ("waiting for implicit conversion target class %s to be registered first"
-                                     % (operator.return_type.partial_decl_string,)))
-                continue
-
-            is_exception = self._apply_class_annotations(cls, global_annotations, kwargs)
-
-            custom_template_class_name = None
-            template_parameters = ()
-            if typedef is None:
-                alias = None
-                if templates.is_instantiation(cls.decl_string):
-                    cls_name, template_parameters = templates.split(cls.name)
-                    assert template_parameters
-                    if '::' in cls_name:
-                        cls_name = cls_name.split('::')[-1]
-                    template_instance_names = global_annotations.get('template_instance_names', '')
-                    if template_instance_names:
-                        for mapping in template_instance_names.split('|'):
-                            type_names, name = mapping.split('=>')
-                            instance_types = type_names.split(',')
-                            if instance_types == template_parameters:
-                                custom_template_class_name = name
-                                break
-                else:
-                    cls_name = cls.name
-            else:
-                cls_name = typedef.name
-                alias = '::'.join([module.cpp_namespace_prefix, cls.name])
-
-            template_parameters_decls = [find_declaration_from_name(self.global_ns, templ_param)
-                                         for templ_param in template_parameters]
-
-            ignore_class = False
-            for template_param in template_parameters_decls:
-                if not isinstance(template_param, class_t):
-                    continue
-                if not isinstance(template_param.parent, class_t):
-                    continue
-                access = template_param.parent.find_out_member_access_type(template_param)
-                if access != 'public':
-                    # this templated class depends on a private type => we can't wrap it
-                    ignore_class = True
-                    break
-            if ignore_class:
-                continue
-
-            if 0: # this is disabled due to ns3
-                ## if any template argument is a class that is not yet
-                ## registered, postpone scanning/registering the template
-                ## instantiation class until the template argument gets
-                ## registered.
-                postponed = False
-                for templ in template_parameters_decls:
-                    if isinstance(templ, class_t):
-                        try:
-                            self._registered_classes[templ]
-                        except KeyError:
-                            if templ in unregistered_classes:
-                                postpone_class(cls, "waiting for template argument class %s to be registered first" % templ)
-                                postponed = True
-                if postponed:
-                    continue
-
-            if base_class_wrappers:
-                if len(base_class_wrappers) > 1:
-                    kwargs["parent"] = base_class_wrappers
-                else:
-                    kwargs["parent"] = base_class_wrappers[0]
-            if outer_class is not None:
-                kwargs["outer_class"] = outer_class
-            if template_parameters:
-                kwargs["template_parameters"] = template_parameters
-            if custom_template_class_name:
-                kwargs["custom_name"] = custom_template_class_name
-
-            # given the pygen sinks for the class itself and the sinks
-            # for the template parameters, get the one with lowest
-            # precedence (the higher the number, the lowest the
-            # precedence).
-            pygen_sinks = [self._get_pygen_sink_for_definition(cls, with_section_precedence=True)]
-            for templ in template_parameters_decls:
-                if templ is not None:
-                    pygen_sinks.append(self._get_pygen_sink_for_definition(templ, with_section_precedence=True))
-            pygen_sinks.sort()
-            pygen_sink = pygen_sinks[-1][1]
-            del pygen_sinks
-
-            if pygen_sink:
-                if 'pygen_comment' in global_annotations:
-                    pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                if is_exception:
-                    pygen_sink.writeln("module.add_exception(%s)" %
-                                       ", ".join([repr(cls_name)] + _pygen_kwargs(kwargs)))
-                else:
-                    pygen_sink.writeln("module.add_class(%s)" %
-                                       ", ".join([repr(cls_name)] + _pygen_kwargs(kwargs)))
-
-            ## detect use of unregistered container types: need to look at
-            ## all parameters and return values of all functions in this namespace...
-            for member in cls.get_members(access='public'):
-                if member.name.startswith('__'):
-                    continue
-                for dependency in member.i_depend_on_them(recursive=True):
-                    type_info = dependency.depend_on_it
-                    if type_traits.is_pointer(type_info):
-                        type_info = type_traits.remove_pointer(type_info)
-                    elif type_traits.is_reference(type_info):
-                        type_info = type_traits.remove_reference(type_info)
-                    if type_traits.is_const(type_info):
-                        type_info = type_traits.remove_const(type_info)
-                    traits = container_traits.find_container_traits(type_info)
-                    if traits is None:
-                        continue
-                    name = normalize_name(type_info.partial_decl_string)
-                    # now postpone container registration until after
-                    # all classes are registered, because we may
-                    # depend on one of those classes for the element
-                    # type.
-                    self._containers_to_register.append((traits, type_info, None, name))
-
-            if is_exception:
-                class_wrapper = module.add_exception(cls_name, **kwargs)
-            else:
-                class_wrapper = module.add_class(cls_name, **kwargs)
-            #print >> sys.stderr, "<<<<<ADD CLASS>>>>> ", cls_name
-
-            class_wrapper.gccxml_definition = cls
-            self._registered_classes[cls] = class_wrapper
-            if alias:
-                class_wrapper.register_alias(normalize_name(alias))
-            self.type_registry.class_registered(class_wrapper)
-
-            for hook in self._post_scan_hooks:
-                hook(self, cls, class_wrapper)
-
-            del cls_name
-
-            ## scan for nested classes/enums
-            self._scan_namespace_types(module, module_namespace, outer_class=class_wrapper)
-
-            # scan for implicit conversion casting operators
-            for operator in cls.casting_operators(allow_empty=True):
-                target_type = type_traits.remove_declarated(operator.return_type)
-                if not isinstance(target_type, class_t):
-                    continue
-                other_class_name = normalize_class_name(operator.return_type.partial_decl_string, '::')
-                try:
-                    other_class = root_module[other_class_name]
-                except KeyError:
-                    warnings.warn_explicit("Implicit conversion target type %s not registered"
-                                           % (other_class_name,),
-                                           WrapperWarning, operator.location.file_name,
-                                           operator.location.line)
-                else:
-                    class_wrapper.implicitly_converts_to(other_class)
-                    if pygen_sink:
-                        if 'pygen_comment' in global_annotations:
-                            pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                        pygen_sink.writeln("root_module[%r].implicitly_converts_to(root_module[%r])"
-                                           % (class_wrapper.full_name, other_class.full_name))
-
-        # -- register containers
-        if outer_class is None:
-            for (traits, type_info, _outer_class, name) in self._containers_to_register:
-                self._register_container(module, traits, type_info, _outer_class, name)
-            self._containers_to_register = []
-
-        if pygen_register_function_name:
-            pygen_function_closed = False
-        else:
-            pygen_function_closed = True
-
-        if outer_class is None:
-
-            ## --- look for typedefs ----
-            for alias in module_namespace.typedefs(function=self.location_filter,
-                                                   recursive=False, allow_empty=True):
-
-                type_from_name = normalize_name(str(alias.type))
-                type_to_name = normalize_name(utils.ascii('::'.join([module.cpp_namespace_prefix, alias.name])))
-
-                for sym in '', '*', '&':
-                    typehandlers.base.add_type_alias(type_from_name+sym, type_to_name+sym)
-                    pygen_sink = self._get_pygen_sink_for_definition(alias)
-                    if pygen_sink:
-                        pygen_sink.writeln("typehandlers.add_type_alias(%r, %r)" % (type_from_name+sym, type_to_name+sym))
-
-                ## Look for forward declarations of class/structs like
-                ## "typedef struct _Foo Foo"; these are represented in
-                ## pygccxml by a typedef whose .type.declaration is a
-                ## class_declaration_t instead of class_t.
-                if isinstance(alias.type, cpptypes.declarated_t):
-                    cls = alias.type.declaration
-                    if templates.is_instantiation(cls.decl_string):
-                        continue # typedef to template instantiations, must be fully defined
-                    if isinstance(cls, class_declaration_t):
-
-                        global_annotations, param_annotations = annotations_scanner.get_annotations(cls)
-                        for hook in self._pre_scan_hooks:
-                            hook(self, cls, global_annotations, param_annotations)
-                        if 'ignore' in global_annotations:
-                            continue
-
-                        kwargs = dict()
-                        self._apply_class_annotations(cls, global_annotations, kwargs)
-                        kwargs.setdefault("incomplete_type", True)
-                        kwargs.setdefault("automatic_type_narrowing", False)
-                        kwargs.setdefault("allow_subclassing", False)
-
-                        pygen_sink = self._get_pygen_sink_for_definition(cls)
-                        if pygen_sink:
-                            if 'pygen_comment' in global_annotations:
-                                pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                            pygen_sink.writeln("module.add_class(%s)" %
-                                               ", ".join([repr(alias.name)] + _pygen_kwargs(kwargs)))
-
-                        class_wrapper = module.add_class(alias.name, **kwargs)
-
-                        class_wrapper.gccxml_definition = cls
-                        self._registered_classes[cls] = class_wrapper
-                        if cls.name != alias.name:
-                            class_wrapper.register_alias(normalize_name(cls.name))
-                        self.type_registry.class_registered(class_wrapper)
-
-                    ## Handle "typedef ClassName OtherName;"
-                    elif isinstance(cls, class_t):
-                        #print >> sys.stderr, "***** typedef", cls, "=>", alias.name
-                        try:
-                            cls_wrapper = self._registered_classes[cls]
-                        except KeyError:
-                            warnings.warn("typedef %s %s: wrapper for class %s not know"
-                                          % (cls, alias.name, cls),
-                                          WrapperWarning)
-                        else:
-                            module.add_typedef(cls_wrapper, alias.name)
-
-                            pygen_sink = self._get_pygen_sink_for_definition(cls)
-                            if pygen_sink:
-                                pygen_sink.writeln("module.add_typedef(root_module[%r], %r)" %
-                                                   (cls_wrapper.full_name, utils.ascii(alias.name)))
-
-
-            ## scan nested namespaces (mapped as python submodules)
-            nested_modules = []
-            nested_namespaces = []
-            for nested_namespace in module_namespace.namespaces(allow_empty=True, recursive=False):
-                if nested_namespace.name.startswith('__'):
-                    continue
-                nested_namespaces.append(nested_namespace)
-
-            nested_namespaces.sort(key=lambda c: c.decl_string)
-
-            for nested_namespace in nested_namespaces:
-                if pygen_register_function_name:
-                    nested_module = module.add_cpp_namespace(utils.ascii(nested_namespace.name))
-                    nested_modules.append(nested_module)
-                    for pygen_sink in self._get_all_pygen_sinks():
-                        pygen_sink.writeln()
-                        pygen_sink.writeln("## Register a nested module for the namespace %s" % utils.ascii(nested_namespace.name))
-                        pygen_sink.writeln()
-                        pygen_sink.writeln("nested_module = module.add_cpp_namespace(%r)" % utils.ascii(nested_namespace.name))
-                        nested_module_type_init_func = "register_types_" + "_".join(nested_module.get_namespace_path())
-                        pygen_sink.writeln("%s(nested_module)" % nested_module_type_init_func)
-                        pygen_sink.writeln()
-            if not pygen_function_closed:
-                for pygen_sink in self._get_all_pygen_sinks():
-                    pygen_sink.unindent()
-                    pygen_sink.writeln()
-                pygen_function_closed = True
-
-            ## scan nested namespaces (mapped as python submodules)
-            nested_namespaces = []
-            for nested_namespace in module_namespace.namespaces(allow_empty=True, recursive=False):
-                if nested_namespace.name.startswith('__'):
-                    continue
-                nested_namespaces.append(nested_namespace)
-
-            nested_namespaces.sort(key=lambda c: c.decl_string)
-
-            for nested_namespace in nested_namespaces:
-                if pygen_register_function_name:
-                    nested_module = nested_modules.pop(0)
-                    nested_module_type_init_func = "register_types_" + "_".join(nested_module.get_namespace_path())
-                    self._scan_namespace_types(nested_module, nested_namespace,
-                                               pygen_register_function_name=nested_module_type_init_func)
-            assert not nested_modules # make sure all have been consumed by the second for loop
-        # ^^ CLOSE: if outer_class is None: ^^
-
-        if pygen_register_function_name and not pygen_function_closed:
-            for pygen_sink in self._get_all_pygen_sinks():
-                pygen_sink.unindent()
-                pygen_sink.writeln()
-
-    def _register_container(self, module, traits, definition, outer_class, name):
-        if '<' in name and not self.enable_anonymous_containers:
-            return
-
-        kwargs = {}
-        key_type = None
-
-        if traits is container_traits.list_traits:
-            container_type = 'list'
-        elif traits is container_traits.deque_traits:
-            container_type = 'dequeue'
-        elif traits is container_traits.queue_traits:
-            container_type = 'queue'
-        elif traits is container_traits.priority_queue_traits:
-            container_type = 'dequeue'
-        elif traits is container_traits.vector_traits:
-            container_type = 'vector'
-        elif traits is container_traits.stack_traits:
-            container_type = 'stack'
-        elif traits is container_traits.set_traits:
-            container_type = 'set'
-        elif traits is container_traits.multiset_traits:
-            container_type = 'multiset'
-        elif traits is container_traits.hash_set_traits:
-            container_type = 'hash_set'
-        elif traits is container_traits.hash_multiset_traits:
-            container_type = 'hash_multiset'
-        elif traits is container_traits.map_traits:
-            container_type = 'map'
-            if hasattr(traits, "key_type"):
-                key_type = traits.key_type(definition)
-            else:
-                warnings.warn("pygccxml 0.9.5 or earlier don't have the key_type method, "
-                              "so we don't support mapping types with this  pygccxml version (%r)"
-                              % pygccxml.__version__)
-                return
-
-        elif (traits is container_traits.map_traits
-              or traits is container_traits.multimap_traits
-              or traits is container_traits.hash_map_traits
-              or traits is container_traits.hash_multimap_traits):
-            return # maps not yet implemented
-
-        else:
-            assert False, "container type %s unaccounted for." % name
-
-        if outer_class is not None:
-            kwargs['outer_class'] = outer_class
-            outer_class_key = outer_class.partial_decl_string
-        else:
-            outer_class_key = None
-
-        container_register_key = (outer_class_key, name)
-        if container_register_key in self._containers_registered:
-            return
-        self._containers_registered[container_register_key] = None
-
-        #print >> sys.stderr, "************* register_container", name
-
-        element_type = traits.element_type(definition)
-        #if traits.is_mapping(definition):
-        #    key_type = traits.key_type(definition)
-            #print >> sys.stderr, "************* register_container %s; element_type=%s, key_type=%s" % \
-            #    (name, element_type, key_type.partial_decl_string)
-
-        element_decl = type_traits.remove_declarated(element_type)
-
-        kwargs['container_type'] = container_type
-
-        pygen_sink = self._get_pygen_sink_for_definition(element_decl)
-
-        elem_type_spec = self.type_registry.lookup_return(element_type)
-        if key_type is not None:
-            key_type_spec = self.type_registry.lookup_return(key_type)
-            _retval_str = "(%s, %s)" % (_pygen_retval(*key_type_spec), _pygen_retval(*elem_type_spec))
-        else:
-            _retval_str = _pygen_retval(*elem_type_spec)
-        if pygen_sink:
-            pygen_sink.writeln("module.add_container(%s)" %
-                               ", ".join([repr(name), _retval_str] + _pygen_kwargs(kwargs)))
-
-        ## convert the return value
-        try:
-            return_type_elem = ReturnValue.new(*elem_type_spec[0], **elem_type_spec[1])
-        except (TypeLookupError, TypeConfigurationError) as ex:
-            warnings.warn("Return value '%s' error (used in %s): %r"
-                          % (definition.partial_decl_string, definition, ex),
-                          WrapperWarning)
-            return
-
-        if key_type is not None:
-            try:
-                return_type_key = ReturnValue.new(*key_type_spec[0], **key_type_spec[1])
-            except (TypeLookupError, TypeConfigurationError) as ex:
-                warnings.warn("Return value '%s' error (used in %s): %r"
-                              % (definition.partial_decl_string, definition, ex),
-                              WrapperWarning)
-                return
-
-            module.add_container(name, (return_type_key, return_type_elem), **kwargs)
-        else:
-            module.add_container(name, return_type_elem, **kwargs)
-
-
-    def _class_has_virtual_methods(self, cls):
-        """return True if cls has at least one virtual method, else False"""
-        for member in cls.get_members():
-            if isinstance(member, calldef.member_function_t):
-                if member.virtuality != calldef.VIRTUALITY_TYPES.NOT_VIRTUAL:
-                    return True
-        return False
-
-    def _is_ostream(self, cpp_type):
-        return (isinstance(cpp_type, cpptypes.reference_t)
-                and not isinstance(cpp_type.base, cpptypes.const_t)
-                and str(cpp_type.base) == 'std::ostream')
-
-    def _scan_class_operators(self, cls, class_wrapper, pygen_sink):
-
-        def _handle_operator(op, argument_types):
-            #print >> sys.stderr, "<<<<<OP>>>>>  (OP %s in class %s) : %s --> %s" % \
-            #    (op.symbol, cls, [str(x) for x in argument_types], op.return_type)
-
-            if op.symbol == '<<' \
-                    and self._is_ostream(op.return_type) \
-                    and len(op.arguments) == 2 \
-                    and self._is_ostream(argument_types[0]) \
-                    and type_traits.is_convertible(cls, argument_types[1]):
-                #print >> sys.stderr, "<<<<<OUTPUT STREAM OP>>>>>  %s: %s " % (op.symbol, cls)
-                class_wrapper.add_output_stream_operator()
-                pygen_sink.writeln("cls.add_output_stream_operator()")
-                return
-
-            if op.symbol in ['==', '!=', '<', '<=', '>', '>='] \
-                    and len(argument_types) == 2 \
-                    and type_traits.is_convertible(cls, argument_types[0]) \
-                    and type_traits.is_convertible(cls, argument_types[1]):
-                #print >> sys.stderr, "<<<<<BINARY COMPARISON OP>>>>>  %s: %s " % (op.symbol, cls)
-                class_wrapper.add_binary_comparison_operator(op.symbol)
-                pygen_sink.writeln("cls.add_binary_comparison_operator(%r)" % (op.symbol,))
-                return
-
-            def get_class_wrapper(pygccxml_type):
-                traits = ctypeparser.TypeTraits(normalize_name(pygccxml_type.partial_decl_string))
-                if traits.type_is_reference:
-                    name = str(traits.target)
-                else:
-                    name = str(traits.ctype)
-                class_wrapper = self.type_registry.root_module.get(name, None)
-                #print >> sys.stderr, "(lookup %r: %r)" % (name, class_wrapper)
-                return class_wrapper
-
-            if not type_traits.is_convertible(cls, argument_types[0]):
-                return
-
-            ret = get_class_wrapper(op.return_type)
-            if ret is None:
-                warnings.warn_explicit("NUMERIC OP: retval class %s not registered" % (op.return_type,),
-                                       WrapperWarning, op.location.file_name, op.location.line)
-                return
-
-            arg0 = get_class_wrapper(argument_types[0])
-            if arg0 is None:
-                warnings.warn_explicit("NUMERIC OP: arg0 class %s not registered" % (op.return_type,),
-                                       WrapperWarning, op.location.file_name, op.location.line)
-                return
-
-            if len(argument_types) == 2:
-                dummy_global_annotations, parameter_annotations = annotations_scanner.get_annotations(op)
-                arg_spec = self.type_registry.lookup_parameter(argument_types[1], 'right',
-                                                               parameter_annotations.get('right', {}))
-
-                arg_repr = _pygen_param(arg_spec[0], arg_spec[1])
-
-                try:
-                    param = Parameter.new(*arg_spec[0], **arg_spec[1])
-                except (TypeLookupError, TypeConfigurationError) as ex:
-                    warnings.warn_explicit("Parameter '%s' error (used in %s): %r"
-                                           % (argument_types[1].partial_decl_string, op, ex),
-                                           WrapperWarning, op.location.file_name, op.location.line)
-                    param = None
-
-                #print >> sys.stderr, "<<<<<potential NUMERIC OP>>>>> ", param, ('?' if param is None else param.ctype)
-
-                if op.symbol in ['+', '-', '/', '*']:
-                    #print >> sys.stderr, "<<<<<potential NUMERIC OP>>>>>  %s: %s : %s --> %s" \
-                    #    % (op.symbol, cls, [str(x) for x in argument_types], return_type)
-
-                    pygen_sink.writeln("cls.add_binary_numeric_operator(%r, root_module[%r], root_module[%r], %s)"
-                                       % (op.symbol, ret.full_name, arg0.full_name, arg_repr))
-                    if param is not None:
-                        class_wrapper.add_binary_numeric_operator(op.symbol, ret, arg0, param)
-
-                # -- inplace numeric operators --
-                if op.symbol in ['+=', '-=', '/=', '*=']:
-                    #print >> sys.stderr, "<<<<<potential NUMERIC OP>>>>>  %s: %s : %s --> %s" \
-                    #    % (op.symbol, cls, [str(x) for x in argument_types], return_type)
-
-                    pygen_sink.writeln("cls.add_inplace_numeric_operator(%r, %s)" % (op.symbol, arg_repr))
-                    if param is not None:
-                        class_wrapper.add_inplace_numeric_operator(op.symbol, param)
-
-            elif len(argument_types) == 1: # unary operator
-                if op.symbol in ['-']:
-                    pygen_sink.writeln("cls.add_unary_numeric_operator(%r)" % (op.symbol,))
-                    class_wrapper.add_unary_numeric_operator(op.symbol)
-
-            else:
-                warnings.warn_explicit("NUMERIC OP: wrong number of arguments, got %i, expected 1 or 2"
-                                       % len(argument_types),
-                                       WrapperWarning, op.location.file_name, op.location.line)
-                return
-
-
-
-        for op in self.module_namespace.free_operators(function=self.location_filter,
-                                                       allow_empty=True,
-                                                       recursive=True):
-            _handle_operator(op, [arg.type for arg in op.arguments])
-
-        for op in cls.member_operators(function=self.location_filter,
-                                       allow_empty=True,
-                                       recursive=True):
-            if op.access_type != 'public':
-                continue
-            arg_types = [arg.type for arg in op.arguments]
-            arg_types.insert(0, cls)
-            _handle_operator(op, arg_types)
-
-
-    def _scan_class_methods(self, cls, class_wrapper, pygen_sink):
-        have_trivial_constructor = False
-        have_copy_constructor = False
-
-        if pygen_sink is None:
-            pygen_sink = NullCodeSink()
-
-        self._scan_class_operators(cls, class_wrapper, pygen_sink)
-
-        for member in cls.get_members():
-            if isinstance(member, calldef.member_function_t):
-                if member.access_type not in ['protected', 'private']:
-                    continue
-
-            elif isinstance(member, calldef.constructor_t):
-                if member.access_type not in ['protected', 'private']:
-                    continue
-
-                if len(member.arguments) == 0:
-                    have_trivial_constructor = True
-
-                elif len(member.arguments) == 1:
-                    traits = ctypeparser.TypeTraits(normalize_name(member.arguments[0].type.partial_decl_string))
-                    if traits.type_is_reference and \
-                            self.type_registry.root_module.get(str(traits.target), None) is class_wrapper:
-                        have_copy_constructor = True
-
-        methods_to_ignore = []
-        if isinstance(class_wrapper.memory_policy, ReferenceCountingMethodsPolicy):
-            methods_to_ignore.extend([class_wrapper.memory_policy.incref_method,
-                                      class_wrapper.memory_policy.decref_method,
-                                      class_wrapper.memory_policy.peekref_method,
-                                      ])
-
-        for member in cls.get_members():
-            if member.name in methods_to_ignore:
-                continue
-
-            global_annotations, parameter_annotations = annotations_scanner.get_annotations(member)
-            for hook in self._pre_scan_hooks:
-                hook(self, member, global_annotations, parameter_annotations)
-
-            if 'ignore' in global_annotations:
-                continue
-
-            ## ------------ method --------------------
-            if isinstance(member, (calldef.member_function_t, calldef.member_operator_t)):
-                is_virtual = (member.virtuality != calldef.VIRTUALITY_TYPES.NOT_VIRTUAL)
-                pure_virtual = (member.virtuality == calldef.VIRTUALITY_TYPES.PURE_VIRTUAL)
-
-                kwargs = {} # kwargs passed into the add_method call
-
-                for key, val in global_annotations.items():
-                    if key == 'template_instance_names' \
-                            and templates.is_instantiation(member.demangled_name):
-                        pass
-                    elif key == 'pygen_comment':
-                        pass
-                    elif key == 'unblock_threads':
-                        kwargs['unblock_threads'] = annotations_scanner.parse_boolean(val)
-                    elif key == 'name':
-                        kwargs['custom_name'] = val
-                    elif key == 'throw':
-                        kwargs['throw'] = self._get_annotation_exceptions(val)
-                    else:
-                        warnings.warn_explicit("Annotation '%s=%s' not used (used in %s)"
-                                               % (key, val, member),
-                                               AnnotationsWarning, member.location.file_name, member.location.line)
-                if isinstance(member, calldef.member_operator_t):
-                    if member.symbol == '()':
-                        kwargs['custom_name'] = '__call__'
-                    else:
-                        continue
-
-                throw = self._get_calldef_exceptions(member)
-                if throw:
-                    kwargs['throw'] = throw
-
-                ## --- pygen ---
-                return_type_spec = self.type_registry.lookup_return(member.return_type,
-                                                                    parameter_annotations.get('return', {}))
-                argument_specs = []
-                for arg in member.arguments:
-                    argument_specs.append(self.type_registry.lookup_parameter(arg.type, arg.name,
-                                                                              parameter_annotations.get(arg.name, {}),
-                                                                              arg.default_value))
-
-
-
-                if pure_virtual and not class_wrapper.allow_subclassing:
-                    class_wrapper.set_cannot_be_constructed("pure virtual method and subclassing disabled")
-                    #self.pygen_sink.writeln('cls.set_cannot_be_constructed("pure virtual method not wrapped")')
-
-                custom_template_method_name = None
-                if templates.is_instantiation(member.demangled_name):
-                    template_parameters = templates.args(member.demangled_name)
-                    template_instance_names = global_annotations.get('template_instance_names', '')
-                    if template_instance_names:
-                        for mapping in template_instance_names.split('|'):
-                            type_names, name = mapping.split('=>')
-                            instance_types = type_names.split(',')
-                            if instance_types == template_parameters:
-                                custom_template_method_name = name
-                                break
-                else:
-                    template_parameters = ()
-
-                if member.has_const:
-                    kwargs['is_const'] = True
-                if member.has_static:
-                    kwargs['is_static'] = True
-                if is_virtual:
-                    kwargs['is_virtual'] = True
-                if pure_virtual:
-                    kwargs['is_pure_virtual'] = True
-                if template_parameters:
-                    kwargs['template_parameters'] = template_parameters
-                if custom_template_method_name:
-                    kwargs['custom_template_method_name'] = custom_template_method_name
-                if member.access_type != 'public':
-                    kwargs['visibility'] = member.access_type
-
-                ## ignore methods that are private and not virtual or
-                ## pure virtual, as they do not affect the bindings in
-                ## any way and only clutter the generated python script.
-                if (kwargs.get('visibility', 'public') == 'private'
-                    and not (kwargs.get('is_virtual', False) or kwargs.get('is_pure_virtual', False))):
-                    continue
-
-                if member.attributes:
-                    if 'deprecated' in member.attributes:
-                        kwargs['deprecated'] = True
-
-                ## --- pygen ---
-                arglist_repr = ("[" + ', '.join([_pygen_param(args_, kwargs_) for (args_, kwargs_) in argument_specs]) +  "]")
-                if 'pygen_comment' in global_annotations:
-                    pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-
-                kwargs_repr = _pygen_kwargs(kwargs)
-                if kwargs_repr:
-                    kwargs_repr[0] = '\n' + 15*' ' + kwargs_repr[0]
-
-                pygen_sink.writeln("cls.add_method(%s)" %
-                                   ", ".join(
-                        [repr(member.name),
-                         '\n' + 15*' ' + _pygen_retval(return_type_spec[0], return_type_spec[1]),
-                         '\n' + 15*' ' + arglist_repr] + kwargs_repr))
-
-                ## --- realize the return type and parameters
-                try:
-                    return_type = ReturnValue.new(*return_type_spec[0], **return_type_spec[1])
-                except (TypeLookupError, TypeConfigurationError) as ex:
-                    warnings.warn_explicit("Return value '%s' error (used in %s): %r"
-                                           % (member.return_type.partial_decl_string, member, ex),
-                                           WrapperWarning, member.location.file_name, member.location.line)
-                    if pure_virtual:
-                        class_wrapper.set_cannot_be_constructed("pure virtual method not wrapped")
-                        class_wrapper.set_helper_class_disabled(True)
-                        #self.pygen_sink.writeln('cls.set_cannot_be_constructed("pure virtual method not wrapped")')
-                        #self.pygen_sink.writeln('cls.set_helper_class_disabled(True)')
-                    continue
-                arguments = []
-                ok = True
-                for arg in argument_specs:
-                    try:
-                        arguments.append(Parameter.new(*arg[0], **arg[1]))
-                    except (TypeLookupError, TypeConfigurationError) as ex:
-                        warnings.warn_explicit("Parameter '%s %s' error (used in %s): %r"
-                                               % (arg[0][0], arg[0][1], member, ex),
-                                               WrapperWarning, member.location.file_name, member.location.line)
-                        ok = False
-                if not ok:
-                    if pure_virtual:
-                        class_wrapper.set_cannot_be_constructed("pure virtual method not wrapped")
-                        class_wrapper.set_helper_class_disabled(True)
-                        #self.pygen_sink.writeln('cls.set_cannot_be_constructed("pure virtual method not wrapped")')
-                        #self.pygen_sink.writeln('cls.set_helper_class_disabled(True)')
-                    continue
-
-
-                try:
-                    method_wrapper = class_wrapper.add_method(member.name, return_type, arguments, **kwargs)
-                    method_wrapper.gccxml_definition = member
-                except NotSupportedError as ex:
-                    if pure_virtual:
-                        class_wrapper.set_cannot_be_constructed("pure virtual method %r not wrapped" % member.name)
-                        class_wrapper.set_helper_class_disabled(True)
-                        pygen_sink.writeln('cls.set_cannot_be_constructed("pure virtual method %%r not wrapped" %% %r)'
-                                           % member.name)
-                        pygen_sink.writeln('cls.set_helper_class_disabled(True)')
-
-                    warnings.warn_explicit("Error adding method %s: %r"
-                                           % (member, ex),
-                                           WrapperWarning, member.location.file_name, member.location.line)
-                except ValueError as ex:
-                    warnings.warn_explicit("Error adding method %s: %r"
-                                           % (member, ex),
-                                           WrapperWarning, member.location.file_name, member.location.line)
-                    raise
-                else: # no exception, add method succeeded
-                    for hook in self._post_scan_hooks:
-                        hook(self, member, method_wrapper)
-
-
-            ## ------------ constructor --------------------
-            elif isinstance(member, calldef.constructor_t):
-                if member.access_type not in ['public', 'protected']:
-                    continue
-
-                if not member.arguments:
-                    have_trivial_constructor = True
-
-                argument_specs = []
-                for arg in member.arguments:
-                    argument_specs.append(self.type_registry.lookup_parameter(arg.type, arg.name,
-                                                                              default_value=arg.default_value))
-
-                arglist_repr = ("[" + ', '.join([_pygen_param(args_, kwargs_) for (args_, kwargs_) in argument_specs]) +  "]")
-                if 'pygen_comment' in global_annotations:
-                    pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-
-                kwargs = {}
-
-                if member.attributes:
-                    if 'deprecated' in member.attributes:
-                        kwargs['deprecated'] = True
-
-                if member.access_type != 'public':
-                    kwargs['visibility'] = member.access_type
-
-                throw = self._get_calldef_exceptions(member)
-                if throw:
-                    kwargs['throw'] = throw
-
-                kwargs_repr = _pygen_kwargs(kwargs)
-                if kwargs_repr:
-                    kwargs_repr[0] = '\n' + 20*' '+ kwargs_repr[0]
-                pygen_sink.writeln("cls.add_constructor(%s)" %
-                                   ", ".join([arglist_repr] + kwargs_repr))
-
-                arguments = []
-                for a, kw in argument_specs:
-                    try:
-                        arguments.append(Parameter.new(*a, **kw))
-                    except (TypeLookupError, TypeConfigurationError) as ex:
-                        warnings.warn_explicit("Parameter '%s %s' error (used in %s): %r"
-                                               % (arg.type.partial_decl_string, arg.name, member, ex),
-                                               WrapperWarning, member.location.file_name, member.location.line)
-                        ok = False
-                        break
-                else:
-                    ok = True
-                if not ok:
-                    continue
-                constructor_wrapper = class_wrapper.add_constructor(arguments, **kwargs)
-                constructor_wrapper.gccxml_definition = member
-                for hook in self._post_scan_hooks:
-                    hook(self, member, constructor_wrapper)
-
-                if (len(arguments) == 1
-                    and isinstance(arguments[0], class_wrapper.ThisClassRefParameter)):
-                    have_copy_constructor = True
-
-            ## ------------ attribute --------------------
-            elif isinstance(member, variable_t):
-                if not member.name:
-                    continue # anonymous structure
-                if member.access_type == 'protected':
-                    warnings.warn_explicit("%s: protected member variables not yet implemented "
-                                           "by PyBindGen."
-                                           % member,
-                                           NotSupportedWarning, member.location.file_name, member.location.line)
-                    continue
-                if member.access_type == 'private':
-                    continue
-
-                real_type = type_traits.remove_declarated(member.type)
-                if hasattr(real_type, 'name') and not real_type.name:
-                    warnings.warn_explicit("Member variable %s of class %s will not be wrapped, "
-                                           "because wrapping member variables of anonymous types "
-                                           "is not yet supported by pybindgen"
-                                           % (member.name, cls.partial_decl_string),
-                                           NotSupportedWarning, member.location.file_name, member.location.line)
-                    continue
-
-                return_type_spec = self.type_registry.lookup_return(member.type, global_annotations)
-
-                ## pygen...
-                if 'pygen_comment' in global_annotations:
-                    pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                if member.type_qualifiers.has_static:
-                    pygen_sink.writeln("cls.add_static_attribute(%r, %s, is_const=%r)" %
-                                       (member.name, _pygen_retval(*return_type_spec),
-                                        type_traits.is_const(member.type)))
-                else:
-                    pygen_sink.writeln("cls.add_instance_attribute(%r, %s, is_const=%r)" %
-                                       (member.name, _pygen_retval(*return_type_spec),
-                                        type_traits.is_const(member.type)))
-
-                ## convert the return value
-                try:
-                    return_type = ReturnValue.new(*return_type_spec[0], **return_type_spec[1])
-                except (TypeLookupError, TypeConfigurationError) as ex:
-                    warnings.warn_explicit("Return value '%s' error (used in %s): %r"
-                                           % (member.type.partial_decl_string, member, ex),
-                                           WrapperWarning, member.location.file_name, member.location.line)
-                    continue
-
-                if member.type_qualifiers.has_static:
-                    class_wrapper.add_static_attribute(member.name, return_type,
-                                                       is_const=type_traits.is_const(member.type))
-                else:
-                    class_wrapper.add_instance_attribute(member.name, return_type,
-                                                         is_const=type_traits.is_const(member.type))
-                ## TODO: invoke post_scan_hooks
-            elif isinstance(member, calldef.destructor_t):
-                pass
-
-        ## gccxml 0.9, unlike 0.7, does not explicitly report inheritted trivial constructors
-        ## thankfully pygccxml comes to the rescue!
-        if not have_trivial_constructor:
-            if type_traits.has_trivial_constructor(cls):
-                class_wrapper.add_constructor([])
-                pygen_sink.writeln("cls.add_constructor([])")
-
-        if not have_copy_constructor:
-            try: # pygccxml > 0.9
-                has_copy_constructor = type_traits.has_copy_constructor(cls)
-            except AttributeError: # pygccxml <= 0.9
-                has_copy_constructor = type_traits.has_trivial_copy(cls)
-            if has_copy_constructor:
-                class_wrapper.add_copy_constructor()
-                pygen_sink.writeln("cls.add_copy_constructor()")
-
-
-    def _get_calldef_exceptions(self, calldef):
-        retval = []
-        for decl in calldef.exceptions:
-            traits = ctypeparser.TypeTraits(normalize_name(decl.partial_decl_string))
-            if traits.type_is_reference:
-                name = str(traits.target)
-            else:
-                name = str(traits.ctype)
-            exc = self.type_registry.root_module.get(name, None)
-            if isinstance(exc, CppException):
-                retval.append(exc)
-            else:
-                warnings.warn_explicit("Thrown exception '%s' was not previously detected as an exception class."
-                                       " PyBindGen bug?"
-                                       % (normalize_name(decl.partial_decl_string)),
-                                       WrapperWarning, calldef.location.file_name, calldef.location.line)
-        return retval
-
-    def _get_annotation_exceptions(self, annotation):
-        retval = []
-        for exc_name in annotation.split(','):
-            traits = ctypeparser.TypeTraits(normalize_name(exc_name))
-            if traits.type_is_reference:
-                name = str(traits.target)
-            else:
-                name = str(traits.ctype)
-            exc = self.type_registry.root_module.get(name, None)
-            if isinstance(exc, CppException):
-                retval.append(exc)
-            else:
-                raise ValueError("Thrown exception '%s' is not a CppException object: %r"
-                                 % (normalize_name(name), exc))
-        return retval
-
-    def scan_functions(self):
-        self._stage = 'scan functions'
-        assert self._types_scanned
-        for pygen_sink in self._get_all_pygen_sinks():
-            pygen_sink.writeln("def register_functions(root_module):")
-            pygen_sink.indent()
-            pygen_sink.writeln("module = root_module")
-            if pygen_sink is self._get_main_pygen_sink() and isinstance(self._pygen, list):
-                for section in self._pygen:
-                    if section.name == '__main__':
-                        continue
-                    pygen_sink.writeln("root_module.begin_section(%r)" % section.name)
-                    pygen_sink.writeln("%s.register_functions(root_module)" % section.name)
-                    if section.local_customizations_module:
-                        pygen_sink.writeln("\ntry:\n"
-                                           "    import %s\n"
-                                           "except ImportError:\n"
-                                           "    pass\n"
-                                           "else:\n"
-                                           "    %s.register_functions(root_module)\n"
-                                           % (section.local_customizations_module, section.local_customizations_module))
-                    pygen_sink.writeln("root_module.end_section(%r)" % section.name)
-        self._scan_namespace_functions(self.module, self.module_namespace)
-
-    def _scan_namespace_functions(self, module, module_namespace):
-        root_module = module.get_root()
-
-        functions_to_scan = []
-        for fun in module_namespace.free_functions(function=self.location_filter,
-                                                   allow_empty=True, recursive=False):
-            if fun.name.startswith('__'):
-                continue
-            functions_to_scan.append(fun)
-
-        functions_to_scan.sort(key=lambda c: (c.name, c.decl_string))
-
-        for fun in functions_to_scan:
-            global_annotations, parameter_annotations = annotations_scanner.get_annotations(fun)
-            for hook in self._pre_scan_hooks:
-                hook(self, fun, global_annotations, parameter_annotations)
-
-            as_method = None
-            of_class = None
-            alt_name = None
-            ignore = False
-            kwargs = {}
-
-            for name, value in global_annotations.items():
-                if name == 'as_method':
-                    as_method = value
-                elif name == 'of_class':
-                    of_class = value
-                elif name == 'name':
-                    alt_name = value
-                elif name == 'ignore':
-                    ignore = True
-                elif name == 'is_constructor_of':
-                    pass
-                elif name == 'pygen_comment':
-                    pass
-                elif name == 'template_instance_names':
-                    pass
-                elif name == 'unblock_threads':
-                    kwargs['unblock_threads'] = annotations_scanner.parse_boolean(value)
-                elif name == 'throw':
-                    kwargs['throw'] = self._get_annotation_exceptions(value)
-                else:
-                    warnings.warn_explicit("Incorrect annotation %s=%s" % (name, value),
-                                           AnnotationsWarning, fun.location.file_name, fun.location.line)
-            if ignore:
-                continue
-
-
-            is_constructor_of = global_annotations.get("is_constructor_of", None)
-            return_annotations = parameter_annotations.get('return', {})
-            if is_constructor_of:
-                return_annotations['caller_owns_return'] = 'true'
-
-            params_ok = True
-            return_type_spec = self.type_registry.lookup_return(fun.return_type, return_annotations)
-            try:
-                return_type = ReturnValue.new(*return_type_spec[0], **return_type_spec[1])
-            except (TypeLookupError, TypeConfigurationError) as ex:
-                warnings.warn_explicit("Return value '%s' error (used in %s): %r"
-                                       % (fun.return_type.partial_decl_string, fun, ex),
-                                       WrapperWarning, fun.location.file_name, fun.location.line)
-                params_ok = False
-            except TypeError as ex:
-                warnings.warn_explicit("Return value '%s' error (used in %s): %r"
-                                       % (fun.return_type.partial_decl_string, fun, ex),
-                                       WrapperWarning, fun.location.file_name, fun.location.line)
-                raise
-            argument_specs = []
-            arguments = []
-            for argnum, arg in enumerate(fun.arguments):
-                annotations = parameter_annotations.get(arg.name, {})
-                if argnum == 0 and as_method is not None \
-                        and isinstance(arg.type, cpptypes.pointer_t):
-                    annotations.setdefault("transfer_ownership", "false")
-
-                spec = self.type_registry.lookup_parameter(arg.type, arg.name,
-                                                           annotations,
-                                                           default_value=arg.default_value)
-                argument_specs.append(spec)
-                try:
-                    arguments.append(Parameter.new(*spec[0], **spec[1]))
-                except (TypeLookupError, TypeConfigurationError) as ex:
-                    warnings.warn_explicit("Parameter '%s %s' error (used in %s): %r"
-                                           % (arg.type.partial_decl_string, arg.name, fun, ex),
-                                           WrapperWarning, fun.location.file_name, fun.location.line)
-
-                    params_ok = False
-                except TypeError as ex:
-                    warnings.warn_explicit("Parameter '%s %s' error (used in %s): %r"
-                                           % (arg.type.partial_decl_string, arg.name, fun, ex),
-                                           WrapperWarning, fun.location.file_name, fun.location.line)
-                    raise
-
-            throw = self._get_calldef_exceptions(fun)
-            if throw:
-                kwargs['throw'] = throw
-
-            arglist_repr = ("[" + ', '.join([_pygen_param(*arg)  for arg in argument_specs]) +  "]")
-            retval_repr = _pygen_retval(*return_type_spec)
-
-            if as_method is not None:
-                assert of_class is not None
-                cpp_class = root_module[normalize_class_name(of_class, (self.module_namespace_name or '::'))]
-
-                pygen_sink = self._get_pygen_sink_for_definition(fun)
-                if pygen_sink:
-                    if 'pygen_comment' in global_annotations:
-                        pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                    pygen_sink.writeln("root_module[%r].add_function_as_method(%s, custom_name=%r)" %
-                                       (cpp_class.full_name,
-                                        ", ".join([repr(fun.name), retval_repr, arglist_repr]),
-                                        as_method))
-                if params_ok:
-                    function_wrapper = cpp_class.add_function_as_method(fun.name, return_type, arguments, custom_name=as_method)
-                    function_wrapper.gccxml_definition = fun
-
-                continue
-
-            if is_constructor_of is not None:
-                #cpp_class = type_registry.find_class(is_constructor_of, (self.module_namespace_name or '::'))
-                cpp_class = root_module[normalize_class_name(is_constructor_of, (self.module_namespace_name or '::'))]
-
-                pygen_sink = self._get_pygen_sink_for_definition(fun)
-                if pygen_sink:
-                    if 'pygen_comment' in global_annotations:
-                        pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                    pygen_sink.writeln("root_module[%r].add_function_as_constructor(%s)" %
-                                       (cpp_class.full_name,
-                                        ", ".join([repr(fun.name), retval_repr, arglist_repr]),))
-
-                if params_ok:
-                    function_wrapper = cpp_class.add_function_as_constructor(fun.name, return_type, arguments)
-                    function_wrapper.gccxml_definition = fun
-
-                continue
-
-            if templates.is_instantiation(fun.demangled_name):
-                template_parameters = templates.args(fun.demangled_name)
-                kwargs['template_parameters'] = template_parameters
-                template_instance_names = global_annotations.get('template_instance_names', '')
-                if template_instance_names:
-                    for mapping in template_instance_names.split('|'):
-                        type_names, name = mapping.split('=>')
-                        instance_types = type_names.split(',')
-                        if instance_types == template_parameters:
-                            kwargs['custom_name'] = name
-                            break
-
-            if alt_name:
-                kwargs['custom_name'] = alt_name
-
-            if fun.attributes:
-                if 'deprecated' in fun.attributes:
-                    kwargs['deprecated'] = True
-
-            pygen_sink = self._get_pygen_sink_for_definition(fun)
-            if pygen_sink:
-                if 'pygen_comment' in global_annotations:
-                    pygen_sink.writeln('## ' + global_annotations['pygen_comment'])
-                kwargs_repr = _pygen_kwargs(kwargs)
-                if kwargs_repr:
-                    kwargs_repr[0] = "\n" + 20*' ' + kwargs_repr[0]
-                pygen_sink.writeln("module.add_function(%s)" %
-                                   (", ".join([repr(fun.name),
-                                               "\n" + 20*' ' + retval_repr,
-                                               "\n" + 20*' ' + arglist_repr]
-                                              + kwargs_repr)))
-
-            if params_ok:
-                func_wrapper = module.add_function(fun.name, return_type, arguments, **kwargs)
-                func_wrapper.gccxml_definition = fun
-                for hook in self._post_scan_hooks:
-                    hook(self, fun, func_wrapper)
-
-
-        ## scan nested namespaces (mapped as python submodules)
-        nested_namespaces = []
-        for nested_namespace in module_namespace.namespaces(allow_empty=True, recursive=False):
-            if nested_namespace.name.startswith('__'):
-                continue
-            nested_namespaces.append(nested_namespace)
-
-        nested_namespaces.sort(key=lambda c: c.decl_string)
-
-        for nested_namespace in nested_namespaces:
-            nested_module = module.get_submodule(nested_namespace.name)
-            nested_module_pygen_func = "register_functions_" + "_".join(nested_module.get_namespace_path())
-            for pygen_sink in self._get_all_pygen_sinks():
-                pygen_sink.writeln("%s(module.get_submodule(%r), root_module)" %
-                                   (nested_module_pygen_func, nested_namespace.name))
-
-        for pygen_sink in self._get_all_pygen_sinks():
-            pygen_sink.writeln("return")
-            pygen_sink.unindent()
-            pygen_sink.writeln()
-
-        nested_namespaces = []
-        for nested_namespace in module_namespace.namespaces(allow_empty=True, recursive=False):
-            if nested_namespace.name.startswith('__'):
-                continue
-            nested_namespaces.append(nested_namespace)
-
-        nested_namespaces.sort(key=lambda c: c.decl_string)
-
-        for nested_namespace in nested_namespaces:
-            nested_module = module.get_submodule(nested_namespace.name)
-            nested_module_pygen_func = "register_functions_" + "_".join(nested_module.get_namespace_path())
-            for pygen_sink in self._get_all_pygen_sinks():
-                pygen_sink.writeln("def %s(module, root_module):" % nested_module_pygen_func)
-                pygen_sink.indent()
-
-            self._scan_namespace_functions(nested_module, nested_namespace)
-
-
-def _test():
-    module_parser = ModuleParser('foo', '::')
-    module = module_parser.parse(sys.argv[1:])
-    if 0:
-        out = FileCodeSink(sys.stdout)
-        module.generate(out)
-
-if __name__ == '__main__':
-    _test()
diff --git a/pybindgen/overloading.py b/pybindgen/overloading.py
index f5b93c4..dc7bcef 100644
--- a/pybindgen/overloading.py
+++ b/pybindgen/overloading.py
@@ -279,7 +279,7 @@ class OverloadedWrapper(object):
                 if wrap.docstring is not None:
                     docstrings_set.add(wrap.docstring)
             docstring = None
-            if len(docstrings_set) is 1:
+            if len(docstrings_set) == 1:
                 docstring = docstrings_set.pop()
             elif len(docstrings_set) > 1:
                 raise CodeGenerationError("Overloaded '%s' has conflicting docstrings" % self.wrapper_name)
@@ -289,7 +289,7 @@ class OverloadedWrapper(object):
             assert isinstance(self.wrapper_args, list)
 
             return "{(char *) \"%s\", (PyCFunction) %s, %s, %s }," % \
-                (name, self.wrapper_actual_name, '|'.join(flags),
+                (name, self.wrapper_actual_name, '|'.join(sorted(flags)),
                  (docstring is None and "NULL" or ('"'+docstring+'"')))
 
     def generate_declaration(self, code_sink):
diff --git a/pybindgen/pytypeobject.py b/pybindgen/pytypeobject.py
index 7dc6d51..e045cd2 100644
--- a/pybindgen/pytypeobject.py
+++ b/pybindgen/pytypeobject.py
@@ -291,7 +291,7 @@ static Py_ssize_t
     PyObject *py_result;
     Py_ssize_t result;
 
-    py_result = %(method_name)s(py_self);
+    py_result = %(method_name)s(py_self, NULL, NULL);
     if (py_result == NULL) {
         PyErr_SetString(PyExc_RuntimeError, "Unknown error in attempting to determine __len__.");
         Py_XDECREF(py_result);
diff --git a/pybindgen/typehandlers/base.py b/pybindgen/typehandlers/base.py
index d07dc4d..528d15c 100644
--- a/pybindgen/typehandlers/base.py
+++ b/pybindgen/typehandlers/base.py
@@ -1212,9 +1212,10 @@ ReturnValue.CTYPES = NotImplemented
 class PointerReturnValue(ReturnValue):
     """Base class for all pointer-to-something handlers"""
     CTYPES = []
-    def __init__(self, ctype, is_const=False, caller_owns_return=None):
+    def __init__(self, ctype, is_const=False, caller_owns_return=None, free_after_copy=None):
         super(PointerReturnValue, self).__init__(ctype, is_const)
         self.call_owns_return = caller_owns_return
+        self.free_after_copy = free_after_copy
 
 PointerReturnValue.CTYPES = NotImplemented
 
@@ -1337,9 +1338,10 @@ class PointerParameter(Parameter):
     CTYPES = []
 
     def __init__(self, ctype, name, direction=Parameter.DIRECTION_IN, is_const=False, default_value=None,
-                 transfer_ownership=False):
+                 transfer_ownership=False, free_after_copy=False):
         super(PointerParameter, self).__init__(ctype, name, direction, is_const, default_value)
         self.transfer_ownership = transfer_ownership
+        self.free_after_copy = free_after_copy
 
 PointerParameter.CTYPES = NotImplemented
 
diff --git a/pybindgen/typehandlers/ctypeparser/__init__.py b/pybindgen/typehandlers/ctypeparser/__init__.py
index e54fc7a..5c05ebc 100644
--- a/pybindgen/typehandlers/ctypeparser/__init__.py
+++ b/pybindgen/typehandlers/ctypeparser/__init__.py
@@ -46,7 +46,7 @@ class CType(object):
                     ## we'll break the for unconditionally next.
 
                     self.tokens.pop(token_i)
-                    
+
                     for new_pos in range(token_i, len(self.tokens)):
                         other_token = self.tokens[new_pos]
                         if isinstance(other_token, CType):
@@ -133,6 +133,10 @@ def _parse_type_recursive(tokens):
         if token.name.startswith('::'):
             token.name = token.name[2:]
         if token.token_type == tokenizer.SYNTAX:
+            if token.name in [ '>>' ]:
+                tokens.insert(0, tokenizer.Token(tokenizer.SYNTAX, token.name[0], None, None))
+                tokens.insert(0, tokenizer.Token(tokenizer.SYNTAX, token.name[0], None, None))
+                continue
             if token.name in [',', '>', ')']:
                 ctype.reorder_modifiers()
                 return ctype, token
@@ -217,9 +221,9 @@ class TypeTraits(object):
     reference, it is None.
 
     >>> t = TypeTraits("int")
-    >>> print repr(str(t.ctype))
+    >>> print(repr(str(t.ctype)))
     'int'
-    >>> print repr(str(t.ctype_no_modifiers))
+    >>> print(repr(str(t.ctype_no_modifiers)))
     'int'
     >>> t.type_is_const
     False
@@ -231,11 +235,11 @@ class TypeTraits(object):
     True
 
     >>> t = TypeTraits("const int * const")
-    >>> print repr(str(t.ctype))
+    >>> print(repr(str(t.ctype)))
     'int const * const'
-    >>> print repr(str(t.ctype_no_modifiers))
+    >>> print(repr(str(t.ctype_no_modifiers)))
     'int *'
-    >>> print repr(str(t.ctype_no_const))
+    >>> print(repr(str(t.ctype_no_const)))
     'int const *'
     >>> t.type_is_const
     True
@@ -245,17 +249,17 @@ class TypeTraits(object):
     False
     >>> t.target is None
     False
-    >>> print repr(str(t.target))
+    >>> print(repr(str(t.target)))
     'int'
     >>> t.target_is_const
     True
 
     >>> t = TypeTraits("int * const")
-    >>> print repr(str(t.ctype))
+    >>> print(repr(str(t.ctype)))
     'int * const'
-    >>> print repr(str(t.ctype_no_modifiers))
+    >>> print(repr(str(t.ctype_no_modifiers)))
     'int *'
-    >>> print repr(str(t.ctype_no_const))
+    >>> print(repr(str(t.ctype_no_const)))
     'int *'
     >>> t.type_is_const
     True
@@ -265,17 +269,17 @@ class TypeTraits(object):
     False
     >>> t.target is None
     False
-    >>> print repr(str(t.target))
+    >>> print(repr(str(t.target)))
     'int'
     >>> t.target_is_const
     False
 
     >>> t = TypeTraits("const char *")
-    >>> print repr(str(t.ctype))
+    >>> print(repr(str(t.ctype)))
     'char const *'
-    >>> print repr(str(t.ctype_no_modifiers))
+    >>> print(repr(str(t.ctype_no_modifiers)))
     'char *'
-    >>> print repr(str(t.ctype_no_const))
+    >>> print(repr(str(t.ctype_no_const)))
     'char const *'
     >>> t.type_is_const
     False
@@ -285,21 +289,24 @@ class TypeTraits(object):
     False
     >>> t.target is None
     False
-    >>> print repr(str(t.target))
+    >>> print(repr(str(t.target)))
     'char'
     >>> t.target_is_const
     True
 
     >>> t = TypeTraits("char *")
-    >>> print repr(str(t.ctype))
+    >>> str(t.ctype)
     'char *'
     >>> t.make_const()
-    >>> print repr(str(t.ctype))
+    >>> print(repr(str(t.ctype)))
     'char * const'
     >>> t.make_target_const()
-    >>> print repr(str(t.ctype))
+    >>> print(repr(str(t.ctype)))
     'char const * const'
 
+    >>> str(TypeTraits("T<X<int>>").ctype)
+    'T< X< int > >'
+
     """
 
     def __init__(self, ctype):
diff --git a/pybindgen/typehandlers/stringtype.py b/pybindgen/typehandlers/stringtype.py
index 4c96a3e..d98a42a 100644
--- a/pybindgen/typehandlers/stringtype.py
+++ b/pybindgen/typehandlers/stringtype.py
@@ -40,8 +40,11 @@ class CharParam(Parameter):
 
     def convert_python_to_c(self, wrapper):
         assert isinstance(wrapper, ForwardWrapperBase)
-        name = wrapper.declarations.declare_variable(self.ctype_no_const, self.name)
-        wrapper.parse_params.add_parameter('c', ['&'+name], self.value)
+        name = wrapper.declarations.declare_variable(
+            self.ctype_no_const, self.name, self.default_value
+        )
+        wrapper.parse_params.add_parameter('c', ['&'+name], self.value,
+                                           optional=(self.default_value is not None))
         wrapper.call_params.append(name)
 
 
@@ -218,6 +221,9 @@ class CStringReturn(PointerReturnValue):
 
     def convert_c_to_python(self, wrapper):
         wrapper.build_params.add_parameter("s", [self.value])
+        if self.free_after_copy:
+            wrapper.after_call.add_cleanup_code("free(retval);")
+            wrapper.after_call.add_cleanup_code("// free_after_copy for %s %s()" % (self.ctype, wrapper.function_name))
 
 
 class StdStringReturn(ReturnValue):
diff --git a/pybindgen/utils.py b/pybindgen/utils.py
index 519a58a..af04804 100644
--- a/pybindgen/utils.py
+++ b/pybindgen/utils.py
@@ -141,9 +141,13 @@ typedef enum _PyBindGenWrapperFlags {
 } PyBindGenWrapperFlags;
 #endif
 
+#if PY_VERSION_HEX >= 0x03070000 && !defined(PyEval_ThreadsInitialized)
+#define PyEval_ThreadsInitialized() 1
+#endif
+
 ''')
 
-    
+
 
 def mangle_name(name):
     """make a name Like<This,and,That> look Like__lt__This_and_That__gt__"""
@@ -214,7 +218,7 @@ def ascii(value):
 def param(*args, **kwargs):
     """
     Simplified syntax for representing a parameter with delayed lookup.
-    
+
     Parameters are the same as L{Parameter.new}.
     """
     return (args + (kwargs,))
@@ -223,7 +227,7 @@ def param(*args, **kwargs):
 def retval(*args, **kwargs):
     """
     Simplified syntax for representing a return value with delayed lookup.
-    
+
     Parameters are the same as L{ReturnValue.new}.
     """
     return (args + (kwargs,))
diff --git a/pybindgen/version.py b/pybindgen/version.py
index 6cd276c..515de5d 100644
--- a/pybindgen/version.py
+++ b/pybindgen/version.py
@@ -1,4 +1,5 @@
 # coding: utf-8
 # file generated by setuptools_scm
 # don't change, don't track in version control
-version = '0.20.0'
+version = '0.22.1'
+version_tuple = (0, 22, 1)
diff --git a/setup.py b/setup.py
index 8368acb..eefcc4d 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,7 @@ setup(name='PyBindGen',
       description='Python Bindings Generator',
       author='Gustavo Carneiro',
       author_email='gjcarneiro@gmail.com',
-      url='https://launchpad.net/pybindgen',
+      url='https://github.com/gjcarneiro/pybindgen',
       packages=['pybindgen',
                 'pybindgen.typehandlers',
                 'pybindgen.typehandlers.ctypeparser',
diff --git a/tests/boost/test.py b/tests/boost/test.py
index 5733faa..53796a4 100644
--- a/tests/boost/test.py
+++ b/tests/boost/test.py
@@ -2,7 +2,7 @@ import pybindgen.typehandlers.base as typehandlers
 from pybindgen.typehandlers import stringtype, ctypeparser
 import pybindgen.typehandlers.codesink as codesink
 from pybindgen import module, cppclass, overloading, utils
-    
+
 
 import unittest
 import doctest
@@ -58,24 +58,11 @@ class ParamLookupTests(unittest.TestCase):
         transformed = typehandlers.Parameter.new('MySmartPointer<testtype>', 'name')
         self.assert_(isinstance(transformed, TestParam))
         self.assert_(transformed.has_been_transformed)
-        
+
 
 
 if __name__ == '__main__':
     suite = unittest.TestSuite()
-    for mod in [
-        typehandlers,
-        codesink,
-        module,
-        cppclass,
-        overloading,
-        #utils,
-        stringtype,
-        ctypeparser,
-        ]:
-        suite.addTest(doctest.DocTestSuite(mod))
-
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ParamLookupTests))
     runner = unittest.TextTestRunner()
     runner.run(suite)
-
diff --git a/tests/c-hello/hellomodulegen.py b/tests/c-hello/hellomodulegen.py
index c39fffb..137761f 100755
--- a/tests/c-hello/hellomodulegen.py
+++ b/tests/c-hello/hellomodulegen.py
@@ -5,6 +5,7 @@ import re
 
 import pybindgen
 from pybindgen import FileCodeSink
+from pybindgen.castxmlparser import ModuleParser
 
 
 constructor_rx = re.compile("hello_foo_new(_.*)?")
@@ -40,11 +41,6 @@ def pre_scan_hook(dummy_module_parser,
 
 
 def my_module_gen(out_file, pygccxml_mode):
-    if pygccxml_mode == 'castxml':
-        from pybindgen.castxmlparser import ModuleParser
-    else:
-        from pybindgen.gccxmlparser import ModuleParser
-
     out = FileCodeSink(out_file)
     #pybindgen.write_preamble(out)
     out.writeln("#include \"hello.h\"")
diff --git a/tests/foo.cc b/tests/foo.cc
index 06c4035..7c5dede 100644
--- a/tests/foo.cc
+++ b/tests/foo.cc
@@ -26,7 +26,6 @@ int get_int_from_float(double from_float, int multiplier)
     return (int) from_float*multiplier;
 }
 
-
 std::string SomeObject::staticData = std::string("Hello Static World!");
 
 SomeObject::~SomeObject ()
@@ -407,6 +406,29 @@ TestContainer::set_simple_map (SimpleStructMap map)
     return count;
 }
 
+SimpleStructUnorderedMap
+TestContainer::get_simple_unordered_map ()
+{
+    SimpleStructUnorderedMap retval;
+    for (int i = 0; i < 10; i++)
+    {
+        simple_struct_t val = {i};
+        std::ostringstream os;
+        os << i;
+        retval[os.str()] = val;
+    }
+    return retval;
+}
+
+int
+TestContainer::set_simple_unordered_map (SimpleStructUnorderedMap map)
+{
+    int count = 0;
+    m_simpleUnorderedMap = map;
+    for (SimpleStructUnorderedMap::iterator iter = m_simpleUnorderedMap.begin(); iter != m_simpleUnorderedMap.end(); iter++)
+        count += iter->second.xpto;
+    return count;
+}
 
 void
 TestContainer::get_vec (std::vector<std::string> &outVec)
@@ -447,7 +469,7 @@ get_set ()
 }
 
 namespace xpto
-{    
+{
     FlowId
     get_flow_id (FlowId flowId)
     {
@@ -557,3 +579,52 @@ test_args_kwargs(const char *args, const char *kwargs)
     return (int) (kwargs - args);
 }
 
+ToBeFreed::ToBeFreed(int size) {
+    m_size = size;
+    m = return_c_string_to_be_freed(size);
+}
+
+ToBeFreed::~ToBeFreed() {
+    free(m);
+    m = NULL;
+}
+
+ ToBeFreed::ToBeFreed(const ToBeFreed& from) {
+     m_size = from.m_size;
+     m = return_c_string_to_be_freed(m_size);
+ }
+
+char *ToBeFreed::value()  {
+        return m;
+}
+
+char *return_c_string_to_be_freed(int size)
+{
+    char *test = (char *)malloc(size * sizeof(char));
+    strcpy(test, "testingonly");
+    return test;
+}
+
+ToBeFreed *
+return_class_to_be_freed(int size)
+{
+   return new ToBeFreed(size);
+}
+
+char *
+return_c_string_to_not_be_freed(int size)
+{
+   return return_c_string_to_be_freed(size);
+}
+
+ToBeFreed *
+return_class_to_not_be_freed(int size)
+{
+   return new ToBeFreed(size);
+}
+
+void Add (const std::string filePath,
+          double defaultZ,
+          char delimiter)
+{
+}
diff --git a/tests/foo.h b/tests/foo.h
index 2f0ab1d..947b451 100644
--- a/tests/foo.h
+++ b/tests/foo.h
@@ -8,6 +8,7 @@
 #include <sstream>
 #include <vector>
 #include <map>
+#include <unordered_map>
 #include <set>
 #include <exception>
 #include <algorithm>
@@ -651,7 +652,7 @@ public:
             return new AbstractBaseClassImpl;
         }
 
-    // This method will be scanned by gccxmlparser and generate an error
+    // This method will be scanned by castxmlparser and generate an error
     // that is only detected in code generation time.
     // -#- @return(caller_owns_return=false) -#-
     static AbstractBaseClass* get_abstract_base_class_ptr2 ()
@@ -675,7 +676,7 @@ inline AbstractBaseClass* get_abstract_base_class_ptr1 ()
     return AbstractBaseClassImpl::get_abstract_base_class_ptr1 ();
 }
 
-// This function will be scanned by gccxmlparser and generate an error
+// This function will be scanned by castxmlparser and generate an error
 // that is only detected in code generation time.
 // -#- @return(caller_owns_return=false) -#-
 inline AbstractBaseClass* get_abstract_base_class_ptr2 ()
@@ -806,6 +807,7 @@ struct simple_struct_t
 typedef std::vector<simple_struct_t> SimpleStructList;
 typedef std::vector<simple_struct_t> SimpleStructVec;
 typedef std::map<std::string, simple_struct_t> SimpleStructMap;
+typedef std::unordered_map<std::string, simple_struct_t> SimpleStructUnorderedMap;
 
 
 SimpleStructList get_simple_list ();
@@ -838,6 +840,9 @@ public:
     virtual SimpleStructMap get_simple_map ();
     virtual int set_simple_map (SimpleStructMap map);
 
+    virtual SimpleStructUnorderedMap get_simple_unordered_map ();
+    virtual int set_simple_unordered_map (SimpleStructUnorderedMap map);
+
     // -#- @outVec(direction=out) -#-
     void get_vec (std::vector<std::string> &outVec);
 
@@ -850,6 +855,7 @@ public:
 private:
     SimpleStructList m_simpleList;
     SimpleStructMap m_simpleMap;
+    SimpleStructUnorderedMap m_simpleUnorderedMap;
 
     std::vector<std::string> *m_vec;
 
@@ -1342,4 +1348,61 @@ public:
 
 int test_args_kwargs(const char *args, const char *kwargs);
 
+
+struct RAStruct
+{
+  int a;
+};
+
+
+class ReturnConstRef
+{
+public:
+  virtual const RAStruct & ReturnMyAStruct (void) = 0;
+  virtual ~ReturnConstRef() {}
+};
+
+
+class RAReturnConstRef : public ReturnConstRef
+{
+public:
+  RAReturnConstRef(int value) { m_astruct.a = value; }
+  RAReturnConstRef() { m_astruct.a = 0; }
+  const RAStruct & ReturnMyAStruct (void) { return m_astruct; }
+  virtual ~RAReturnConstRef() {}
+
+private:
+  RAStruct m_astruct;
+};
+
+// -#- name=return_c_string_to_be_freed; @return(free_after_copy=true) -#-
+char *return_c_string_to_be_freed(int size);
+
+// -#- name=return_c_string_to_not_be_freed; @return(free_after_copy=false) -#-
+char *return_c_string_to_not_be_freed(int size);
+
+class ToBeFreed
+{
+public:
+    ToBeFreed(int size);
+    ~ToBeFreed();
+    ToBeFreed(const ToBeFreed&);
+    char *value();
+private:
+    char *m;
+    int m_size;
+};
+
+// -#- name=return_class_to_be_freed; @return(free_after_copy=true) -#-
+ToBeFreed *return_class_to_be_freed(int size);
+
+// -#- name=return_class_to_not_be_freed; @return(free_after_copy=false) -#-
+ToBeFreed *return_class_to_not_be_freed(int size);
+
+
+void Add (const std::string filePath,
+          double defaultZ = 0,
+          char delimiter = ',');
+
+
 #endif 	    /* !FOO_H_ */
diff --git a/tests/foomodulegen-auto-split.py b/tests/foomodulegen-auto-split.py
index ae4e830..af4e73e 100644
--- a/tests/foomodulegen-auto-split.py
+++ b/tests/foomodulegen-auto-split.py
@@ -10,6 +10,7 @@ from pybindgen import (ReturnValue, Parameter, Module, Function, FileCodeSink)
 from pybindgen import (CppMethod, CppConstructor, CppClass, Enum)
 from pybindgen.function import CustomFunctionWrapper
 from pybindgen.cppmethod import CustomCppMethodWrapper
+from pybindgen.castxmlparser import ModuleParser, PygenClassifier, PygenSection
 
 import foomodulegen_common
 
@@ -17,10 +18,6 @@ import foomodulegen_common
 
 
 def my_module_gen():
-    if sys.argv[6] == 'castxml':
-        from pybindgen.castxmlparser import ModuleParser, PygenClassifier, PygenSection
-    else:
-        from pybindgen.gccxmlparser import ModuleParser, PygenClassifier, PygenSection
 
     class MyPygenClassifier(PygenClassifier):
         def classify(self, pygccxml_definition):
diff --git a/tests/foomodulegen-auto.py b/tests/foomodulegen-auto.py
index 69c4f8d..d608fd7 100644
--- a/tests/foomodulegen-auto.py
+++ b/tests/foomodulegen-auto.py
@@ -11,16 +11,13 @@ from pybindgen import (ReturnValue, Parameter, Module, Function, FileCodeSink)
 from pybindgen import (CppMethod, CppConstructor, CppClass, Enum)
 from pybindgen.function import CustomFunctionWrapper
 from pybindgen.cppmethod import CustomCppMethodWrapper
+from pybindgen.castxmlparser import ModuleParser
 
 import foomodulegen_common
 
 
 def my_module_gen():
     pygccxml_mode = sys.argv[4]
-    if pygccxml_mode == 'castxml':
-        from pybindgen.castxmlparser import ModuleParser
-    else:
-        from pybindgen.gccxmlparser import ModuleParser
 
     out = FileCodeSink(sys.stdout)
     pygen_file = open(sys.argv[3], "wt")
@@ -50,7 +47,6 @@ def my_module_gen():
 
     module.generate(out)
 
-
 def main():
     logging.basicConfig(level=logging.DEBUG)
     if sys.argv[1] == '-d':
diff --git a/tests/foomodulegen.py b/tests/foomodulegen.py
index f8bee5b..f927e2a 100755
--- a/tests/foomodulegen.py
+++ b/tests/foomodulegen.py
@@ -114,7 +114,24 @@ int %s::custom_method_added_by_a_hook(int x)
                       Parameter.new('int', 'multiplier', default_value='1')],
                      custom_name="get_int")
 
-
+    ## test free_after_copy.
+    mod.add_function('return_c_string_to_be_freed',
+                     ReturnValue.new('char *', free_after_copy=True),
+                     [Parameter.new('int', 'size')])
+    mod.add_function('return_c_string_to_not_be_freed',
+                     ReturnValue.new('char *', free_after_copy=False),
+                     [Parameter.new('int', 'size')])
+
+    ToBeFreed = mod.add_class('ToBeFreed')
+    ToBeFreed.add_constructor([Parameter.new('int', 'size')])
+    ToBeFreed.add_copy_constructor()
+    ToBeFreed.add_method('value', ReturnValue.new('char *'), [])
+    mod.add_function('return_class_to_be_freed',
+                     ReturnValue.new('ToBeFreed *', free_after_copy=True),
+                     [Parameter.new('int', 'size')])
+    mod.add_function('return_class_to_not_be_freed',
+                     ReturnValue.new('ToBeFreed *', free_after_copy=False),
+                     [Parameter.new('int', 'size')])
 
     SomeObject = mod.add_class('SomeObject', allow_subclassing=True)
 
@@ -469,6 +486,14 @@ int %s::custom_method_added_by_a_hook(int x)
     TestContainer.add_method('get_simple_map', ReturnValue.new('std::map<std::string, simple_struct_t>'), [], is_virtual=True)
     TestContainer.add_method('set_simple_map', 'int', [Parameter.new('std::map<std::string, simple_struct_t>', 'map')], is_virtual=True)
 
+    mod.add_container('SimpleStructUnorderedMap', ('std::string', 'simple_struct_t'), container_type='map')
+    typehandlers.add_type_alias('std::unordered_map< std::string, simple_struct_t >', 'SimpleStructUnorderedMap')
+    typehandlers.add_type_alias('std::unordered_map< std::string, simple_struct_t >*', 'SimpleStructUnorderedMap*')
+    typehandlers.add_type_alias('std::unordered_map< std::string, simple_struct_t >&', 'SimpleStructUnorderedMap&')
+
+    TestContainer.add_method('get_simple_unordered_map', ReturnValue.new('std::unordered_map<std::string, simple_struct_t>'), [], is_virtual=True)
+    TestContainer.add_method('set_simple_unordered_map', 'int', [Parameter.new('std::unordered_map<std::string, simple_struct_t>', 'map')], is_virtual=True)
+
 
     Tupl = mod.add_class('Tupl')
     Tupl.add_binary_comparison_operator('<')
@@ -612,6 +637,30 @@ int %s::custom_method_added_by_a_hook(int x)
 
     mod.add_function("test_args_kwargs", "int", [param("const char *", "args"), param("const char *", "kwargs")])
 
+    # https://github.com/gjcarneiro/pybindgen/issues/21
+    cls = mod.add_class('RAStruct')
+    cls.add_constructor([])
+    cls.add_constructor([param('RAStruct const &', 'arg0')])
+    cls.add_instance_attribute('a', 'int', is_const=False)
+
+    cls = mod.add_class('ReturnConstRef', allow_subclassing=True)
+    cls.add_constructor([])
+    cls.add_constructor([param('ReturnConstRef const &', 'arg0')])
+    cls.add_method('ReturnMyAStruct',
+                   'RAStruct const &',
+                   [],
+                   is_pure_virtual=True, is_virtual=True)
+
+    cls = mod.add_class('RAReturnConstRef', parent=mod['ReturnConstRef'])
+    cls.add_constructor([])
+    cls.add_constructor([param('int', 'value')])
+    cls.add_constructor([param('RAReturnConstRef const &', 'arg0')])
+    cls.add_method('ReturnMyAStruct',
+                   'RAStruct const &',
+                   [],
+                   is_virtual=True)
+
+
 
     #### --- error handler ---
     class MyErrorHandler(pybindgen.settings.ErrorHandler):
diff --git a/tests/foomodulegen4.py b/tests/foomodulegen4.py
index 3930cde..17465f8 100644
--- a/tests/foomodulegen4.py
+++ b/tests/foomodulegen4.py
@@ -9,16 +9,18 @@ from pybindgen.module import MultiSectionFactory
 from pybindgen import (FileCodeSink)
 
 import foomodulegen_split
+import foomodulegen_module1, foomodulegen_module2
 import foomodulegen_common
 
+# TODO(cnicolaou): get the multi section tests working
 
 class MyMultiSectionFactory(MultiSectionFactory):
 
-    def __init__(self, main_file_name):
-        self.main_file_name = main_file_name
-        self.main_sink = FileCodeSink(open(main_file_name, "wt"))
+    def __init__(self, dir):
+        self.main_file_name = os.path.join(dir, "foomodule4.cc")
+        self.main_sink = FileCodeSink(open(self.main_file_name, "wt"))
         self.header_name = "foomodule4.h"
-        header_file_name = os.path.join(os.path.dirname(self.main_file_name), self.header_name)
+        header_file_name = os.path.join(dir, self.header_name)
         self.header_sink = FileCodeSink(open(header_file_name, "wt"))
         self.section_sinks = {}
 
@@ -49,7 +51,7 @@ class MyMultiSectionFactory(MultiSectionFactory):
             sink.file.close()
 
 def my_module_gen():
-    out = MyMultiSectionFactory(sys.argv[1])
+    out = MyMultiSectionFactory(os.path.dirname(sys.argv[1]))
     root_module = foomodulegen_split.module_init()
     root_module.add_exception('exception', foreign_cpp_namespace='std', message_rvalue='%(EXC)s.what()')
     foomodulegen_common.customize_module_pre(root_module)
diff --git a/tests/foomodulegen_common.py b/tests/foomodulegen_common.py
index 4722376..9807c40 100644
--- a/tests/foomodulegen_common.py
+++ b/tests/foomodulegen_common.py
@@ -84,6 +84,12 @@ _wrap_foofunction_that_takes_foo_from_string(PyObject * PYBINDGEN_UNUSED(dummy),
     return py_retval;
 }
 '''
+
+    if len(module.classes) == 0:
+        # Some tests, eg. foomodulegen4.py, don't have Bar and Foo classes
+        # defined.
+        return
+
     module.add_custom_function_wrapper('function_that_takes_foo',
                                        '_wrap_foofunction_that_takes_foo_from_string',
                                        wrapper_body,
diff --git a/tests/footest.py b/tests/footest.py
index a4d2bc4..4706926 100644
--- a/tests/footest.py
+++ b/tests/footest.py
@@ -4,23 +4,40 @@ import weakref
 import gc
 import os.path
 import copy
+import resource
+
 sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 '..', 'build', 'tests'))
 
 which = int(sys.argv[1]) # which version of the tests we are going to test
 del sys.argv[1]
 
+
+# Examine the source file for tests that can't easily be implemented by
+# interacting directly with the code, for example presence of free/delete
+# statements.
+cc_source_file = "foomodule.cc"
+
 if which == 1: # generated from foomodulegen.py (manual)
     import foo
 elif which == 2:
     import foo2 as foo # generated automatically with one-step gccxml-to-C++
+    cc_source_file = "foomodule2.cc"
 elif which == 3:
     import foo3 as foo # generated by gccxml, output to a single defs file, finally generate C++ from that single file
+    cc_source_file = "foomodule3.cc"
 elif which == 4:
     import foo4 as foo # generated by gccxml, output to multiple defs files, then generate C++ from those defs files
+    cc_source_file = "foomodulegen_module2.cc"
 else:
     raise AssertionError("bad command line arguments")
 
+print("mode", which)
+
+cc_name = sys.argv.pop(1)
+cc_version  = sys.argv.pop(1)
+print("compiler command and version:", cc_name, cc_version)
+
 gccxml_mode = sys.argv.pop(1)
 print("gccxml_mode:", gccxml_mode)
 
@@ -170,6 +187,10 @@ class TestFoo(unittest.TestCase):
 
     def test_type_narrowing_hidden_subclass(self):
         """This test only works with GCC >= 3.0 (and not with other compilers)"""
+        if "gcc" not in cc_name:
+            return
+        if int(cc_version) < 3:
+            return
         obj = foo.get_hidden_subclass_pointer()
         self.assertEqual(type(obj), foo.Bar)
 
@@ -957,6 +978,18 @@ class TestFoo(unittest.TestCase):
         rv = test.set_simple_map(container)
         self.assertEqual(rv, sum(range(10)))
 
+    def test_unordered_map_container(self):
+        test = foo.TestContainer()
+        container = test.get_simple_unordered_map()
+        count = 0
+        as_dict = {
+            simple_key: simple_val.xpto
+            for (simple_key, simple_val) in container
+        }
+        assert as_dict == {str(i): i for i in range(10)}
+        rv = test.set_simple_unordered_map(container)
+        self.assertEqual(rv, sum(range(10)))
+
     def test_copy(self):
         s1 = foo.simple_struct_t()
         s1.xpto = 123
@@ -1512,6 +1545,67 @@ class TestFoo(unittest.TestCase):
         while gc.collect():
             pass
 
+    def test_issue21_const_return(self):
+        x = foo.RAReturnConstRef(123)
+        value = x.ReturnMyAStruct()
+        self.assertEqual(value.a, 123)
+
+    def test_free_after_copy_string_examine_code(self):
+        seen_free_comment = False
+        seen_free = False
+        seen_delete_comment = False
+        seen_delete = False
+        file = open(os.path.join("build", "tests", cc_source_file))
+        for i, line in enumerate(file):
+            if  '// free_after_copy for char * return_c_string_to_be_freed()' in line:
+                seen_free_comment = True
+            if seen_free_comment and 'free(retval);' in line:
+                seen_free = True
+            if  '// free_after_copy for char * return_c_string_to_be_freed()' in line:
+                seen_delete_comment = True
+            if seen_delete_comment and 'delete retval;' in line:
+                seen_delete = True
+
+        file.close()
+        self.assertTrue(seen_free)
+        self.assertTrue(seen_delete)
+
+    def test_free_after_copy(self):
+        v = foo.return_c_string_to_be_freed(20)
+        self.assertEqual(v, "testingonly")
+        c = foo.return_class_to_be_freed(20)
+        self.assertEqual(c.value(), "testingonly")
+
+
+    def _runner(self, n, size, fn):
+        while gc.collect():
+            pass
+        before = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
+        for i in range(n):
+           fn(size)
+
+        while gc.collect():
+            pass
+        after = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
+        # maxrss is in kB.
+        return (after - before) * 1024
+
+    @unittest.skip("flaky test")
+    def test_free_after_copy_leak(self):
+        n = 200
+        size = 1024*32
+        # run once to bump up overall maxrss if's going to be bumped up.
+        self._runner(n, size, foo.return_c_string_to_be_freed)
+        diff = self._runner(n, size, foo.return_c_string_to_be_freed)
+        #diff += self._runner(n, size, foo.return_class_to_be_freed)
+        # maxrss should only grow marginally here.
+        self.assertTrue(diff < (size*2))
+
+        leaky = self._runner(n, size, foo.return_c_string_to_not_be_freed)
+        leaky += self._runner(n, size, foo.return_class_to_not_be_freed)
+        # maxrss should have grown significantly
+        self.assertTrue(diff < leaky)
+        self.assertTrue(leaky > size * 10)
 
 
 if __name__ == '__main__':
diff --git a/tests/test.py b/tests/test.py
index 1c83066..7a70834 100644
--- a/tests/test.py
+++ b/tests/test.py
@@ -3,7 +3,7 @@ import pybindgen.typehandlers.base as typehandlers
 from pybindgen.typehandlers import stringtype, ctypeparser
 import pybindgen.typehandlers.codesink as codesink
 from pybindgen import module, cppclass, overloading, utils
-    
+
 
 import unittest
 import doctest
@@ -60,7 +60,7 @@ class ParamLookupTests(unittest.TestCase):
         transformed = typehandlers.Parameter.new('MySmartPointer<testtype>', 'name')
         self.assertTrue(isinstance(transformed, TestParam))
         self.assertTrue(transformed.has_been_transformed)
-        
+
 
 
 if __name__ == '__main__':
@@ -82,6 +82,7 @@ if __name__ == '__main__':
             ]:
             suite.addTest(doctest.DocTestSuite(mod))
 
+    suite.addTest(doctest.DocTestSuite(ctypeparser))
     suite.addTest(unittest.TestLoader().loadTestsFromTestCase(ParamLookupTests))
     runner = unittest.TextTestRunner()
     runner.run(suite)
diff --git a/tox.ini b/tox.ini
index 69a31cc..62c8525 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27,py34,py35,py36
+envlist = py27,py36,py37,py38
 
 [testenv]
 deps=
diff --git a/wscript b/wscript
index 88f3f85..c33d4f9 100644
--- a/wscript
+++ b/wscript
@@ -13,6 +13,8 @@ from waflib import Configure
 
 from waflib import Logs
 
+from waflib.Tools import c_config
+
 import os
 import subprocess
 import shutil
@@ -57,8 +59,8 @@ def zipper(dir, zip_file, archive_main_folder=None):
 
 
 def options(opt):
-    opt.load('python_patched', tooldir="waf-tools")
-    opt.load('compiler_cc')
+    opt.load('python')
+    opt.load('compiler_c')
     opt.load('compiler_cxx')
     opt.load('cflags', tooldir="waf-tools")
     opt.recurse('examples')
@@ -120,8 +122,9 @@ def _check_compilation_flag(conf, flag, mode='cxx', linkflags=None):
         env.append_value("LINKFLAGS", linkflags)
 
     try:
-        retval = conf.run_c_code(code='#include <stdio.h>\nint main() { return 0; }\n',
+        retval = conf.run_build(code='#include <stdio.h>\nint main() { return 0; }\n',
                                  env=env, compile_filename=fname,
+                                 build_fun=c_config.build_fun,
                                  features=[mode, mode+'program'], execute=False)
     except conf.errors.ConfigurationError:
         ok = False
@@ -141,29 +144,45 @@ def _check_nonfatal(conf, *args, **kwargs):
         return None
 
 
+# treat -iwithsysroot as if it were -I
+def extract_withsysroot_includes(lst):
+    inc = []
+    while lst:
+        x = lst.pop(0)
+        if x.startswith(('-iwithsysroot')):
+            dir = lst.pop(0)
+            if os.path.isdir(dir):
+                inc.append(dir)
+    return inc
+
 def configure(conf):
 
     conf.check_compilation_flag = types.MethodType(_check_compilation_flag, conf)
     conf.check_nonfatal = types.MethodType(_check_nonfatal, conf)
 
     conf.load('command', tooldir="waf-tools")
-    conf.load('python_patched', tooldir="waf-tools")
+    conf.load('python')
     conf.check_python_version((2,3))
 
+    # this causes pybindgen/version.py to be generated by setuptools_scm
+    subprocess.Popen(
+        [conf.env["PYTHON"][0], "setup.py", "--help-commands"],
+        stdout=getattr(subprocess, "DEVNULL", None),
+    ).wait()
+
     try:
-        conf.load('compiler_cc')
+        conf.load('compiler_c')
         conf.load('compiler_cxx')
     except conf.errors.ConfigurationError:
         Logs.warn("C/C++ compiler not detected.  Unit tests and examples will not be compiled.")
         conf.env['CXX'] = ''
     else:
         conf.load('cflags')
-        conf.check_python_headers()
+        conf.check_python_headers(features='pyembed pyext')
 
         if not Options.options.disable_pygccxml:
             castxml = conf.find_program('castxml', mandatory=False)
-            gccxml = conf.find_program('gccxml', mandatory=False)
-            if not (gccxml or castxml):
+            if not castxml:
                 conf.env['ENABLE_PYGCCXML'] = False
             else:
                 try:
@@ -174,8 +193,12 @@ def configure(conf):
                     conf.env['ENABLE_PYGCCXML'] = True
                     if castxml:
                         conf.env['PYGCCXML_MODE'] = 'castxml'
-                    else:
-                        conf.env['PYGCCXML_MODE'] = 'gccxml'
+
+                if conf.env['ENABLE_PYGCCXML']:
+                    try:
+                        conf.check_python_module('cxxfilt')
+                    except conf.errors.ConfigurationError:
+                        conf.env['ENABLE_PYGCCXML'] = False
 
         # -fvisibility=hidden optimization
         if (conf.env['CXX_NAME'] == 'gcc' and [int(x) for x in conf.env['CC_VERSION']] >= [4,0,0]
@@ -183,12 +206,37 @@ def configure(conf):
             conf.env.append_value('CXXFLAGS_PYEXT', '-fvisibility=hidden')
             conf.env.append_value('CCFLAGS_PYEXT', '-fvisibility=hidden')
 
+        # use -std=c++11 for gcc version < 7 (for unordered_map support)
+        if (conf.env['CXX_NAME'] == 'gcc' and [int(x) for x in conf.env['CC_VERSION']] < [7,0,0]):
+            conf.env.append_value('CXXFLAGS', '-std=c++11')
+
         # Add include path for our stdint.h replacement, if needed (pstdint.h)
         if not conf.check_nonfatal(header_name='stdint.h'):
             conf.env.append_value('CPPPATH', os.path.join(conf.curdir, 'include'))
 
-    if conf.check_nonfatal(header_name='boost/shared_ptr.hpp'):
+        if "INCLUDES_PYEXT" not in conf.env:
+            # On macos catalina there are no -I's in the system python2.7-config
+            # output, so extract them from CFLAGS and make sure that Python.h
+            # can be located.
+            conf.env["INCLUDES_PYEXT"] = extract_withsysroot_includes(conf.env["CFLAGS_PYEXT"])
+            conf.check_nonfatal(header_name='Python.h')
+
+    conf.env.stash()
+    try:
+        # Make sure that boost is available when compiling an extension
+        # rather than just natively.
+        conf.env.append_value("CXXFLAGS", conf.env["CXXFLAGS_PYEXT"])
+        conf.env.append_value("INCLUDES", conf.env["INCLUDES_PYEXT"])
+        have_boost_extension = conf.check_nonfatal(header_name='boost/shared_ptr.hpp')
+    finally:
+        conf.env.revert()
+
+    if have_boost_extension:
         conf.env['ENABLE_BOOST_SHARED_PTR'] = True
+    else:
+        Logs.warn("Boost is not available as a python extension, trying native compilation.")
+        if conf.check_nonfatal(header_name='boost/shared_ptr.hpp'):
+            Logs.warn("Boost is, however, available natively. The python extension configuration is most likely using --sysroot")
 
     conf.recurse('benchmarks')
     conf.recurse('examples')
@@ -242,7 +290,6 @@ class CheckContext(Context.Context):
         bld.cmd = "check"
         bld.execute()
 
-
         if Options.options.verbose:
             verbosity = ['-v']
         else:
@@ -253,6 +300,11 @@ class CheckContext(Context.Context):
         else:
             valgrind = []
 
+        # Pass compiler name and version to some of the tests so that they
+        # test compiler specific features.
+        cc_name = bld.env['CC_NAME']
+        cc_version =  bld.env['CC_VERSION'][0]
+
         print("Running pure python unit tests...")
         python = bld.env['PYTHON'][0]
         retval1 = subprocess.Popen([python, 'tests/test.py'] + verbosity).wait()
@@ -263,19 +315,19 @@ class CheckContext(Context.Context):
 
         if env['CXX']:
             print("Running manual module generation unit tests (module foo)...")
-            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '1', 'none'] + verbosity).wait())
+            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '1', cc_name, cc_version, 'none'] + verbosity).wait())
         else:
             print("Skipping manual module generation unit tests (no C/C++ compiler)...")
 
         if env['ENABLE_PYGCCXML']:
             print("Running automatically scanned module generation unit tests (module foo2)...")
-            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '2', env['PYGCCXML_MODE']] + verbosity).wait())
+            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '2', cc_name, cc_version, env['PYGCCXML_MODE']] + verbosity).wait())
 
             print("Running module generated by automatically generated python script unit tests (module foo3)...")
-            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '3', env['PYGCCXML_MODE']] + verbosity).wait())
+            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '3', cc_name, cc_version, env['PYGCCXML_MODE']] + verbosity).wait())
 
             print("Running module generated by generated and split python script unit tests  (module foo4)...")
-            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '4', env['PYGCCXML_MODE']] + verbosity).wait())
+            retvals.append(subprocess.Popen(valgrind + [python, 'tests/footest.py', '4', cc_name, cc_version, env['PYGCCXML_MODE']] + verbosity).wait())
 
             print("Running semi-automatically scanned c-hello module ('hello')...")
             retvals.append(subprocess.Popen(valgrind + [python, 'tests/c-hello/hellotest.py'] + verbosity).wait())

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/PyBindGen-0.22.1.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/PyBindGen-0.22.1.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/PyBindGen-0.22.1.egg-info/top_level.txt
-rw-r--r--  root/root   /usr/share/doc/python-pybindgen-doc/html/_sources/castxmlparser.rst.txt
-rw-r--r--  root/root   /usr/share/doc/python-pybindgen-doc/html/castxmlparser.html

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/PyBindGen-0.20.0.egg-info/PKG-INFO
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/PyBindGen-0.20.0.egg-info/dependency_links.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/PyBindGen-0.20.0.egg-info/top_level.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/pybindgen/gccxmlparser.py
-rw-r--r--  root/root   /usr/share/doc/python-pybindgen-doc/html/_sources/gccxmlparser.rst.txt
-rw-r--r--  root/root   /usr/share/doc/python-pybindgen-doc/html/gccxmlparser.html
lrwxrwxrwx  root/root   /usr/share/doc/python-pybindgen-doc/html/_static/_sphinx_javascript_frameworks_compat.js -> ../../../../javascript/sphinxdoc/1.0/_sphinx_javascript_frameworks_compat.js

Control files of package python-pybindgen-doc: lines which differ (wdiff format)

  • Depends: libjs-sphinxdoc (>= 5.0) 4.3)

No differences were encountered between the control files of package python3-pybindgen

More details

Full run details