from typing import (
Any,
Callable,
Dict,
Optional,
Sequence,
Tuple,
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,
DynamicTemplate,
FileMixin,
StringValue,
)
from ...constants import DEFAULT_TEXT_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.pdf_generator import BasePdfGenerator
from ..mixins.graphic_image_mixin import GraphicImageMixin
__author__ = "Artur Barseghyan <artur.barseghyan@gmail.com>"
__copyright__ = "2022-2023 Artur Barseghyan"
__license__ = "MIT"
__all__ = (
"DEFAULT_PDF_GENERATOR",
"GraphicPdfFileProvider",
"PDFKIT_PDF_GENERATOR",
"PIL_PDF_GENERATOR",
"PdfFileProvider",
"REPORTLAB_PDF_GENERATOR",
)
PDFKIT_PDF_GENERATOR = (
"faker_file.providers.pdf_file.generators.pdfkit_generator"
".PdfkitPdfGenerator"
)
PIL_PDF_GENERATOR = (
"faker_file.providers.pdf_file.generators.pil_generator.PilPdfGenerator"
)
REPORTLAB_PDF_GENERATOR = (
"faker_file.providers.pdf_file.generators.reportlab_generator"
".ReportlabPdfGenerator"
)
DEFAULT_PDF_GENERATOR = PDFKIT_PDF_GENERATOR
[docs]class PdfFileProvider(BaseProvider, FileMixin):
"""PDF file provider.
Usage example:
.. code-block:: python
from faker import Faker
from faker_file.providers.pdf_file import PdfFileProvider
FAKER = Faker()
FAKER.add_provider(PdfFileProvider)
file = FAKER.pdf_file()
Usage example with options:
.. code-block:: python
file = FAKER.pdf_file(
prefix="zzz",
max_nb_chars=100_000,
wrap_chars_after=80,
)
Usage example with `FileSystemStorage` storage (for `Django`):
.. code-block:: python
from django.conf import settings
from faker_file.storages.filesystem import FileSystemStorage
file = FAKER.pdf_file(
storage=FileSystemStorage(
root_path=settings.MEDIA_ROOT,
rel_path="tmp",
),
prefix="zzz",
max_nb_chars=100_000,
wrap_chars_after=80,
)
Default PDF generator class is `PdfkitPdfGenerator` which uses `pdfkit`
Python package and `wkhtmltopdf` system package for generating PDFs from
randomly generated text. The quality of the produced PDFs is very good,
but it's less performant than `ReportlabPdfGenerator` (factor 40x), which
does not require additional system dependencies to run. To use it, pass
`ReportlabPdfGenerator` class in `pdf_generator_cls` argument.
.. code-block:: python
from faker_file.providers.pdf_file.generators import (
reportlab_generator,
)
file = FAKER.pdf_file(
max_nb_chars=1_000,
wrap_chars_after=80,
pdf_generator_cls=reportlab_generator.ReportlabPdfGenerator,
)
"""
extension: str = "pdf"
@overload
def pdf_file(
self: "PdfFileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
max_nb_chars: int = DEFAULT_TEXT_MAX_NB_CHARS,
wrap_chars_after: Optional[int] = None,
content: Optional[Union[str, DynamicTemplate]] = None,
pdf_generator_cls: Optional[Union[str, Type[BasePdfGenerator]]] = (
DEFAULT_PDF_GENERATOR
),
pdf_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 pdf_file(
self: "PdfFileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
max_nb_chars: int = DEFAULT_TEXT_MAX_NB_CHARS,
wrap_chars_after: Optional[int] = None,
content: Optional[Union[str, DynamicTemplate]] = None,
pdf_generator_cls: Optional[Union[str, Type[BasePdfGenerator]]] = (
DEFAULT_PDF_GENERATOR
),
pdf_generator_kwargs: Optional[Dict[str, Any]] = None,
format_func: Callable[
[Union[Faker, Generator, Provider], str], str
] = DEFAULT_FORMAT_FUNC,
**kwargs,
) -> StringValue:
...
[docs] def pdf_file(
self: "PdfFileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
max_nb_chars: int = DEFAULT_TEXT_MAX_NB_CHARS,
wrap_chars_after: Optional[int] = None,
content: Optional[Union[str, DynamicTemplate]] = None,
pdf_generator_cls: Optional[Union[str, Type[BasePdfGenerator]]] = (
DEFAULT_PDF_GENERATOR
),
pdf_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 PDF 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 wrap_chars_after: If given, the output string would be separated
by line breaks after the given position.
:param content: File content. Might contain dynamic elements, which
are then replaced by correspondent fixtures.
:param pdf_generator_cls: PDF generator class.
:param pdf_generator_kwargs: PDF 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,
)
if pdf_generator_cls is None:
pdf_generator_cls = DEFAULT_PDF_GENERATOR
if isinstance(pdf_generator_cls, str):
pdf_generator_cls = load_class_from_path(pdf_generator_cls)
if not pdf_generator_kwargs:
pdf_generator_kwargs = {}
pdf_generator_kwargs["content_specs"] = {
"max_nb_chars": max_nb_chars,
"wrap_chars_after": wrap_chars_after,
}
pdf_generator = pdf_generator_cls(
generator=self.generator,
**pdf_generator_kwargs,
)
data = {"content": "", "filename": filename, "storage": storage}
if isinstance(content, DynamicTemplate):
_content = content
else:
_content = self._generate_text_content(
max_nb_chars=max_nb_chars,
wrap_chars_after=wrap_chars_after,
content=content,
format_func=format_func,
)
data["content"] = _content
_raw_content = pdf_generator.generate(
content=_content,
data=data,
provider=self,
)
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
[docs]class GraphicPdfFileProvider(BaseProvider, GraphicImageMixin):
"""Graphic PDF file provider.
Usage example:
.. code-block:: python
from faker import Faker
from faker_file.providers.pdf_file import GraphicPdfFileProvider
FAKER = Faker()
FAKER.add_provider(GraphicPdfFileProvider)
file = FAKER.graphic_pdf_file()
Usage example with options:
.. code-block:: python
file = FAKER.graphic_pdf_file(
prefix="zzz",
size=(800, 800),
)
Usage example with `FileSystemStorage` storage (for `Django`):
.. code-block:: python
from django.conf import settings
from faker_file.storages.filesystem import FileSystemStorage
file = FAKER.graphic_pdf_file(
storage=FileSystemStorage(
root_path=settings.MEDIA_ROOT,
rel_path="tmp",
),
basename="yyy",
size=(1024, 1024),
)
"""
extension: str = "pdf"
image_format: str = "pdf"
@overload
def graphic_pdf_file(
self: "GraphicPdfFileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
size: Tuple[int, int] = (256, 256),
hue: Union[int, Sequence[int], str, None] = None,
luminosity: Optional[str] = None,
raw: bool = True,
**kwargs,
) -> BytesValue:
...
@overload
def graphic_pdf_file(
self: "GraphicPdfFileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
size: Tuple[int, int] = (256, 256),
hue: Union[int, Sequence[int], str, None] = None,
luminosity: Optional[str] = None,
**kwargs,
) -> StringValue:
...
[docs] def graphic_pdf_file(
self: "GraphicPdfFileProvider",
storage: Optional[BaseStorage] = None,
basename: Optional[str] = None,
prefix: Optional[str] = None,
size: Tuple[int, int] = (256, 256),
hue: Union[int, Sequence[int], str, None] = None,
luminosity: Optional[str] = None,
raw: bool = False,
**kwargs,
) -> Union[BytesValue, StringValue]:
"""Generate a graphic PDF file with random lines.
:param storage: Storage. Defaults to `FileSystemStorage`.
:param basename: File basename (without extension).
:param prefix: File name prefix.
:param size: Image size in pixels.
:param hue: Read more about
://faker.readthedocs.io/en/dev/providers/faker.providers.color.html
:param luminosity: If given, the output string would be separated
by line breaks after the given position.
: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.
"""
return self._image_file(
image_format=self.image_format,
storage=storage,
basename=basename,
prefix=prefix,
size=size,
hue=hue,
luminosity=luminosity,
raw=raw,
**kwargs,
)