Пример #1
0
def test_reset(setup):
    runner = CliRunner()

    # Reset habit that does not exist on record
    result = runner.invoke(habiter, ['reset', '--yes', 't0'])
    assert result.exit_code == 1

    # Reset habit that exists on record
    runner.invoke(habiter, ['add', 't0'])
    with SQLiteDataFileOperations() as fo:
        # Reset habit that exists on record
        fo.cur.execute('UPDATE habit SET curr_tally = 5, '
                       'total_tally = 30, num_of_trials = 4, '
                       'wait_period = 1, is_active = True, '
                       'prev_tally = 1 '
                       'WHERE habit_name="t0"')
    runner.invoke(habiter, ['reset', '--yes', 't0'])
    with SQLiteDataFileOperations() as fo:
        fo.cur.execute('SELECT * FROM habit WHERE habit_name="t0"')
        row = fo.cur.fetchone()
    assert row['curr_tally'] == 0
    assert row['total_tally'] == 0
    assert row['num_of_trials'] == 0
    assert row['wait_period'] == 0
    assert row['is_active'] == 0
    assert row['prev_tally'] is None
Пример #2
0
def test_add(setup):
    runner = CliRunner()

    # Normal behavior
    result = runner.invoke(habiter, ['add', 't0', 't1'])
    assert result.exit_code == 0
    with SQLiteDataFileOperations() as fo:

        fo.cur.execute('SELECT habit_name FROM habit')
        rows = fo.cur.fetchall()
        assert rows[0]['habit_name'] in ['t0', 't1']
        assert rows[1]['habit_name'] in ['t0', 't1']

    # Add habit that already exists on record
    runner.invoke(habiter, ['add', 't2'])
    result = runner.invoke(habiter, ['add', 't2'])
    assert result.exit_code == 1
    with SQLiteDataFileOperations() as fo:
        fo.cur.execute('SELECT habit_name FROM habit '
                       'WHERE habit_name = "t2"')
        rows = fo.cur.fetchall()
        assert len(rows) < 2

    # Abnormal behavior (habit name is duplicated)
    result = runner.invoke(habiter, ['add', 't3', 't3'])
    assert result.exit_code == 0
    with SQLiteDataFileOperations() as fo:
        fo.cur.execute('SELECT habit_name FROM habit '
                       'WHERE habit_name = "t3"')
        rows = fo.cur.fetchall()
        assert len(rows) == 1
Пример #3
0
def add(habits):
    existing_habit_detected = False

    # Cast to set to remove possible duplicates
    habits = set(habits)

    with SQLiteDataFileOperations() as fo:

        # TODO: Instead of invoking a query on each habit_name, try to use one query for all habits
        for habit_name in habits:
            fo.cur.execute(
                'SELECT curr_tally, prev_tally, is_active, '
                'last_updated, num_of_trials FROM habit WHERE '
                'habit_name=?', (habit_name, ))
            row = fo.cur.fetchone()
            if row is not None:
                existing_habit_detected = True
                echo_failure(f"Habit \"{habit_name}\" already exists.")
                continue
            curr_time = datetime.now().strftime(HAB_DATE_FORMAT)
            fo.cur.execute(
                'INSERT INTO habit (habit_name, curr_tally, '
                'total_tally, num_of_trials, wait_period, is_active, '
                'last_updated, date_added) '
                'VALUES(?, 0, 0, 0, 0, False, ?, ?)',
                (habit_name, curr_time, curr_time))
            echo_success(f"Habit \"{habit_name}\" has been added.")

        if existing_habit_detected:
            sys.exit(1)
Пример #4
0
def list(habits, verbose):
    nonExistingHabitDetected = False
    data = []
    habits = set(habits)  # Cast to set to remove possible duplicates
    with SQLiteDataFileOperations() as fo:
        if len(habits) != 0:
            for habit_name in habits:
                fo.cur.execute('SELECT * FROM habit WHERE '
                               'habit_name=?', (habit_name,))
                row = fo.cur.fetchone()
                if row is None:
                    nonExistingHabitDetected = True
                    echo_failure(f"Habit \"{habit_name}\" does not exist.")
                    continue
                data.append(row)
        else:
            data = fo.cur.execute('SELECT * FROM habit').fetchall()
        meta_data = fo.cur.execute('SELECT last_logged FROM meta_info') \
            .fetchone()
    if not verbose:
        print("Habit\n-------------------")
        for habit in data:
            print(habit["habit_name"])
        print("-------------------")
    else:
        curr_day = datetime.strptime(meta_data["last_logged"], HAB_DATE_FORMAT).date()
        print("Habit + Attributes\t\t\tValue")
        print("-------------------\t\t\t-----")
        for habit in data:
            print_verbose(habit, curr_day)
        print("-------------------\t\t\t-----")
        echo_info("Note: More data captured = increased statistical accuracy!\n")
    if nonExistingHabitDetected:
        sys.exit(1)
Пример #5
0
def reset(habits):
    non_existing_habit_detected = False

    # Cast to set to remove possible duplicates
    habits = set(habits)

    with SQLiteDataFileOperations() as fo:

        for habit_name in habits:
            fo.cur.execute('SELECT habit_id FROM habit WHERE habit_name=?',
                           (habit_name, ))
            row = fo.cur.fetchone()

            if row is None:
                echo_failure(f"No habit with the name \"{habit_name}\".")
                non_existing_habit_detected = True
            else:
                fo.cur.execute(
                    'UPDATE habit SET curr_tally = 0, '
                    'total_tally = 0, num_of_trials = 0, '
                    'wait_period = 0, is_active = False, '
                    'last_updated = ?, prev_tally = NULL '
                    'WHERE habit_id=?',
                    (datetime.now().strftime(HAB_DATE_FORMAT),
                     row['habit_id']))
                echo_success(f"Habit \"{habit_name}\" has been reset.")

        if non_existing_habit_detected:
            sys.exit(1)
Пример #6
0
def main():
    dir_path = user_data_dir(HAB_NAME, HAB_AUTHOR)
    data_file_creator = SQLiteDataFileCreator(dir_path, HAB_F_RECORD_NAME)
    data_file_creator.create()
    data_file_path = data_file_creator.get_data_f_path()

    # Set the data file path that all classes using this can have access to
    SQLiteDataFileOperations().set_f_path(data_file_path)

    data_file_updater = SQLiteDataFileUpdater(data_file_path)
    data_file_updater.update()

    cli.habiter()
Пример #7
0
def test_tally(setup):
    runner = CliRunner()
    # Tally habit that does not exist on record
    result = runner.invoke(habiter, ['tally', 't0'])
    assert result.exit_code == 1

    # Tally habit that does exist on record
    runner.invoke(habiter, ['add', 't0'])
    runner.invoke(habiter, ['tally', 't0'])
    with SQLiteDataFileOperations() as fo:
        fo.cur.execute('SELECT curr_tally FROM habit WHERE habit_name="t0"')
        row = fo.cur.fetchone()
        assert row['curr_tally'] == 1

    # Tally existing habit using '-n/--num' option
    runner.invoke(habiter, ['add', 't1'])
    runner.invoke(habiter, ['tally', '-n', 2, 't1'])
    runner.invoke(habiter, ['tally', '--num', 2, 't1'])
    with SQLiteDataFileOperations() as fo:
        fo.cur.execute('SELECT curr_tally FROM habit WHERE habit_name="t1"')
        row = fo.cur.fetchone()
        assert row['curr_tally'] == 4

    # Mark habit as active using '-z/--zero' option
    runner.invoke(habiter, ['add', 't2'])
    runner.invoke(habiter, ['tally', '-z', 't2'])
    runner.invoke(habiter, ['tally', '--zero', 't2'])
    with SQLiteDataFileOperations() as fo:
        # When a habit is added, it will by default be considered inactive
        # until the end user makes a tally, so we are testing to see if this
        # option marks it as active
        fo.cur.execute('SELECT is_active FROM habit WHERE habit_name="t2"')
        row = fo.cur.fetchone()
        assert row['is_active']

    # Use the '-z/--zero' option' but the habit has already been active
    result = runner.invoke(habiter, ['tally', '-z', 't1'])
    assert result.exit_code == 1  # evaluates to a true expression
Пример #8
0
def test_remove(setup):
    runner = CliRunner()
    # Remove habit from an empty record
    result = runner.invoke(habiter, ['remove', '--yes', 't0'])
    assert result.exit_code == 1

    # Remove habit that exists on record
    runner.invoke(habiter, ['add', 't0'])
    runner.invoke(habiter, ['remove', '--yes', 't0'])

    with SQLiteDataFileOperations() as fo:
        fo.cur.execute('SELECT habit_name FROM habit WHERE habit_name="t0"')
        rows = fo.cur.fetchall()
        assert len(rows) == 0
Пример #9
0
    def export(self) -> None:

        with SQLiteDataFileOperations(HAB_TRACE_FPATH) as fo:
            # Retrieve all rows from database
            fo.cur.execute('SELECT * FROM habit')

            to_dir_path = os.path.join(self.export_dir,
                                       f'{self.export_name}.csv')
            with open(to_dir_path, 'w') as csvfile:
                csv_writer = csv.writer(csvfile)

                # Retrieve columns
                # 'i[0]' because description returns a 7-tuple for each column
                csv_writer.writerow(i[0] for i in fo.cur.description)

                # Retrieve rows
                csv_writer.writerows(fo.cur)
Пример #10
0
    def update(self) -> None:

        with SQLiteDataFileOperations() as fo:
            fo.cur.execute('SELECT * FROM meta_info')
            # There should be a single row from the meta_info table
            row = fo.cur.fetchone()

            logged_time = datetime.strptime(row['last_logged'],
                                            HAB_DATE_FORMAT).date()
            curr_time = datetime.now().date()

            # Check if habit data has already been updated
            if logged_time >= curr_time:
                return

            echo_info('Last accessed: {}\n'.format(row['last_logged']))

            # Update row
            fo.cur.execute(
                'UPDATE meta_info SET version=?, '
                'last_logged=? WHERE meta_id=?',
                (__version__, datetime.now().strftime(HAB_DATE_FORMAT),
                 row['meta_id']))
            # Retrieve all habit data with active column set to 'True'
            fo.cur.execute('SELECT curr_tally, prev_tally, is_active, '
                           'last_updated, num_of_trials, habit_name, habit_id '
                           'FROM habit WHERE is_active=True')
            data = fo.cur.fetchall()
            for habit in data:
                habit_date = datetime \
                    .strptime(habit["last_updated"], HAB_DATE_FORMAT) \
                    .date()
                # TODO: implementation really inefficient but sqlite3 is challenging to use
                if habit_date < curr_time:
                    prev_tally = 0
                    num_of_trials = habit['num_of_trials'] + 1
                    is_active = False
                    curr_tally = 0
                    fo.cur.execute(
                        'UPDATE habit SET '
                        'prev_tally = ?, num_of_trials = ?, '
                        'is_active = ?, curr_tally = ? '
                        'WHERE habit_id = ?',
                        (prev_tally, num_of_trials, is_active, curr_tally,
                         habit['habit_id']))
Пример #11
0
def remove(habits):
    non_existing_habit_detected = False

    # Cast to set to remove possible duplicates
    habits = set(habits)

    with SQLiteDataFileOperations() as fo:

        for habit_name in habits:
            fo.cur.execute('SELECT habit_id FROM habit WHERE habit_name=?',
                           (habit_name, ))
            row = fo.cur.fetchone()

            if row is None:
                echo_failure(f"No habit with the name \"{habit_name}\".")
                non_existing_habit_detected = True
            else:
                fo.cur.execute('DELETE FROM habit WHERE habit_id=?',
                               (row['habit_id'], ))
                echo_success(f"Habit \"{habit_name}\" has been deleted.")

        if non_existing_habit_detected:
            sys.exit(1)
Пример #12
0
def setup(get_init_data_f_path):
    SQLiteDataFileOperations.set_f_path(get_init_data_f_path)
    return SQLiteDataFileOperations.get_f_path()