Add meta format mapper

This commit is contained in:
Joakim Soderlund 2017-11-10 23:38:49 +01:00
parent 478b2e7080
commit 4ee0824230
2 changed files with 85 additions and 3 deletions

View file

@ -24,11 +24,12 @@ Mappers for Fimfarchive.
import os import os
from abc import abstractmethod from abc import abstractmethod
from typing import Generic, Optional, TypeVar from typing import Dict, Generic, Optional, Set, TypeVar
from arrow import api as arrow, Arrow from arrow import api as arrow, Arrow
from fimfarchive.exceptions import InvalidStoryError from fimfarchive.exceptions import InvalidStoryError
from fimfarchive.flavors import MetaFormat
from fimfarchive.stories import Story from fimfarchive.stories import Story
@ -115,3 +116,24 @@ class StoryPathMapper(Mapper[str]):
key = str(story.key) key = str(story.key)
return os.path.join(directory, key) return os.path.join(directory, key)
class MetaFormatMapper(Mapper[Optional[MetaFormat]]):
"""
Guesses the meta format of stories.
"""
spec: Dict[MetaFormat, Set[str]] = {
MetaFormat.ALPHA: {'likes', 'dislikes', 'words'},
MetaFormat.BETA: {'num_likes', 'num_dislikes', 'num_words'},
}
def __call__(self, story: Story) -> Optional[MetaFormat]:
items = self.spec.items()
meta = set(story.meta.keys())
matches = {fmt for fmt, spec in items if spec & meta}
if len(matches) == 1:
return next(iter(matches))
else:
return None

View file

@ -23,12 +23,16 @@ Mapper tests.
import os import os
from typing import no_type_check, Dict, Any
from unittest.mock import patch, MagicMock, PropertyMock from unittest.mock import patch, MagicMock, PropertyMock
import pytest import pytest
from fimfarchive.exceptions import InvalidStoryError from fimfarchive.exceptions import InvalidStoryError
from fimfarchive.mappers import StaticMapper, StoryDateMapper, StoryPathMapper from fimfarchive.flavors import MetaFormat
from fimfarchive.mappers import (
MetaFormatMapper, StaticMapper, StoryDateMapper, StoryPathMapper
)
from fimfarchive.stories import Story from fimfarchive.stories import Story
@ -108,7 +112,7 @@ class TestStoryDateMapper:
""" """
Tests `None` is returned when meta contains no dates. Tests `None` is returned when meta contains no dates.
""" """
meta = { meta: Dict[str, Any] = {
CHAPTERS: [ CHAPTERS: [
dict(), dict(),
dict(), dict(),
@ -259,6 +263,7 @@ class TestStoryPathMapper:
assert mapper(story) == path assert mapper(story) == path
@no_type_check
def test_casts_values(self, tmpdir, story): def test_casts_values(self, tmpdir, story):
""" """
Tests casts all values to string when joining. Tests casts all values to string when joining.
@ -274,3 +279,58 @@ class TestStoryPathMapper:
assert mapper(story) == os.path.join('dir', 'key') assert mapper(story) == os.path.join('dir', 'key')
assert directory.__str__.called_once_with() assert directory.__str__.called_once_with()
assert story.key.__str__.called_once_with() assert story.key.__str__.called_once_with()
class TestMetaFormatMapper:
"""
MetaFormatMapper tests.
"""
@pytest.fixture
def mapper(self):
"""
Returns a meta format mapper instance.
"""
return MetaFormatMapper()
@pytest.fixture(params=['likes', 'dislikes', 'words'])
def alpha(self, request):
"""
Returns an alpha meta key.
"""
return request.param
@pytest.fixture(params=['num_likes', 'num_dislikes', 'num_words'])
def beta(self, request):
"""
Returns a beta meta key.
"""
return request.param
def merge(self, story, *keys):
"""
Returns a story containing the requested meta keys.
"""
meta = {key: i for i, key in enumerate(keys, 1)}
return story.merge(meta=meta)
def test_alpha_format(self, mapper, story, alpha):
"""
Tests alpha meta format is detected.
"""
story = self.merge(story, alpha, 'misc')
assert mapper(story) == MetaFormat.ALPHA
def test_beta_format(self, mapper, story, beta):
"""
Tests beta meta format is detected.
"""
story = self.merge(story, beta, 'misc')
assert mapper(story) == MetaFormat.BETA
def test_conflict(self, mapper, story, alpha, beta):
"""
Tests None is returned for conflicting meta keys.
"""
story = self.merge(story, alpha, beta)
assert mapper(story) is None