Пример #1
0
    def test_add_to_db(self, beethoven, debussy, mockdb):
        """Test adding composers to the database."""
        beethoven.add_to_db(mockdb)
        comptable = mockdb.table('composers')
        assert db_interface.explore_table(comptable,
                                          search=('name',
                                                  'Ludwig van Beethoven'))

        debussy.add_to_db(mockdb)
        assert db_interface.explore_table(comptable,
                                          search=('name', 'Claude Debussy'))
Пример #2
0
    def load_from_db(cls, name, db):
        """
        Loads a composer from the database.

        :param name: part or all of a composer's name
        :param db: a TinyDB instance
        """
        table = db.table('composers')
        name_parts = name.split(' ')
        lname = name_parts.pop()
        comps = db_interface.explore_table(table=table, search=('name', lname))
        if not isinstance(comps, list):
            comps = [comps]
        for item in comps:
            if name_parts[0] in item:
                data = db_interface.load_name_from_table(item, db=db,
                                                         tablename='composers')
                name = data['name']
                try:
                    mutopianame = data['mutopianame']
                except KeyError:
                    mutopianame = None
                try:
                    shortname = data['shortname']
                except KeyError:
                    shortname = None

        return cls(name=name, mutopianame=mutopianame, shortname=shortname)
Пример #3
0
def instrument_prompt(curr_instruments, db_):
    """
    Prompt for creating instruments in the score.
    :param curr_instruments: list of existing instruments
    :param db_: database to laod to/from
    :return:
    """
    prompt_help = ("Options:\n"
                   f"{BOLD}print{END} instruments\n"
                   f"{BOLD}create{END} a new instrument\n"
                   f"{BOLD}delete{END} an instrument\n"
                   f"{BOLD}reorder{END} instruments\n"
                   f"{BOLD}help{END} to view this message\n"
                   f"{BOLD}done{END} to save and return to main prompt")
    command_completer = WordCompleter(
        ['create', 'delete', 'reorder', 'help', 'done', 'print'])
    instrument_names = db_interface.explore_table(db_.table("instruments"),
                                                  search=("name", ""))
    instruments = [
        titlecase(' '.join(name.split('_'))) for name in instrument_names
    ]
    print(prompt_help)
    while True:
        # DEBUG LINE
        # print(curr_instruments)
        command = prompt("Instruments> ", completer=command_completer)
        if len(command) == 0:
            continue
        elif command.lower()[0] == 'p':
            for ins in curr_instruments:
                print(ins.part_name(key=True))
        elif command.lower()[0] == 'c':
            new_ins = create_instrument(instruments, db_, instrument_names)
            curr_instruments.append(new_ins)
        elif command.lower()[0:2] == 'de':
            while True:
                instruments_with_indexes(curr_instruments)
                del_idx = prompt(
                    "Enter the number of the instrument to delete or [enter] to "
                    "finish: ") or None
                if del_idx is None:
                    break
                elif del_idx.isdigit():
                    curr_instruments.pop(int(del_idx))
                else:
                    print("Invalid index")
        elif command.lower()[0] == 'r':
            curr_instruments = reorder_instruments(curr_instruments)
        elif command.lower()[0] == 'h':
            print(prompt_help)
        elif command.lower()[0:2] == 'do':
            return curr_instruments
        else:
            print(INVALID)
Пример #4
0
def composer_prompt(db):
    composers = db_interface.explore_table(db.table("composers"),
                                           search=("name", ""))
    comp = prompt("Enter Composer: ",
                  completer=InsensitiveCompleter(composers))
    matches = []
    for item in composers:
        if comp in item:
            matches.append(item)
    if matches:
        load = prompt(f"Would you like to load {comp} from the database? ",
                      default='Y',
                      validator=YNValidator())
        if answered_yes(load):
            if len(matches) > 1:
                for num, match in enumerate(matches):
                    print(f"{num}. {match}")
                choice = prompt(
                    "Please enter the number of the "
                    "matching composer or press [enter] if none match: ",
                    validator=IndexValidator(len(matches) - 1,
                                             allow_empty=True))
                if choice:
                    found = matches[int(choice[0])]
            else:
                found = matches[0]
            try:
                return info.Composer.load_from_db(found, db)
            except NameError:
                pass
    new_comp = info.Composer(comp)
    guess_short_name = new_comp.get_short_name()
    try:
        guess_mutopia_name = new_comp.get_mutopia_name(guess=True)
    except AttributeError:
        guess_mutopia_name = ''
    new_comp.shortname = prompt("Enter the abbreviated name of the composer: ",
                                default=guess_short_name)
    new_comp.mutopianame = prompt(
        "Enter the mutopia formatted name of the composer "
        "or [enter] for none: ",
        default=guess_mutopia_name)
    add_to_db = prompt(
        "Would you like to add this composer to the database for easy usage next time? ",
        default='Y',
        validator=YNValidator())
    if answered_yes(add_to_db):
        new_comp.add_to_db(db)
    return new_comp
Пример #5
0
def composer(ctx, name):
    """Add composer to the database."""
    db_ = ctx.obj['DB']
    newcomp = Composer(name)
    try:
        mutopianame = input(
            f"Assumed Mutopia Name is {newcomp.get_mutopia_name(guess=True)}"
            " Is this correct? [Y/n] ") or "Y"
        if mutopianame[0].lower() == 'n':
            newcomp.mutopianame = input("Enter correct Mutopia Name: ")
    except MutopiaError:
        newcomp.mutopianame = input("Enter correct Mutopia Name: ")
    shortname = input(f"Assumed short name is {newcomp.get_short_name()}"
                      " Correct? [Y/n] ") or "Y"
    if shortname[0].lower() == 'n':
        newcomp.shortname = input("Enter correct short name: ")
    newcomp.add_to_db(db_)
    newrec = db_interface.explore_table(db_.table("composers"),
                                        search=("shortname",
                                                newcomp.shortname))
    print(newrec)
Пример #6
0
    def add_to_db(self, db):
        """
        Serializes the Ensemble and adds it to the supplied database in the
        'ensembles' table.
        This should only be called after load_from_db fails or the databse is
        otherwise checked so duplicates aren't added to the database.

        :param db: a tinydb instance to insert into.
        """
        ens_table = db.table('ensembles')
        ins_table = db.table('instruments')
        data = dict(name=self.name)
        data['instruments'] = []
        for instrument in self.instruments:
            # if the instrument isn't in the database
            if not explore_table(ins_table, search=('name', instrument.name)):
                instrument.add_to_db(db)
            data['instruments'].append({
                'name': instrument.name,
                'number': instrument.number
            })
        ens_table.insert(data)
Пример #7
0
def ensemble_prompt(curr_instruments, db_):
    """
    Prompt for creating ensembles.

    :param curr_instruments: Current list of instruments.
    :param db_: database to load to/from
    :return: lynames.Ensemble object
    """
    ensemble_names = db_interface.explore_table(db_.table("ensembles"),
                                                search=("name", ""))
    ensembles = [
        titlecase(' '.join(name.split('_'))) for name in ensemble_names
    ]
    ensemble_name = prompt("Please enter a name for the ensemble: ",
                           completer=InsensitiveCompleter(ensembles))
    ensemble_name_normal = lynames.normalize_name(ensemble_name)
    new_ens = None
    if ensemble_name_normal in ensemble_names:
        load = prompt(
            f"{ensemble_name} is in the database, would you like to load it? "
            "[Y/n] ",
            default='Y',
            validator=YNValidator())
        if answered_yes(load):
            return lynames.Ensemble.load_from_db(ensemble_name, db_)
    while True:
        new_ens = common.create_ensemble(ensemble_name, db_, curr_instruments)
        if isinstance(new_ens, lynames.Ensemble):
            break
        else:
            retry = prompt(f"No new ensemble was created. Try again? ",
                           validator=YNValidator(),
                           default='Y')
            if not answered_yes(retry):
                break
    return new_ens
Пример #8
0
def search(ctx, table, field, term):
    """Search the database"""
    db_ = ctx.obj['DB']
    print(db_interface.explore_table(db_.table(table), search=(field, term)))
Пример #9
0
def create_ensemble(name, db, instruments_to_add=[]):
    """
    Create an ensemble from new or old instruments

    :param name: The name of the ensemble
    :param db: the database to add the ensemble to and load instruments from.
    :param instruments_to_add: (Optional) existing instrument objects to add to
    the ensemble

    :return: ensemble object created by the dialog
    """
    instrument_names = db_interface.explore_table(db.table("instruments"),
                                                  search=("name", ""))
    instruments = [
        titlecase(' '.join(name.split('_'))) for name in instrument_names
    ]
    ins_list = []
    new_ens = Ensemble(name)
    for ins in instruments_to_add:
        if isinstance(ins, Instrument):
            ins_list.append(ins)
            continue
        ins_name = ins
        num = None
        for group in ins.split():
            if group.isdigit():
                num = int(group)
                ins_name = ins.replace(f" {group}", '')
        if normalize_name(ins_name) in instrument_names:
            ins_list.append(
                Instrument.load_from_db(normalize_name(ins_name),
                                        db,
                                        number=num))
        else:
            print(f"{ins_name} not in db")
    if not ins_list:
        print(
            "You will need to create some instruments to add to the ensemble.")
        ins_list.append(create_instrument(instruments, db, instrument_names))
    prompt_help = (
        "You can:\n"
        f"{BOLD}reorder{END}, {BOLD}add{END}, {BOLD}delete{END}, {BOLD}print{END}"
        f"\nor {BOLD}done{END} if you are satisfied with the instruments.")
    print(prompt_help)
    instruments_with_indexes(ins_list)
    while True:
        choice = prompt(
            "Ensemble> ",
            completer=WordCompleter(
                ['reorder', 'add', 'delete', 'continue', 'print']),
        )
        if len(choice) == 0:
            continue
        elif choice.lower()[0] == 'r':
            ins_list = reorder_instruments(ins_list)
        elif choice.lower()[0] == 'a':
            ins_list.append(
                create_instrument(instruments, db, instrument_names))
        elif choice.lower()[0:2] == 'de':
            while True:
                instruments_with_indexes(ins_list)
                del_idx = prompt(
                    "Enter the number of the instrument to delete or [enter] to "
                    "finish: ") or None
                if del_idx is None:
                    break
                elif del_idx.isdigit():
                    ins_list.pop(int(del_idx))
                else:
                    print("Invalid index")
        elif choice.lower()[0] == 'p':
            print(name + ':')
            instruments_with_indexes(ins_list)
        elif choice.lower()[0:2] == 'do':
            break
    for ins in ins_list:
        new_ens.add_instrument_from_obj(ins)
    print(new_ens)
    good = prompt("Save? ", validator=YNValidator(), default='Y')
    if not answered_yes(good):
        return ins_list
    add_to_db = prompt("Add to database for future use? ",
                       validator=YNValidator(),
                       default='Y')
    if answered_yes(add_to_db):
        new_ens.add_to_db(db)
    return new_ens
Пример #10
0
def header_prompt(curr_headers, db):
    prompt_help = (
        "You may edit any of the following headers:\n"
        "title\t\tcomposer\n"
        "dedication\tsubtitle\n"
        "subsubtitle\tpoet\n"
        "meter\t\tarranger\n"
        "tagline\t\tcopyright\n"
        f"Enter {BOLD}print{END} to print the current headers and {BOLD}done{END} to finish"
        "and return to the main prompt.")
    print(prompt_help)
    titlewords = WordCompleter(
        db_interface.explore_table(db.table("titlewords"),
                                   search=("word", "")))
    field_completer = WordCompleter([
        "title", "composer", "subtitle", "subsubtitle", "poet", "meter",
        "arranger", "tagline", "copyright", "print", "done"
    ])
    if curr_headers is None:
        composer = composer_prompt(db)
        title = prompt("Enter Title: ", completer=titlewords)
        curr_headers = info.Headers(title=title, composer=composer)
    while 1:
        # DEBUG LINE
        # print(curr_headers)
        command = prompt("Headers> ", completer=field_completer)
        if len(command) == 0:
            continue
        field = command.lower().strip()
        if field == "title":
            title = prompt(
                "Current title is \"{}\" enter a new title or press "
                "enter to keep the current one: ".format(curr_headers.title))
            if len(title) != 0:
                curr_headers.title = title
        elif "comp" in field:
            change_comp = prompt(
                "Current composer is {}. Would you like to change "
                "it? ".format(curr_headers.composer.name),
                default='N',
                validator=YNValidator())
            if answered_yes(change_comp):
                curr_headers.composer = composer_prompt(db)
        elif field in [
                "dedication", "subtitle", "subsubtitle", "poet", "meter",
                "arranger", "tagline", "copyright"
        ]:
            print("{} is {}".format(field, getattr(curr_headers, field,
                                                   "blank")))
            new = prompt(
                f"Enter value for {field} or press enter to leave unchanged: ")
            if len(new) > 0:
                setattr(curr_headers, field, new)
        # Logistical commands
        elif field[0] == 'h':
            print(prompt_help)
        elif field[0] == 'p':
            print(curr_headers)
        elif field[0] == 'd' or field == "save":
            print("Saving headers")
            return curr_headers
        else:
            print(INVALID)
Пример #11
0
def test_explore_table(mocktable, livetable):
    """
    Test exploring a database table.
    NOTE: some assertions use set.issubset() so that if additional matching
    items are added the tests will still pass.
    """
    assert {'violin', 'violoncello', 'clarinet_in_bb'} ==\
        set(db_interface.explore_table(mocktable)), ("Without search terms "
                                                     "it should return all "
                                                     "names.")
    assert {'violin', 'viola', 'violoncello'}.issubset(
        set(db_interface.explore_table(livetable, search=('name', 'vio')))
    ), "With search terms it should return matching subset."
    assert {'violoncello', 'double_bass', 'contrabass'}.issubset(
        set(db_interface.explore_table(livetable, search=('clef', 'bass')))
    ), "With search terms it should return matching subset."
    assert {'violin', 'viola', 'violoncello', 'double_bass',
            'contrabass'}.issubset(db_interface.explore_table(
                livetable, search=('family', 'strings'))), ("With search "
                                                            "terms it should "
                                                            "return matching "
                                                            "subset.")
    assert db_interface.explore_table(livetable, search=(
        'name', 'this is not the table')) == [], ("If nothing matches "
                                                  "return empty list.")
    assert db_interface.explore_table(livetable, search=(
        'not a field', 'fail')) == [], "If nothing matches return empty list."

    assert db_interface.explore_table(livetable, search=('name', 'vio')),\
        "A search that finds something should be implicitly true"
    assert not db_interface.explore_table(livetable, search=(
        'name', 'not in the database')), ("A search that returns nothing "
                                          "should be implicitly false.")

    with pytest.raises(TypeError, match='.*tuple.*', message=(
            'Expect TypeError if search is not a tuple.')):
        db_interface.explore_table(livetable, search='hi')

    with pytest.raises(TypeError, match='.*tinydb.*', message=(
            'Expect TypeError if table is not a tinydb table.')):
        db_interface.explore_table(123, search=('name', 'test'))

    # test that it handles malformed data
    mocktable.search.return_value = [
        {'name': 'hi'}, {'fake': 'table'}, {'key': 'value'},
        {'name': 'test'}]
    assert db_interface.explore_table(mocktable, search=('name', 'test')) ==\
        ['hi', 'test']