Skip to content

Commit

Permalink
Allow for configuring the progress save folder
Browse files Browse the repository at this point in the history
Prepares for #816.
  • Loading branch information
fniessink committed Oct 7, 2024
1 parent d1004e5 commit 43f1e1c
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to Toisto will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Make the folder configurable where Toisto saves progress. Use `toisto configure --progress-folder {folder}` to change the folder. Note that Toisto does not copy or move your existing progress save files for you.

## 0.26.0 - 2024-10-05

### Added
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,21 @@ my_concepts2.json
> [!NOTE]
> See the [software documentation](docs/software.md) on how to create extra concept files.
### How to configure the folder where to save progress

By default, Toisto saves progress to your home folder. To save progress to a different folder, for example a cloud drive, configure the progress folder as follows:

```console
$ toisto configure --progress-folder /home/user/drive
```

When running the previous command, Toisto creates a file `.toisto.cfg` in your home directory if it doesn't exist, adds the `progress` section if it doesn't exist, and adds the folder:

```ini
[progress]
folder=/home/user/drive
```

### How to configure progress updates

To prevent having to pass the desired progress update frequency as command-line argument each time you run Toisto, you can save the progress update frequency to Toisto's configuration file:
Expand Down
3 changes: 3 additions & 0 deletions src/toisto/command/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def configure(argument_parser: ArgumentParser, config: ConfigParser, args: Names
if language in args and getattr(args, language):
ensure_section(config, "languages")
config.set("languages", language.split("_")[0], getattr(args, language))
if "progress_folder" in args:
ensure_section(config, "progress")
config.set("progress", "folder", str(args.progress_folder))
if "progress_update" in args:
ensure_section(config, "practice")
config.set("practice", "progress_update", str(args.progress_update))
Expand Down
3 changes: 3 additions & 0 deletions src/toisto/persistence/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ class Option:
practice=dict(
progress_update=Option(Quantifier.INTEGER, ["0", "1", "2", "3", "..."], lambda value: value.isdigit(), "0"),
),
progress=dict(
folder=Option(Quantifier.ANY, default_value=str(home())),
),
identity=dict(uuid=Option(Quantifier.ANY, default_value=str(uuid1()))),
files=[],
)
Expand Down
27 changes: 26 additions & 1 deletion src/toisto/ui/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from toisto.metadata import BUILT_IN_LANGUAGES, README_URL, SUMMARY, VERSION, latest_version
from toisto.model.language.concept import Concept
from toisto.model.language.iana_language_subtag_registry import ALL_LANGUAGES, IANA_LANGUAGE_SUBTAG_REGISTRY_URL
from toisto.persistence.folder import home

if TYPE_CHECKING:
from argparse import _SubParsersAction
Expand All @@ -25,6 +26,14 @@ def check_language(language: str) -> str:
raise ArgumentTypeError(message)


def check_folder(folder: str) -> str:
"""Check that the folder exists."""
if Path(folder).is_dir():
return folder
message = f"folder '{folder}' does not exist or is not a folder"
raise ArgumentTypeError(message)


class CommandBuilder:
"""Command builder."""

Expand Down Expand Up @@ -83,6 +92,17 @@ def add_file_arguments(self, parser: ArgumentParser) -> None:
type=Path,
)

def add_progress_folder_argument(self, parser: ArgumentParser) -> None:
"""Add the progress folder argument to the command."""
default = self.config.get("progress", "folder")
parser.add_argument(
"--progress-folder",
metavar="{folder}",
type=check_folder,
default=default,
help=f"folder where to save progress; default: {default}",
)

def add_progress_update_argument(self, parser: ArgumentParser) -> None:
"""Add the progress update argument to the command."""
default = self.config.get("practice", "progress_update")
Expand Down Expand Up @@ -118,9 +138,14 @@ def add_command(self) -> None:
"configure options, for example `%(prog)s configure --target fi --source en` to make "
"practicing Finnish from English the default"
)
parser = self._add_command("configure", "Configure options and save them in ~/.toisto.cfg.", command_help)
parser = self._add_command(
"configure",
f"Configure options and save them in {home()!s}/.toisto.cfg.",
command_help,
)
self.add_language_arguments(parser)
self.add_file_arguments(parser)
self.add_progress_folder_argument(parser)
self.add_progress_update_argument(parser)
self.add_mp3player_argument(parser)

Expand Down
6 changes: 6 additions & 0 deletions tests/toisto/command/test_configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,9 @@ def test_change_files(self, write_config: Mock) -> None:
config = ConfigParser()
configure(self.argument_parser, config, Namespace(file=[Path("/home/user/extra.json")]))
self.assert_configured(write_config, config, ("files", "/home/user/extra.json", ""))

def test_progress_folder(self, write_config: Mock) -> None:
"""Test changing the progress folder."""
config = ConfigParser()
configure(self.argument_parser, config, Namespace(progress_folder="/home/user/toisto"))
self.assert_configured(write_config, config, ("progress", "folder", "/home/user/toisto"))
39 changes: 37 additions & 2 deletions tests/toisto/ui/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
from toisto.model.language.concept import Concept, ConceptId
from toisto.model.language.label import Label, Labels
from toisto.persistence.config import default_config
from toisto.persistence.folder import home
from toisto.ui.cli import create_argument_parser, parse_arguments

CONFIGURE_USAGE = (
"Usage: toisto configure [-h] [-t {language}] [-s {language}] [-f {file}] [-p {frequency}] [-m {mp3player}]"
"Usage: toisto configure [-h] [-t {language}] [-s {language}] [-f {file}] [--progress-folder {folder}] "
"[-p {frequency}]\n"
" [-m {mp3player}]"
)
CONFIGURE_DESCRIPTION = "Configure options and save them in ~/.toisto.cfg."
PRACTICE_USAGE = "Usage: toisto practice [-h] -t {language} -s {language} [-f {file}] [-p {frequency}] [{concept} ...]"
CONFIGURE_DESCRIPTION = f"Configure options and save them in {home()!s}/.toisto.cfg."
PRACTICE_USAGE_OPTIONAL_TARGET = (
"Usage: toisto practice [-h] [-t {language}] -s {language} [-f {file}] [-p {frequency}] [{concept} ...]"
)
Expand All @@ -31,6 +34,8 @@
SOURCE_OPTION = """-s, --source {language}
source language; languages available in built-in concepts: en, fi, nl"""
FILE_OPTION = "-f, --file {file} file with extra concepts to read, can be repeated"
PROGRESS_FOLDER = f"""--progress-folder {{folder}}
folder where to save progress; default: {home()!s}"""
PROGRESS_OPTION = """-p, --progress-update {frequency}
show a progress update after each {frequency} quizzes; default: %s (0 means never)"""
MP3PLAYER_OPTION = """-m, --mp3player {mp3player}
Expand Down Expand Up @@ -92,12 +97,41 @@ def test_configure_command(self) -> None:
command="configure",
file=[],
mp3player="afplay",
progress_folder=str(home()),
progress_update=0,
source_language="fi",
target_language="nl",
)
self.assertEqual(expected_namespace, parse_arguments(self.argument_parser()))

@patch("sys.platform", "darwin")
@patch("sys.argv", ["toisto", "configure", "--progress-folder", "/home/user/toisto"])
@patch("toisto.ui.cli.Path.is_dir", Mock(return_value=True))
def test_configure_progress_folder(self) -> None:
"""Test that the progress folder can be configured."""
expected_namespace = Namespace(
command="configure",
file=[],
mp3player="afplay",
progress_folder="/home/user/toisto",
progress_update=0,
source_language=None,
target_language=None,
)
self.assertEqual(expected_namespace, parse_arguments(self.argument_parser()))

@patch("sys.platform", "darwin")
@patch("sys.argv", ["toisto", "configure", "--progress-folder", "/home/user/toisto"])
@patch("toisto.ui.cli.Path.is_dir", Mock(return_value=False))
@patch("sys.stderr.write")
def test_configure_non_existing_progress_folder(self, sys_stderr_write: Mock) -> None:
"""Test that the progress folder is checked for existence."""
self.assertRaises(SystemExit, parse_arguments, self.argument_parser())
self.assertIn(
"error: argument --progress-folder: folder '/home/user/toisto' does not exist or is not a folder",
sys_stderr_write.call_args_list[1][0][0],
)

@patch("sys.platform", "darwin")
@patch("sys.argv", ["toisto", "configure", "--help"])
@patch("sys.stdout.write")
Expand All @@ -114,6 +148,7 @@ def test_configure_help(self, sys_stdout_write: Mock) -> None:
{TARGET_OPTION % ""}
{SOURCE_OPTION}
{FILE_OPTION}
{PROGRESS_FOLDER}
{PROGRESS_OPTION % "0"}
{MP3PLAYER_OPTION}
""",
Expand Down

0 comments on commit 43f1e1c

Please sign in to comment.