aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsetup.py3
-rw-r--r--src/vgstash_cli.py88
-rw-r--r--tests/data/test_import.yml8
-rw-r--r--tests/test_vgstash_cli.py43
4 files changed, 100 insertions, 42 deletions
diff --git a/setup.py b/setup.py
index f978307..4cfc126 100755
--- a/setup.py
+++ b/setup.py
@@ -10,7 +10,7 @@ with open('README.md') as f:
setup(
name='vgstash',
- version='0.3-beta3',
+ version='0.3-beta4',
description='a video game collection management module, backed by SQLite',
long_description=readme,
long_description_content_type="text/markdown; variant=CommonMark",
@@ -30,6 +30,7 @@ setup(
install_requires=[
'Click>=6.0', # for CLI
'PyYAML', # import/export YAML files
+ 'json' # part of the standard library, but someone might've compiled Python without it
],
classifiers=(
"Development Status :: 4 - Beta",
diff --git a/src/vgstash_cli.py b/src/vgstash_cli.py
index 7996086..b92201f 100644
--- a/src/vgstash_cli.py
+++ b/src/vgstash_cli.py
@@ -6,6 +6,7 @@ import subprocess
import sys
import tempfile
import yaml
+import json
# Click also has this, but it doesn't support a fallback value.
from shutil import get_terminal_size
@@ -207,7 +208,7 @@ def notes(title, system, edit):
@cli.command("import")
-@click.option("--format", "-f", type=click.Choice(["yaml"]), required=False, default="yaml")
+@click.option("--format", "-f", type=click.Choice(["yaml", "json"]), required=False, default="yaml")
@click.option("--update", "-u", is_flag=True, default=False, help="Overwrite existing games with the file's data")
@click.argument("filepath",
type=click.Path(
@@ -223,34 +224,42 @@ def import_file(format, filepath, update):
Import game data from an external file matching the chosen format.
The default format is YAML.
+
+ Available formats:
+
+ * JSON
+ * YAML
"""
- if format == "yaml":
- with open(filepath) as fp:
+ with open(filepath) as fp:
+ if format == "yaml":
data = yaml.safe_load(fp)
- db = get_db()
- count = len(data)
- for game in data:
- try:
- db.add_game(
- vgstash.Game(
- game["title"],
- game["system"],
- game["ownership"],
- game["progress"],
- game["notes"]
- ),
- update=update
- )
- except sqlite3.IntegrityError as e:
- count -= 1
- if count > 0:
- click.echo("Successfully imported {} games from {}.".format(count, filepath))
- else:
- click.echo("Couldn't import any games. Is the YAML file formatted correctly?")
+ if format == "json":
+ data = json.load(fp)
+ db = get_db()
+ count = len(data)
+ for game in data:
+ try:
+ db.add_game(
+ vgstash.Game(
+ game["title"],
+ game["system"],
+ game["ownership"],
+ game["progress"],
+ game["notes"]
+ ),
+ update=update
+ )
+ except sqlite3.IntegrityError as e:
+ # skip games that already exist
+ count -= 1
+ if count > 0:
+ click.echo("Successfully imported {} games from {}.".format(count, filepath))
+ else:
+ click.echo("Couldn't import any games. Is the file formatted correctly?")
@cli.command("export")
-@click.option("--format", "-f", type=click.Choice(["yaml"]), required=False, default="yaml")
+@click.option("--format", "-f", type=click.Choice(["yaml", "json"]), required=False, default="yaml")
@click.argument("filepath",
type=click.Path(
exists=False,
@@ -267,22 +276,29 @@ def export_file(format, filepath):
Export the game database to a file written in the chosen format.
The default format is YAML.
+
+ Available formats:
+
+ * JSON
+ * YAML
"""
db = get_db()
data = db.list_games()
game_set = []
- # Time to re-read master's code
- if format == "yaml":
- for game in data:
- g = {}
- for field in game.keys():
- g.update({field: game[field]})
- game_set.append(g)
- with open(filepath, "w") as fp:
+ # Time to re-read the master branch's code
+ for game in data:
+ g = {}
+ for field in game.keys():
+ g.update({field: game[field]})
+ game_set.append(g)
+ with open(filepath, "w") as fp:
+ if format == "yaml":
yaml.dump(game_set, fp, default_flow_style=False,
indent=4, allow_unicode=True)
- if len(game_set) > 0:
- click.echo("Successfully exported {} games to {}.".format(len(game_set), filepath))
- else:
- click.echo("Could not export any games; have you made sure your collection has games in it?")
+ if format == "json":
+ json.dump(game_set, fp, allow_nan=False, indent=1, skipkeys=True, sort_keys=True)
+ if len(game_set) > 0:
+ click.echo("Successfully exported {} games to {}.".format(len(game_set), filepath))
+ else:
+ click.echo("Could not export any games; have you made sure your collection has games in it?")
diff --git a/tests/data/test_import.yml b/tests/data/test_import.yml
index eb93579..b01538f 100644
--- a/tests/data/test_import.yml
+++ b/tests/data/test_import.yml
@@ -1,13 +1,13 @@
# vgstash DB file version 0.2
- ownership: 1
progress: 3
- system: NES
- title: Super Mario Bros.
+ system: GBA
+ title: Fire Emblem
notes: ''
- ownership: 2
progress: 4
- system: 3DS
- title: The Legend of Zelda
+ system: Switch
+ title: Puyo Puyo Tetris
notes: ''
- ownership: 2
progress: 3
diff --git a/tests/test_vgstash_cli.py b/tests/test_vgstash_cli.py
index c3b60d6..30eff62 100644
--- a/tests/test_vgstash_cli.py
+++ b/tests/test_vgstash_cli.py
@@ -241,6 +241,38 @@ def test_notes_edit():
assert list_result.exit_code == 0
+def test_import_file_json():
+ runner = CliRunner()
+ result = runner.invoke(vgstash_cli.cli, ["import", "tests/data/test_import.json"])
+ if verbose:
+ print(result.output)
+ assert result.exit_code == 0
+ assert result.output == "Successfully imported 2 games from {}.\n".format(os.path.join(os.getcwd(), "tests/data/test_import.json"))
+
+ # List the results to make sure they match what the editor has.
+ list_runner = CliRunner()
+ list_result = runner.invoke(vgstash_cli.cli, ['list', '-w', '40'])
+ if verbose:
+ print(list_result.output)
+ assert list_result.exit_code == 0
+
+
+def test_import_file_json_update():
+ runner = CliRunner()
+ result = runner.invoke(vgstash_cli.cli, ["import", "tests/data/test_import.json", "-u"])
+ if verbose:
+ print(result.output)
+ assert result.exit_code == 0
+ assert result.output == "Successfully imported 3 games from {}.\n".format(os.path.join(os.getcwd(), "tests/data/test_import.json"))
+
+ # List the results to make sure they match what the editor has.
+ list_runner = CliRunner()
+ list_result = runner.invoke(vgstash_cli.cli, ['list', '-w', '40'])
+ if verbose:
+ print(list_result.output)
+ assert list_result.exit_code == 0
+
+
def test_import_file_yaml():
runner = CliRunner()
result = runner.invoke(vgstash_cli.cli, ["import", "tests/data/test_import.yml"])
@@ -273,10 +305,19 @@ def test_import_file_yaml_update():
assert list_result.exit_code == 0
+def test_export_file_json():
+ runner = CliRunner()
+ result = runner.invoke(vgstash_cli.cli, ["export", "-f", "json", "tests/data/test_export.json"])
+ if verbose:
+ print(result.output)
+ assert result.exit_code == 0
+ assert result.output == "Successfully exported 8 games to {}.\n".format(os.path.join(os.getcwd(), "tests/data/test_export.json"))
+
+
def test_export_file_yaml():
runner = CliRunner()
result = runner.invoke(vgstash_cli.cli, ["export", "-f", "yaml", "tests/data/test_export.yml"])
if verbose:
print(result.output)
assert result.exit_code == 0
- assert result.output == "Successfully exported 6 games to {}.\n".format(os.path.join(os.getcwd(), "tests/data/test_export.yml"))
+ assert result.output == "Successfully exported 8 games to {}.\n".format(os.path.join(os.getcwd(), "tests/data/test_export.yml"))