# -*- python -*-
#                           Package   : omniidl
# python.py                 Created on: 1999/10/29
#			    Author    : Duncan Grisby (dpg1)
#
#    Copyright (C) 2002-2015 Apasphere Ltd
#    Copyright (C) 1999 AT&T Laboratories Cambridge
#
#  This file is part of omniidl.
#
#  omniidl is free software; you can redistribute it and/or modify it
#  under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see http://www.gnu.org/licenses/
#
# Description:
#   
#   Back-end for Python

"""omniORB Python bindings"""

from omniidl import idlast, idltype, idlutil, idlvisitor, output, main
import sys, os.path, keyword

cpp_args = ["-D__OMNIIDL_PYTHON__"]
usage_string = """\
  -Wbstdout       Send generated stubs to stdout rather than a file
  -Wbinline       Output stubs for #included files in line with the main file
  -Wbfactories    Register value factories for all valuetypes
  -Wbpackage=p    Put both Python modules and stub files in package p
  -Wbmodules=p    Put Python modules in package p
  -Wbstubs=p      Put stub files in package p
  -Wbextern=f:p   Assume Python stub file for file f is in package p.
  -Wbglobal=g     Module to use for global IDL scope (default _GlobalIDL)
  -Wbami          Generate code for AMI"""

#""" Uncomment this line to get syntax highlighting on the output strings

# Output strings

pymodule_template = """\
# DO NOT EDIT THIS FILE!
#
# Python module @module@ generated by omniidl

import omniORB
omniORB.updateModule("@package@@module@")

# ** 1. Stub files contributing to this module

# ** 2. Sub-modules

# ** 3. End"""

file_start = """\
# Python stubs generated by omniidl from @filename@
# DO NOT EDIT THIS FILE!

import omniORB, _omnipy
from omniORB import CORBA, PortableServer
_0_CORBA = CORBA
@ami_import@

_omnipy.checkVersion(4,2, __file__, 1)

try:
    property
except NameError:
    def property(*args):
        return None
"""

file_end = """\
_exported_modules = ( @export_string@)

# The end."""

module_start = """
#
# Start of module "@sname@"
#
__name__ = "@package@@sname@"
_0_@sname@ = omniORB.openModule("@package@@sname@", r"@filename@")
_0_@s_sname@ = omniORB.openModule("@package@@s_sname@", r"@filename@")
"""

module_end = """
#
# End of module "@sname@"
#
__name__ = "@package@@modname@"
"""

import_idl_file = """
# #include "@idlfile@"
import @ifilename@"""

open_imported_module_name = """\
_0_@imodname@ = omniORB.openModule("@package@@imodname@")
_0_@s_imodname@ = omniORB.openModule("@package@@s_imodname@")"""

forward_interface = """\

# forward @abstract@interface @ifid@;
_0_@modname@._d_@ifid@ = (omniORB.tcInternal.@tvkind@, "@repoId@", "@ifid@")
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@ifid@"""


interface_class = """\

# @abstract@interface @ifid@
_0_@modname@._d_@ifid@ = (omniORB.tcInternal.@tvkind@, "@repoId@", "@ifid@")
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@ifid@
_0_@modname@.@ifid@ = omniORB.newEmptyClass()
class @ifid@ @inherits@:
    _NP_RepositoryId = _0_@modname@._d_@ifid@[1]

    def __init__(self, *args, **kw):
        raise RuntimeError("Cannot construct objects of this type.")

    _nil = CORBA.Object._nil
"""

interface_descriptor = """
_0_@modname@.@ifid@ = @ifid@
_0_@modname@._tc_@ifid@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@ifid@)
omniORB.registerType(@ifid@._NP_RepositoryId, _0_@modname@._d_@ifid@, _0_@modname@._tc_@ifid@)"""

callables_header = """
# @ifid@ operations and attributes"""

attribute_get_descriptor = """\
@ifid@._d__get_@attr@ = ((),(@descr@,),None)"""

attribute_set_descriptor = """\
@ifid@._d__set_@attr@ = ((@descr@,),(),None)"""

operation_descriptor = """\
@ifid@._d_@opname@ = (@inds@, @outds@, @excs@@options@)"""

objref_class = """\

# @ifid@ object reference
class _objref_@ifid@ (@inherits@):
    _NP_RepositoryId = @ifid@._NP_RepositoryId

    def __init__(self, obj):"""

objref_inherit_init = """\
        @inclass@.__init__(self, obj)"""

objref_object_init = """\
        CORBA.Object.__init__(self, obj)"""

objref_attribute_get = """
    def _get_@attr@(self, *args):
        return self._obj.invoke("_get_@attr@", _0_@modname@.@ifid@._d__get_@attr@, args)"""

objref_attribute_set = """
    def _set_@attr@(self, *args):
        return self._obj.invoke("_set_@attr@", _0_@modname@.@ifid@._d__set_@attr@, args)"""

objref_attribute_property = """
    @attr@ = property(_get_@attr@, _set_@attr@)
"""

objref_readonly_attribute_property = """
    @attr@ = property(_get_@attr@)
"""

objref_operation = """
    def @opname@(self, *args):
        return self._obj.invoke("@r_opname@", _0_@modname@.@ifid@._d_@opname@, args)"""

objref_ami_sendc = """
    def @ami_opname@(self, ami_handler, *args):
        return self._obj.invoke_sendc("@r_opname@", _0_@modname@.@ifid@._d_@opname@, args, "@excep_name@", ami_handler)"""

objref_ami_sendp = """
    def @ami_opname@(self, *args):
        return _0_@modname@._impl_@poller_class@(self._obj.invoke_sendp("@r_opname@", _0_@modname@.@ifid@._d_@opname@, args, "@excep_name@"))"""

objref_register = """
omniORB.registerObjref(@ifid@._NP_RepositoryId, _objref_@ifid@)
_0_@modname@._objref_@ifid@ = _objref_@ifid@
del @ifid@, _objref_@ifid@"""

skeleton_class = """
# @ifid@ skeleton
__name__ = "@package@@s_modname@"
class @ifid@ (@inherits@):
    _NP_RepositoryId = _0_@modname@.@ifid@._NP_RepositoryId
"""

skeleton_methodmap = """
    _omni_op_d = @methodmap@"""

skeleton_inheritmap = """\
    _omni_op_d.update(@inheritclass@._omni_op_d)"""

skeleton_end = """
@ifid@._omni_skeleton = @ifid@
_0_@s_modname@.@ifid@ = @ifid@
omniORB.registerSkeleton(@ifid@._NP_RepositoryId, @ifid@)
del @ifid@
__name__ = "@package@@modname@"\
"""

skeleton_set_skel = """
@ifid@._omni_skeleton = @ifid@
"""

constant_at_module_scope = """\
_0_@modname@.@cname@ = @value@"""

constant = """\
@cname@ = @value@"""

typedef_header = """\

# typedef ... @tdname@
class @tdname@:
    _NP_RepositoryId = "@repoId@"
    def __init__(self, *args, **kw):
        raise RuntimeError("Cannot construct objects of this type.")"""

typedef_struct_union_header = """\

# typedef ... @tdname@
class @tdname@ (@parent@):
    _NP_RepositoryId = "@repoId@"
"""

typedef_fixed_header = """\
# typedef ... @tdname@
@tdname@ = omniORB.fixedConstructor("@repoId@", @digits@, @scale@)"""

typedef_at_module_scope = """\
_0_@modname@.@tdname@ = @tdname@
_0_@modname@._d_@tdname@  = @desc@
_0_@modname@._ad_@tdname@ = (omniORB.tcInternal.tv_alias, @tdname@._NP_RepositoryId, "@tdname@", @tddesc@)
_0_@modname@._tc_@tdname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._ad_@tdname@)
omniORB.registerType(@tdname@._NP_RepositoryId, _0_@modname@._ad_@tdname@, _0_@modname@._tc_@tdname@)
del @tdname@"""

typedef = """\
_d_@tdname@  = @desc@
_ad_@tdname@ = (omniORB.tcInternal.tv_alias, @tdname@._NP_RepositoryId, "@tdname@", @tddesc@)
_tc_@tdname@ = omniORB.tcInternal.createTypeCode(_ad_@tdname@)
omniORB.registerType(@tdname@._NP_RepositoryId, _ad_@tdname@, _tc_@tdname@)"""

forward_struct_descr_at_module_scope = """
# Forward struct @sname@
_0_@modname@._d_@sname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@sname@"""

forward_struct_descr = """
# Forward struct @sname@
_d_@sname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _d_@sname@"""

recursive_struct_descr_at_module_scope = """
# Recursive struct @sname@
_0_@modname@._d_@sname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@sname@"""

recursive_struct_descr = """
# Recursive struct @sname@
_d_@sname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
_0_@scope@._d_@sname@ = _d_@sname@
omniORB.typeMapping["@repoId@"] = _d_@sname@"""

struct_class = """
# struct @sname@
_0_@scopedname@ = omniORB.newEmptyClass()
class @sname@ (omniORB.StructBase):
    _NP_RepositoryId = "@repoId@"
"""

struct_class_name = """\
    _NP_ClassName = "@cname@"
"""

struct_class_init = """\
    def __init__(self@mnames@):"""

struct_init_member = """\
        self.@mname@ = @mname@"""

struct_descriptor_at_module_scope = """\

_0_@modname@.@sname@ = @sname@
_0_@modname@._d_@sname@  = (omniORB.tcInternal.tv_struct, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)"""

struct_register_at_module_scope = """\
_0_@modname@._tc_@sname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _0_@modname@._d_@sname@, _0_@modname@._tc_@sname@)
del @sname@"""

struct_descriptor = """\

_d_@sname@  = _0_@scope@._d_@sname@ = (omniORB.tcInternal.tv_struct, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)"""

struct_register = """\
_tc_@sname@ = omniORB.tcInternal.createTypeCode(_d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _d_@sname@, _tc_@sname@)"""

struct_module_descriptors = """
_0_@modname@._d_@sname@  = _d_@sname@
_0_@modname@._tc_@sname@ = _tc_@sname@
del @sname@, _d_@sname@, _tc_@sname@"""

exception_class = """\

# exception @sname@
_0_@scopedname@ = omniORB.newEmptyClass()
class @sname@ (CORBA.UserException):
    _NP_RepositoryId = "@repoId@"
"""

exception_class_init = """\
    def __init__(self@mnames@):
        CORBA.UserException.__init__(self@mnames@)"""

exception_init_member = """\
        self.@mname@ = @mname@"""

exception_descriptor_at_module_scope = """\

_0_@modname@.@sname@ = @sname@
_0_@modname@._d_@sname@  = (omniORB.tcInternal.tv_except, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)
_0_@modname@._tc_@sname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _0_@modname@._d_@sname@, _0_@modname@._tc_@sname@)
del @sname@"""

exception_descriptor = """\

_d_@sname@  = (omniORB.tcInternal.tv_except, @sname@, @sname@._NP_RepositoryId, "@sname@"@mdescs@)
_tc_@sname@ = omniORB.tcInternal.createTypeCode(_d_@sname@)
omniORB.registerType(@sname@._NP_RepositoryId, _d_@sname@, _tc_@sname@)"""

forward_union_descr_at_module_scope = """
# Forward union @uname@
_0_@modname@._d_@uname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@uname@"""

forward_union_descr = """
# Forward union @uname@
_d_@uname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _d_@uname@"""

recursive_union_descr_at_module_scope = """
# Recursive union @uname@
_0_@modname@._d_@uname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@uname@"""

recursive_union_descr = """
# Recursive union @uname@
_d_@uname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
_0_@scope@._d_@uname@ = _d_@uname@
omniORB.typeMapping["@repoId@"] = _d_@uname@"""

union_class = """
# union @uname@
_0_@scopedname@ = omniORB.newEmptyClass()
class @uname@ (omniORB.Union):
    _NP_RepositoryId = "@repoId@"\
"""

union_class_name = """\
    _NP_ClassName = "@cname@"
"""

union_descriptor_at_module_scope = """
_0_@modname@.@uname@ = @uname@

@uname@._m_to_d = {@m_to_d@}
@uname@._d_to_m = {@d_to_m@}
@uname@._def_m  = @def_m@
@uname@._def_d  = @def_d@

_0_@modname@._m_@uname@  = (@m_un@,)
_0_@modname@._d_@uname@  = (omniORB.tcInternal.tv_union, @uname@, @uname@._NP_RepositoryId, "@uname@", @stype@, @defpos@, _0_@modname@._m_@uname@, @m_def@, {@d_map@})"""

union_register_at_module_scope = """\
_0_@modname@._tc_@uname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@uname@)
omniORB.registerType(@uname@._NP_RepositoryId, _0_@modname@._d_@uname@, _0_@modname@._tc_@uname@)
del @uname@"""

union_descriptor = """
@uname@._m_to_d = {@m_to_d@}
@uname@._d_to_m = {@d_to_m@}
@uname@._def_m  = @def_m@
@uname@._def_d  = @def_d@

_m_@uname@  = (@m_un@,)
_d_@uname@  = _0_@scope@._d_@uname@ = (omniORB.tcInternal.tv_union, @uname@, @uname@._NP_RepositoryId, "@uname@", @stype@, @defpos@, _m_@uname@, @m_def@, {@d_map@})"""

union_register = """\
_tc_@uname@ = omniORB.tcInternal.createTypeCode(_d_@uname@)
omniORB.registerType(@uname@._NP_RepositoryId, _d_@uname@, _tc_@uname@)"""


enum_start = """
# enum @ename@\
"""

enum_item_at_module_scope = """\
_0_@modname@.@eitem@ = omniORB.EnumItem("@item@", @eval@)"""

enum_object_and_descriptor_at_module_scope = """\
_0_@modname@.@ename@ = omniORB.Enum("@repoId@", (@eitems@,))

_0_@modname@._d_@ename@  = (omniORB.tcInternal.tv_enum, _0_@modname@.@ename@._NP_RepositoryId, "@ename@", _0_@modname@.@ename@._items)
_0_@modname@._tc_@ename@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@ename@)
omniORB.registerType(_0_@modname@.@ename@._NP_RepositoryId, _0_@modname@._d_@ename@, _0_@modname@._tc_@ename@)"""

enum_item = """\
@eitem@ = omniORB.EnumItem("@item@", @eval@)"""

enum_object_and_descriptor = """\
@ename@ = omniORB.Enum("@repoId@", (@eitems@,))

_d_@ename@  = (omniORB.tcInternal.tv_enum, @ename@._NP_RepositoryId, "@ename@", @ename@._items)
_tc_@ename@ = omniORB.tcInternal.createTypeCode(_d_@ename@)
omniORB.registerType(@ename@._NP_RepositoryId, _d_@ename@, _tc_@ename@)"""


value_forward_at_module_scope = """
# forward valuetype @vname@
_0_@modname@._d_@vname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@vname@
"""

value_class = """
# valuetype @vname@
_0_@modname@._d_@vname@ = (omniORB.tcInternal.tv__indirect, ["@repoId@"])
omniORB.typeMapping["@repoId@"] = _0_@modname@._d_@vname@
_0_@modname@.@vname@ = omniORB.newEmptyClass()

class @vname@ (@inherits@):
    _NP_RepositoryId = "@repoId@"

    def __init__(self, *args, **kwargs):
        if args:
            if len(args) != @arglen@:
                raise TypeError("@vname@() takes @arglen@ argument@s@ "
                                "(%d given)" % len(args))
            @set_args@
        if kwargs:
            self.__dict__.update(kwargs)
"""

valueabs_class = """
# abstract valuetype @vname@
class @vname@ (@inherits@):
    _NP_RepositoryId = "@repoId@"

    def __init__(self, *args, **kwargs):
        raise RuntimeError("Cannot construct objects of this type.")
"""

value_register_factory = """\
omniORB.registerValueFactory(@vname@._NP_RepositoryId, @vname@)
"""

value_descriptor_at_module_scope = """\
_0_@modname@.@vname@ = @vname@
_0_@modname@._d_@vname@  = (omniORB.tcInternal.tv_value, @vname@, @vname@._NP_RepositoryId, "@vname@", @modifier@, @tbaseids@, @basedesc@, @mdescs@)
_0_@modname@._tc_@vname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@vname@)
omniORB.registerType(@vname@._NP_RepositoryId, _0_@modname@._d_@vname@, _0_@modname@._tc_@vname@)
del @vname@
"""

value_objref_register = """
omniORB.registerObjref(@ifid@._NP_RepositoryId, _objref_@ifid@)
_0_@modname@._objref_@ifid@ = _objref_@ifid@
del _objref_@ifid@"""


valuebox = """\

# valuebox @boxname@
class @boxname@:
    _NP_RepositoryId = "@repoId@"
    def __init__(self, *args, **kw):
        raise RuntimeError("Cannot construct objects of this type.")

_0_@modname@.@boxname@ = @boxname@
_0_@modname@._d_@boxname@  = (omniORB.tcInternal.tv_value_box, @boxname@, @boxname@._NP_RepositoryId, "@boxname@", @boxdesc@)
_0_@modname@._tc_@boxname@ = omniORB.tcInternal.createTypeCode(_0_@modname@._d_@boxname@)
omniORB.registerType(@boxname@._NP_RepositoryId, _0_@modname@._d_@boxname@, _0_@modname@._tc_@boxname@)
omniORB.registerValueFactory(@boxname@._NP_RepositoryId, @boxname@)
del @boxname@
"""

ami_poller_impl = """
# Implementation of @vname@
class _impl_@vname@ (@vname@, omniORB.ami.PollerImpl):
    def __init__(self, poller):
        omniORB.ami.PollerImpl.__init__(self, poller)
"""

ami_poller_op = """\
    def @poller_opname@(self, ami_timeout):
        return self._poller.poll("@opname@", ami_timeout)
"""

ami_poller_register = """
_0_@modname@._impl_@vname@ = _impl_@vname@
omniORB.registerValueFactory(@vname@._NP_RepositoryId, _impl_@vname@)
del _impl_@vname@
"""


example_start = """\
#!/usr/bin/env python

# Python example implementations generated from @filename@

import CORBA, PortableServer

# Import the Python stub modules so type definitions are available.
"""

example_import_skels = """
# Import the Python Skeleton modules so skeleton base classes are available.
"""

example_import = """\
import @module@"""

example_classdef = """

# Implementation of interface @ccname@

class @ifname@_i (@skname@):
@inheritance_note@
    def __init__(self):
        # Initialise member variables here
        pass
"""

example_opdef = """\
    # @signature@
    def @opname@(self@args@):
        raise CORBA.NO_IMPLEMENT(0, CORBA.COMPLETED_NO)
        # *** Implement me
        # Must return: @returnspec@
"""

example_end = """
def main():
    import sys
    
    # Initialise the ORB
    orb = CORBA.ORB_init(sys.argv)
    
    # As an example, we activate an object in the Root POA
    poa = orb.resolve_initial_references("RootPOA")

    # Create an instance of a servant class
    servant = @ifname@_i()

    # Activate it in the Root POA
    poa.activate_object(servant)

    # Get the object reference to the object
    objref = servant._this()
    
    # Print a stringified IOR for it
    print orb.object_to_string(objref)

    # Activate the Root POA's manager
    poa._get_the_POAManager().activate()

    # Run the ORB, blocking this thread
    orb.run()


if __name__ == "__main__":
    main()
"""


# Global state
imported_files   = {}
exported_modules = {}

# Command line options
output_inline    = 0
global_module    = "_GlobalIDL"
module_package   = ""
stub_package     = ""
stub_directory   = ""
all_factories    = 0
example_impl     = 0
extern_stub_pkgs = {}
generate_ami     = 0


def error_exit(message):
    sys.stderr.write(main.cmdname + ": " + message + "\n")
    sys.exit(1)

def run(tree, args):
    global main_idl_file, imported_files, exported_modules, output_inline
    global global_module, module_package, stub_package, stub_directory
    global all_factories, example_impl, extern_stub_pkgs, generate_ami

    imported_files.clear()
    exported_modules.clear()

    # Look at the args:
    use_stdout     = 0
    create_package = 1
    for arg in args:

        if arg == "stdout":
            use_stdout     = 1
            create_package = 0

        elif arg == "no_package":
            create_package = 0

        elif arg == "inline":
            output_inline = 1

        elif arg == "factories":
            all_factories = 1

        elif arg[:8] == "modules=":
            module_package = arg[8:]
            if module_package != "":
                module_package = module_package + "."

        elif arg[:6] == "stubs=":
            stub_package   = arg[6:]
            stub_directory = os.path.join(*(stub_package.split(".")))
            if stub_package != "":
                stub_package = stub_package + "."

        elif arg[:8] == "package=":
            module_package = stub_package = arg[8:]
            stub_directory = os.path.join(*(stub_package.split(".")))
            if module_package != "":
                module_package = stub_package = module_package + "."

        elif arg[:7] == "global=":
            global_module = arg[7:]
            if global_module == "":
                error_exit("You may not have an unnamed global module.")

        elif arg == "example":
            example_impl = 1

        elif arg[:7] == "extern=":
            f_p = arg[7:].split(":", 1)
            if len(f_p) == 1:
                extern_stub_pkgs[f_p[0]] = None
            else:
                extern_stub_pkgs[f_p[0]] = f_p[1]

        elif arg == "ami":
            generate_ami = 1

        else:
            sys.stderr.write(main.cmdname + ": Warning: Python " \
                             "back-end does not understand argument: " + \
                             arg + "\n")

    main_idl_file = tree.file()

    outpybasename = outputFileName(main_idl_file)
    outpymodule   = stub_package + outpybasename
    outpyname     = os.path.join(stub_directory, outpybasename + ".py")

    imported_files[outpybasename] = 1

    if create_package:
        checkStubPackage(stub_package)

    if use_stdout:
        st = output.Stream(sys.stdout, 4)
    else:
        try:
            st = output.Stream(open(outpyname, "w"), 4)
        except IOError:
            error_exit('Cannot open "%s" for writing.' % outpyname)

    if generate_ami:
        ami_import = "import omniORB.ami"
        imported_files["messaging_idl"] = 1
        from omniidl_be import ami
        tree.accept(ami.AMIVisitor())
    else:
        ami_import = ""
        
    st.out(file_start, filename=main_idl_file, ami_import=ami_import)

    pv = PythonVisitor(st, outpymodule)
    tree.accept(pv)

    dv = DocstringVisitor(st)
    tree.accept(dv)
    dv.output()

    exports = sorted(exported_modules.keys())
    export_list = [ '"%s%s"' % (module_package, s) for s in exports ]
    if len(export_list) == 1:
        export_list.append("")

    export_string = ", ".join(export_list)

    st.out(file_end, export_string=export_string)

    if create_package:
        updateModules(exports, outpymodule)

    if example_impl:
        implname = os.path.join(stub_directory, outpybasename + "_example.py")
        exst = output.Stream(open(implname, "w"), 4)
        exst.out(example_start, filename=main_idl_file)
        for mod in exports:
            exst.out(example_import, module=mod)
        exst.out(example_import_skels)
        for mod in exports:
            exst.out(example_import, module=skeletonModuleName(mod))

        ev = ExampleVisitor(exst)
        tree.accept(ev)

        exst.out(example_end, ifname=ev.first)


class PythonVisitor:
    def __init__(self, st, outpymodule):
        self.st          = st
        self.outpymodule = outpymodule

    def handleImported(self, node):
        global imported_files

        if node.mainFile() or output_inline:
            return 0
        else:
            ifilename = outputFileName(node.file())
            if ifilename not in imported_files:
                imported_files[ifilename] = 1
                ibasename,ext = os.path.splitext(os.path.basename(node.file()))
                if ibasename in extern_stub_pkgs:
                    ipackage = extern_stub_pkgs[ibasename]
                    if ipackage:
                        fn = ipackage + '.' + ifilename
                    else:
                        fn = ifilename
                else:
                    fn = stub_package + ifilename

                self.st.out(import_idl_file,
                            idlfile=node.file(),
                            ifilename=fn)
            return 1
        
    #
    # The global module
    #
    def visitAST(self, node):
        self.at_module_scope = 1
        self.at_global_scope = 1
        self.currentScope    = ["_0_" + global_module]

        decls_in_global_module = 0

        for n in node.declarations():
            if not isinstance(n, idlast.Module):
                decls_in_global_module = 1
                break

        if decls_in_global_module:
            self.modname = global_module
            self.st.out(module_start,
                        sname=global_module,
                        s_sname=skeletonModuleName(global_module),
                        filename=node.file(), package=module_package)
        else:
            self.modname = self.outpymodule

        for n in node.declarations():
            n.accept(self)

        if decls_in_global_module:
            exported_modules[global_module] = 1
            self.st.out(module_end, modname=self.outpymodule,
                        sname=global_module,
                        package="")

    #
    # Module
    #
    def visitModule(self, node):
        if self.handleImported(node):
            imodname = dotName(node.scopedName())
            ibasename,ext = os.path.splitext(os.path.basename(node.file()))

            if ibasename in extern_stub_pkgs:
                package = extern_stub_pkgs[ibasename]
                if package is None:
                    package = ""
                else:
                    package = package + "."
            else:
                package = module_package

            self.st.out(open_imported_module_name,
                        imodname=imodname,
                        s_imodname=skeletonModuleName(imodname),
                        package=package)

        assert self.at_module_scope

        sname = dotName(node.scopedName())

        if node.mainFile() or output_inline:
            self.st.out(module_start,
                        sname = sname,
                        s_sname = skeletonModuleName(sname),
                        filename = node.file(), package=module_package)

        parentmodname = self.modname
        self.modname  = dotName(node.scopedName())

        ags = self.at_global_scope
        if ags:
            self.currentScope = ["_0_" + node.identifier()]
        else:
            self.currentScope.append(node.identifier())

        self.at_global_scope = 0

        for n in node.definitions():
            n.accept(self)

        if ags:
            self.currentScope = ["_0_" + global_module]
        else:
            self.currentScope.pop()
        self.at_global_scope = ags
        self.modname         = parentmodname

        if node.mainFile() or output_inline:
            exported_modules[sname] = 1
            if parentmodname == self.outpymodule:
                end_package = ""
            else:
                end_package = module_package

            self.st.out(module_end, modname=parentmodname, sname=sname,
                        package=end_package)

    #
    # Forward interface
    #
    def visitForward(self, node):
        if self.handleImported(node): return

        assert self.at_module_scope
        ifid   = mangle(node.identifier())
        repoId = node.repoId()
        if node.abstract():
            tvkind = "tv_abstract_interface"
            abstract = "abstract "
        else:
            tvkind = "tv_objref"
            abstract = ""

        self.st.out(forward_interface, ifid=ifid, tvkind=tvkind,
                    repoId=repoId, abstract=abstract, modname=self.modname)

    #
    # Interface
    #
    def visitInterface(self, node):
        if self.handleImported(node): return

        assert self.at_module_scope
        ifid = mangle(node.identifier())

        if len(node.inherits()) > 0:
            inheritl = []
            for i in node.inherits():
                i = i.fullDecl()
                inheritl.append(dotName(fixupScopedName(i.scopedName())))
            
            inherits = "(" + ", ".join(inheritl) + ")"
        else:
            inherits = ""

        if node.abstract():
            tvkind = "tv_abstract_interface"
            abstract = "abstract "
        else:
            tvkind = "tv_objref"
            abstract = ""

        # Class header
        self.st.out(interface_class, ifid=ifid, tvkind=tvkind,
                    inherits=inherits, repoId=node.repoId(),
                    abstract=abstract, modname=self.modname)

        # Declarations within the interface
        if len(node.declarations()) > 0:
            self.st.inc_indent()
            self.at_module_scope = 0
            self.currentScope.append(node.identifier())

            for d in node.declarations():
                d.accept(self)

            self.currentScope.pop()
            self.at_module_scope = 1
            self.st.dec_indent()
            self.st.out("")

        # Descriptor and TypeCode for the interface
        self.st.out(interface_descriptor,
                    modname = self.modname, ifid = ifid)

        # Attributes and operations
        # *** Was there a good reason for putting these in the class def?
        if len(node.callables()) > 0:
            self.st.out(callables_header, ifid=ifid)

        for c in node.callables():
            if isinstance(c, idlast.Attribute):

                descr = typeToDescriptor(c.attrType())

                for attr in c.identifiers():

                    self.st.out(attribute_get_descriptor,
                                attr=attr, descr=descr, ifid=ifid)

                    if not c.readonly():

                        self.st.out(attribute_set_descriptor,
                                    attr=attr, descr=descr, ifid=ifid)
            else: # Operation

                inds, outds, excs, ctxts, cv = operationToDescriptors(c)

                options = ""

                if cv:
                    ctxts = ctxts or "None"

                if ctxts:
                    options = ", " + ctxts

                if cv:
                    options = options + ", 1"

                # Output the declaration
                self.st.out(operation_descriptor,
                            opname  = mangle(c.identifier()),
                            inds    = inds,
                            outds   = outds,
                            excs    = excs,
                            options = options,
                            ifid    = ifid)

        # Objref class
        if node.inherits():
            inheritl = []
            for i in node.inherits():
                i = i.fullDecl()
                sn = fixupScopedName(i.scopedName())
                inheritl.append(dotName(sn[:-1] + ["_objref_" + sn[-1]]))
                
            inherits = ", ".join(inheritl)
        else:
            inherits = "CORBA.Object"

        self.st.out(objref_class, ifid=ifid, inherits=inherits)

        if node.inherits():
            for inclass in inheritl:
                self.st.out(objref_inherit_init, inclass=inclass)
        else:
            self.st.out(objref_object_init)

        # Operations and attributes
        for c in node.callables():
            if isinstance(c, idlast.Attribute):

                for attr in c.identifiers():

                    self.st.out(objref_attribute_get,
                                attr    = attr,
                                ifid    = ifid,
                                modname = self.modname)
                    
                    if c.readonly():
                        self.st.out(objref_readonly_attribute_property,
                                    attr = attr)

                    else:
                        self.st.out(objref_attribute_set,
                                    attr    = attr,
                                    ifid    = ifid,
                                    modname = self.modname)
                        
                        self.st.out(objref_attribute_property,
                                    attr = attr)

            else: # Operation
                opname = mangle(c.identifier())
                
                self.st.out(objref_operation,
                            opname   = opname,
                            r_opname = c.identifier(),
                            ifid     = ifid,
                            modname  = self.modname)
                
        for c in getattr(node, "_ami_ops", []):
            ami_opname = mangle(c.identifier())

            ami_from   = c._ami_from
            from_ident = ami_from.identifier()

            if isinstance(ami_from, idlast.Declarator):
                # Attribute
                if c._ami_setter:
                    from_op  = "_set_" + from_ident
                    excep_op = ami_from._ami_set_handler_excep.identifier()
                else:
                    from_op  = "_get_" + from_ident
                    excep_op = ami_from._ami_get_handler_excep.identifier()
            else:
                from_op  = from_ident
                excep_op = ami_from._ami_handler_excep.identifier()


            send = c.identifier().split("_")[0]
            if send == "sendc":
                self.st.out(objref_ami_sendc,
                            ami_opname = ami_opname,
                            opname     = mangle(from_op),
                            r_opname   = from_op,
                            excep_name = excep_op,
                            ifid       = ifid,
                            modname    = self.modname)
            else:
                poller_class = node._ami_poller.identifier()

                self.st.out(objref_ami_sendp,
                            ami_opname   = ami_opname,
                            opname       = mangle(from_op),
                            r_opname     = from_op,
                            excep_name   = excep_op,
                            ifid         = ifid,
                            modname      = self.modname,
                            poller_class = poller_class)

        # registerObjRef()
        self.st.out(objref_register, ifid = ifid, modname = self.modname)

        # Skeleton class
        if node.inherits():
            inheritl = []
            for i in node.inherits():
                i = i.fullDecl()
                fsn = fixupScopedName(i.scopedName())
                dsn = dotName(fsn)
                ssn = skeletonModuleName(dsn)
                inheritl.append(ssn)
                
            inherits = ", ".join(inheritl)
        else:
            inherits = "PortableServer.Servant"

        self.st.out(skeleton_class,
                    ifid      = ifid,
                    inherits  = inherits,
                    modname   = self.modname,
                    s_modname = skeletonModuleName(self.modname),
                    package   = module_package)

        # Operations and attributes
        methodl = []

        for c in node.callables():
            if isinstance(c, idlast.Attribute):

                for attr in c.identifiers():

                    methodl.append('"_get_' + attr + '": ' + \
                                   '_0_' + self.modname + '.' + \
                                   ifid + '.' + '_d__get_' + attr)

                    if not c.readonly():

                        methodl.append('"_set_' + attr + '": ' + \
                                       '_0_' + self.modname + '.' + \
                                       ifid + '.' + '_d__set_' + attr)

            else: # Operation
                opname   = c.identifier()
                m_opname = mangle(opname)
                
                methodl.append('"' + opname + '": ' + '_0_' + self.modname +
                               '.' + ifid + '.' + '_d_' + m_opname)

        methodmap = "{" + ", ".join(methodl) + "}"

        self.st.out(skeleton_methodmap, methodmap = methodmap)

        if node.inherits():
            for inheritclass in inheritl:
                self.st.out(skeleton_inheritmap, inheritclass = inheritclass)

        self.st.out(skeleton_end,
                    ifid      = ifid,
                    modname   = self.modname,
                    s_modname = skeletonModuleName(self.modname),
                    package   = module_package)

    #
    # Constant
    #
    def visitConst(self, node):
        if self.handleImported(node): return

        cname = mangle(node.identifier())

        if self.at_module_scope:
            value = valueToString(node.value(), node.constKind(), [])
        else:
            value = valueToString(node.value(), node.constKind(),
                                  self.currentScope)
        if self.at_module_scope:
            self.st.out(constant_at_module_scope,
                        cname   = cname,
                        value   = value,
                        modname = self.modname)
        else:
            self.st.out(constant,
                        cname   = cname,
                        value   = value)

    #
    # Typedef
    #
    def visitTypedef(self, node):
        if self.handleImported(node): return

        if node.constrType():
            node.aliasType().decl().accept(self)

        for decl in node.declarators():
            tdname = mangle(decl.identifier())
            if self.at_module_scope:
                desc   = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl, [])
                tddesc = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl, [], 1)

                unaliased_type = node.aliasType().unalias()

                if len(decl.sizes()) == 0 and \
                   unaliased_type.kind() in [idltype.tk_struct,
                                             idltype.tk_union]:

                    parent = dotName(fixupScopedName(unaliased_type.decl().\
                                                     scopedName()))

                    self.st.out(typedef_struct_union_header,
                                tdname = tdname,
                                repoId = decl.repoId(),
                                parent = parent)

                elif len(decl.sizes()) == 0 and\
                     unaliased_type.kind() == idltype.tk_fixed:

                    self.st.out(typedef_fixed_header,
                                tdname = tdname,
                                repoId = decl.repoId(),
                                digits = unaliased_type.digits(),
                                scale  = unaliased_type.scale())
                    
                else:
                    self.st.out(typedef_header,
                                tdname  = tdname,
                                repoId  = decl.repoId())

                self.st.out(typedef_at_module_scope,
                            tdname  = tdname,
                            desc    = desc,
                            tddesc  = tddesc,
                            modname = self.modname)
            else:
                desc   = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl,
                                                       self.currentScope)
                tddesc = typeAndDeclaratorToDescriptor(node.aliasType(),
                                                       decl,
                                                       self.currentScope, 1)

                unaliased_type = node.aliasType().unalias()

                if len(decl.sizes()) == 0 and \
                   unaliased_type.kind() in [idltype.tk_struct,
                                             idltype.tk_union]:

                    psname  = unaliased_type.decl().scopedName()
                    myscope = decl.scopedName()[:-1]

                    # If the struct/union definition is in the same
                    # scope as the typedef, we must use a relative
                    # name to refer to the parent class, since the
                    # enclosing Python class has not yet been fully
                    # defined.

                    if psname[:len(myscope)] == myscope:
                        parent = dotName(psname[len(myscope):])
                    else:
                        parent = dotName(fixupScopedName(psname))

                    self.st.out(typedef_struct_union_header,
                                tdname = tdname,
                                repoId = decl.repoId(),
                                parent = parent)
                else:
                    self.st.out(typedef_header,
                                tdname  = tdname,
                                repoId  = decl.repoId())

                self.st.out(typedef,
                            tdname  = tdname,
                            desc    = desc,
                            tddesc  = tddesc)
    #
    # Struct
    #
    def visitStruct(self, node):
        if self.handleImported(node): return

        sname = mangle(node.identifier())

        fscopedName = fixupScopedName(node.scopedName(), "")

        if node.recursive():
            if self.at_module_scope:
                self.st.out(recursive_struct_descr_at_module_scope,
                            sname   = sname,
                            repoId  = node.repoId(),
                            modname = self.modname)
            else:
                self.st.out(recursive_struct_descr,
                            sname   = sname,
                            repoId  = node.repoId(),
                            scope   = dotName(fscopedName[:-1]))

        self.st.out(struct_class,
                    sname      = sname,
                    repoId     = node.repoId(),
                    scopedname = dotName(fscopedName))

        if not self.at_module_scope:
            self.st.out(struct_class_name, cname = dotName(fscopedName))

        mnamel = []
        mdescl = []
        for mem in node.members():

            # Deal with nested declarations
            if mem.constrType():
                self.st.inc_indent()
                ams = self.at_module_scope
                self.at_module_scope = 0
                self.currentScope.append(node.identifier())
                
                mem.memberType().decl().accept(self)

                self.currentScope.pop()
                self.at_module_scope = ams
                self.st.dec_indent()
                self.st.out("")

            for decl in mem.declarators():
                mnamel.append(mangle(decl.identifier()))
                mdescl.append('"' + mangle(decl.identifier()) + '"')
                
                if self.at_module_scope:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      []))
                else:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      self.currentScope))
        if len(mnamel) > 0:
            mnames = ", " + ", ".join(mnamel)

            self.st.out(struct_class_init, mnames = mnames)

            for mname in mnamel:
                self.st.out(struct_init_member, mname = mname)

        if len(mdescl) > 0:
            mdescs = ", " + ", ".join(mdescl)
        else:
            mdescs = ""

        if self.at_module_scope:
            self.st.out(struct_descriptor_at_module_scope,
                        sname   = sname,
                        mdescs  = mdescs,
                        modname = self.modname)
            
            self.st.out(struct_register_at_module_scope,
                        sname   = sname,
                        modname = self.modname)
        else:
            self.st.out(struct_descriptor,
                        sname  = sname,
                        mdescs = mdescs,
                        scope  = dotName(fscopedName[:-1]))

            self.st.out(struct_register, sname = sname)

    #
    # Forward struct
    #
    def visitStructForward(self, node):
        if self.handleImported(node): return

        sname = mangle(node.identifier())

        if self.at_module_scope:
            self.st.out(forward_struct_descr_at_module_scope,
                        sname   = sname,
                        repoId  = node.repoId(),
                        modname = self.modname)
        else:
            self.st.out(forward_struct_descr,
                        sname   = sname,
                        repoId  = node.repoId(),
                        modname = self.modname)

    #
    # Exception
    #
    def visitException(self, node):
        if self.handleImported(node): return

        sname = mangle(node.identifier())
        fscopedName = fixupScopedName(node.scopedName(), "")
        self.st.out(exception_class,
                    sname = sname,
                    repoId = node.repoId(),
                    scopedname = dotName(fscopedName))

        if not self.at_module_scope:
            self.st.out(struct_class_name, cname = dotName(fscopedName))

        mnamel = []
        mdescl = []
        for mem in node.members():

            # Deal with nested declarations
            if mem.constrType():
                self.st.inc_indent()
                ams = self.at_module_scope
                self.at_module_scope = 0
                self.currentScope.append(node.identifier())
                
                mem.memberType().decl().accept(self)

                self.currentScope.pop()
                self.at_module_scope = ams
                self.st.dec_indent()
                self.st.out("")

            for decl in mem.declarators():
                mnamel.append(mangle(decl.identifier()))
                mdescl.append('"' + mangle(decl.identifier()) + '"')

                if self.at_module_scope:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      []))
                else:
                    mdescl.append(\
                        typeAndDeclaratorToDescriptor(mem.memberType(),
                                                      decl,
                                                      self.currentScope))

        if len(mnamel) > 0:
            mnames = ", " + ", ".join(mnamel)
        else:
            mnames = ""

        self.st.out(exception_class_init, mnames = mnames)

        for mname in mnamel:
            self.st.out(exception_init_member, mname = mname)

        if len(mdescl) > 0:
            mdescs = ", " + ", ".join(mdescl)
        else:
            mdescs = ""

        if self.at_module_scope:
            self.st.out(exception_descriptor_at_module_scope,
                        sname = sname, mdescs = mdescs, modname = self.modname)
        else:
            self.st.out(exception_descriptor, sname = sname, mdescs = mdescs)

    #
    # Union
    #
    def visitUnion(self, node):
        if self.handleImported(node): return

        uname = mangle(node.identifier())
        if self.at_module_scope:
            stype = typeToDescriptor(node.switchType(), [])
        else:
            stype = typeToDescriptor(node.switchType(), self.currentScope)

        fscopedName = fixupScopedName(node.scopedName(), "")
        
        if node.recursive():
            if self.at_module_scope:
                self.st.out(recursive_union_descr_at_module_scope,
                            uname   = uname,
                            repoId  = node.repoId(),
                            modname = self.modname)
            else:
                self.st.out(recursive_union_descr,
                            uname   = uname,
                            repoId  = node.repoId(),
                            scope   = dotName(fscopedName[:-1]))

        self.st.out(union_class,
                    uname      = uname,
                    repoId     = node.repoId(),
                    scopedname = dotName(fscopedName))

        if not self.at_module_scope:
            self.st.out(union_class_name, cname = dotName(fscopedName))

        if node.constrType():
            self.st.inc_indent()
            ams = self.at_module_scope
            self.at_module_scope = 0
            self.currentScope.append(node.identifier())
            
            node.switchType().decl().accept(self)

            self.currentScope.pop()
            self.at_module_scope = ams
            self.st.dec_indent()

        def_m    = "None"
        def_d    = "None"
        m_def    = "None"
        defpos   = "-1"
        m_to_d_l = []
        d_to_m_l = []
        m_un_l   = []
        d_map_l  = []

        i = 0
        for case in node.cases():

            # Deal with nested declarations
            if case.constrType():
                self.st.inc_indent()
                ams = self.at_module_scope
                self.at_module_scope = 0
                self.currentScope.append(node.identifier())
                
                case.caseType().decl().accept(self)

                self.currentScope.pop()
                self.at_module_scope = ams
                self.st.dec_indent()
                self.st.out("")

            if self.at_module_scope:
                ctype = typeAndDeclaratorToDescriptor(case.caseType(),
                                                      case.declarator(),
                                                      [])
            else:
                ctype = typeAndDeclaratorToDescriptor(case.caseType(),
                                                      case.declarator(),
                                                      self.currentScope)

            cname = mangle(case.declarator().identifier())

            for label in case.labels():
                if label.default():
                    def_m  = '"' + cname + '"'
                    defpos = str(i)
                    if self.at_module_scope:
                        def_d  = valueToString(label.value(),
                                               label.labelKind(), [])
                        m_def  = "_0_" + self.modname + "._m_" + uname + \
                                 "[" + defpos + "]"
                    else:
                        def_d  = valueToString(label.value(),
                                               label.labelKind(),
                                               self.currentScope)
                        m_def  = "_m_" + uname + "[" + defpos + "]"

                    m_un_l.append('(' + def_d + ', "' + cname + '", ' +\
                                  ctype + ')')
                else:
                    if self.at_module_scope:
                        slabel = valueToString(label.value(),
                                               label.labelKind(), [])
                    else:
                        slabel = valueToString(label.value(),
                                               label.labelKind(),
                                               self.currentScope)

                    m_to_d_l.append('"' + cname + '": ' + slabel)
                    d_to_m_l.append(slabel + ': "' + cname + '"')

                    m_un_l.append('(' + slabel + ', "' + cname + '", ' +\
                                  ctype + ')')

                    if self.at_module_scope:
                        d_map_l.append(slabel + ': ' + '_0_' + self.modname + \
                                       "._m_" + uname + "[" + str(i) + "]")
                    else:
                        d_map_l.append(slabel + ': ' + "_m_" + \
                                       uname + "[" + str(i) + "]")
                i = i + 1

        m_to_d = ", ".join(m_to_d_l)
        d_to_m = ", ".join(d_to_m_l)
        m_un   = ", ".join(m_un_l)
        d_map  = ", ".join(d_map_l)

        if self.at_module_scope:
            self.st.out(union_descriptor_at_module_scope,
                        uname   = uname,
                        m_to_d  = m_to_d,
                        d_to_m  = d_to_m,
                        def_m   = def_m,
                        def_d   = def_d,
                        m_un    = m_un,
                        stype   = stype,
                        defpos  = defpos,
                        m_def   = m_def,
                        d_map   = d_map,
                        modname = self.modname)
            
            self.st.out(union_register_at_module_scope,
                        uname   = uname,
                        modname = self.modname)
        else:
            self.st.out(union_descriptor,
                        uname   = uname,
                        m_to_d  = m_to_d,
                        d_to_m  = d_to_m,
                        def_m   = def_m,
                        def_d   = def_d,
                        m_un    = m_un,
                        stype   = stype,
                        defpos  = defpos,
                        m_def   = m_def,
                        d_map   = d_map,
                        scope   = dotName(fscopedName[:-1]))
            
            self.st.out(union_register, uname = uname)

    #
    # Forward union
    #
    def visitUnionForward(self, node):
        if self.handleImported(node): return

        uname = mangle(node.identifier())

        if self.at_module_scope:
            self.st.out(forward_union_descr_at_module_scope,
                        uname   = uname,
                        repoId  = node.repoId(),
                        modname = self.modname)
        else:
            self.st.out(forward_union_descr,
                        uname   = uname,
                        repoId  = node.repoId(),
                        modname = self.modname)

    #
    # Enum
    #
    def visitEnum(self, node):
        if self.handleImported(node): return

        ename = mangle(node.identifier())
        self.st.out(enum_start, ename = ename)

        i=0
        elist = []
        for item in node.enumerators():
            eval = str(i)

            if self.at_module_scope:
                self.st.out(enum_item_at_module_scope,
                            item    = item.identifier(),
                            eitem   = mangle(item.identifier()),
                            eval    = eval,
                            modname = self.modname)
            else:
                self.st.out(enum_item,
                            item    = item.identifier(),
                            eitem   = mangle(item.identifier()),
                            eval    = eval)

            if self.at_module_scope:
                elist.append(dotName(fixupScopedName(item.scopedName())))
            else:
                elist.append(mangle(item.identifier()))

            i = i + 1

        eitems = ", ".join(elist)

        if self.at_module_scope:
            self.st.out(enum_object_and_descriptor_at_module_scope,
                        ename   = ename,
                        repoId  = node.repoId(),
                        eitems  = eitems,
                        modname = self.modname)
        else:
            self.st.out(enum_object_and_descriptor,
                        ename   = ename,
                        repoId  = node.repoId(),
                        eitems  = eitems)

    def visitNative(self, node):
        if self.handleImported(node): return

        sys.stderr.write(main.cmdname + \
                         ": Warning: ignoring declaration of native " + \
                         node.identifier() + "\n")

    def visitValueForward(self, node):
        if self.handleImported(node): return

        vname = mangle(node.identifier())

        self.st.out(value_forward_at_module_scope,
                    vname=vname, repoId=node.repoId(), modname=self.modname)


    def visitValueBox(self, node):
        if self.handleImported(node): return

        boxname = mangle(node.identifier())
        boxdesc = typeToDescriptor(node.boxedType())

        self.st.out(valuebox, boxname=boxname, repoId=node.repoId(),
                    boxdesc=boxdesc, modname=self.modname)


    def visitValueAbs(self, node):
        if self.handleImported(node): return

        vname = mangle(node.identifier())

        fscopedName = fixupScopedName(node.scopedName(), "")
        scopedname  = dotName(fscopedName)

        if node.inherits():
            inheritl = []
            for i in node.inherits():
                i = i.fullDecl()
                inheritl.append(dotName(fixupScopedName(i.scopedName())))
            
            inherits = ", ".join(inheritl)
        else:
            inherits = "_0_CORBA.ValueBase"

        self.st.out(valueabs_class,
                    vname=vname, scopedname=scopedname, repoId=node.repoId(),
                    inherits=inherits, modname=self.modname)

        # Declarations within the value
        if len(node.declarations()) > 0:
            self.st.inc_indent()
            self.at_module_scope = 0
            self.currentScope.append(node.identifier())

            for d in node.declarations():
                d.accept(self)

            self.currentScope.pop()
            self.at_module_scope = 1
            self.st.dec_indent()
            self.st.out("")

        if hasattr(node, "_ami_gen"):
            # This is a poller valuetype generated for AMI, so
            # generate the implementation class

            self.st.out(ami_poller_impl,
                        vname = vname)

            for c in node.callables():
                if isinstance(c._ami_from, idlast.Declarator):
                    opname = "_" + c.identifier()
                else:
                    opname = c.identifier()

                self.st.out(ami_poller_op,
                            poller_opname = c.identifier(),
                            opname        = opname)

            self.st.out(ami_poller_register,
                        vname   = vname,
                        modname = self.modname,
                        ifname  = node._ami_from.identifier())


        basedesc = "_0_CORBA.tcInternal.tv_null"

        self.st.out(value_descriptor_at_module_scope,
                    vname=vname, modifier="_0_CORBA.VM_ABSTRACT",
                    tbaseids="None", basedesc=basedesc, mdescs="",
                    modname=self.modname)


    def visitValue(self, node):
        if self.handleImported(node): return

        vname = mangle(node.identifier())

        fscopedName = fixupScopedName(node.scopedName(), "")
        scopedname  = dotName(fscopedName)

        if node.inherits():
            inheritl = []
            for i in node.inherits():
                i = i.fullDecl()
                inheritl.append(dotName(fixupScopedName(i.scopedName())))
            
        else:
            inheritl = ["_0_CORBA.ValueBase"]

        skeleton_opl = []
        for i in node.supports():
            i = i.fullDecl()
            sn = fixupScopedName(i.scopedName())
            sn[0] = sn[0] + "__POA"
            dn = dotName(sn)
            inheritl.append(dn)
            skeleton_opl.append(dn)

        inherits = ", ".join(inheritl)

        # Go up the chain of inherited interfaces, picking out the
        # state members
        members = []
        ilist   = []
        cnode   = node
        
        while 1:
            cin = cnode.inherits()
            if not cin:
                break
            i = cin[0].fullDecl()
            if not isinstance(i, idlast.Value):
                break
            ilist.append(i)
            cnode = i

        ilist.reverse()
        ilist.append(node)
        
        for i in ilist:
            members.extend(i.statemembers())

        set_argl = []

        for i in range(len(members)):
            member = members[i]
            for d in member.declarators():
                set_argl.append("self.%s = args[%d]" %
                                (mangle(d.identifier()),i))

        if set_argl:
            set_args = "\n".join(set_argl)
        else:
            set_args = "pass"

        if len(set_argl) == 1:
            s = ""
        else:
            s = "s"

        self.st.out(value_class,
                    vname=vname, scopedname=scopedname, repoId=node.repoId(),
                    inherits=inherits, set_args=set_args, arglen=len(set_argl),
                    s=s, modname=self.modname)

        # Declarations within the value
        if len(node.declarations()) > 0:
            self.st.inc_indent()
            self.at_module_scope = 0
            self.currentScope.append(node.identifier())

            for d in node.declarations():
                d.accept(self)

            self.currentScope.pop()
            self.at_module_scope = 1
            self.st.dec_indent()
            self.st.out("")

        # Skeleton operation declarations if necessary
        if node.supports():
            self.st.out(skeleton_methodmap, methodmap="{}")
            for i in skeleton_opl:
                self.st.out(skeleton_inheritmap, inheritclass=i)

            self.st.out(skeleton_set_skel, ifid=vname)

        # Register factory if no callables or factories
        register_factory = 1

        if not all_factories:
            cnode = node
            while 1:
                if cnode.callables() or cnode.factories() or cnode.supports():
                    register_factory = 0
                    break
                cin = cnode.inherits()
                if not cin:
                    break
                for n in cin:
                    n = n.fullDecl()
                    if not isinstance(n, idlast.Value):
                        register_factory = 0
                        break
                cnode = cin[0].fullDecl()

        if register_factory:
            self.st.out(value_register_factory, vname=vname)
        
        # If value supports some interfaces, output an objref class for it
        if node.supports():
            inheritl = []
            for i in node.supports():
                i = i.fullDecl()
                sn = fixupScopedName(i.scopedName())
                inheritl.append(dotName(sn[:-1] + ["_objref_" + sn[-1]]))
            
            inherits = ", ".join(inheritl)

            self.st.out(objref_class, ifid=vname, inherits=inherits)

            for inclass in inheritl:
                self.st.out(objref_inherit_init, inclass=inclass)

            # registerObjRef()
            self.st.out(value_objref_register,
                        ifid=vname, modname=self.modname)

        # Modifier
        if node.custom():
            modifier = "_0_CORBA.VM_CUSTOM"
        elif node.truncatable():
            modifier = "_0_CORBA.VM_TRUNCATABLE"
        else:
            modifier = "_0_CORBA.VM_NONE"

        # Truncatable bases
        tbasel = []
        cnode  = node
        while 1:
            cin = cnode.inherits()
            if not cin:
                break
            i = cin[0]
            i = i.fullDecl()
            if not isinstance(i, idlast.Value):
                break
            if cnode.truncatable():
                sn = fixupScopedName(i.scopedName())
                tbasel.append(dotName(sn) + "._NP_RepositoryId")
            else:
                break
            cnode = i

        if tbasel:
            tbaseids = "(%s._NP_RepositoryId, %s)" % (vname, ", ".join(tbasel))
        else:
            tbaseids = "None"

        basedesc = None
        if node.inherits():
            i = node.inherits()[0].fullDecl()
            if isinstance(i, idlast.Value):
                sn = i.scopedName()[:]
                sn[-1] = "_d_" + sn[-1]
                basedesc = dotName(fixupScopedName(sn))

        if basedesc is None:
            basedesc = "_0_CORBA.tcInternal.tv_null"

        mlist = []
        for m in node.statemembers():
            for d in m.declarators():
                mlist.append('"%s"' % mangle(d.identifier()))
                mlist.append(typeAndDeclaratorToDescriptor(m.memberType(),
                                                           d, []))
                if m.memberAccess() == 1:
                    mlist.append("_0_CORBA.PRIVATE_MEMBER")
                else:
                    mlist.append("_0_CORBA.PUBLIC_MEMBER")
                    
        mdescs = ", ".join(mlist)
        self.st.out(value_descriptor_at_module_scope,
                    vname=vname, modifier=modifier, tbaseids=tbaseids,
                    basedesc=basedesc, mdescs=mdescs, modname=self.modname)



def docConst(node):
    if isinstance(node, idlast.Const)        and \
       node.constKind() == idltype.tk_string and \
       node.identifier()[-7:] == "__doc__":
        return node.identifier()[:-7]
    else:
        return None

def nodeId(node):
    if hasattr(node, "identifier"):
        return node.identifier()
    else:
        return None

def docWarning(node):
    sys.stderr.write(main.cmdname + \
                     ": Warning: Constant '" + node.identifier() + "' looks "
                     "like a Python docstring, but there is no declaration "
                     "named '" + node.identifier()[:-7] + "'.\n")
    
class DocstringVisitor (idlvisitor.AstVisitor):
    def __init__(self, st):
        self.docs = []
        self.st   = st

    def output(self):
        if self.docs:
            self.st.out("""\
#
# Docstrings
#
""")
        for nsn, dsn in self.docs:
            nsn = fixupScopedName(nsn)
            dsn = fixupScopedName(dsn)

            self.st.out("@node@.__doc__ = @doc@",
                        node=dotName(nsn), doc=dotName(dsn))
            
        if self.docs:
            self.st.out("")

    def visitAST(self, node):
        for n in node.declarations():
            if not output_inline and not n.mainFile(): continue
            
            d = docConst(n)
            if d:
                ok = 0
                for o in node.declarations():
                    if nodeId(o) == d:
                        self.docs.append((o.scopedName(), n.scopedName()))
                        if isinstance(o, idlast.Interface):
                            sn = o.scopedName()[:]
                            sn[-1] = "_objref_" + sn[-1]
                            self.docs.append((sn, n.scopedName()))
                        ok = 1
                        break
                if not ok:
                    docWarning(n)
            n.accept(self)

    def visitModule(self, node):
        for n in node.definitions():
            d = docConst(n)
            if d:
                if d == node.identifier():
                    self.docs.append((node.scopedName(), n.scopedName()))
                else:
                    ok = 0
                    for o in node.definitions():
                        if nodeId(o) == d:
                            self.docs.append((o.scopedName(), n.scopedName()))
                            if isinstance(o, idlast.Interface):
                                sn = o.scopedName()[:]
                                sn[-1] = "_objref_" + sn[-1]
                                self.docs.append((sn, n.scopedName()))
                            ok = 1
                            break
                    if not ok:
                        docWarning(n)
            n.accept(self)

    def visitInterface(self, node):
        for n in node.declarations():
            d = docConst(n)
            if d:
                if d == node.identifier():
                    self.docs.append((node.scopedName(), n.scopedName()))
                    sn = node.scopedName()[:]
                    sn[-1] = "_objref_" + sn[-1]
                    self.docs.append((sn, n.scopedName()))
                else:
                    ok = 0
                    for o in node.declarations():
                        if nodeId(o) == d:
                            self.docs.append((o.scopedName(), n.scopedName()))
                            ok = 1
                            break
                                
                    if ok:
                        continue

                    for o in node.callables():
                        self.target_id   = d
                        self.target_node = n
                        self.ok          = 0
                        o.accept(self)
                        if self.ok:
                            break
                    
                    if not self.ok:    
                        docWarning(n)

    def visitOperation(self, node):
        if node.identifier() == self.target_id:
            sn = node.scopedName() + ["im_func"]
            sn[-3] = "_objref_" + sn[-3]
            self.docs.append((sn, self.target_node.scopedName()))
            self.ok = 1

    def visitAttribute(self, node):
        for n in node.declarators():
            if n.identifier() == self.target_id:
                sn = n.scopedName() + ["im_func"]
                sn[-3] = "_objref_" + sn[-3]
                sn[-2] = "_get_"    + sn[-2]
                self.docs.append((sn, self.target_node.scopedName()))
                if not node.readonly():
                    sn = sn[:]
                    sn[-2] = "_set_" + n.identifier()
                    self.docs.append((sn, self.target_node.scopedName()))
                self.ok = 1


class ExampleVisitor (idlvisitor.AstVisitor, idlvisitor.TypeVisitor):
    def __init__(self, st):
        self.st = st
        self.first = None

    def visitAST(self, node):
        for n in node.declarations():
            if not output_inline and not n.mainFile(): continue

            if isinstance(n, idlast.Module) or isinstance(n, idlast.Interface):
                n.accept(self)

    def visitModule(self, node):
        for n in node.definitions():
            if not output_inline and not n.mainFile(): continue

            if isinstance(n, idlast.Module) or isinstance(n, idlast.Interface):
                n.accept(self)

    def visitInterface(self, node):
        ifname = mangle(node.identifier())
        sname  = node.scopedName()
        ccname = idlutil.ccolonName(sname)
        fsname = fixupScopedName(sname, prefix="")
        dname  = dotName(fsname)
        skname = skeletonModuleName(dname)

        if self.first is None:
            self.first = ifname

        if len(node.inherits()) == 1:
            inheritance_note = """
    # Note: this interface inherits from another interface. You must
    # either multiply inherit from the servant class implementing the
    # base interface, or explicitly implement the inherited operations
    # here.
    #
    # Inherited interface:
    #
"""
        elif node.inherits():
            inheritance_note = """
    # Note: this interface inherits from other interfaces. You must either
    # multiply inherit from the servant classes implementing the base
    # interfaces, or explicitly implement the inherited operations here.
    #
    # Inherited interfaces:
    #
"""
        else:
            inheritance_note = ""

        for inh in node.inherits():
            iname = idlutil.ccolonName(inh.fullDecl().scopedName())
            inheritance_note = inheritance_note + "    #   %s\n" % iname
        
        self.st.out(example_classdef, ifname=ifname,
                    ccname=ccname, skname=skname,
                    inheritance_note = inheritance_note)

        for c in node.callables():

            if isinstance(c, idlast.Attribute):

                c.attrType().accept(self)
                attrtype = self.__result_type

                for attr in c.identifiers():

                    signature = "attribute %s %s" % (attrtype, attr)

                    if c.readonly():
                        signature = "readonly " + signature

                    if not c.readonly():
                        self.st.out(example_opdef,
                                    signature = signature,
                                    opname = "_set_" + attr,
                                    args = ", value",
                                    returnspec = "None")

                    self.st.out(example_opdef,
                                signature = signature,
                                opname = "_get_" + attr,
                                args = "",
                                returnspec = "attribute value")
            else:
                # Operation
                innames  = []
                outnames = []
                siglist  = []

                c.returnType().accept(self)
                rettype = self.__result_type

                if c.returnType().kind() != idltype.tk_void:
                    outnames.append("result")

                for p in c.parameters():
                    if p.is_in():
                        innames.append(p.identifier())
                    if p.is_out():
                        outnames.append(p.identifier())

                    direction = {0:"in", 1:"out", 2:"inout"}[p.direction()]

                    p.paramType().accept(self)
                    siglist.append("%s %s %s" % (direction,
                                                 self.__result_type,
                                                 p.identifier()))

                signature = "%s %s(%s)" % (rettype, c.identifier(),
                                           ", ".join(siglist))

                if innames:
                    args = ", " + ", ".join(innames)
                else:
                    args = ""

                if outnames:
                    returnspec = ", ".join(outnames)
                else:
                    returnspec = "None"

                self.st.out(example_opdef,
                            signature = signature,
                            opname = c.identifier(),
                            args = args,
                            returnspec = returnspec)


    ttsMap = {
        idltype.tk_void:       "void",
        idltype.tk_short:      "short",
        idltype.tk_long:       "long",
        idltype.tk_ushort:     "unsigned short",
        idltype.tk_ulong:      "unsigned long",
        idltype.tk_float:      "float",
        idltype.tk_double:     "double",
        idltype.tk_boolean:    "boolean",
        idltype.tk_char:       "char",
        idltype.tk_octet:      "octet",
        idltype.tk_any:        "any",
        idltype.tk_TypeCode:   "CORBA::TypeCode",
        idltype.tk_Principal:  "CORBA::Principal",
        idltype.tk_longlong:   "long long",
        idltype.tk_ulonglong:  "unsigned long long",
        idltype.tk_longdouble: "long double",
        idltype.tk_wchar:      "wchar"
        }

    def visitBaseType(self, type):
        self.__result_type = self.ttsMap[type.kind()]

    def visitStringType(self, type):
        if type.bound() == 0:
            self.__result_type = "string"
        else:
            self.__result_type = "string<" + str(type.bound()) + ">"

    def visitWStringType(self, type):
        if type.bound() == 0:
            self.__result_type = "wstring"
        else:
            self.__result_type = "wstring<" + str(type.bound()) + ">"

    def visitDeclaredType(self, type):
        self.__result_type = idlutil.ccolonName(type.decl().scopedName())



def operationToDescriptors(op):
    """Return the descriptors for an operation.

    Returns a tuple containing strings of (in descriptor, out
    descriptor, exception map, context list, contains values)
    """

    indl  = []
    outdl = []
    cv    = 0

    if op.returnType() is not None and \
       op.returnType().kind() != idltype.tk_void:

        outdl.append(typeToDescriptor(op.returnType()))
        cv = idltype.containsValueType(op.returnType())

    # Make the lists of in and out parameters
    for p in op.parameters():

        if p.is_in():
            indl.append(typeToDescriptor(p.paramType()))
        if p.is_out():
            outdl.append(typeToDescriptor(p.paramType()))

        cv = cv or idltype.containsValueType(p.paramType())

    # Fudge single-item lists so that single item tuples work
    if len(indl)  == 1: indl.append("")
    if len(outdl) == 1: outdl.append("")

    inds = "(" + ", ".join(indl) + ")"
    if op.oneway():
        outds = "None"
    else:
        outds = "(" + ", ".join(outdl) + ")"

    # Exceptions
    excl = []

    for e in op.raises():
        sn = fixupScopedName(e.scopedName())
        ename = dotName(sn)
        edesc = dotName(sn[:-1] + [ "_d_" + sn[-1]])
        excl.append(ename + "._NP_RepositoryId: " + edesc)

    if len(excl) > 0:
        excs = "{" + ", ".join(excl) + "}"
    else:
        excs = "None"

    if op.contexts():
        ctxts = "[" + ", ".join(map(repr, op.contexts())) + "]"
    else:
        ctxts = None

    return inds, outds, excs, ctxts, cv



ttdMap = {
    idltype.tk_short:      "omniORB.tcInternal.tv_short",
    idltype.tk_long:       "omniORB.tcInternal.tv_long",
    idltype.tk_ushort:     "omniORB.tcInternal.tv_ushort",
    idltype.tk_ulong:      "omniORB.tcInternal.tv_ulong",
    idltype.tk_float:      "omniORB.tcInternal.tv_float",
    idltype.tk_double:     "omniORB.tcInternal.tv_double",
    idltype.tk_boolean:    "omniORB.tcInternal.tv_boolean",
    idltype.tk_char:       "omniORB.tcInternal.tv_char",
    idltype.tk_octet:      "omniORB.tcInternal.tv_octet",
    idltype.tk_any:        "omniORB.tcInternal.tv_any",
    idltype.tk_TypeCode:   "omniORB.tcInternal.tv_TypeCode",
    idltype.tk_Principal:  "omniORB.tcInternal.tv_Principal",
    idltype.tk_longlong:   "omniORB.tcInternal.tv_longlong",
    idltype.tk_ulonglong:  "omniORB.tcInternal.tv_ulonglong",
    idltype.tk_wchar:      "omniORB.tcInternal.tv_wchar"
}

unsupportedMap = {
    idltype.tk_longdouble: "long double",
}

def typeToDescriptor(tspec, from_scope=[], is_typedef=0):
    if hasattr(tspec, "python_desc"):
        return tspec.python_desc

    if tspec.kind() in ttdMap:
        tspec.python_desc = ttdMap[tspec.kind()]
        return tspec.python_desc

    if tspec.kind() in unsupportedMap:
        error_exit("omniORBpy does not support the %s type." %
                   unsupportedMap[tspec.kind()])

    if tspec.kind() == idltype.tk_string:
        ret = "(omniORB.tcInternal.tv_string," + str(tspec.bound()) + ")"

    elif tspec.kind() == idltype.tk_wstring:
        ret = "(omniORB.tcInternal.tv_wstring," + str(tspec.bound()) + ")"

    elif tspec.kind() == idltype.tk_sequence:
        ret = "(omniORB.tcInternal.tv_sequence, " + \
              typeToDescriptor(tspec.seqType(), from_scope) + \
              ", " + str(tspec.bound()) + ")"

    elif tspec.kind() == idltype.tk_fixed:
        ret = "(omniORB.tcInternal.tv_fixed, " + \
              str(tspec.digits()) + ", " + str(tspec.scale()) + ")"

    elif tspec.kind() == idltype.tk_alias:
        if is_typedef:
            return 'omniORB.typeCodeMapping["%s"]._d' % tspec.decl().repoId()
        else:
            return 'omniORB.typeMapping["%s"]' % tspec.decl().repoId()

    else:
        ret = 'omniORB.typeMapping["%s"]' % tspec.decl().repoId()

    tspec.python_desc = ret
    return ret


def typeAndDeclaratorToDescriptor(tspec, decl, from_scope, is_typedef=0):
    desc = typeToDescriptor(tspec, from_scope, is_typedef)

    if len(decl.sizes()) > 0:
        sizes = decl.sizes()[:]
        sizes.reverse()
        for size in sizes:
            desc = "(omniORB.tcInternal.tv_array, " + \
                   desc + ", " + str(size) + ")"
    return desc

def skeletonModuleName(mname):
    """Convert a scoped name string into the corresponding skeleton
module name. e.g. M1.M2.I -> M1__POA.M2.I"""
    l = mname.split(".")
    l[0] = l[0] + "__POA"
    return ".".join(l)

def dotName(scopedName, our_scope=[]):
    if scopedName[:len(our_scope)] == our_scope:
        l = [ mangle(s) for s in scopedName[len(our_scope):] ]
    else:
        l = [ mangle(s) for s in scopedName ]
    return ".".join(l)

def mangle(name):
    if keyword.iskeyword(name): return "_" + name

    # None is a pseudo-keyword that cannot be assigned to.
    if name == "None": return "_None"

    return name

def fixupScopedName(scopedName, prefix="_0_"):
    """Add a prefix and _GlobalIDL to the front of a ScopedName if necessary"""

    try:
        decl = idlast.findDecl([scopedName[0]])
    except idlast.DeclNotFound:
        decl = None

    if isinstance(decl, idlast.Module):
        scopedName = [prefix + mangle(scopedName[0])] + scopedName[1:]
    else:
        scopedName = [prefix + global_module] + scopedName

    return scopedName

def valueToString(val, kind, scope=[]):
    if kind == idltype.tk_enum:
        return dotName(fixupScopedName(val.scopedName()), scope)

    elif kind in [idltype.tk_string, idltype.tk_char]:
        return '"' + idlutil.escapifyString(val) + '"'

    elif kind == idltype.tk_wstring:
        return 'u"' + idlutil.escapifyWString(val) + '"'

    elif kind == idltype.tk_wchar:
        return 'u"' + idlutil.escapifyWString([val]) + '"'

    elif kind == idltype.tk_long and val == -2147483647 - 1:
        return "-2147483647 - 1"

    elif kind in [idltype.tk_float, idltype.tk_double, idltype.tk_longdouble]:
        return idlutil.reprFloat(val)

    elif kind == idltype.tk_fixed:
        return "CORBA.fixed('" + val + "')"

    else:
        return str(val)


try:
    __translate_table = str.maketrans(" -.,", "____")

except AttributeError:
    import string
    __translate_table = string.maketrans(" -.,", "____")

def outputFileName(idlname):
    return os.path.basename(idlname).translate(__translate_table)

def checkStubPackage(package):
    """Check the given package name for use as a stub directory

    Make sure all fragments of the package name are directories, or
    create them. Make __init__.py files in all directories."""

    if len(package) == 0:
        return

    if package[-1] == ".":
        package = package[:-1]

    path = ""
    for name in package.split("."):
        path = os.path.join(path, name)
        
        if os.path.exists(path):
            if not os.path.isdir(path):
                error_exit('Output error: "%s" exists and is not '
                           'a directory.' % path)
        else:
            try:
                os.mkdir(path)
            except:
                error_exit('Cannot create directory "%s".\n' % path)

        initfile = os.path.join(path, "__init__.py")

        if os.path.exists(initfile):
            if not os.path.isfile(initfile):
                error_exit('Output error: "%s" exists and is not a file.' %
                           initfile)
        else:
            try:
                open(initfile, "w").write("# omniORB stub directory\n")
            except:
                error_exit('Cannot create "%s".' % initfile)


def updateModules(modules, pymodule):
    """Create or update the Python modules corresponding to the IDL
    module names"""

    checkStubPackage(module_package)

    poamodules = [ skeletonModuleName(m) for m in modules ]

    real_updateModules(modules,    pymodule)
    real_updateModules(poamodules, pymodule)


def real_updateModules(modules, pymodule):

    for module in modules:
        modlist = module_package.split(".") + module.split(".")
        modpath = os.path.join(*modlist)
        modfile = os.path.join(modpath, "__init__.py")
        tmpfile = os.path.join(modpath, "new__init__.py")

        if not os.path.exists(modpath):
            try:
                os.makedirs(modpath)
            except:
                error_exit('Cannot create path "%s".' % modpath)

        # Make the __init__.py file if it does not already exist
        if not os.path.exists(modfile):
            try:
                f = open(modfile, "w")
            except:
                error_exit('Cannot create "%s".' % modfile)
            
            st = output.Stream(f, 4)

            st.out(pymodule_template, module=module, package=module_package)

            f.close()
            del f, st

        if not os.path.isfile(modfile):
            error_exit('Output error: "%s" exists but is not a file.' %
                       modfile)

        # Insert the import line for the current IDL file
        try:
            inf = open(modfile, "r")
        except:
            error_exit('Cannot open "%s" for reading.' % modfile)

        try:
            outf = open(tmpfile, "w")
        except:
            error_exit('Cannot open "%s" for writing.' % tmpfile)

        line = ""
        while line[:7] != "# ** 1.":
            line = inf.readline()
            if line == "":
                error_exit('Output error: "%s" ended before I found a '
                           '"# ** 1." tag.\n'
                           'Have you left behind some files from a '
                           'different Python ORB?' % modfile)
                
            outf.write(line)
            
        already    = 0
        outputline = "import " + pymodule + "\n"

        while line != "\n":
            line = inf.readline()
            if line == "":
                error_exit('Output error: "%s" ended while I was '
                           'looking at imports.' % modfile)

            if line != "\n":
                outf.write(line)
                if line == outputline:
                    already = 1

        if not already:
            outf.write(outputline)

        outf.write("\n")

        # Output the rest of the file
        while line != "":
            line = inf.readline()
            outf.write(line)

        inf.close()
        outf.close()

        try:
            os.remove(modfile)
        except:
            error_exit('Cannot remove "%s".' % modfile)
        try:
            os.rename(tmpfile, modfile)
        except:
            error_exit('Cannot rename "%s" to "%s".' % (tmpfile, modfile))

    # Go round again, importing sub-modules from their parent modules
    for module in modules:
        modlist = module.split(".")

        if len(modlist) == 1:
            continue

        modlist = module_package.split(".") + modlist
        submod  = modlist[-1]
        modpath = os.path.join(*modlist[:-1])
        modfile = os.path.join(modpath, "__init__.py")
        tmpfile = os.path.join(modpath, "new__init__.py")

        # Insert the import line for the sub-module
        try:
            inf = open(modfile, "r")
        except:
            error_exit('Cannot open "%s" for reading.' % modfile)

        try:
            outf = open(tmpfile, "w")
        except:
            error_exit('Cannot open "%s" for writing.' % tmpfile)

        line = ""
        while line[:7] != "# ** 2.":
            line = inf.readline()
            if line == "":
                error_exit('Output error: "%s" ended before I found a '
                           '"# ** 1." tag.\n'
                           'Have you left behind some files from a '
                           'different Python ORB?' % modfile)
                
            outf.write(line)
            
        already        = 0
        outputline     = "from . import " + submod + "\n"
        old_outputline = "import " + submod + "\n"

        while line != "\n":
            line = inf.readline()
            if line == "":
                error_exit('Output error: "%s" ended while I was '
                           'looking at imports.' % modfile)

            if line != "\n" and line != old_outputline:
                outf.write(line)
                if line == outputline:
                    already = 1

        if not already:
            outf.write(outputline)

        outf.write("\n")

        # Output the rest of the file
        while line != "":
            line = inf.readline()
            outf.write(line)

        inf.close()
        outf.close()

        try:
            os.remove(modfile)
        except:
            error_exit('Cannot remove "%s".' % modfile)
        try:
            os.rename(tmpfile, modfile)
        except:
            error_exit('Cannot rename "%s" to "%s".' % (tmpfile, modfile))
