feat: add tagspaces plugin with folder and any-file-type plugin support
This commit is contained in:
parent
712fe264be
commit
4cfbd581bc
6 changed files with 225 additions and 9 deletions
117
tests/test_tagspaces.py
Normal file
117
tests/test_tagspaces.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
import json
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import orvanitag.orvani as orvani
|
||||
from orvanitag.cmd import main
|
||||
from orvanitag.entry import Entry
|
||||
from orvanitag.orvani import OrvaniTag
|
||||
from orvanitag.errors import UnsupportedType
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cwd(tmp_path, monkeypatch):
|
||||
monkeypatch.chdir(tmp_path)
|
||||
return tmp_path
|
||||
|
||||
|
||||
def sidecar(cwd, name):
|
||||
return json.loads((cwd / '.ts' / f'{name}.json').read_text())
|
||||
|
||||
|
||||
def test_sidecar_roundtrip(cwd):
|
||||
(cwd / 'song.mp3').touch()
|
||||
OrvaniTag().add('song.mp3', '+album', '@drums', '#lofi', 'a note')
|
||||
OrvaniTag().write_metadata('song.mp3', 'tagspaces')
|
||||
data = sidecar(cwd, 'song.mp3')
|
||||
assert [tag['title'] for tag in data['tags']] == ['+album', '@drums', 'lofi']
|
||||
assert data['tags'][0]['type'] == 'sidecar' and len(data['id']) == 32
|
||||
|
||||
(cwd / orvani.CONTEXT_FILE).unlink()
|
||||
assert OrvaniTag().scan('.') == ({'song.mp3': Entry(['album'], ['drums'], ['lofi'])}, [])
|
||||
|
||||
|
||||
def test_existing_sidecar_keeps_its_data(cwd):
|
||||
(cwd / 'a.heic').touch()
|
||||
(cwd / '.ts').mkdir()
|
||||
(cwd / '.ts' / 'a.heic.json').write_text(json.dumps({
|
||||
'appName': 'TagSpaces', 'id': 'x1', 'description': '# Trip\n\nin *markdown*', 'lastUpdated': 1,
|
||||
'tags': [{'title': 'new york', 'color': '#ffcc24', 'textcolor': '#ffffff', 'type': 'sidecar'},
|
||||
{'title': '#gone', 'type': 'sidecar'}],
|
||||
}))
|
||||
assert OrvaniTag().read_metadata('a.heic') == Entry(tags=['new_york', 'gone'])
|
||||
|
||||
OrvaniTag().remove('a.heic', '#gone')
|
||||
OrvaniTag().add('a.heic', '@city')
|
||||
OrvaniTag().write_metadata('a.heic', 'tagspaces')
|
||||
data = sidecar(cwd, 'a.heic')
|
||||
assert data['tags'] == [{'title': '@city', 'type': 'sidecar'},
|
||||
{'title': 'new york', 'color': '#ffcc24', 'textcolor': '#ffffff', 'type': 'sidecar'}]
|
||||
assert data['description'] == '# Trip\n\nin *markdown*' and data['id'] == 'x1' and data['appName'] == 'TagSpaces'
|
||||
assert data['lastUpdated'] > 1
|
||||
|
||||
|
||||
def test_folder_tags(cwd):
|
||||
(cwd / 'sub' / 'deeper').mkdir(parents=True)
|
||||
OrvaniTag().add('sub', '+trip')
|
||||
OrvaniTag().write_metadata('sub', 'tagspaces')
|
||||
assert json.loads((cwd / 'sub' / '.ts' / 'tsm.json').read_text())['tags'] == [{'title': '+trip', 'type': 'sidecar'}]
|
||||
|
||||
(cwd / 'sub' / 'deeper' / '.ts').mkdir()
|
||||
(cwd / 'sub' / 'deeper' / '.ts' / 'tsm.json').write_text('{"tags": [{"title": "deep"}]}')
|
||||
(cwd / orvani.CONTEXT_FILE).unlink()
|
||||
assert OrvaniTag().scan('sub') == ({'sub/deeper': Entry(tags=['deep'])}, []) # the scanned folder itself is skipped
|
||||
assert OrvaniTag().scan('.', recursive=True)[0] == {'sub': Entry(['trip']), 'sub/deeper': Entry(tags=['deep'])}
|
||||
assert (cwd / orvani.CONTEXT_FILE).read_text() == 'sub/ --- +trip\n'
|
||||
|
||||
|
||||
def test_name_tags_are_read_and_not_repeated(cwd):
|
||||
(cwd / 'IMG[vacation alps].heic').touch()
|
||||
assert OrvaniTag().read_metadata('IMG[vacation alps].heic') == Entry(tags=['vacation', 'alps'])
|
||||
OrvaniTag().add('IMG[vacation alps].heic', '#beach')
|
||||
OrvaniTag().write_metadata('IMG[vacation alps].heic', 'tagspaces')
|
||||
assert sidecar(cwd, 'IMG[vacation alps].heic')['tags'] == [{'title': 'beach', 'type': 'sidecar'}]
|
||||
assert (cwd / 'IMG[vacation alps].heic').exists()
|
||||
|
||||
|
||||
def test_clear_keeps_the_sidecar_data(cwd):
|
||||
(cwd / 'a.txt').touch()
|
||||
(cwd / 'b.txt').touch()
|
||||
(cwd / '.ts').mkdir()
|
||||
(cwd / '.ts' / 'a.txt.json').write_text('{"id": "x1", "description": "d", "tags": [{"title": "t"}]}')
|
||||
OrvaniTag().write_metadata('a.txt', 'tagspaces', clear=True)
|
||||
assert sidecar(cwd, 'a.txt') == {'id': 'x1', 'description': 'd', 'tags': []}
|
||||
OrvaniTag().write_metadata('b.txt', 'tagspaces', clear=True)
|
||||
assert not (cwd / '.ts' / 'b.txt.json').exists()
|
||||
|
||||
|
||||
def test_broken_sidecar_is_a_scan_error(cwd):
|
||||
(cwd / 'a.txt').touch()
|
||||
(cwd / '.ts').mkdir()
|
||||
(cwd / '.ts' / 'a.txt.json').write_text('{broken')
|
||||
found, errors = OrvaniTag().scan('.')
|
||||
assert found == {} and len(errors) == 1 and 'a.txt.json is no valid JSON' in errors[0]
|
||||
|
||||
|
||||
def test_configured_types_narrow_plugins_for_any_type(cwd):
|
||||
(cwd / orvani.CONFIG_FILE).write_text('[tagspaces]\ntypes = [".jpg"]\n')
|
||||
for name in ['a.jpg', 'a.png']:
|
||||
(cwd / name).touch()
|
||||
OrvaniTag().add(name, '#x')
|
||||
OrvaniTag().write_metadata('a.jpg', 'tagspaces')
|
||||
with pytest.raises(UnsupportedType):
|
||||
OrvaniTag().write_metadata('a.png', 'tagspaces')
|
||||
|
||||
|
||||
def test_other_plugins_do_not_handle_folders(cwd, monkeypatch, capsys):
|
||||
(cwd / 'sub.py').mkdir()
|
||||
(cwd / 'sub.py' / 'x.py').write_text('# otag: #inner\n')
|
||||
OrvaniTag().add('sub.py', '#x')
|
||||
with pytest.raises(UnsupportedType, match="can't write to folders"):
|
||||
OrvaniTag().write_metadata('sub.py', 'comment')
|
||||
assert OrvaniTag().scan('.')[0] == {}
|
||||
|
||||
monkeypatch.setattr(sys, 'argv', ['otag', 'w', 'tagspaces', 'sub.py/'])
|
||||
main()
|
||||
assert (cwd / 'sub.py' / '.ts' / 'tsm.json').exists()
|
||||
Loading…
Add table
Add a link
Reference in a new issue