From 5697beceebd029aa6026d2bbd00232bb7b8aeb1e Mon Sep 17 00:00:00 2001 From: Arun Mahapatra Date: Fri, 12 Jan 2024 20:55:20 +0530 Subject: [PATCH] chore: ruff formatting and pre-commit tool. --- .github/workflows/linux.yml | 45 +++++++++--------- .github/workflows/windows.yml | 39 ++++++++------- .pre-commit-config.yaml | 9 ++++ development.txt | 5 +- habito/commands/add.py | 21 ++++---- habito/commands/checkin.py | 53 ++++++++++++--------- habito/commands/delete.py | 25 ++++++---- habito/commands/edit.py | 25 ++++++---- habito/commands/list.py | 29 ++++++++---- habito/main.py | 1 + habito/models.py | 87 ++++++++++++++++++++-------------- pyproject.toml | 29 +++++++++++- setup.cfg | 19 -------- setup.py | 13 +---- tests/__init__.py | 40 +++++++++------- tests/commands/__init__.py | 12 +++-- tests/commands/test_add.py | 3 +- tests/commands/test_checkin.py | 49 ++++++++++--------- tests/commands/test_delete.py | 39 +++++++++------ tests/commands/test_edit.py | 14 ++++-- tests/commands/test_list.py | 12 +++-- tests/test_habito.py | 17 ++++--- tests/test_models.py | 29 +++++++----- 23 files changed, 352 insertions(+), 263 deletions(-) create mode 100644 .pre-commit-config.yaml delete mode 100644 setup.cfg diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1fe693a..eee9915 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -5,34 +5,33 @@ name: linux on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] workflow_dispatch: jobs: build: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.8 - uses: actions/setup-python@v4 - with: - python-version: 3.8 - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r development.txt - pip install codecov - pip freeze - - name: Lint with flake8 - run: | - flake8 - - name: Test with pytest - run: | - pytest - - name: Upload coverage results - run: | - codecov + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.12 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r development.txt + pip install codecov + pip freeze + - name: Lint with ruff + run: | + ruff + - name: Test with pytest + run: | + pytest + - name: Upload coverage results + run: | + codecov diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 2974a97..5ecc6a6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -5,33 +5,32 @@ name: windows on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] workflow_dispatch: jobs: build: - runs-on: windows-latest strategy: matrix: - python-version: [3.9] + python-version: [3.10, 3.11, 3.12] steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r development.txt - pip freeze - - name: Lint with flake8 - run: | - flake8 - - name: Test with pytest - run: | - pytest + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r development.txt + pip freeze + - name: Lint with ruff + run: | + ruff + - name: Test with pytest + run: | + pytest diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..906aaeb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.12 + hooks: + - id: ruff + types_or: [python, pyi, jupyter] + args: [--fix] + - id: ruff-format + types_or: [python, pyi, jupyter] diff --git a/development.txt b/development.txt index 0bb24c9..132c0f7 100644 --- a/development.txt +++ b/development.txt @@ -1,11 +1,12 @@ -r requirements.txt coverage -flake8 -flake8-docstrings mkdocs mkdocs-material +pre-commit pytest pytest-cov pytest-mock +ruff twine +types-peewee wheel diff --git a/habito/commands/add.py b/habito/commands/add.py index a91b4e0..e1e523d 100644 --- a/habito/commands/add.py +++ b/habito/commands/add.py @@ -13,14 +13,15 @@ @click.option("--units", "-u", default="units", help="Units of data.") def add(name, quantum, units): """Add a habit.""" - habit_name = ' '.join(name) - models.Habit.add(name=habit_name, - created_date=datetime.now(), - quantum=quantum, - units=units, - magica="") + habit_name = " ".join(name) + models.Habit.add( + name=habit_name, + created_date=datetime.now(), + quantum=quantum, + units=units, + magica="", + ) - msg_unit = click.style("{0} {1}".format(quantum, units), fg='green') - msg_name = click.style("{0}".format(habit_name), fg='green') - click.echo("You have commited to {0} of {1} every day!" - .format(msg_unit, msg_name)) + msg_unit = click.style("{0} {1}".format(quantum, units), fg="green") + msg_name = click.style("{0}".format(habit_name), fg="green") + click.echo("You have commited to {0} of {1} every day!".format(msg_unit, msg_name)) diff --git a/habito/commands/checkin.py b/habito/commands/checkin.py index 3ff63b0..5f3dafe 100644 --- a/habito/commands/checkin.py +++ b/habito/commands/checkin.py @@ -10,43 +10,49 @@ @click.command() @click.argument("name", nargs=-1) -@click.option("--review", "-r", is_flag=True, - help="Update activity for all tracked habits.") -@click.option("--date", "-d", - help="Date of activity in mm/dd format (defaults to today).", - default=datetime.now().strftime("%m/%d")) +@click.option( + "--review", "-r", is_flag=True, help="Update activity for all tracked habits." +) +@click.option( + "--date", + "-d", + help="Date of activity in mm/dd format (defaults to today).", + default=datetime.now().strftime("%m/%d"), +) @click.option("--quantum", "-q", type=float, help="Progress for the day.") def checkin(name, review, date, quantum): """Commit progress for a habit.""" # Set a date for this checkin. Use past year if month/day is in future - query = ' '.join(name) + query = " ".join(name) date = date.strip() d = datetime.strptime(date, "%m/%d").replace(year=datetime.now().year) - update_date = d if d < datetime.now() else d.replace(year=d.year-1) + update_date = d if d < datetime.now() else d.replace(year=d.year - 1) update_date_str = update_date.strftime("%a %b %d %Y") def print_header(date_str): header = "Please update progress of habits for {0}:" - click.echo(header.format(click.style(date_str, fg='green'))) + click.echo(header.format(click.style(date_str, fg="green"))) def get_quantum(habit, required=True): msg = " - {0} (Goal: {1} {2})" # Keep prompting until we have a value if required is True value = None if required else float_info.max - q = click.prompt(msg.format(habit.name, habit.quantum, habit.units), - type=float, - show_default=False, - default=value) + q = click.prompt( + msg.format(habit.name, habit.quantum, habit.units), + type=float, + show_default=False, + default=value, + ) if not required and q == value: return None return q def update_activity(habit, quantum, date): # Create an activity for this checkin - activity = models.Activity.create(for_habit=habit, - quantum=quantum, - update_date=update_date) + activity = models.Activity.create( + for_habit=habit, quantum=quantum, update_date=update_date + ) # Update streak for the habit models.Summary.update_streak(habit) @@ -70,12 +76,14 @@ def update_activity(habit, quantum, date): habits = models.Habit.all_active().where(models.Habit.name.regexp(query)) if habits.count() == 0: error = "No habit matched the name '{0}'.".format(query) - click.secho(error, fg='red') + click.secho(error, fg="red") return elif habits.count() > 1: - error = ("More than one habits matched the name '{0}'. " - "Don't know which to update.").format(query) - click.secho(error, fg='red') + error = ( + "More than one habits matched the name '{0}'. " + "Don't know which to update." + ).format(query) + click.secho(error, fg="red") for h in habits: click.echo("- {0}".format(h.name)) click.echo("Try a different filter, or `habito checkin --review`.") @@ -88,8 +96,7 @@ def update_activity(habit, quantum, date): quantum = get_quantum(habit, required=True) activity = update_activity(habit, quantum, update_date) - act_msg = click.style("{0} {1}".format(activity.quantum, habit.units), - fg='green') - act_date = click.style(update_date_str, fg='green') - habit_msg = click.style("{0}".format(habit.name), fg='green') + act_msg = click.style("{0} {1}".format(activity.quantum, habit.units), fg="green") + act_date = click.style(update_date_str, fg="green") + habit_msg = click.style("{0}".format(habit.name), fg="green") click.echo("Added {0} to habit {1} for {2}.".format(act_msg, habit_msg, act_date)) diff --git a/habito/commands/delete.py b/habito/commands/delete.py index bec05e6..07bca20 100644 --- a/habito/commands/delete.py +++ b/habito/commands/delete.py @@ -7,8 +7,12 @@ @click.command() @click.argument("id", type=click.INT) -@click.option("--keeplogs", is_flag=True, default=False, - help="Preserve activity logs for the habit.") +@click.option( + "--keeplogs", + is_flag=True, + default=False, + help="Preserve activity logs for the habit.", +) def delete(id, keeplogs): """Delete a habit.""" try: @@ -16,16 +20,19 @@ def delete(id, keeplogs): except models.Habit.DoesNotExist: click.echo("The habit you want to remove does not seem to exist!") raise SystemExit(1) - confirm = click.confirm("Are you sure you want to delete habit" - " {}: {} (this cannot be undone!)" - .format(habit.id, habit.name)) + confirm = click.confirm( + "Are you sure you want to delete habit" + " {}: {} (this cannot be undone!)".format(habit.id, habit.name) + ) if confirm: click.echo("Habit {}: {} has been deleted!".format(habit.id, habit.name)) if not keeplogs: - models.Activity.delete().where(models.Activity.for_habit == - habit.id).execute() - models.Summary.delete().where(models.Summary.for_habit == - habit.id).execute() + models.Activity.delete().where( + models.Activity.for_habit == habit.id + ).execute() + models.Summary.delete().where( + models.Summary.for_habit == habit.id + ).execute() habit.delete_instance() else: habit.active = False diff --git a/habito/commands/edit.py b/habito/commands/edit.py index 4e036e1..f2c290b 100644 --- a/habito/commands/edit.py +++ b/habito/commands/edit.py @@ -7,11 +7,13 @@ @click.command() @click.argument("id", type=click.INT) -@click.option('--name', '-n', - help="The new name (leave empty to leave unchanged).") -@click.option('--quantum', '-q', - type=click.FLOAT, - help="The new quantum (leave empty to leave unchanged).") +@click.option("--name", "-n", help="The new name (leave empty to leave unchanged).") +@click.option( + "--quantum", + "-q", + type=click.FLOAT, + help="The new quantum (leave empty to leave unchanged).", +) def edit(id, name, quantum): """Edit a habit.""" try: @@ -23,8 +25,11 @@ def edit(id, name, quantum): habit.quantum = quantum or habit.quantum habit.save() - msg_id = click.style(str(habit.id), fg='green') - msg_name = click.style(habit.name, fg='green') - msg_quantum = click.style(str(habit.quantum), fg='green') - click.echo("Habit with id {} has been saved with name: {} and quantum: {}." - .format(msg_id, msg_name, msg_quantum)) + msg_id = click.style(str(habit.id), fg="green") + msg_name = click.style(habit.name, fg="green") + msg_quantum = click.style(str(habit.quantum), fg="green") + click.echo( + "Habit with id {} has been saved with name: {} and quantum: {}.".format( + msg_id, msg_name, msg_quantum + ) + ) diff --git a/habito/commands/list.py b/habito/commands/list.py index 8538664..95f9a1a 100644 --- a/habito/commands/list.py +++ b/habito/commands/list.py @@ -8,16 +8,25 @@ from habito import models as models -TICK = u"\u25A0" # tick - 2713, black square - 25A0, 25AA, 25AF -CROSS = u"\u25A1" # cross - 2717, white square - 25A1, 25AB, 25AE -PARTIAL = u"\u25A0" # tick - 2713, black square - 25A0, 25AA, 25AF +TICK = "\u25A0" # tick - 2713, black square - 25A0, 25AA, 25AF +CROSS = "\u25A1" # cross - 2717, white square - 25A1, 25AB, 25AE +PARTIAL = "\u25A0" # tick - 2713, black square - 25A0, 25AA, 25AF logger = logging.getLogger("habito") @click.command() -@click.option("-l", "long_list", is_flag=True, help="Long listing with date and quantum.") -def list(long_list): +@click.option( + "-l", "long_list", is_flag=True, help="Long listing with date and quantum." +) +@click.option( + "-f", + "--format", + type=click.Choice(["csv", "table"], case_sensitive=False), + default="table", + help="Output format. Default is table.", +) +def list(long_list, format="table"): """List all tracked habits.""" from terminaltables import SingleTable from textwrap import wrap @@ -26,9 +35,13 @@ def list(long_list): nr_of_dates = terminal_width // 10 - 4 if nr_of_dates < 1: - logger.debug("list: Actual terminal width = {0}.".format(shutil.get_terminal_size()[0])) + logger.debug( + "list: Actual terminal width = {0}.".format(shutil.get_terminal_size()[0]) + ) logger.debug("list: Observed terminal width = {0}.".format(terminal_width)) - click.echo("Your terminal window is too small. Please make it wider and try again") + click.echo( + "Your terminal window is too small. Please make it wider and try again" + ) raise SystemExit(1) table_title = ["Habit", "Goal", "Streak"] @@ -70,6 +83,6 @@ def list(long_list): max_col_width = max_col_width if max_col_width > 0 else 20 for r in table_rows: - r[0] = '\n'.join(wrap(r[0], max_col_width)) + r[0] = "\n".join(wrap(r[0], max_col_width)) click.echo(table.table) diff --git a/habito/main.py b/habito/main.py index 962ca0a..6ce2a7f 100644 --- a/habito/main.py +++ b/habito/main.py @@ -3,4 +3,5 @@ if __name__ == "__main__": from habito.commands import cli + cli() diff --git a/habito/models.py b/habito/models.py index 4f9b0d6..548a15c 100644 --- a/habito/models.py +++ b/habito/models.py @@ -3,14 +3,13 @@ import logging from datetime import datetime, timedelta -from peewee import * # noqa +from peewee import * # noqa from playhouse import reflection from playhouse.sqlite_ext import SqliteExtDatabase from playhouse.migrate import SqliteMigrator, migrate DB_VERSION = 2 -db = SqliteExtDatabase(None, pragmas=(('foreign_keys', 'on'),), - regexp_function=True) +db = SqliteExtDatabase(None, pragmas=(("foreign_keys", "on"),), regexp_function=True) logger = logging.getLogger("habito.models") @@ -25,9 +24,11 @@ def get_activities(days): """Get activities of habits for specified days. Args: + ---- days (int): Number of days of activities to fetch. Returns: + ------- List of habits with the activities. """ @@ -36,9 +37,11 @@ def get_activities(days): from_date = datetime.now() - timedelta(days=days) habits = Habit.all_active() - activities = Activity.select()\ - .where(Activity.update_date > from_date)\ + activities = ( + Activity.select() + .where(Activity.update_date > from_date) .order_by(Activity.update_date.desc()) + ) habits_with_activities = prefetch(habits, activities) return habits_with_activities @@ -48,9 +51,11 @@ def get_daily_activities(days): """Get activities for all habits grouped by day for specified days. Args: + ---- days (int): Number of days of activities to fetch. Returns: + ------- Tuple of habit and list of daily activities. Daily activities are the sum of all activities for the habit for the day. @@ -105,7 +110,8 @@ class Meta: class Config(BaseModel): """Database configuration. - Attributes: + Attributes + ---------- name (str): Name of the setting value (str): Value @@ -118,7 +124,8 @@ class Config(BaseModel): class Habit(BaseModel): """Represents a single habit. - Attributes: + Attributes + ---------- name (str): Description of the habit. created_date (datetime): Date on which the habit was added. quantum (float): Amount for the habit. @@ -142,24 +149,24 @@ def add(cls, **query): """Add a habit. Args: + ---- query (kwargs): List of fields and values. Returns: + ------- A Habit. """ habit = cls.create(**query) - Summary.create(for_habit=habit, - target=0, - target_date=datetime.now(), - streak=0) + Summary.create(for_habit=habit, target=0, target_date=datetime.now(), streak=0) return habit @classmethod def all_active(cls): """Add a habit. - Returns: + Returns + ------- All active habits. """ @@ -169,15 +176,15 @@ def all_active(cls): class Activity(BaseModel): """Updates for a Habit. - Attributes: + Attributes + ---------- for_habit (int): Id of the Habit. Foreign key. update_date (date): Date time of the update. quantum (float): Amount for the habit. """ - for_habit = ForeignKeyField(Habit, backref="activities", - index=True) + for_habit = ForeignKeyField(Habit, backref="activities", index=True) quantum = DoubleField() update_date = DateTimeField(default=datetime.now()) @@ -185,7 +192,8 @@ class Activity(BaseModel): class Summary(BaseModel): """Continuous metrics for a Habit. - Attributes: + Attributes + ---------- for_habit (int): Id of the Habit. Foreign key. target (float): A target for the Habit. Computed from the quantum. target_date (date): Date for the target. @@ -194,8 +202,7 @@ class Summary(BaseModel): """ - for_habit = ForeignKeyField(Habit, backref="summary", - index=True) + for_habit = ForeignKeyField(Habit, backref="summary", index=True) target = DoubleField() target_date = DateField() streak = IntegerField(default=0) @@ -205,17 +212,23 @@ def update_streak(cls, habit): """Update streak for a habit. Args: + ---- habit (Habit): Habit to update. """ # Check-in now supports past updates for upto 365 days # TODO need an index on date, this query will scan entire table summary = cls.get(for_habit=habit) - activities = list((Activity - .select(Activity.update_date, - fn.SUM(Activity.quantum).alias('total_quantum')) - .where(Activity.for_habit == habit) - .group_by(fn.date(Activity.update_date)) - .order_by(Activity.update_date.desc()))) + activities = list( + ( + Activity.select( + Activity.update_date, + fn.SUM(Activity.quantum).alias("total_quantum"), + ) + .where(Activity.for_habit == habit) + .group_by(fn.date(Activity.update_date)) + .order_by(Activity.update_date.desc()) + ) + ) if len(activities) == 0: return summary @@ -245,14 +258,13 @@ class Migration: """Migrations for habito database.""" # Error codes for the migrations - error_codes = {-1: "not run", - 0: "success", - 1: "generic failure"} + error_codes = {-1: "not run", 0: "success", 1: "generic failure"} def __init__(self, database): """Create an instance of the migration. Args: + ---- database: database instance """ self._db = database @@ -265,9 +277,11 @@ def get_version(self): DB version is the actual version otherwise. Args: + ---- database (Database): peewee database instance Returns: + ------- Database version (int). """ @@ -290,8 +304,7 @@ def execute(self, list_only=False): # Set current version to 0, we will only run migration_0 act_ver = self.get_version() cur_ver = 0 if act_ver == 0 else DB_VERSION - logger.debug("DB version: actual = {0}, current = {1}" - .format(act_ver, cur_ver)) + logger.debug("DB version: actual = {0}, current = {1}".format(act_ver, cur_ver)) if cur_ver != 0 and act_ver == cur_ver: logger.debug("DB versions are same. Skip migration.") @@ -300,7 +313,7 @@ def execute(self, list_only=False): def get_migration(version): return self.__getattribute__("_migration_{}".format(version)) - m = {x: (get_migration(x), -1) for x in range(act_ver, cur_ver+1)} + m = {x: (get_migration(x), -1) for x in range(act_ver, cur_ver + 1)} if list_only: # List the migration and status without running return {f[0]: f[1][1] for f in m.items()} @@ -322,7 +335,8 @@ def _migration_1(self): with self._db.transaction(): migrate( migrator.rename_table("habitmodel", "habit"), - migrator.rename_table("activitymodel", "activity")) + migrator.rename_table("activitymodel", "activity"), + ) logger.debug("Migration #1: Renamed habit, activity tables.") # Create new tables @@ -335,9 +349,11 @@ def _migration_1(self): # Update summaries for h in Habit.select(): - activities = Activity.select()\ - .where(Activity.for_habit == h)\ - .order_by(Activity.update_date.asc()) + activities = ( + Activity.select() + .where(Activity.for_habit == h) + .order_by(Activity.update_date.asc()) + ) streak = 0 if len(activities) != 0: last_date = activities[0].update_date @@ -349,8 +365,7 @@ def _migration_1(self): last_date = a.update_date # Update summary for the habit - s = Summary.get_or_create(for_habit=h, target=0, - target_date=h.created_date) + s = Summary.get_or_create(for_habit=h, target=0, target_date=h.created_date) s[0].streak = streak s[0].save() logger.debug("Migration #1: Summary updated for habits.") diff --git a/pyproject.toml b/pyproject.toml index b0471b7..58c7448 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,30 @@ [build-system] requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta:__legacy__" \ No newline at end of file +build-backend = "setuptools.build_meta:__legacy__" + +[tool.coverage.run] +omit = ["habito/main.py"] + +[tool.coverage.report] +show_missing = "true" + +[tool.pytest.ini_options] +addopts = "--cov=habito --cov-report=term-missing --cov-fail-under=100 --quiet" + +[tool.ruff] +exclude = [".venv", "venv"] +ignore = [] +line-length = 88 +select = [ + "D", + "E", + "F", + "W", +] + +[tool.ruff.per-file-ignores] +"tests/*.py" = [ + "D101", + "D102", +] +"**/*.py" = ["F405"] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index a165575..0000000 --- a/setup.cfg +++ /dev/null @@ -1,19 +0,0 @@ -[tool:pytest] -addopts= - --cov=habito - --cov-report=term-missing - --cov-fail-under=100 - --quiet - -[coverage:run] -omit = habito/main.py - -[coverage:report] -show_missing=True - -[flake8] -max-line-length=120 -exclude=.venv -per-file-ignores = - **/*.py: F405 - tests/*.py: D101,D102 diff --git a/setup.py b/setup.py index f609943..258f04e 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ # Load the package's __version__.py module as a dictionary. about = {} -about["__version__"] = '.'.join(map(str, VERSION)) +about["__version__"] = ".".join(map(str, VERSION)) class UploadCommand(Command): @@ -57,8 +57,7 @@ def run(self): pass self.status("Building Source and Wheel (universal) distribution…") - os.system("{0} setup.py sdist bdist_wheel --universal" - .format(sys.executable)) + os.system("{0} setup.py sdist bdist_wheel --universal".format(sys.executable)) self.status("Uploading the package to PyPi via Twine…") os.system("twine upload dist/*") @@ -74,35 +73,27 @@ def run(self): url=URL, author=AUTHOR, author_email=EMAIL, - packages=find_packages(exclude=["contrib", "docs", "tests*"]), entry_points={ "console_scripts": ["habito=habito.commands:cli"], }, install_requires=REQUIRED, python_requires=">=3.5", - license="MIT", classifiers=[ "Development Status :: 3 - Alpha", - "Environment :: Console", - "Intended Audience :: End Users/Desktop", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: MacOS", "Operating System :: Microsoft", "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", - "Topic :: Utilities", ], keywords="habits goals track tracking quantified self", diff --git a/tests/__init__.py b/tests/__init__.py index eba2cd1..e87fb40 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -13,26 +13,32 @@ class HabitoTestCase(TestCase): one_day_ago = datetime.today() - timedelta(days=1) two_days_ago = datetime.today() - timedelta(days=2) - def create_habit(self, name="HabitOne", created_date=datetime.now(), - active=True, quantum=0, magica="be awesome!"): - habit = models.Habit.create(name=name, - created_date=created_date, - quantum=quantum, - active=active, - units="dummy_units", - magica=magica) + def create_habit( + self, + name="HabitOne", + created_date=datetime.now(), + active=True, + quantum=0, + magica="be awesome!", + ): + habit = models.Habit.create( + name=name, + created_date=created_date, + quantum=quantum, + active=active, + units="dummy_units", + magica=magica, + ) return habit def add_activity(self, habit, quantum=0.0, update_date=datetime.now()): - activity = models.Activity.create(for_habit=habit, - quantum=quantum, - update_date=update_date) + activity = models.Activity.create( + for_habit=habit, quantum=quantum, update_date=update_date + ) return activity - def add_summary(self, habit, target=0, target_date=datetime.now(), - streak=0): - summary = models.Summary.create(for_habit=habit, - target=target, - target_date=target_date, - streak=streak) + def add_summary(self, habit, target=0, target_date=datetime.now(), streak=0): + summary = models.Summary.create( + for_habit=habit, target=target, target_date=target_date, streak=streak + ) return summary diff --git a/tests/commands/__init__.py b/tests/commands/__init__.py index 91323c9..2309d37 100644 --- a/tests/commands/__init__.py +++ b/tests/commands/__init__.py @@ -18,12 +18,16 @@ def setUp(self): models.setup(habito.commands.database_name) def tearDown(self): - models.db.drop_tables([models.Habit, models.Activity, models.Summary], - safe=True) + models.db.drop_tables( + [models.Habit, models.Activity, models.Summary], safe=True + ) def _verify_checkin_date(self, date_str, year, output): - date = datetime.strptime(date_str, "%m/%d") \ - .replace(year=year).strftime("%a %b %d %Y") + date = ( + datetime.strptime(date_str, "%m/%d") + .replace(year=year) + .strftime("%a %b %d %Y") + ) assert date in output def _run_command(self, command, args=[]): diff --git a/tests/commands/test_add.py b/tests/commands/test_add.py index 8ece8ae..4d56bc5 100644 --- a/tests/commands/test_add.py +++ b/tests/commands/test_add.py @@ -8,8 +8,7 @@ class HabitoAddTestCase(HabitoCommandTestCase): def test_habito_add_should_add_a_habit(self): - result = self._run_command(habito.commands.add, - ["dummy habit", "10.01"]) + result = self._run_command(habito.commands.add, ["dummy habit", "10.01"]) assert result.exit_code == 0 assert models.Habit.get().name == "dummy habit" diff --git a/tests/commands/test_checkin.py b/tests/commands/test_checkin.py index 8356a8d..e245c14 100644 --- a/tests/commands/test_checkin.py +++ b/tests/commands/test_checkin.py @@ -10,8 +10,7 @@ class HabitoCheckinCommandTestCase(HabitoCommandTestCase): def test_habito_checkin_should_show_error_if_no_habit_exists(self): - result = self._run_command(habito.commands.checkin, - ["dummy habit", "-q 9.1"]) + result = self._run_command(habito.commands.checkin, ["dummy habit", "-q 9.1"]) assert result.exit_code == 0 assert result.output.startswith("No habit matched the") @@ -25,13 +24,11 @@ def test_habito_checkin_should_show_error_if_name_is_empty(self): def test_habito_checkin_should_show_error_if_multiple_habits_match(self): dummy_date = date(1201, 10, 12) self.create_habit() - self.create_habit(name="Habit Two", - created_date=dummy_date, - quantum=0, - magica="be awesome!") + self.create_habit( + name="Habit Two", created_date=dummy_date, quantum=0, magica="be awesome!" + ) - result = self._run_command(checkin, - ["Habit", "-q 9.1"]) + result = self._run_command(checkin, ["Habit", "-q 9.1"]) assert result.exit_code == 0 assert result.output.startswith("More than one habits matched the") @@ -41,10 +38,8 @@ def test_habito_checkin_should_add_data_for_a_habit(self): self.add_summary(habit) result_units = "9.1 dummy_units" - result = self._run_command(checkin, - ["Habit", "-q 9.1"]) - activity_entry = models.Activity \ - .get(models.Activity.for_habit == habit) + result = self._run_command(checkin, ["Habit", "-q 9.1"]) + activity_entry = models.Activity.get(models.Activity.for_habit == habit) assert result.output.find(result_units) != -1 assert result.output.find(habit.name) != -1 @@ -55,11 +50,11 @@ def test_habito_checkin_should_skip_inactive_habit(self): self.add_summary(habit) result_units = "9.1 dummy_units" - result = self._run_command(checkin, - ["Habit", "-q 9.1"]) + result = self._run_command(checkin, ["Habit", "-q 9.1"]) - activity_entry = models.Activity \ - .select().where(models.Activity.for_habit == habit) + activity_entry = models.Activity.select().where( + models.Activity.for_habit == habit + ) assert result.output.find(result_units) == -1 assert result.output.find(habit.name) == -1 assert activity_entry.count() == 0 @@ -70,7 +65,9 @@ def test_habito_checkin_should_update_past_date(self): for i in range(5): d = datetime.now() - timedelta(days=i) date_str = "{d.month}/{d.day}".format(d=d).strip() - checkin_result = self._run_command(checkin, ["Habit", "-d {}".format(date_str), "-q 35.0"]) + checkin_result = self._run_command( + checkin, ["Habit", "-d {}".format(date_str), "-q 35.0"] + ) self._verify_checkin_date(date_str, d.year, checkin_result.output) assert "35.0 dummy_units" in checkin_result.output @@ -83,12 +80,17 @@ def test_habito_checkin_should_update_past_year(self): d = datetime.now() + timedelta(days=2) date_str = "{d.month}/{d.day}".format(d=d).strip() - checkin_result = self._run_command(checkin, ["Habit", "-d {}".format(date_str), "-q 35.0"]) + checkin_result = self._run_command( + checkin, ["Habit", "-d {}".format(date_str), "-q 35.0"] + ) - a = models.Activity.select() \ - .where(models.Activity.update_date.year == d.year-1).get() + a = ( + models.Activity.select() + .where(models.Activity.update_date.year == d.year - 1) + .get() + ) assert a.quantum == 35.0 - self._verify_checkin_date(date_str, d.year-1, checkin_result.output) + self._verify_checkin_date(date_str, d.year - 1, checkin_result.output) assert "35.0 dummy_units" in checkin_result.output def test_habito_checkin_can_add_multiple_data_points_on_same_day(self): @@ -100,8 +102,9 @@ def test_habito_checkin_can_add_multiple_data_points_on_same_day(self): self._run_command(checkin, ["Habit", "-q 9.1"]) result = self._run_command(checkin, ["Habit", "-q 10.0001"]) - activity_entry = models.Activity \ - .select().where(models.Activity.for_habit == habit) + activity_entry = models.Activity.select().where( + models.Activity.for_habit == habit + ) assert result.output.find(result_units_one) != 1 assert result.output.find(result_units_two) != -1 diff --git a/tests/commands/test_delete.py b/tests/commands/test_delete.py index 6bac86f..e9ff9fe 100644 --- a/tests/commands/test_delete.py +++ b/tests/commands/test_delete.py @@ -11,14 +11,17 @@ def test_delete_removes_habit_activity(self): self.add_summary(habit) self._run_command(habito.commands.checkin, [habit.name, "-q 3"]) - delete_result = self._run_command_with_stdin(habito.commands.delete, - ["1"], "y") + delete_result = self._run_command_with_stdin(habito.commands.delete, ["1"], "y") - msg = "Are you sure you want to delete habit 1: {} (this cannot be" \ - " undone!)".format(habit.name) + msg = ( + "Are you sure you want to delete habit 1: {} (this cannot be" + " undone!)".format(habit.name) + ) assert msg in delete_result.output - assert "{0}: {1} has been deleted!".format(habit.id, - habit.name) in delete_result.output + assert ( + "{0}: {1} has been deleted!".format(habit.id, habit.name) + in delete_result.output + ) assert habito.models.Habit.select().count() == 0 def test_delete_should_not_delete_for_no_confirm(self): @@ -26,28 +29,34 @@ def test_delete_should_not_delete_for_no_confirm(self): self.add_summary(habit) self._run_command(habito.commands.checkin, [habit.name, "-q 3"]) - delete_result = self._run_command_with_stdin(habito.commands.delete, - ["1"], "n") + delete_result = self._run_command_with_stdin(habito.commands.delete, ["1"], "n") - msg = "Are you sure you want to delete habit 1: {} (this cannot be" \ - " undone!)".format(habit.name) + msg = ( + "Are you sure you want to delete habit 1: {} (this cannot be" + " undone!)".format(habit.name) + ) assert msg in delete_result.output assert habito.models.Habit.select().count() == 1 def test_non_existing_delete(self): delete_result = self._run_command(habito.commands.delete, ["20"]) - assert "The habit you want to remove does not seem to exist!" in delete_result.output + assert ( + "The habit you want to remove does not seem to exist!" + in delete_result.output + ) def test_delete_with_keep_logs_marks_habit_inactive(self): habit = self.create_habit() self.add_summary(habit) self._run_command(habito.commands.checkin, [habit.name, "-q 3"]) - delete_result = self._run_command_with_stdin(habito.commands.delete, - ["1", "--keeplogs"], "y") + delete_result = self._run_command_with_stdin( + habito.commands.delete, ["1", "--keeplogs"], "y" + ) assert delete_result.exit_code == 0 assert habito.models.Activity.select().count() == 1 - assert habito.models.Habit.select().where( - habito.models.Habit.active).count() == 0 + assert ( + habito.models.Habit.select().where(habito.models.Habit.active).count() == 0 + ) diff --git a/tests/commands/test_edit.py b/tests/commands/test_edit.py index 50b4dde..039ca4f 100644 --- a/tests/commands/test_edit.py +++ b/tests/commands/test_edit.py @@ -10,10 +10,13 @@ def test_edit(self): habit = self.create_habit() self.add_summary(habit) - edit_result = self._run_command(habito.commands.edit, [str(habit.id), "-n EHabit"]) + edit_result = self._run_command( + habito.commands.edit, [str(habit.id), "-n EHabit"] + ) - assert edit_result.output == ("Habit with id 1 has been saved with" - " name: EHabit and quantum: 0.0.\n") + assert edit_result.output == ( + "Habit with id 1 has been saved with" " name: EHabit and quantum: 0.0.\n" + ) list_result = self._run_command(habito.commands.list) assert "EHabit" in list_result.output assert habit.name not in list_result.output @@ -24,8 +27,9 @@ def test_edit_quantum(self): edit_result = self._run_command(habito.commands.edit, [str(habit.id), "-q 3.0"]) - assert edit_result.output == ("Habit with id 1 has been saved with" - " name: HabitOne and quantum: 3.0.\n") + assert edit_result.output == ( + "Habit with id 1 has been saved with" " name: HabitOne and quantum: 3.0.\n" + ) list_result = self._run_command(habito.commands.list) assert "3.0" in list_result.output assert "0.0" not in list_result.output diff --git a/tests/commands/test_list.py b/tests/commands/test_list.py index d359e30..1540ca2 100644 --- a/tests/commands/test_list.py +++ b/tests/commands/test_list.py @@ -18,7 +18,7 @@ def test_habito_list_lists_off_track_habits(self): # Habit is off track with quanta <= goal. Verify 'x' assert habit.name in result.output - assert u"-9.1" in result.output + assert "-9.1" in result.output def test_habito_list_lists_on_track_habits(self): habit = self.create_habit() @@ -29,7 +29,7 @@ def test_habito_list_lists_on_track_habits(self): # Habit is on track with quanta >= goal. Verify 'tick' assert habit.name in result.output - assert u"9.1" in result.output + assert "9.1" in result.output def test_habito_list_skips_inactive_habits(self): habit = self.create_habit() @@ -42,7 +42,7 @@ def test_habito_list_skips_inactive_habits(self): # Habit is on track with quanta >= goal. Verify 'tick' assert habit.name not in result.output - assert u"9.1" not in result.output + assert "9.1" not in result.output def test_habito_list_should_show_streak(self): habit = self.create_habit() @@ -56,7 +56,7 @@ def test_habito_list_should_show_streak(self): def test_habito_list_table_adapts_to_terminal_width(self, term_mock): for terminal_width in range(0, 101, 5): term_mock.return_value = (terminal_width, 80) - nr_of_dates = terminal_width//10 - 4 + nr_of_dates = terminal_width // 10 - 4 result = self._run_command(habito.commands.list, ["-l"]) if nr_of_dates < 1: assert "terminal window is too small" in result.output @@ -64,5 +64,7 @@ def test_habito_list_table_adapts_to_terminal_width(self, term_mock): else: assert result.exit_code == 0 for i in range(nr_of_dates): - date_string = "{dt.month}/{dt.day}".format(dt=(datetime.now() - timedelta(days=i))) + date_string = "{dt.month}/{dt.day}".format( + dt=(datetime.now() - timedelta(days=i)) + ) assert date_string in result.output diff --git a/tests/test_habito.py b/tests/test_habito.py index 41d5e18..e882259 100644 --- a/tests/test_habito.py +++ b/tests/test_habito.py @@ -27,17 +27,20 @@ def setUp(self): models.setup(habito.commands.database_name) def tearDown(self): - models.db.drop_tables([models.Habit, models.Activity, models.Summary], - safe=True) + models.db.drop_tables( + [models.Habit, models.Activity, models.Summary], safe=True + ) def test_habito_cli_sets_up_default_commandset(self): result = habito.commands.cli - commands = {'list': habito.commands.list, - 'add': habito.commands.add, - 'checkin': habito.commands.checkin, - 'edit': habito.commands.edit, - 'delete': habito.commands.delete} + commands = { + "list": habito.commands.list, + "add": habito.commands.add, + "checkin": habito.commands.checkin, + "edit": habito.commands.edit, + "delete": habito.commands.delete, + } assert result.commands == commands diff --git a/tests/test_models.py b/tests/test_models.py index 8dc95a9..22c9168 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -209,16 +209,19 @@ def setUp(self): models.setup(":memory:") def tearDown(self): - models.db.drop_tables([models.Habit, models.Activity, models.Summary], - safe=True) + models.db.drop_tables( + [models.Habit, models.Activity, models.Summary], safe=True + ) def test_habit_add_creates_a_habit(self): dummy_date = datetime.now() - habit = models.Habit.add(name="Dummy Habit", - created_date=dummy_date, - quantum=1, - units="dummy_units", - magica="magica") + habit = models.Habit.add( + name="Dummy Habit", + created_date=dummy_date, + quantum=1, + units="dummy_units", + magica="magica", + ) assert habit.name == "Dummy Habit" assert habit.created_date == dummy_date @@ -229,10 +232,9 @@ def test_habit_add_creates_a_habit(self): assert habit.active is True def test_habit_add_creates_a_summary_for_habit(self): - habit = models.Habit.add(name="Dummy Habit", - quantum=1, - units="dummy_units", - magica="magica") + habit = models.Habit.add( + name="Dummy Habit", quantum=1, units="dummy_units", magica="magica" + ) summary = models.Summary.get(for_habit=habit) assert summary.streak == 0 @@ -243,8 +245,9 @@ def setUp(self): models.setup(":memory:") def tearDown(self): - models.db.drop_tables([models.Habit, models.Activity, models.Summary], - safe=True) + models.db.drop_tables( + [models.Habit, models.Activity, models.Summary], safe=True + ) def test_update_streak_sets_streak_unchanged_for_no_activities(self): habit = self.create_habit()