Source code for guitarpro.io

import os
from typing import Optional

from .iobase import GPFileBase
from .gp3 import GP3File
from .gp4 import GP4File
from .gp5 import GP5File
from .models import GPException, Song

__all__ = ('parse', 'write')

_GPFILES = {
    'FICHIER GUITAR PRO v3.00': ((3, 0, 0), GP3File),

    'FICHIER GUITAR PRO v4.00': ((4, 0, 0), GP4File),
    'FICHIER GUITAR PRO v4.06': ((4, 0, 6), GP4File),
    'FICHIER GUITAR PRO L4.06': ((4, 0, 6), GP4File),
    'CLIPBOARD GUITAR PRO 4.0 [c6]': ((4, 0, 6), GP4File),

    'FICHIER GUITAR PRO v5.00': ((5, 0, 0), GP5File),
    'FICHIER GUITAR PRO v5.10': ((5, 1, 0), GP5File),
    'CLIPBOARD GP 5.0': ((5, 0, 0), GP5File),
    'CLIPBOARD GP 5.1': ((5, 1, 0), GP5File),
    'CLIPBOARD GP 5.2': ((5, 2, 0), GP5File),
}

_VERSIONS = {
    # (versionTuple, isClipboard): versionString,
    ((3, 0, 0), False): 'FICHIER GUITAR PRO v3.00',

    ((4, 0, 0), False): 'FICHIER GUITAR PRO v4.00',
    ((4, 0, 6), False): 'FICHIER GUITAR PRO v4.06',
    ((4, 0, 6), True): 'CLIPBOARD GUITAR PRO 4.0 [c6]',

    ((5, 0, 0), False): 'FICHIER GUITAR PRO v5.00',
    ((5, 1, 0), False): 'FICHIER GUITAR PRO v5.10',
    ((5, 2, 0), False): 'FICHIER GUITAR PRO v5.10',  # sic
    ((5, 0, 0), True): 'CLIPBOARD GP 5.0',
    ((5, 1, 0), True): 'CLIPBOARD GP 5.1',
    ((5, 2, 0), True): 'CLIPBOARD GP 5.2',
}

_EXT_VERSIONS = {
    'gp3': (3, 0, 0),
    'gp4': (4, 0, 6),
    'gp5': (5, 1, 0),
    'tmp': (5, 2, 0),
}


[docs]def parse(stream, encoding='cp1252') -> Song: """Open a GP file and read its contents. :param stream: path to a GP file or file-like object. :param encoding: decode strings in tablature using this charset. Given encoding must be an 8-bit charset. """ gpfile, shouldClose = _open(None, stream, 'rb', encoding=encoding) try: return gpfile.readSong() finally: if shouldClose: gpfile.close()
[docs]def write(song: Song, stream, version: Optional[tuple] = None, encoding='cp1252'): """Write a song into GP file. :param song: a song to write. :param stream: path to save GP file or file-like object. :param version: explicitly set version of GP file to save, e.g. ``(5, 1, 0)``. :param encoding: encode strings into given 8-bit charset. """ gpfile, shouldClose = _open(song, stream, 'wb', version=version, encoding=encoding) try: gpfile.writeSong(song) finally: if shouldClose: gpfile.close()
def _open(song, stream, mode='rb', version=None, encoding=None): """Open a GP file path for reading or writing.""" if mode not in ('rb', 'wb'): raise ValueError(f"cannot read or write unless in binary mode, not '{mode}'") shouldClose = False if isinstance(stream, (str, bytes, os.PathLike)): fp = open(stream, mode) shouldClose = True filename = stream else: fp = stream filename = getattr(fp, 'name', '<file>') if mode == 'rb': gpfilebase = GPFileBase(fp, encoding) versionString = gpfilebase.readVersion() elif mode == 'wb': isClipboard = song.clipboard is not None if version is None: version = song.versionTuple if version is None: version = guessVersionByExtension(filename) versionString = _VERSIONS[(version, isClipboard)] version, GPFile = getVersionAndGPFile(versionString) gpfile = GPFile(fp, encoding, version=versionString, versionTuple=version) return gpfile, shouldClose def getVersionAndGPFile(versionString): try: return _GPFILES[versionString] except KeyError: raise GPException(f"unsupported version '{versionString}'") def guessVersionByExtension(filename): __, ext = os.path.splitext(filename) ext = ext.lstrip('.') version = _EXT_VERSIONS.get(ext) if version is None: version = _EXT_VERSIONS['gp5'] return version