from typing import Any, Callable, Dict, Optional, Type, Union, overload
from faker import Faker
from faker.generator import Generator
from faker.providers import BaseProvider
from faker.providers.python import Provider
from ...base import DEFAULT_FORMAT_FUNC, BytesValue, FileMixin, StringValue
from ...constants import DEFAULT_AUDIO_MAX_NB_CHARS
from ...helpers import load_class_from_path
from ...registry import FILE_REGISTRY
from ...storages.base import BaseStorage
from ...storages.filesystem import FileSystemStorage
from ..base.mp3_generator import BaseMp3Generator
__author__ = "Artur Barseghyan <artur.barseghyan@gmail.com>"
__copyright__ = "2022-2023 Artur Barseghyan"
__license__ = "MIT"
__all__ = (
"DEFAULT_MP3_GENERATOR",
"EDGE_TTS_MP3_GENERATOR",
"GTTS_MP3_GENERATOR",
"Mp3FileProvider",
)
GTTS_MP3_GENERATOR = (
"faker_file.providers.mp3_file.generators.gtts_generator.GttsMp3Generator"
)
EDGE_TTS_MP3_GENERATOR = (
"faker_file.providers.mp3_file.generators.edge_tts_generator"
".EdgeTtsMp3Generator"
)
DEFAULT_MP3_GENERATOR = GTTS_MP3_GENERATOR
[docs]class Mp3FileProvider(BaseProvider, FileMixin):
"""MP3 file provider.
Usage example:
.. code-block:: python
from faker import Faker
from faker_file.providers.mp3_file import Mp3FileProvider
FAKER = Faker()
FAKER.add_provider(Mp3FileProvider)
file = FAKER.mp3_file()
Usage example with options:
.. code-block:: python
file = FAKER.mp3_file(
prefix="zzz",
max_nb_chars=500,
)
Usage example with `FileSystemStorage` storage (for `Django`):
.. code-block:: python
from django.conf import settings
from faker_file.storages.filesystem import FileSystemStorage
file = FAKER.mp3_file(
storage=FileSystemStorage(
root_path=settings.MEDIA_ROOT,
rel_path="tmp",
),
prefix="zzz",
max_nb_chars=500,
)
Default MP3 generator class is `GttsMp3Generator` which uses Google
Text-to-Speech services to generate an MP3 file from given or
randomly generated text. It does not require additional services to
run and the only dependency here is the `gtts` package. You can
however implement your own custom MP3 generator class and pass it to
te `mp3_file` method in `mp3_generator_cls` argument instead of the
default `GttsMp3Generator`.
Usage with custom MP3 generator class.
.. code-block:: python
# Imaginary `marytts` Python library
from marytts import MaryTTS
# Import BaseMp3Generator
from faker_file.providers.base.mp3_generator import (
BaseMp3Generator,
)
# Define custom MP3 generator
class MaryTtsMp3Generator(BaseMp3Generator):
locale: str = "cmu-rms-hsmm"
voice: str = "en_US"
def handle_kwargs(self, **kwargs) -> None:
# Since it's impossible to unify all TTS systems it's allowed
# to pass arbitrary arguments to the `BaseMp3Generator`
# constructor. Each implementation class contains its own
# additional tuning arguments. Check the source code of the
# implemented MP3 generators as an example.
if "locale" in kwargs:
self.locale = kwargs["locale"]
if "voice" in kwargs:
self.voice = kwargs["voice"]
def generate(self) -> bytes:
# Your implementation here. Note, that `self.content`
# in this context is the text to make MP3 from.
# `self.generator` would be the `Faker` or `Generator`
# instance from which you could extract information on
# active locale.
# What comes below is pseudo implementation.
mary_tts = MaryTTS(locale=self.locale, voice=self.voice)
return mary_tts.synth_mp3(self.content)
# Generate MP3 file from random text
file = FAKER.mp3_file(
mp3_generator_cls=MaryTtsMp3Generator,
)
"""
extension: str = "mp3"
@overload
def mp3_file(
self: "Mp3FileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
max_nb_chars: int = DEFAULT_AUDIO_MAX_NB_CHARS,
content: Optional[str] = None,
mp3_generator_cls: Optional[
Union[str, Type[BaseMp3Generator]]
] = DEFAULT_MP3_GENERATOR,
mp3_generator_kwargs: Optional[Dict[str, Any]] = None,
format_func: Callable[
[Union[Faker, Generator, Provider], str], str
] = DEFAULT_FORMAT_FUNC,
raw: bool = True,
**kwargs,
) -> BytesValue:
...
@overload
def mp3_file(
self: "Mp3FileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
max_nb_chars: int = DEFAULT_AUDIO_MAX_NB_CHARS,
content: Optional[str] = None,
mp3_generator_cls: Optional[
Union[str, Type[BaseMp3Generator]]
] = DEFAULT_MP3_GENERATOR,
mp3_generator_kwargs: Optional[Dict[str, Any]] = None,
format_func: Callable[
[Union[Faker, Generator, Provider], str], str
] = DEFAULT_FORMAT_FUNC,
**kwargs,
) -> StringValue:
...
[docs] def mp3_file(
self: "Mp3FileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
max_nb_chars: int = DEFAULT_AUDIO_MAX_NB_CHARS,
content: Optional[str] = None,
mp3_generator_cls: Optional[
Union[str, Type[BaseMp3Generator]]
] = DEFAULT_MP3_GENERATOR,
mp3_generator_kwargs: Optional[Dict[str, Any]] = None,
format_func: Callable[
[Union[Faker, Generator, Provider], str], str
] = DEFAULT_FORMAT_FUNC,
raw: bool = False,
**kwargs,
) -> Union[BytesValue, StringValue]:
"""Generate a MP3 file with random text.
:param storage: Storage. Defaults to `FileSystemStorage`.
:param basename: File basename (without extension).
:param prefix: File name prefix.
:param max_nb_chars: Max number of chars for the content.
:param content: File content. Might contain dynamic elements, which
are then replaced by correspondent fixtures.
:param mp3_generator_cls: Mp3 generator class.
:param mp3_generator_kwargs: Mp3 generator kwargs.
:param format_func: Callable responsible for formatting template
strings.
:param raw: If set to True, return `BytesValue` (binary content of
the file). Otherwise, return `StringValue` (path to the saved
file).
:return: Relative path (from root directory) of the generated file
or raw content of the file.
"""
# Generic
if storage is None:
storage = FileSystemStorage()
filename = storage.generate_filename(
extension=self.extension,
prefix=prefix,
basename=basename,
)
content = self._generate_text_content(
max_nb_chars=max_nb_chars,
content=content,
format_func=format_func,
)
data = {"content": content, "filename": filename, "storage": storage}
if mp3_generator_cls is None:
mp3_generator_cls = DEFAULT_MP3_GENERATOR
if isinstance(mp3_generator_cls, str):
mp3_generator_cls = load_class_from_path(mp3_generator_cls)
if not mp3_generator_kwargs:
mp3_generator_kwargs = {}
mp3_generator = mp3_generator_cls(
content=content,
generator=self.generator,
**mp3_generator_kwargs,
)
_raw_content = mp3_generator.generate()
if raw:
raw_content = BytesValue(_raw_content)
raw_content.data = data
return raw_content
storage.write_bytes(filename, _raw_content)
# Generic
file_name = StringValue(storage.relpath(filename))
file_name.data = data
FILE_REGISTRY.add(file_name)
return file_name