

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))

[((316, 348), 'fmpy.read_model_description', 'read_model_description', (['filename'], {}), '(filename)\n', (338, 348), False, 'from fmpy import read_model_description, extract, sharedLibraryExtension, platform, __version__\n'), ((599, 616), 'fmpy.extract', 'extract', (['filename'], {}), '(filename)\n', (606, 616), False, 'from fmpy import read_model_description, extract, sharedLibraryExtension, platform, __version__\n'), ((628, 674), 'os.path.join', 'os.path.join', (['unzipdir', '"""modelDescription.xml"""'], {}), "(unzipdir, 'modelDescription.xml')\n", (640, 674), False, 'import os\n'), ((687, 703), 'lxml.etree.parse', 'etree.parse', (['xml'], {}), '(xml)\n', (698, 703), False, 'from lxml import etree\n'), ((1400, 1429), 'lxml.etree.Element', 'etree.Element', (['"""CoSimulation"""'], {}), "('CoSimulation')\n", (1413, 1429), False, 'from lxml import etree\n'), ((1759, 1810), 'os.path.join', 'os.path.join', (['unzipdir', '"""documentation"""', '"""licenses"""'], {}), "(unzipdir, 'documentation', 'licenses')\n", (1771, 1810), False, 'import os\n'), ((2164, 2200), 'shutil.rmtree', 'rmtree', (['unzipdir'], {'ignore_errors': '(True)'}), '(unzipdir, ignore_errors=True)\n', (2170, 2200), False, 'from shutil import copyfile, rmtree\n'), ((1600, 1625), 'os.path.dirname', 'os.path.dirname', (['__file__'], {}), '(__file__)\n', (1615, 1625), False, 'import os\n'), ((1697, 1722), 'os.path.dirname', 'os.path.dirname', (['__file__'], {}), '(__file__)\n', (1712, 1722), False, 'import os\n'), ((1823, 1850), 'os.path.isdir', 'os.path.isdir', (['licenses_dir'], {}), '(licenses_dir)\n', (1836, 1850), False, 'import os\n'), ((1860, 1882), 'os.mkdir', 'os.mkdir', (['licenses_dir'], {}), '(licenses_dir)\n', (1868, 1882), False, 'import os\n'), ((2037, 2110), 'os.path.join', 'os.path.join', (['unzipdir', '"""documentation"""', '"""licenses"""', '"""fmpy-cswrapper.txt"""'], {}), "(unzipdir, 'documentation', 'licenses', 'fmpy-cswrapper.txt')\n", (2049, 2110), False, 'import os\n'), ((2293, 2345), 'zipfile.ZipFile', 'zipfile.ZipFile', (['filename', '"""w"""', 'zipfile.ZIP_DEFLATED'], {}), "(filename, 'w', zipfile.ZIP_DEFLATED)\n", (2308, 2345), False, 'import zipfile\n'), ((2373, 2401), 'os.path.normpath', 'os.path.normpath', (['source_dir'], {}), '(source_dir)\n', (2389, 2401), False, 'import os\n'), ((2446, 2465), 'os.walk', 'os.walk', (['source_dir'], {}), '(source_dir)\n', (2453, 2465), False, 'import os\n'), ((1921, 2012), 'os.path.join', 'os.path.join', (['unzipdir', '"""binaries"""', 'platform', '(model_identifier + sharedLibraryExtension)'], {}), "(unzipdir, 'binaries', platform, model_identifier +\n    sharedLibraryExtension)\n", (1933, 2012), False, 'import os\n'), ((2766, 2786), 'os.path.isfile', 'os.path.isfile', (['path'], {}), '(path)\n', (2780, 2786), False, 'import os\n'), ((2549, 2576), 'os.path.join', 'os.path.join', (['dirpath', 'name'], {}), '(dirpath, name)\n', (2561, 2576), False, 'import os\n'), ((2609, 2641), 'os.path.relpath', 'os.path.relpath', (['path', 'base_path'], {}), '(path, base_path)\n', (2624, 2641), False, 'import os\n'), ((2718, 2745), 'os.path.join', 'os.path.join', (['dirpath', 'name'], {}), '(dirpath, name)\n', (2730, 2745), False, 'import os\n'), ((2823, 2855), 'os.path.relpath', 'os.path.relpath', (['path', 'base_path'], {}), '(path, base_path)\n', (2838, 2855), False, 'import os\n')]