Ejemplo n.º 1
0
def read_egg_metadata(path):
    """Return a dict representing egg metadata."""
    if os.path.isfile(path):
        pkg_info = read_pkg_info(path)
    else:
        pkginfo_path = os.path.join(path, 'PKG-INFO')
        pkg_info = read_pkg_info(pkginfo_path)

    return pkg_info
Ejemplo n.º 2
0
def copy_file(filename, destination):
    """Copy the file and put the correct tag"""

    print("Updating file %s" % filename)
    out_dir = os.path.abspath(destination)

    tags = filename[:-4].split("-")

    tags[-2] = tags[-2].replace("m", "")

    new_name = "-".join(tags) + ".whl"
    wheel_flag = "-".join(tags[2:])

    with InWheelCtx(os.path.join(destination, filename)) as ctx:
        info_fname = os.path.join(_dist_info_dir(ctx.path), 'WHEEL')
        infos = pkginfo.read_pkg_info(info_fname)
        print("Current Tags: ",
              ", ".join([v for k, v in infos.items() if k == "Tag"]))
        print("Adding Tag", wheel_flag)
        del infos['Tag']
        infos.add_header('Tag', wheel_flag)
        pkginfo.write_pkg_info(info_fname, infos)

        ctx.out_wheel = os.path.join(out_dir, new_name)

        print("Saving new wheel into %s" % ctx.out_wheel)
Ejemplo n.º 3
0
 def add_requirements(self, metadata_path):
     """Add additional requirements from setup.cfg to file metadata_path"""
     additional = list(self.setupcfg_requirements())
     if not additional: return
     pkg_info = read_pkg_info(metadata_path)
     if 'Provides-Extra' in pkg_info or 'Requires-Dist' in pkg_info:
         warnings.warn('setup.cfg requirements overwrite values from setup.py')
         del pkg_info['Provides-Extra']
         del pkg_info['Requires-Dist']
     for k, v in additional:
         pkg_info[k] = v
     write_pkg_info(metadata_path, pkg_info)
Ejemplo n.º 4
0
 def add_requirements(self, metadata_path):
     """Add additional requirements from setup.cfg to file metadata_path"""
     additional = list(self.setupcfg_requirements())
     if not additional: return
     pkg_info = read_pkg_info(metadata_path)
     if 'Provides-Extra' in pkg_info or 'Requires-Dist' in pkg_info:
         warnings.warn(
             'setup.cfg requirements overwrite values from setup.py')
         del pkg_info['Provides-Extra']
         del pkg_info['Requires-Dist']
     for k, v in additional:
         pkg_info[k] = v
     write_pkg_info(metadata_path, pkg_info)
Ejemplo n.º 5
0
def add_platforms(wheel_ctx, platforms):
    """Add platform tags `platforms` to a wheel

    Add any platform tags in `platforms` that are missing
    to wheel_ctx's filename and ``WHEEL`` file.

    Parameters
    ----------
    wheel_ctx : InWheelCtx
        An open wheel context
    platforms : iterable
        platform tags to add to wheel filename and WHEEL tags - e.g.
        ``('macosx_10_9_intel', 'macosx_10_9_x86_64')
    """
    info_fname = pjoin(_dist_info_dir(wheel_ctx.path), 'WHEEL')
    info = read_pkg_info(info_fname)
    if info['Root-Is-Purelib'] == 'true':
        raise WheelToolsError('Cannot add platforms to pure wheel')

    # Check what tags we have
    if wheel_ctx.out_wheel is None:
        in_wheel = wheel_ctx.in_wheel
    else:
        raise NotImplementedError()

    parsed_fname = WHEEL_INFO_RE(basename(in_wheel))
    in_fname_tags = parsed_fname.groupdict()['plat'].split('.')
    extra_fname_tags = [tag for tag in platforms if tag not in in_fname_tags]
    in_wheel_base, ext = splitext(basename(in_wheel))
    out_wheel_base = '.'.join([in_wheel_base] + list(extra_fname_tags))
    out_wheel = out_wheel_base + ext

    in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
    # Python version, C-API version combinations
    pyc_apis = ['-'.join(tag.split('-')[:2]) for tag in in_info_tags]
    # unique Python version, C-API version combinations
    pyc_apis = unique_by_index(pyc_apis)
    # Add new platform tags for each Python version, C-API combination
    required_tags = ['-'.join(tup) for tup in product(pyc_apis, platforms)]
    needs_write = False
    for req_tag in required_tags:
        if req_tag in in_info_tags:
            continue
        needs_write = True
        info.add_header('Tag', req_tag)
    if needs_write:
        write_pkg_info(info_fname, info)
        # Tell context manager to write wheel on exit by setting filename
        wheel_ctx.out_wheel = out_wheel
    return wheel_ctx.out_wheel
Ejemplo n.º 6
0
def add_platforms(wheel_ctx, platforms):
    """Add platform tags `platforms` to a wheel

    Add any platform tags in `platforms` that are missing
    to wheel_ctx's filename and ``WHEEL`` file.

    Parameters
    ----------
    wheel_ctx : InWheelCtx
        An open wheel context
    platforms : iterable
        platform tags to add to wheel filename and WHEEL tags - e.g.
        ``('macosx_10_9_intel', 'macosx_10_9_x86_64')
    """
    info_fname = pjoin(_dist_info_dir(wheel_ctx.path), 'WHEEL')
    info = read_pkg_info(info_fname)
    if info['Root-Is-Purelib'] == 'true':
        raise WheelToolsError('Cannot add platforms to pure wheel')

    # Check what tags we have
    if wheel_ctx.out_wheel is None:
        in_wheel = wheel_ctx.in_wheel
    else:
        raise NotImplementedError()

    parsed_fname = WHEEL_INFO_RE(basename(in_wheel))
    in_fname_tags = parsed_fname.groupdict()['plat'].split('.')
    extra_fname_tags = [tag for tag in platforms if tag not in in_fname_tags]
    in_wheel_base, ext = splitext(basename(in_wheel))
    out_wheel_base = '.'.join([in_wheel_base] + list(extra_fname_tags))
    out_wheel = out_wheel_base + ext

    in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
    # Python version, C-API version combinations
    pyc_apis = ['-'.join(tag.split('-')[:2]) for tag in in_info_tags]
    # unique Python version, C-API version combinations
    pyc_apis = unique_by_index(pyc_apis)
    # Add new platform tags for each Python version, C-API combination
    required_tags = ['-'.join(tup) for tup in product(pyc_apis, platforms)]
    needs_write = False
    for req_tag in required_tags:
        if req_tag in in_info_tags:
            continue
        needs_write = True
        info.add_header('Tag', req_tag)
    if needs_write:
        write_pkg_info(info_fname, info)
        # Tell context manager to write wheel on exit by setting filename
        wheel_ctx.out_wheel = out_wheel
    return wheel_ctx.out_wheel
Ejemplo n.º 7
0
def copy_file(filename):
    """Copy the file and put the correct tag"""

    print("Updating file %s" % filename)
    out_dir = os.path.abspath(DIRECTORY)

    tags = filename[:-4].split("-")

    tags[-2] = tags[-2].replace("m", "")

    new_name = "-".join(tags) + ".whl"
    wheel_flag = "-".join(tags[2:])

    with InWheelCtx(os.path.join(DIRECTORY, filename)) as ctx:
        info_fname = os.path.join(_dist_info_dir(ctx.path), 'WHEEL')
        infos = pkginfo.read_pkg_info(info_fname)
        print("Changing Tag %s to %s" % (infos["Tag"], wheel_flag))
        del infos['Tag']
        infos.add_header('Tag', wheel_flag)
        pkginfo.write_pkg_info(info_fname, infos)

        ctx.out_wheel = os.path.join(out_dir, new_name)

        print("Saving new wheel into %s" % ctx.out_wheel)
Ejemplo n.º 8
0
def copy_file(filename):
    """Copy the file and put the correct tag"""

    print("Updating file %s" % filename)
    out_dir = os.path.abspath(DIRECTORY)

    tags = filename[:-4].split("-")

    tags[-2] = tags[-2].replace("m", "")

    new_name = "-".join(tags) + ".whl"
    wheel_flag = "-".join(tags[2:])

    with InWheelCtx(os.path.join(DIRECTORY, filename)) as ctx:
        info_fname = os.path.join(_dist_info_dir(ctx.path), 'WHEEL')
        infos = pkginfo.read_pkg_info(info_fname)
        print("Changing Tag %s to %s" % (infos["Tag"], wheel_flag))
        del infos['Tag']
        infos.add_header('Tag', wheel_flag)
        pkginfo.write_pkg_info(info_fname, infos)

        ctx.out_wheel = os.path.join(out_dir, new_name)

        print("Saving new wheel into %s" % ctx.out_wheel)
Ejemplo n.º 9
0
def _convert_to_generic_platform_wheel(wheel_ctx, py2_py3,
                                       additional_platforms):
    """Switch to generic python tags and remove ABI tags from a wheel

    Convert implementation specific python tags to their generic equivalent and
    remove all ABI tags from wheel_ctx's filename and ``WHEEL`` file.

    Parameters
    ----------
    wheel_ctx : InWheelCtx
        An open wheel context
    py2_py3: Bool
        Wether the pyver tag shall be py2.py3 or just the one inferred from the wheel name
    additional_platforms : Optional[Iterable[str]]
        An optional iterable of additional platform to add to the wheel
    """

    abi_tags = ['none']

    wf = WheelFile(wheel_ctx.in_wheel)
    info_fname = _get_wheelinfo_name(wf)
    info = read_pkg_info(info_fname)

    # Check what tags we have
    if wheel_ctx.out_wheel is not None:
        out_dir = dirname(wheel_ctx.out_wheel)
        wheel_fname = basename(wheel_ctx.out_wheel)
    else:
        out_dir = '.'
        wheel_fname = basename(wheel_ctx.in_wheel)

    # Update wheel filename
    fparts = wf.parsed_filename.groupdict()
    platform_tags = fparts['plat'].split('.')
    logger.debug('Previous platform tags: %s', ', '.join(platform_tags))
    if additional_platforms:
        platform_tags = list(
            sorted(set(platform_tags + [p for p in additional_platforms])))
        fparts['plat'] = '.'.join(platform_tags)
        logger.debug('New platform tags ....: %s', ', '.join(platform_tags))
    else:
        logger.debug('No platform tags change needed.')

    original_abi_tags = fparts['abi'].split('.')
    logger.debug('Previous ABI tags: %s', ', '.join(original_abi_tags))
    if abi_tags != original_abi_tags:
        logger.debug('New ABI tags ....: %s', ', '.join(abi_tags))
        fparts['abi'] = '.'.join(abi_tags)
    else:
        logger.debug('No ABI tags change needed.')

    original_pyver_tags = fparts['pyver'].split('.')
    logger.debug('Previous pyver tags: %s', ', '.join(original_pyver_tags))
    pyver_tags = _to_generic_pyver(original_pyver_tags)
    if py2_py3:
        if len({"py2", "py3"} & set(pyver_tags)) == 0:
            raise ValueError("pyver_tags does not contain py2 nor py3")
        pyver_tags = list(sorted(set(pyver_tags + ["py2", "py3"])))
    if pyver_tags != original_pyver_tags:
        logger.debug('New pyver tags ....: %s', ', '.join(pyver_tags))
        fparts['pyver'] = '.'.join(pyver_tags)
    else:
        logger.debug('No pyver change needed.')

    _, ext = splitext(wheel_fname)
    fparts['ext'] = ext
    out_wheel_fname = "{namever}-{pyver}-{abi}-{plat}{ext}".format(**fparts)

    logger.info('Previous filename: %s', wheel_fname)
    if out_wheel_fname != wheel_fname:
        logger.info('New filename ....: %s', out_wheel_fname)
    else:
        logger.info('No filename change needed.')

    out_wheel = pjoin(out_dir, out_wheel_fname)

    # Update wheel tags
    in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
    logger.info('Previous WHEEL info tags: %s', ', '.join(in_info_tags))

    # Python version, C-API version combinations
    pyc_apis = []
    for py_ver in pyver_tags:
        abi = 'none'
        pyc_apis.append('-'.join([py_ver, abi]))
    # unique Python version, C-API version combinations
    pyc_apis = unique_by_index(pyc_apis)

    # Set tags for each Python version, C-API combination
    updated_tags = ['-'.join(tup) for tup in product(pyc_apis, platform_tags)]

    if updated_tags != in_info_tags:
        del info['Tag']
        for tag in updated_tags:
            info.add_header('Tag', tag)

        logger.info('New WHEEL info tags ....: %s',
                    ', '.join(info.get_all('Tag')))
        write_pkg_info(info_fname, info)
    else:
        logger.info('No WHEEL info change needed.')
    return out_wheel
Ejemplo n.º 10
0
def add_platforms(wheel_ctx, platforms, remove_platforms=()):
    """Add platform tags `platforms` to a wheel

    Add any platform tags in `platforms` that are missing
    to wheel_ctx's filename and ``WHEEL`` file.

    Parameters
    ----------
    wheel_ctx : InWheelCtx
        An open wheel context
    platforms : iterable
        platform tags to add to wheel filename and WHEEL tags - e.g.
        ``('macosx_10_9_intel', 'macosx_10_9_x86_64')
    remove_platforms : iterable
        platform tags to remove to the wheel filename and WHEEL tags, e.g.
        ``('linux_x86_64',)`` when ``('manylinux_x86_64')`` is added
    """
    definitely_not_purelib = False

    info_fname = pjoin(_dist_info_dir(wheel_ctx.path), 'WHEEL')
    info = read_pkg_info(info_fname)
    # Check what tags we have
    if wheel_ctx.out_wheel is not None:
        out_dir = dirname(wheel_ctx.out_wheel)
        wheel_fname = basename(wheel_ctx.out_wheel)
    else:
        out_dir = '.'
        wheel_fname = basename(wheel_ctx.in_wheel)

    parsed_fname = WHEEL_INFO_RE(wheel_fname)
    fparts = parsed_fname.groupdict()
    original_fname_tags = fparts['plat'].split('.')
    logger.info('Previous filename tags: %s', ', '.join(original_fname_tags))
    fname_tags = {
        tag
        for tag in original_fname_tags if tag not in remove_platforms
    }
    fname_tags |= set(platforms)

    # Can't be 'any' and another platform
    if 'any' in fname_tags and len(fname_tags) > 1:
        fname_tags.remove('any')
        remove_platforms.append('any')
        definitely_not_purelib = True

    if fname_tags != original_fname_tags:
        logger.info('New filename tags: %s', ', '.join(fname_tags))
    else:
        logger.info('No filename tags change needed.')

    _, ext = splitext(wheel_fname)
    fparts['plat'] = '.'.join(fname_tags)
    fparts['ext'] = ext
    out_wheel_fname = "{namever}-{pyver}-{abi}-{plat}{ext}".format(**fparts)
    out_wheel = pjoin(out_dir, out_wheel_fname)

    in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
    logger.info('Previous WHEEL info tags: %s', ', '.join(in_info_tags))
    # Python version, C-API version combinations
    pyc_apis = ['-'.join(tag.split('-')[:2]) for tag in in_info_tags]
    # unique Python version, C-API version combinations
    pyc_apis = unique_by_index(pyc_apis)
    # Add new platform tags for each Python version, C-API combination
    wanted_tags = ['-'.join(tup) for tup in product(pyc_apis, platforms)]
    new_tags = [tag for tag in wanted_tags if tag not in in_info_tags]
    unwanted_tags = [
        '-'.join(tup) for tup in product(pyc_apis, remove_platforms)
    ]
    updated_tags = [tag for tag in in_info_tags if tag not in unwanted_tags]
    updated_tags += new_tags
    if updated_tags != in_info_tags:
        del info['Tag']
        for tag in updated_tags:
            info.add_header('Tag', tag)

        if definitely_not_purelib:
            info['Root-Is-Purelib'] = 'False'
            logger.info('Changed wheel type to Platlib')

        logger.info('New WHEEL info tags: %s', ', '.join(info.get_all('Tag')))
        write_pkg_info(info_fname, info)
    else:
        logger.info('No WHEEL info change needed.')
    return out_wheel
Ejemplo n.º 11
0
def add_platforms(wheel_ctx, platforms, remove_platforms=()):
    """Add platform tags `platforms` to a wheel

    Add any platform tags in `platforms` that are missing
    to wheel_ctx's filename and ``WHEEL`` file.

    Parameters
    ----------
    wheel_ctx : InWheelCtx
        An open wheel context
    platforms : iterable
        platform tags to add to wheel filename and WHEEL tags - e.g.
        ``('macosx_10_9_intel', 'macosx_10_9_x86_64')
    remove_platforms : iterable
        platform tags to remove to the wheel filename and WHEEL tags, e.g.
        ``('linux_x86_64',)`` when ``('manylinux_x86_64')`` is added
    """
    info_fname = pjoin(_dist_info_dir(wheel_ctx.path), 'WHEEL')
    info = read_pkg_info(info_fname)
    if info['Root-Is-Purelib'] == 'true':
        print('No need to add platforms to pure wheel - Skipping {}'.format(wheel_ctx.in_wheel))
        return

    # Check what tags we have
    if wheel_ctx.out_wheel is not None:
        out_dir = dirname(wheel_ctx.out_wheel)
        wheel_fname = basename(wheel_ctx.out_wheel)
    else:
        out_dir = '.'
        wheel_fname = basename(wheel_ctx.in_wheel)

    parsed_fname = WHEEL_INFO_RE(wheel_fname)
    fparts = parsed_fname.groupdict()
    original_fname_tags = fparts['plat'].split('.')
    print('Previous filename tags:', ', '.join(original_fname_tags))
    fname_tags = [tag for tag in original_fname_tags
                  if tag not in remove_platforms]
    for platform in platforms:
        if platform not in fname_tags:
            fname_tags.append(platform)
    if fname_tags != original_fname_tags:
        print('New filename tags:', ', '.join(fname_tags))
    else:
        print('No filename tags change needed.')

    wheel_base, ext = splitext(wheel_fname)
    fparts['plat'] = '.'.join(fname_tags)
    fparts['ext'] = ext
    out_wheel_fname = "{namever}-{pyver}-{abi}-{plat}{ext}".format(**fparts)
    out_wheel = pjoin(out_dir, out_wheel_fname)

    in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
    print('Previous WHEEL info tags:', ', '.join(in_info_tags))
    # Python version, C-API version combinations
    pyc_apis = ['-'.join(tag.split('-')[:2]) for tag in in_info_tags]
    # unique Python version, C-API version combinations
    pyc_apis = unique_by_index(pyc_apis)
    # Add new platform tags for each Python version, C-API combination
    wanted_tags = ['-'.join(tup) for tup in product(pyc_apis, platforms)]
    new_tags = [tag for tag in wanted_tags if tag not in in_info_tags]
    unwanted_tags = ['-'.join(tup)
                     for tup in product(pyc_apis, remove_platforms)]
    updated_tags = [tag for tag in in_info_tags if tag not in unwanted_tags]
    updated_tags += new_tags
    needs_write = updated_tags != in_info_tags
    if needs_write:
        del info['Tag']
        for tag in updated_tags:
            info.add_header('Tag', tag)
        print('New WHEEL info tags:', ', '.join(info.get_all('Tag')))
        write_pkg_info(info_fname, info)
    else:
        print('No WHEEL info change needed.')
    return out_wheel
def _convert_to_generic_platform_wheel(wheel_ctx):
    """Switch to generic python tags and remove ABI tags from a wheel

    Convert implementation specific python tags to their generic equivalent and
    remove all ABI tags from wheel_ctx's filename and ``WHEEL`` file.

    Parameters
    ----------
    wheel_ctx : InWheelCtx
        An open wheel context
    """

    abi_tags = ['none']

    wf = WheelFile(wheel_ctx.in_wheel)
    info_fname = _get_wheelinfo_name(wf)
    info = read_pkg_info(info_fname)

    # Check what tags we have
    if wheel_ctx.out_wheel is not None:
        out_dir = dirname(wheel_ctx.out_wheel)
        wheel_fname = basename(wheel_ctx.out_wheel)
    else:
        out_dir = '.'
        wheel_fname = basename(wheel_ctx.in_wheel)

    # Update wheel filename
    fparts = wf.parsed_filename.groupdict()
    original_platform_tags = fparts['plat'].split('.')

    original_abi_tags = fparts['abi'].split('.')
    logger.debug('Previous ABI tags: %s', ', '.join(original_abi_tags))
    if abi_tags != original_abi_tags:
        logger.debug('New ABI tags ....: %s', ', '.join(abi_tags))
        fparts['abi'] = '.'.join(abi_tags)
    else:
        logger.debug('No ABI tags change needed.')

    original_pyver_tags = fparts['pyver'].split('.')
    logger.debug('Previous pyver tags: %s', ', '.join(original_pyver_tags))
    pyver_tags = _to_generic_pyver(original_pyver_tags)
    if pyver_tags != original_pyver_tags:
        logger.debug('New pyver tags ....: %s', ', '.join(pyver_tags))
        fparts['pyver'] = '.'.join(pyver_tags)
    else:
        logger.debug('No pyver change needed.')

    _, ext = splitext(wheel_fname)
    fparts['ext'] = ext
    out_wheel_fname = "{namever}-{pyver}-{abi}-{plat}{ext}".format(**fparts)

    logger.info('Previous filename: %s', wheel_fname)
    if out_wheel_fname != wheel_fname:
        logger.info('New filename ....: %s', out_wheel_fname)
    else:
        logger.info('No filename change needed.')

    out_wheel = pjoin(out_dir, out_wheel_fname)

    # Update wheel tags
    in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
    logger.info('Previous WHEEL info tags: %s', ', '.join(in_info_tags))

    # Python version, C-API version combinations
    pyc_apis = []
    for tag in in_info_tags:
        py_ver = '.'.join(_to_generic_pyver(tag.split('-')[0].split('.')))
        abi = 'none'
        pyc_apis.append('-'.join([py_ver, abi]))
    # unique Python version, C-API version combinations
    pyc_apis = unique_by_index(pyc_apis)

    # Set tags for each Python version, C-API combination
    updated_tags = ['-'.join(tup) for tup in product(pyc_apis, original_platform_tags)]

    if updated_tags != in_info_tags:
        del info['Tag']
        for tag in updated_tags:
            info.add_header('Tag', tag)

        logger.info('New WHEEL info tags ....: %s', ', '.join(info.get_all('Tag')))
        write_pkg_info(info_fname, info)
    else:
        logger.info('No WHEEL info change needed.')
    return out_wheel
Ejemplo n.º 13
0
def add_platforms(in_wheel, platforms, out_path=None, clobber=False):
    """ Add platform tags `platforms` to `in_wheel` filename and WHEEL tags

    Add any platform tags in `platforms` that are missing from `in_wheel`
    filename.

    Add any platform tags in `platforms` that are missing from `in_wheel`
    ``WHEEL`` file.

    Parameters
    ----------
    in_wheel : str
        Filename of wheel to which to add platform tags
    platforms : iterable
        platform tags to add to wheel filename and WHEEL tags - e.g.
        ``('macosx_10_9_intel', 'macosx_10_9_x86_64')
    out_path : None or str, optional
        Directory to which to write new wheel.  Default is directory containing
        `in_wheel`
    clobber : bool, optional
        If True, overwrite existing output filename, otherwise raise error

    Returns
    -------
    out_wheel : None or str
        Absolute path of wheel file written, or None if no wheel file written.
    """
    in_wheel = abspath(in_wheel)
    out_path = dirname(in_wheel) if out_path is None else abspath(out_path)
    wf = WheelFile(in_wheel)
    info_fname = _get_wheelinfo_name(wf)
    # Check what tags we have
    in_fname_tags = wf.parsed_filename.groupdict()['plat'].split('.')
    extra_fname_tags = [tag for tag in platforms if tag not in in_fname_tags]
    in_wheel_base, ext = splitext(basename(in_wheel))
    out_wheel_base = '.'.join([in_wheel_base] + list(extra_fname_tags))
    out_wheel = pjoin(out_path, out_wheel_base + ext)
    if exists(out_wheel) and not clobber:
        raise WheelToolsError('Not overwriting {0}; set clobber=True '
                              'to overwrite'.format(out_wheel))
    with InWheelCtx(in_wheel) as ctx:
        info = read_pkg_info(info_fname)
        if info['Root-Is-Purelib'] == 'true':
            raise WheelToolsError('Cannot add platforms to pure wheel')
        in_info_tags = [tag for name, tag in info.items() if name == 'Tag']
        # Python version, C-API version combinations
        pyc_apis = ['-'.join(tag.split('-')[:2]) for tag in in_info_tags]
        # unique Python version, C-API version combinations
        pyc_apis = unique_by_index(pyc_apis)
        # Add new platform tags for each Python version, C-API combination
        required_tags = ['-'.join(tup) for tup in product(pyc_apis, platforms)]
        needs_write = False
        for req_tag in required_tags:
            if req_tag in in_info_tags:
                continue
            needs_write = True
            info.add_header('Tag', req_tag)
        if needs_write:
            write_pkg_info(info_fname, info)
            # Tell context manager to write wheel on exit by setting filename
            ctx.out_wheel = out_wheel
    return ctx.out_wheel