Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added meta/bindings/python/.doctrees/environment.pickle
Binary file not shown.
Binary file added meta/bindings/python/.doctrees/examples.doctree
Binary file not shown.
Binary file not shown.
Binary file added meta/bindings/python/.doctrees/index.doctree
Binary file not shown.
Binary file added meta/bindings/python/.doctrees/readme.doctree
Binary file not shown.
303 changes: 303 additions & 0 deletions meta/bindings/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
# Paper Muncher Python Bindings

## Usage examples

### Functional Usage

Paper Muncher includes both synchronous and asynchronous functional APIs.

```python
from paper_muncher.synchronous import render


html = """
<h1>Hello, Paper Muncher!</h1>
<p>This is a simple example of using Paper Muncher in a synchronous context.</p>
"""


def main():
pdf_bytes = render(html, mode="print")
with open("output.pdf", "wb") as f:
f.write(pdf_bytes)
```

**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.

1. For POSIX systems, it relies on selectors.
2. For Windows with Python 3.12+, it puts the file in non-blocking mode.
3. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.

```python
from paper_muncher.asynchronous import render


html = """
<h1>Hello, Paper Muncher!</h1>
<p>This is a simple example of using Paper Muncher in an asynchronous context.</p>
"""


async def main():
pdf_bytes = await render(html, mode="print")
with open("output_async.pdf", "wb") as f:
f.write(pdf_bytes)
```

In addition to that it also includes a context based approach to automatically
handle synchronous and asynchronous code execution.

```python
from paper_muncher import render


html = """
<h1>Hello, Paper Muncher!</h1>
<p>This is a simple example of using Paper Muncher in an auto context.</p>
"""

async def main_async():
pdf_bytes = await render(html, mode="print")
with open("output_async.pdf", "wb") as f:
f.write(pdf_bytes)

print("PDF generated and saved as output_async.pdf")


def main_sync():
pdf_bytes = render(html, mode="print")
with open("output_sync.pdf", "wb") as f:
f.write(pdf_bytes)

print("PDF generated and saved as output_sync.pdf")
```

### Context Manager Usage

Paper Muncher includes both synchronous and asynchronous context manager APIs.

```python
from paper_muncher.synchronous import rendered


html = """
<h1>Hello, Paper Muncher!</h1>
<p>This is a simple example of using Paper Muncher in a synchronous context.</p>
"""


def main():
with rendered(html, mode="print") as (pdf_io_stream, std_err):
pdf = pdf_io_stream.read()

with open("output_sync.pdf", "wb") as f:
```

**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.

1. For POSIX systems, it relies on selectors.
2. For Windows with Python 3.12+, it puts the file in non-blocking mode.
3. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.

```python
from paper_muncher.asynchronous import rendered


html = """
<h1>Hello, Paper Muncher!</h1>
<p>This is a simple example of using Paper Muncher in an asynchronous context.</p>
"""


async def main():
async with rendered(html, mode="print") as (pdf_stream_reader, std_err):
pdf = await pdf_stream_reader.read()

with open("output_async.pdf", "wb") as f:
f.write(pdf)
```

In addition to that it also includes a context based approach to automatically
handle synchronous and asynchronous code execution.

```python
from paper_muncher import rendered


html = """
<h1>Hello, Paper Muncher!</h1>
<p>This is a simple example of using Paper Muncher in an auto context.</p>
"""

def main_sync():
with rendered(html, mode="print") as (pdf_io_stream, std_err):
pdf = pdf_io_stream.read()

with open("output_sync.pdf", "wb") as f:
f.write(pdf)

print("PDF generated and saved as output_sync.pdf")


async def main_async():
async with rendered(html, mode="print") as (pdf_stream_reader, std_err):
pdf = await pdf_stream_reader.read()

with open("output_async.pdf", "wb") as f:
f.write(pdf)

print("PDF generated and saved as output_async.pdf")
```

Paper Muncher comes with pre-made integration with some
of the most popular frameworks as well!

* Flask
* Quart
* Fast API
* Django

Your favorite framework is not in the list?
No worries! Some general implementation are also
present!

* agnostic WSGI integration
* agnostic ASGI integration

### Flask

```python
from paper_muncher.frameworks.flask import register_paper_muncher
from flask import Flask, Response

app = Flask(__name__)
register_paper_muncher(app)


@app.route("/")
def index():
html_content = "<h1>Hello, Paper Muncher with Flask!</h1>"
pdf_bytes = app.run_paper_muncher(html_content, mode="print")
return Response(pdf_bytes, mimetype="application/pdf")
```

### Quart

```python
from paper_muncher.frameworks.quart import register_paper_muncher
from quart import Quart, Response

app = Quart(__name__)
register_paper_muncher(app)


@app.route("/")
async def index():
html_content = "<h1>Hello, Paper Muncher with Quart!</h1>"
pdf_bytes = await app.run_paper_muncher(html_content, mode="print")
return Response(pdf_bytes, mimetype="application/pdf")
```

### FastAPI

```python
from fastapi import FastAPI, Response
from paper_muncher.frameworks.fastapi import register_paper_muncher

app = FastAPI()
register_paper_muncher(app)


@app.get("/")
async def index():
html_content = "<h1>Hello, Paper Muncher with FastAPI!</h1>"
pdf_bytes = await app.run_paper_muncher(html_content)
return Response(content=pdf_bytes, media_type="application/pdf")
```

### Django

WSGI.

```python
import os
from wsgiref.simple_server import make_server

from django.conf import settings
from django.core.wsgi import get_wsgi_application
from django.http import HttpResponse
from django.urls import path
from django.core.management import execute_from_command_line

from paper_muncher.frameworks.django_wsgi import register_paper_muncher


BASE_DIR = os.path.dirname(__file__)
settings.configure(
DEBUG=True,
ROOT_URLCONF=__name__,
SECRET_KEY="dummy",
ALLOWED_HOSTS=["*"],
MIDDLEWARE=[],
)


def index(request):
html = "<h1>Hello from Django WSGI!</h1>"
pdf = application.run_paper_muncher(html)
return HttpResponse(pdf, content_type="application/pdf")


urlpatterns = [
path("", index),
]

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "__main__")

django_wsgi_app = get_wsgi_application()
application = register_paper_muncher(django_wsgi_app)
```

ASGI.

```python
import os
import asyncio

from django.conf import settings
from django.core.asgi import get_asgi_application
from django.http import HttpResponse
from django.urls import path
from django.core.management import execute_from_command_line

from asgiref.sync import async_to_sync
from hypercorn.config import Config
from hypercorn.asyncio import serve

from paper_muncher.frameworks.django_asgi import register_paper_muncher # Your patch


BASE_DIR = os.path.dirname(__file__)
settings.configure(
DEBUG=True,
ROOT_URLCONF=__name__,
SECRET_KEY="dummy",
ALLOWED_HOSTS=["*"],
MIDDLEWARE=[],
)


def index(request):
html = "<h1>Hello from Django!</h1>"
pdf = async_to_sync(application.run_paper_muncher)(html)
return HttpResponse(pdf, content_type="application/pdf")


urlpatterns = [
path("", index),
]

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "__main__")
django_asgi_app = get_asgi_application()
application = register_paper_muncher(django_asgi_app)
```
Binary file not shown.
Binary file not shown.
15 changes: 15 additions & 0 deletions meta/bindings/python/documentation_source/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
extensions = [
"myst_parser",
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
]
extensions.append("sphinx_markdown_builder")
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown',
}
master_doc = 'readme'
exclude_patterns = [
'examples.rst',
'framework_examples.rst'
]
70 changes: 70 additions & 0 deletions meta/bindings/python/documentation_source/examples.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
================
Functional Usage
================
Paper Muncher includes both synchronous and asynchronous functional APIs.

.. literalinclude:: ../examples/sync_example.py
:language: python
:linenos:
:lines: 1-13
:caption: Synchronous example
:name: sync_example

**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.

#. For POSIX systems, it relies on `selectors`.
#. For Windows with Python 3.12+, it puts the file in non-blocking mode.
#. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.

.. literalinclude:: ../examples/async_example.py
:language: python
:linenos:
:lines: 1-13
:caption: Asynchronous example
:name: async_example

In addition to that it also includes a context based approach to automatically
handle synchronous and asynchronous code execution.

.. literalinclude:: ../examples/auto_mode_example.py
:language: python
:linenos:
:lines: 1-22
:caption: Auto Switching example
:name: auto_example


=====================
Context Manager Usage
=====================
Paper Muncher includes both synchronous and asynchronous context manager APIs.

.. literalinclude:: ../examples/sync_cm_example.py
:language: python
:linenos:
:lines: 1-14
:caption: Synchronous Context Manager example
:name: sync_cm_example

**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.

#. For POSIX systems, it relies on `selectors`.
#. For Windows with Python 3.12+, it puts the file in non-blocking mode.
#. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.

.. literalinclude:: ../examples/async_cm_example.py
:language: python
:linenos:
:lines: 1-15
:caption: Asynchronous Context Manager example
:name: async_cm_example

In addition to that it also includes a context based approach to automatically
handle synchronous and asynchronous code execution.

.. literalinclude:: ../examples/auto_mode_cm_example.py
:language: python
:linenos:
:lines: 1-26
:caption: Auto Switching example
:name: auto_cm_example
Loading
Loading