[C++-sig] pyste suggestion: easier overriding of exporters

scott snyder snyder at fnal.gov
Tue Oct 14 04:44:02 CEST 2003


hi -

In the course of playing with pyste, i've made numerous minor
fixes and extensions.  In such cases, i'd like to be able to keep
my new code in the .pyste file (or something imported from there)
rather than having to change the pyste code itself.

One way of extending pyste is to use one's own Exporter classes.
In most cases, these can derive from the existing ones, modifying
any needed behaviors.

There is, however, no clean way to specify in a .pyste file that you
want to use a custom exporter class.  In the past, i've done this
by duplicating the classes that derive from DeclarationInfo and
changing the Exporter class, i.e., doing something like this:

class Class (DeclarationInfo):
    def __init__(self, name, include, tail=None, otherInfo=None):
        DeclarationInfo.__init__(self, otherInfo)
        self._Attribute('name', name)
        self._Attribute('include', include)
        self._Attribute('exclude', False)
        # create a ClassExporter
        exporter = My_Class_Exporter(InfoWrapper(self), tail)
        exporters.exporters.append(exporter)
        exporter.interface_file = exporters.current_interface

and then importing this into the pyste file.

This is not entirely satisfactory, due to the pyste code that must
be duplicated here.  One also runs into a problem with ClassExporter,
as its ExportNestedClasses method also has a reference to
`ClassExporter' literally coded.

I would suggest allowing for such extensions by adding an (optional)
argument to the constructors of the info classes giving the class
to use for the exporter.  Thus, if someone wants to use a non-standard
exporter for a particular declaration, it can just be specified
in the Class() or whatever call.  Then if i want all classes to use
my custom exporter, i can do something like this:

def Class (name, include, tail=None, otherInfo=None):
    return ClassInfo (name, include, tail, otherInfo,
                      exporter_class = My_Class_Exporter)

avoiding having to duplicate the code from ClassInfo.

The patches below implement this.
I added an optional parameter `exporter_class' to the info class
constructors, giving the class to use for the exporter.  I also
modified ClassExporter.ExportNestedClasses to create the nested
class exporters using the same class as the current exporter,
rather than hardwiring in ClassExporter.

sss



Index: ClassExporter.py
===================================================================
RCS file: /cvsroot/boost/boost/libs/python/pyste/src/Pyste/ClassExporter.py,v
retrieving revision 1.14
diff -u -p -r1.14 ClassExporter.py
--- ClassExporter.py	6 Oct 2003 19:10:50 -0000	1.14
+++ ClassExporter.py	13 Oct 2003 18:29:32 -0000
@@ -598,7 +600,7 @@ class ClassExporter(Exporter):
             nested_info = self.info[nested_class.name]
             nested_info.include = self.info.include
             nested_info.name = nested_class.FullName()
-            exporter = ClassExporter(nested_info)
+            exporter = self.__class__(nested_info)
             exporter.SetDeclarations(self.declarations)
             codeunit = SingleCodeUnit(None, None)
             exporter.Export(codeunit, exported_names)
Index: infos.py
===================================================================
RCS file: /cvsroot/boost/boost/libs/python/pyste/src/Pyste/infos.py,v
retrieving revision 1.9
diff -u -p -r1.9 infos.py
--- infos.py	6 Oct 2003 19:10:50 -0000	1.9
+++ infos.py	13 Oct 2003 18:29:32 -0000
@@ -56,13 +56,14 @@ class DeclarationInfo:
 #==============================================================================
 class FunctionInfo(DeclarationInfo):
 
-    def __init__(self, name, include, tail=None, otherOption=None):        
+    def __init__(self, name, include, tail=None, otherOption=None,
+                 exporter_class = FunctionExporter):        
         DeclarationInfo.__init__(self, otherOption)
         self._Attribute('name', name)
         self._Attribute('include', include)
         self._Attribute('exclude', False)
         # create a FunctionExporter
-        exporter = FunctionExporter(InfoWrapper(self), tail)
+        exporter = exporter_class(InfoWrapper(self), tail)
         if exporter not in exporters.exporters:
             exporters.exporters.append(exporter)
         exporter.interface_file = exporters.current_interface
@@ -73,13 +74,14 @@ class FunctionInfo(DeclarationInfo):
 #==============================================================================
 class ClassInfo(DeclarationInfo):
 
-    def __init__(self, name, include, tail=None, otherInfo=None):
+    def __init__(self, name, include, tail=None, otherInfo=None,
+                 exporter_class = ClassExporter):
         DeclarationInfo.__init__(self, otherInfo)
         self._Attribute('name', name)
         self._Attribute('include', include)
         self._Attribute('exclude', False)
         # create a ClassExporter
-        exporter = ClassExporter(InfoWrapper(self), tail)
+        exporter = exporter_class(InfoWrapper(self), tail)
         if exporter not in exporters.exporters: 
             exporters.exporters.append(exporter) 
         exporter.interface_file = exporters.current_interface 
@@ -96,10 +98,12 @@ def GenerateName(name, type_list):
     
 class ClassTemplateInfo(DeclarationInfo):
 
-    def __init__(self, name, include):
+    def __init__(self, name, include,
+                 exporter_class = ClassExporter):
         DeclarationInfo.__init__(self)
         self._Attribute('name', name)
         self._Attribute('include', include)
+        self._exporter_class = exporter_class
 
 
     def Instantiate(self, type_list, rename=None):
@@ -111,7 +115,8 @@ class ClassTemplateInfo(DeclarationInfo)
         tail += 'void __instantiate_%s()\n' % rename
         tail += '{ sizeof(%s); }\n\n' % rename
         # create a ClassInfo
-        class_ = ClassInfo(rename, self._Attribute('include'), tail, self)
+        class_ = ClassInfo(rename, self._Attribute('include'), tail, self,
+                           exporter_class = self._exporter_class)
         return class_
 
 
@@ -125,13 +130,13 @@ class ClassTemplateInfo(DeclarationInfo)
 #==============================================================================
 class EnumInfo(DeclarationInfo):
     
-    def __init__(self, name, include):
+    def __init__(self, name, include, exporter_class = EnumExporter):
         DeclarationInfo.__init__(self)
         self._Attribute('name', name)
         self._Attribute('include', include)
         self._Attribute('exclude', False)
         self._Attribute('export_values', False)
-        exporter = EnumExporter(InfoWrapper(self))
+        exporter = exporter_class(InfoWrapper(self))
         if exporter not in exporters.exporters: 
             exporters.exporters.append(exporter)
         exporter.interface_file = exporters.current_interface 
@@ -142,10 +147,10 @@ class EnumInfo(DeclarationInfo):
 #==============================================================================
 class HeaderInfo(DeclarationInfo):
 
-    def __init__(self, include):
+    def __init__(self, include, exporter_class = HeaderExporter):
         DeclarationInfo.__init__(self)
         self._Attribute('include', include)
-        exporter = HeaderExporter(InfoWrapper(self))
+        exporter = exporter_class(InfoWrapper(self))
         if exporter not in exporters.exporters: 
             exporters.exporters.append(exporter)
         exporter.interface_file = exporters.current_interface 
@@ -156,11 +161,11 @@ class HeaderInfo(DeclarationInfo):
 #==============================================================================
 class VarInfo(DeclarationInfo):
     
-    def __init__(self, name, include):
+    def __init__(self, name, include, exporter_class = VarExporter):
         DeclarationInfo.__init__(self)
         self._Attribute('name', name)
         self._Attribute('include', include)
-        exporter = VarExporter(InfoWrapper(self))
+        exporter = exporter_class(InfoWrapper(self))
         if exporter not in exporters.exporters: 
             exporters.exporters.append(exporter)
         exporter.interface_file = exporters.current_interface 
@@ -171,11 +176,11 @@ class VarInfo(DeclarationInfo):
 #==============================================================================
 class CodeInfo(DeclarationInfo):
 
-    def __init__(self, code, section):
+    def __init__(self, code, section, exporter_class = CodeExporter):
         DeclarationInfo.__init__(self)
         self._Attribute('code', code)
         self._Attribute('section', section)
-        exporter = CodeExporter(InfoWrapper(self))
+        exporter = exporter_class(InfoWrapper(self))
         if exporter not in exporters.exporters:
             exporters.exporters.append(exporter)
         exporter.interface_file = exporters.current_interface




More information about the Cplusplus-sig mailing list