# Path: fimfarchive/flavors.py
# class Flavor(Enum):
#     """
#     Base class for flavors.
#     """
# 
#     def __new__(cls, *args):
#         """
#         Automatically assigns an enum value.
#         """
#         value = len(cls.__members__) + 1
#         obj = object.__new__(cls)
#         obj._value_ = value
#         return obj
# 
#     def __repr__(self):
#         """
#         Custom representation for instances.
#         """
#         return "<flavor '{}.{}'>".format(
#             type(self).__name__,
#             getattr(self, 'name', None),
#         )
# 
# Path: fimfarchive/stories.py
# class Story:
#     """
#     Represents a story.
#     """
# 
#     def __init__(
#             self,
#             key: int,
#             fetcher: Fetcher = None,
#             meta: Dict[str, Any] = None,
#             data: bytes = None,
#             flavors: Iterable[Flavor] = (),
#             ) -> None:
#         """
#         Constructor.
# 
#         Args:
#             key: Primary key of the story.
#             fetcher: Fetcher to use for lazy fetching.
#             meta: Meta to populate the story with.
#             data: Data to populate the story with.
#             flavors: Content type hints.
#         """
#         if fetcher is None and (data is None or meta is None):
#             raise ValueError("Story must contain fetcher if lazy.")
# 
#         self.key = key
#         self.fetcher = fetcher
#         self.flavors = set(flavors)
#         self._meta = meta
#         self._data = data
# 
#     @property
#     def is_fetched(self) -> bool:
#         """
#         True if no more fetches are necessary.
#         """
#         return self.has_meta and self.has_data
# 
#     @property
#     def has_meta(self) -> bool:
#         """
#         True if story meta has been fetched.
#         """
#         return self._meta is not None
# 
#     @property
#     def meta(self) -> Dict[str, Any]:
#         """
#         Returns the story meta.
# 
#         Meta may be fetched if this story instance is lazy.
# 
#         Raises:
#             InvalidStoryError: If a valid story is not found.
#             StorySourceError: If source does not return any data.
#         """
#         if self._meta is None and self.fetcher:
#             self._meta = self.fetcher.fetch_meta(self.key)
# 
#         if self._meta is None:
#             raise StorySourceError("Meta is missing.")
# 
#         return self._meta
# 
#     @property
#     def has_data(self) -> bool:
#         """
#         True if story data has been fetched.
#         """
#         return self._data is not None
# 
#     @property
#     def data(self) -> bytes:
#         """
#         Returns the story data.
# 
#         Data may be fetched if this story instance is lazy.
# 
#         Raises:
#             InvalidStoryError: If a valid story is not found.
#             StorySourceError: If source does not return any data.
#         """
#         if self._data is None and self.fetcher:
#             self._data = self.fetcher.fetch_data(self.key)
# 
#         if self._data is None:
#             raise StorySourceError("Data is missing.")
# 
#         return self._data
# 
#     def merge(self, **params) -> 'Story':
#         """
#         Returns a shallow copy, optionally replacing attributes.
# 
#         Args:
#             **params: Overrides parameters from the current instance.
# 
#         Raises:
#             TypeError: If passed an unexpected parameter.
#         """
#         kwargs = {k.lstrip('_'): v for k, v in vars(self).items()}
#         kwargs.update(params)
# 
#         return type(self)(**kwargs)


from typing import FrozenSet
from fimfarchive.flavors import Flavor
from fimfarchive.stories import Story
        Fetches story information.

        Args:
            key: Primary key of the story.
            prefetch_meta: Force prefetching of meta.
            prefetch_data: Force prefetching of data.

        Returns:
            Story: A new `Story` object.

        Raises:
            InvalidStoryError: If a valid story is not found.
            StorySourceError: If source does not return any data.
        """
        if prefetch_meta is None:
            prefetch_meta = self.prefetch_meta

        if prefetch_meta:
            meta = self.fetch_meta(key)
        else:
            meta = None

        if prefetch_data is None:
            prefetch_data = self.prefetch_data

        if prefetch_data:
            data = self.fetch_data(key)
        else:
            data = None


# Path: fimfarchive/flavors.py
# class Flavor(Enum):
#     """
#     Base class for flavors.
#     """
# 
#     def __new__(cls, *args):
#         """
#         Automatically assigns an enum value.
#         """
#         value = len(cls.__members__) + 1
#         obj = object.__new__(cls)
#         obj._value_ = value
#         return obj
# 
#     def __repr__(self):
#         """
#         Custom representation for instances.
#         """
#         return "<flavor '{}.{}'>".format(
#             type(self).__name__,
#             getattr(self, 'name', None),
#         )
# 
# Path: fimfarchive/stories.py
# class Story:
#     """
#     Represents a story.
#     """
# 
#     def __init__(
#             self,
#             key: int,
#             fetcher: Fetcher = None,
#             meta: Dict[str, Any] = None,
#             data: bytes = None,
#             flavors: Iterable[Flavor] = (),
#             ) -> None:
#         """
#         Constructor.
# 
#         Args:
#             key: Primary key of the story.
#             fetcher: Fetcher to use for lazy fetching.
#             meta: Meta to populate the story with.
#             data: Data to populate the story with.
#             flavors: Content type hints.
#         """
#         if fetcher is None and (data is None or meta is None):
#             raise ValueError("Story must contain fetcher if lazy.")
# 
#         self.key = key
#         self.fetcher = fetcher
#         self.flavors = set(flavors)
#         self._meta = meta
#         self._data = data
# 
#     @property
#     def is_fetched(self) -> bool:
#         """
#         True if no more fetches are necessary.
#         """
#         return self.has_meta and self.has_data
# 
#     @property
#     def has_meta(self) -> bool:
#         """
#         True if story meta has been fetched.
#         """
#         return self._meta is not None
# 
#     @property
#     def meta(self) -> Dict[str, Any]:
#         """
#         Returns the story meta.
# 
#         Meta may be fetched if this story instance is lazy.
# 
#         Raises:
#             InvalidStoryError: If a valid story is not found.
#             StorySourceError: If source does not return any data.
#         """
#         if self._meta is None and self.fetcher:
#             self._meta = self.fetcher.fetch_meta(self.key)
# 
#         if self._meta is None:
#             raise StorySourceError("Meta is missing.")
# 
#         return self._meta
# 
#     @property
#     def has_data(self) -> bool:
#         """
#         True if story data has been fetched.
#         """
#         return self._data is not None
# 
#     @property
#     def data(self) -> bytes:
#         """
#         Returns the story data.
# 
#         Data may be fetched if this story instance is lazy.
# 
#         Raises:
#             InvalidStoryError: If a valid story is not found.
#             StorySourceError: If source does not return any data.
#         """
#         if self._data is None and self.fetcher:
#             self._data = self.fetcher.fetch_data(self.key)
# 
#         if self._data is None:
#             raise StorySourceError("Data is missing.")
# 
#         return self._data
# 
#     def merge(self, **params) -> 'Story':
#         """
#         Returns a shallow copy, optionally replacing attributes.
# 
#         Args:
#             **params: Overrides parameters from the current instance.
# 
#         Raises:
#             TypeError: If passed an unexpected parameter.
#         """
#         kwargs = {k.lstrip('_'): v for k, v in vars(self).items()}
#         kwargs.update(params)
# 
#         return type(self)(**kwargs)


# Path: fimfarchive/fetchers/base.py
from typing import FrozenSet
from fimfarchive.flavors import Flavor
from fimfarchive.stories import Story

        Fetches story information.

        Args:
            key: Primary key of the story.
            prefetch_meta: Force prefetching of meta.
            prefetch_data: Force prefetching of data.

        Returns:
            Story: A new `Story` object.

        Raises:
            InvalidStoryError: If a valid story is not found.
            StorySourceError: If source does not return any data.
        """
        if prefetch_meta is None:
            prefetch_meta = self.prefetch_meta

        if prefetch_meta:
            meta = self.fetch_meta(key)
        else:
            meta = None

        if prefetch_data is None:
            prefetch_data = self.prefetch_data

        if prefetch_data:
            data = self.fetch_data(key)
        else:
            data = None


        return Story(key, self, meta, data, self.flavors)