#!/usr/bin/env python ############################################################################# # Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1997, 1998, 1999 # All Rights Reserved. # # The software contained on this media is the property of the DSTC Pty # Ltd. Use of this software is strictly in accordance with the # license agreement in the accompanying LICENSE.HTML file. If your # distribution of this software does not contain a LICENSE.HTML file # then you have no rights to use this software in any manner and # should contact DSTC at the address below to determine an appropriate # licensing arrangement. # # DSTC Pty Ltd # Level 7, GP South # Staff House Road # University of Queensland # St Lucia, 4072 # Australia # Tel: +61 7 3365 4310 # Fax: +61 7 3365 4311 # Email: enquiries@dstc.edu.au # # This software is being provided "AS IS" without warranty of any # kind. In no event shall DSTC Pty Ltd be liable for damage of any # kind arising out of or in connection with the use or performance of # this software. # # Project: Fnorb # File: $Source: /cvsroot/fnorb/fnorb/compiler/StubGenerator.py,v $ # Version: @(#)$RCSfile: StubGenerator.py,v $ $Revision: 1.14 $ # ############################################################################# """ Python stub generator for CORBA IDL. """ # Standard/built-in modules. import string # Fnorb modules. from Fnorb.orb import CORBA, Util # Compiler modules. import CodeGenerator class StubGenerator(CodeGenerator.CodeGenerator): """ Python stub generator for CORBA IDL. """ ######################################################################### # CodeGenerator protected interface. ######################################################################### def _generate_attribute(self, context, file, ifr_object, indent): """ Generate Python code for an IDL attribute. """ # Get the description of the attribute. description = ifr_object.describe() attribute_desc = description.value.value() ##################################################################### # Accessor. ##################################################################### # Method header. file.write(self._indent(indent)) file.write('def _get_%s(self):\n' % attribute_desc.name) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Attribute: %s """\n\n' % attribute_desc.id) # Create the output typecode. file.write(self._indent(indent)) file.write('# Typecode for the attribute value.\n') file.write(self._indent(indent)) file.write('outputs = []\n') file.write(self._indent(indent)) file.write('outputs.append(') file.write(self._get_typecode(attribute_desc.type)) file.write(')\n\n') # Boiler plate. file.write(self._indent(indent)) file.write('# Create a request object.\n') file.write(self._indent(indent)) file.write('request = self._create_request(') file.write('"_get_%s", ' % attribute_desc.name) file.write('[], outputs, [])\n\n') file.write(self._indent(indent)) file.write('# Make the request!\n') file.write(self._indent(indent)) file.write('request.invoke()\n\n') file.write(self._indent(indent)) file.write('# Return the attribute value.\n') file.write(self._indent(indent)) file.write('return request.results()\n\n') # Outdent. indent = indent - 1 ##################################################################### # Modifier (unless the attribute is read only ;^). ##################################################################### if attribute_desc.mode != CORBA.ATTR_READONLY: # Method header. file.write(self._indent(indent)) file.write('def _set_%s(self, _value):\n' % attribute_desc.name) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Attribute: %s """\n\n' % attribute_desc.id) # Create the input typecodes. file.write(self._indent(indent)) file.write("# Typecode for the attribute value.\n") file.write(self._indent(indent)) file.write('inputs = []\n') file.write(self._indent(indent)) file.write('inputs.append(') file.write(self._get_typecode(attribute_desc.type)) file.write(')\n\n') # Boiler plate. file.write(self._indent(indent)) file.write('# Create a request object.\n') file.write(self._indent(indent)) file.write('request = self._create_request(') file.write('"_set_%s", ' % attribute_desc.name) file.write('inputs, [], [])\n\n') file.write(self._indent(indent)) file.write('# Make the request!\n') file.write(self._indent(indent)) file.write('request.invoke(_value)\n\n') file.write(self._indent(indent)) file.write('return\n\n') return def _generate_constant(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL constant. """ # Get the description of the constant. description = ifr_object.describe() const_desc = description.value.value() # Make sure that the constant name is not a Python keyword. py_const_name = Util.python_name(const_desc.name) # Repository id comment. file.write(self._indent(indent)) file.write('# Constant: %s\n' % const_desc.id) # Create and initialise a corresponding Python variable. file.write(self._indent(indent)) file.write('%s = %s' % (py_const_name, repr(const_desc.value.value()))) file.write('\n\n') # Get the constant's typecode. typecode = const_desc.type # Add a typecode constant to the stub. self._write_typecode_constant(file, indent, const_desc.id, typecode, py_const_name) return def _generate_exception(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL exception. """ # Get the description of the exception. description = ifr_object.describe() exception_desc = description.value.value() # Make sure that the structure name is not a Python keyword. py_exception_name = Util.python_name(exception_desc.name) # Get the members of the exception. members = ifr_object._get_members() # Class header (inheriting from CORBA.UserException). file.write(self._indent(indent)) file.write('class %s(Fnorb.orb.CORBA.UserException):\n' \ % py_exception_name) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Exception: %s """\n\n' % exception_desc.id) # Repository id attribute. file.write(self._indent(indent)) file.write('_FNORB_ID = "%s"\n\n' % exception_desc.id) # Create a constructor parameter for every member of the exception. parameters = ['self'] for member in members: parameters.append('_' + member.name) # Method header for the constructor. file.write(self._indent(indent)) file.write('def __init__(%s):\n' % string.join(parameters, ', ')) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Constructor. """\n\n') # Initialise every member of the exception in the constructor body. for member in members: # Make sure that the member name is not a Python keyword. py_member_name = Util.python_name(member.name) file.write(self._indent(indent)) file.write("self.%s = _%s\n" % (py_member_name, member.name)) # Return statement. file.write(self._indent(indent)) file.write('return\n\n') # Outdent. indent = indent - 1 # Create the __getinitargs__ method. if len(members) > 0: # Method header. file.write(self._indent(indent)) file.write('def __getinitargs__(self):\n') # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" ') file.write('Return the constructor arguments for unpickling.') file.write(' """\n\n') # Special case for the singleton tuple ;^) if len(members) == 1: # Make sure that the member name is not a Python keyword. py_member_name = Util.python_name(members[0].name) file.write(self._indent(indent)) file.write('return (self.%s,)\n\n' % py_member_name) else: results = [] for member in members: # Make sure that the member name is not a Python keyword. py_member_name = Util.python_name(member.name) results.append('self.%s' % py_member_name) file.write(self._indent(indent)) file.write('return (%s)\n\n' % string.join(results, ', ')) # Outdent. indent = indent - 1 # Outdent. indent = indent - 1 # Get the exceptions's typecode. typecode = ifr_object._get_type() # Add a typecode constant to the stub. self._write_typecode_constant(file, indent, exception_desc.id, typecode, py_exception_name) return def _generate_interface(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL interface. """ # Get the description of the interface. description = ifr_object.describe() interface_desc = description.value.value() # Make sure that the interface name is not a Python keyword. py_interface_name = Util.python_name(interface_desc.name) # Get the scoped name of the interface. interface_scoped_name =Util.ScopedName(ifr_object._get_absolute_name()) # Fix up any clashes with Python keywords. interface_scoped_name.pythonise() # Base interfaces. bases = ['Fnorb.orb.CORBA.Object'] packages = [] for base in ifr_object._get_base_interfaces(): # Get the scoped name of the base interface. base_scoped_name = Util.ScopedName(base._get_absolute_name()) # Fix up any clashes with Python keywords. base_scoped_name.pythonise() # If the base interface is defined in a different IDL module (ie. # in a different Python package). if base_scoped_name[:-1] != interface_scoped_name[:-1]: # If the base interface is defined at the global scope then # add the name of the global package. if len(base_scoped_name) == 1: base_scoped_name.insert(0, context.globals()) # Use the full scoped name in the Python class header. base_python_name = base_scoped_name.join('.') # Add the Python package that the base interface is defined in # to the list of packages to import. packages.append(base_scoped_name[:-1].join('.')) # Otherwise, the base interface is defined in the same IDL module # as the interface itself, so we just use the base interface name # in the Python class header. else: base_python_name = base_scoped_name[-1] # Add to the list of base classes for the class header. bases.append(base_python_name) # Import base interface packages. if len(packages) > 0: file.write(self._indent(indent)) file.write('# Import base interface packages.\n') for package in packages: file.write(self._indent(indent)) file.write(context.create_import_statement(package)) file.write('\n') file.write('\n') # Class header. file.write(self._indent(indent)) file.write('class %s' % py_interface_name) file.write('(%s):\n' % string.join(bases, ', ')) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Interface: %s """\n\n' % interface_desc.id) # Repository id attribute. file.write(self._indent(indent)) file.write('_FNORB_ID = "%s"\n\n' % interface_desc.id) # Generate code for every definition contained in the interface # (ignoring inherited definitions). contents = ifr_object.contents(CORBA.dk_all, 1) if len(contents) > 0: for contained in contents: self.generate(context, file, contained, indent) # Empty interface. else: file.write(self._indent(indent)) file.write('pass\n\n') # Outdent. indent = indent - 1 # Get the interface's typecode. typecode = ifr_object._get_type() # Add a typecode constant to the stub. self._write_typecode_constant(file, indent, interface_desc.id, typecode, py_interface_name) return def _generate_module(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL module. """ # Get the description of the module. description = ifr_object.describe() module_desc = description.value.value() # Get the scoped name of the module. package = Util.ScopedName(ifr_object._get_absolute_name()) # Fix up any clashes with Python keywords. package.pythonise() # Create a Python package to represent the IDL module. file = self._create_package(context, package.join('/'), module_desc.id) # Generate code for every definition contained in the module. for contained in ifr_object.contents(CORBA.dk_all, 0): self.generate(context, file, contained, 0) # End of the package. self._end_package(file, indent) # All done! file.close() return def _generate_operation(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL operation. """ # Get the description of the operation. description = ifr_object.describe() operation_desc = description.value.value() # Make sure that the operation name is not a Python keyword. py_operation_name = Util.python_name(operation_desc.name) # Method header. file.write(self._indent(indent)) file.write('def %s(self, *args, **kw):\n' % py_operation_name) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Operation: %s """\n\n' % operation_desc.id) # Create the input typecodes. file.write(self._indent(indent)) file.write("# Typecodes for 'in' and 'inout' parameters.\n") file.write(self._indent(indent)) file.write('inputs = []\n') for p in operation_desc.parameters: if p.mode == CORBA.PARAM_IN or p.mode == CORBA.PARAM_INOUT: file.write(self._indent(indent)) file.write('inputs.append(%s)' % self._get_typecode(p.type)) file.write('\n') file.write('\n') # Create the output typecodes. file.write(self._indent(indent)) file.write("# Typecodes for the result, 'inout' and 'out' parameters.") file.write('\n') file.write(self._indent(indent)) file.write('outputs = []\n') # The result. if operation_desc.result.kind() != CORBA.tk_void: file.write(self._indent(indent)) file.write('outputs.append(') file.write(self._get_typecode(operation_desc.result)) file.write(')\n') # 'inout' and 'out' parameters. for p in operation_desc.parameters: if p.mode == CORBA.PARAM_INOUT or p.mode == CORBA.PARAM_OUT: file.write(self._indent(indent)) file.write('outputs.append(%s)' % self._get_typecode(p.type)) file.write('\n') file.write('\n') # Create the exception typecodes. file.write(self._indent(indent)) file.write("# Typecodes for user exceptions.\n") file.write(self._indent(indent)) file.write('exceptions = []\n') for ex in operation_desc.exceptions: file.write(self._indent(indent)) file.write('exceptions.append(Fnorb.orb.CORBA.typecode("%s"))\n' \ % ex.id) file.write('\n') # Boiler plate. file.write(self._indent(indent)) file.write('# Create a request object.\n') file.write(self._indent(indent)) file.write('request = self._create_request("') file.write(operation_desc.name) file.write('", inputs, outputs, exceptions)\n\n') file.write(self._indent(indent)) file.write('# Make the request!\n') if operation_desc.mode == CORBA.OP_ONEWAY: file.write(self._indent(indent)) file.write('apply(request.invoke_oneway, args, kw)\n\n') file.write(self._indent(indent)) file.write('return\n\n') else: file.write(self._indent(indent)) file.write('apply(request.invoke, args, kw)\n\n') file.write(self._indent(indent)) file.write('# Return the results.\n') file.write(self._indent(indent)) file.write('return request.results()\n\n') return def _generate_struct(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL structure. """ # Get the description of the structure. description = ifr_object.describe() struct_desc = description.value.value() # Make sure that the structure name is not a Python keyword. py_struct_name = Util.python_name(struct_desc.name) # Get the members of the structure. members = ifr_object._get_members() # Class header. file.write(self._indent(indent)) file.write('class %s:\n' % py_struct_name) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Struct: %s """\n\n' % struct_desc.id) # Repository id attribute. file.write(self._indent(indent)) file.write('_FNORB_ID = "%s"\n\n' % struct_desc.id) # Generate code for every structure definition contained in # the structure contents = ifr_object.contents(CORBA.dk_Struct, 1) for contained in contents: self.generate(context, file, contained, indent) # Generate code for every union definition contained in # the structure contents = ifr_object.contents(CORBA.dk_Union, 1) for contained in contents: self.generate(context, file, contained, indent) # Create a constructor parameter for every member of the structure. parameters = ['self'] for member in members: parameters.append('_' + member.name) # Method header for the constructor. file.write(self._indent(indent)) file.write('def __init__(%s):\n' % string.join(parameters, ', ')) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Constructor. """\n\n') # Initialise every member of the structure in the constructor body. for member in members: # Make sure that the member name is not a Python keyword. py_member_name = Util.python_name(member.name) file.write(self._indent(indent)) file.write("self.%s = _%s\n" % (py_member_name, member.name)) # Return statement. file.write(self._indent(indent)) file.write('return\n\n') # Outdent. indent = indent - 1 # Create the __getinitargs__ method. if len(members) > 0: # Method header. file.write(self._indent(indent)) file.write('def __getinitargs__(self):\n') # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" ') file.write('Return the constructor arguments for unpickling.') file.write(' """\n\n') # Special case for the singleton tuple ;^) if len(members) == 1: # Make sure that the member name is not a Python keyword. py_member_name = Util.python_name(members[0].name) file.write(self._indent(indent)) file.write('return (self.%s,)\n\n' % py_member_name) else: results = [] for member in members: # Make sure that the member name is not a Python keyword. py_member_name = Util.python_name(member.name) results.append('self.%s' % py_member_name) file.write(self._indent(indent)) file.write('return (%s)\n\n' % string.join(results, ', ')) # Outdent. indent = indent - 1 # Outdent. indent = indent - 1 # Get the structure's typecode. typecode = ifr_object._get_type() # Add a typecode constant to the stub. self._write_typecode_constant(file, indent, struct_desc.id, typecode, py_struct_name) return def _generate_union(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL union. """ # Get the description of the structure. description = ifr_object.describe() union_desc = description.value.value() # Make sure that the union name is not a Python keyword. py_union_name = Util.python_name(union_desc.name) # Class header. file.write(self._indent(indent)) file.write('class %s(Fnorb.orb.Util.Union):\n' % py_union_name) # Indent. indent = indent + 1 # Documentation string. file.write(self._indent(indent)) file.write('""" Union: %s """\n\n' % union_desc.id) # Repository id attribute. file.write(self._indent(indent)) file.write('_FNORB_ID = "%s"\n\n' % union_desc.id) # Generate code for every structure definition contained in # the union contents = ifr_object.contents(CORBA.dk_Struct, 1) for contained in contents: self.generate(context, file, contained, indent) # Generate code for every union definition contained in # the union contents = ifr_object.contents(CORBA.dk_Union, 1) for contained in contents: self.generate(context, file, contained, indent) file.write(self._indent(indent)) file.write('pass\n\n') # Outdent. indent = indent - 1 # Get the unions's typecode. typecode = ifr_object._get_type() # Add a typecode constant to the stub. self._write_typecode_constant(file, indent, union_desc.id, typecode, py_union_name) return def _generate_enum(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL enumeration. """ # Get the description of the enumeration. description = ifr_object.describe() enum_desc = description.value.value() # Make sure that the enumeration name is not a Python keyword. py_enum_name = Util.python_name(enum_desc.name) # Get the members of the enumeration. members = ifr_object._get_members() # Repository id comment. file.write(self._indent(indent)) file.write('# Enum: %s\n' % enum_desc.id) # Create an Util.EnumMember instance for every member of the # enumeration. i = 0 for member in members: # Make sure that the member name is not a Python keyword. py_member_name = Util.python_name(member) file.write(self._indent(indent)) file.write('%s = ' % py_member_name) file.write('Fnorb.orb.Util.EnumMember("%s", %d)\n' % (member, i)) i = i + 1 # Use the enumeration name to create an instance of the 'Util.Enum' # class to emulate a list containing all of the enumeration members. file.write(self._indent(indent)) py_member_names = string.join(map(Util.python_name, members), ', ') file.write('%s = Fnorb.orb.Util.Enum("%s", [%s])\n\n' \ % (py_enum_name, enum_desc.id, py_member_names)) # Get the enum's typecode. typecode = ifr_object._get_type() # Add a typecode constant to the stub. self._write_typecode_constant(file, indent, enum_desc.id, typecode, py_enum_name) return def _generate_alias(self, context, file, ifr_object, indent): """ Generate Python code to represent an IDL alias. """ # Get the description of the alias. description = ifr_object.describe() alias_desc = description.value.value() # Repository id comment. file.write(self._indent(indent)) file.write('# Alias: %s\n' % alias_desc.id) # 'Unwind' the alias until we find a 'real' definition! type_def = ifr_object._get_original_type_def() while type_def._get_def_kind() == CORBA.dk_Alias: type_def = type_def._get_original_type_def() # Get the 'real' typecode. typecode = type_def._get_type() # Add a typecode constant to the stub. self._write_typecode_constant(file, indent, alias_desc.id, typecode, 'None') if type_def._get_def_kind() == CORBA.dk_Fixed: digits = type_def._get_digits() scale = type_def._get_scale() fixed_name = Util.python_name(alias_desc.name) file.write(self._indent(indent)) file.write('class %s(Fnorb.orb.CORBA.fixed):\n' % fixed_name) indent = indent + 1 file.write(self._indent(indent)) file.write('def __init__(self, value):\n') indent = indent + 1 file.write(self._indent(indent)) file.write('Fnorb.orb.CORBA.fixed.__init__(self, %d, %d, value)\n\n' % (digits, scale)) indent = indent - 1 indent = indent - 1 return #############################################################################