

def add_cswrapper(filename, outfilename=None):

    from fmpy import read_model_description, extract, sharedLibraryExtension, platform, __version__
    from lxml import etree
    import os
    from shutil import copyfile, rmtree

    if outfilename is None:
        outfilename = filename

    model_description = read_model_description(filename)

    if model_description.fmiVersion != '2.0':
        raise Exception("%s is not an FMI 2.0 FMU." % filename)

    if model_description.modelExchange is None:
        raise Exception("%s does not support Model Exchange." % filename)

    unzipdir = extract(filename)

    xml = os.path.join(unzipdir, 'modelDescription.xml')

    tree = etree.parse(xml)

    root = tree.getroot()

    # update description
    generation_tool = root.attrib.get('generationTool', 'Unknown') + " with FMPy %s Co-Simulation wrapper" % __version__
    root.attrib['generationTool'] = generation_tool

    # remove any existing <CoSimulation> element
    for e in root.findall('CoSimulation'):
        root.remove(e)

    for i, child in enumerate(root):
        if child.tag == 'ModelExchange':
            break

    model_identifier = '%s_%s_%s' % (model_description.modelExchange.modelIdentifier,
                                     model_description.numberOfContinuousStates,
                                     model_description.numberOfEventIndicators)

    e = etree.Element("CoSimulation")
    e.attrib['modelIdentifier'] = model_identifier
    root.insert(i + 1, e)

    tree.write(xml, pretty_print=True, encoding='utf-8')

    shared_library = os.path.join(os.path.dirname(__file__), 'cswrapper' + sharedLibraryExtension)
    license_file = os.path.join(os.path.dirname(__file__), 'license.txt')

    licenses_dir = os.path.join(unzipdir, 'documentation', 'licenses')

    if not os.path.isdir(licenses_dir):
        os.mkdir(licenses_dir)

    copyfile(src=shared_library, dst=os.path.join(unzipdir, 'binaries', platform, model_identifier + sharedLibraryExtension))
    copyfile(license_file, os.path.join(unzipdir, 'documentation', 'licenses', 'fmpy-cswrapper.txt'))

    create_zip_archive(outfilename, unzipdir)

    rmtree(unzipdir, ignore_errors=True)


def create_zip_archive(filename, source_dir):

    import zipfile
    import os

    with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zf:
        base_path = os.path.normpath(source_dir)
        for dirpath, dirnames, filenames in os.walk(source_dir):
            for name in sorted(dirnames):
                path = os.path.normpath(os.path.join(dirpath, name))
                zf.write(path, os.path.relpath(path, base_path))
            for name in filenames:
                path = os.path.normpath(os.path.join(dirpath, name))
                if os.path.isfile(path):
                    zf.write(path, os.path.relpath(path, base_path))

[((13, 24, 13, 56), 'fmpy.read_model_description', 'read_model_description', ({(13, 47, 13, 55): 'filename'}, {}), '(filename)', False, 'from fmpy import read_model_description, extract, sharedLibraryExtension, platform, __version__\n'), ((21, 15, 21, 32), 'fmpy.extract', 'extract', ({(21, 23, 21, 31): 'filename'}, {}), '(filename)', False, 'from fmpy import read_model_description, extract, sharedLibraryExtension, platform, __version__\n'), ((23, 10, 23, 56), 'os.path.join', 'os.path.join', ({(23, 23, 23, 31): 'unzipdir', (23, 33, 23, 55): '"""modelDescription.xml"""'}, {}), "(unzipdir, 'modelDescription.xml')", False, 'import os\n'), ((25, 11, 25, 27), 'lxml.etree.parse', 'etree.parse', ({(25, 23, 25, 26): 'xml'}, {}), '(xml)', False, 'from lxml import etree\n'), ((45, 8, 45, 37), 'lxml.etree.Element', 'etree.Element', ({(45, 22, 45, 36): '"""CoSimulation"""'}, {}), "('CoSimulation')", False, 'from lxml import etree\n'), ((54, 19, 54, 70), 'os.path.join', 'os.path.join', ({(54, 32, 54, 40): 'unzipdir', (54, 42, 54, 57): '"""documentation"""', (54, 59, 54, 69): '"""licenses"""'}, {}), "(unzipdir, 'documentation', 'licenses')", False, 'import os\n'), ((64, 4, 64, 40), 'shutil.rmtree', 'rmtree', (), '', False, 'from shutil import copyfile, rmtree\n'), ((51, 34, 51, 59), 'os.path.dirname', 'os.path.dirname', ({(51, 50, 51, 58): '__file__'}, {}), '(__file__)', False, 'import os\n'), ((52, 32, 52, 57), 'os.path.dirname', 'os.path.dirname', ({(52, 48, 52, 56): '__file__'}, {}), '(__file__)', False, 'import os\n'), ((56, 11, 56, 38), 'os.path.isdir', 'os.path.isdir', ({(56, 25, 56, 37): 'licenses_dir'}, {}), '(licenses_dir)', False, 'import os\n'), ((57, 8, 57, 30), 'os.mkdir', 'os.mkdir', ({(57, 17, 57, 29): 'licenses_dir'}, {}), '(licenses_dir)', False, 'import os\n'), ((60, 27, 60, 100), 'os.path.join', 'os.path.join', ({(60, 40, 60, 48): 'unzipdir', (60, 50, 60, 65): '"""documentation"""', (60, 67, 60, 77): '"""licenses"""', (60, 79, 60, 99): '"""fmpy-cswrapper.txt"""'}, {}), "(unzipdir, 'documentation', 'licenses', 'fmpy-cswrapper.txt')", False, 'import os\n'), ((72, 9, 72, 61), 'zipfile.ZipFile', 'zipfile.ZipFile', ({(72, 25, 72, 33): 'filename', (72, 35, 72, 38): '"""w"""', (72, 40, 72, 60): 'zipfile.ZIP_DEFLATED'}, {}), "(filename, 'w', zipfile.ZIP_DEFLATED)", False, 'import zipfile\n'), ((73, 20, 73, 48), 'os.path.normpath', 'os.path.normpath', ({(73, 37, 73, 47): 'source_dir'}, {}), '(source_dir)', False, 'import os\n'), ((74, 44, 74, 63), 'os.walk', 'os.walk', ({(74, 52, 74, 62): 'source_dir'}, {}), '(source_dir)', False, 'import os\n'), ((59, 37, 59, 124), 'os.path.join', 'os.path.join', ({(59, 50, 59, 58): 'unzipdir', (59, 60, 59, 70): '"""binaries"""', (59, 72, 59, 80): 'platform', (59, 82, 59, 123): '(model_identifier + sharedLibraryExtension)'}, {}), "(unzipdir, 'binaries', platform, model_identifier +\n    sharedLibraryExtension)", False, 'import os\n'), ((80, 19, 80, 39), 'os.path.isfile', 'os.path.isfile', ({(80, 34, 80, 38): 'path'}, {}), '(path)', False, 'import os\n'), ((76, 40, 76, 67), 'os.path.join', 'os.path.join', ({(76, 53, 76, 60): 'dirpath', (76, 62, 76, 66): 'name'}, {}), '(dirpath, name)', False, 'import os\n'), ((77, 31, 77, 63), 'os.path.relpath', 'os.path.relpath', ({(77, 47, 77, 51): 'path', (77, 53, 77, 62): 'base_path'}, {}), '(path, base_path)', False, 'import os\n'), ((79, 40, 79, 67), 'os.path.join', 'os.path.join', ({(79, 53, 79, 60): 'dirpath', (79, 62, 79, 66): 'name'}, {}), '(dirpath, name)', False, 'import os\n'), ((81, 35, 81, 67), 'os.path.relpath', 'os.path.relpath', ({(81, 51, 81, 55): 'path', (81, 57, 81, 66): 'base_path'}, {}), '(path, base_path)', False, 'import os\n')]