Skip to content

Commit 3bc9436

Browse files
committed
add python paper muncher package
1 parent cd0f588 commit 3bc9436

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+2690
-153
lines changed
19.2 KB
Binary file not shown.
16.2 KB
Binary file not shown.
3.7 KB
Binary file not shown.
2.47 KB
Binary file not shown.
27.2 KB
Binary file not shown.

meta/bindings/python/README.md

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
# Paper Muncher Python Bindings
2+
3+
## Usage examples
4+
5+
### Functional Usage
6+
7+
Paper Muncher includes both synchronous and asynchronous functional APIs.
8+
9+
```python
10+
from paper_muncher.synchronous import render
11+
12+
13+
html = """
14+
<h1>Hello, Paper Muncher!</h1>
15+
<p>This is a simple example of using Paper Muncher in a synchronous context.</p>
16+
"""
17+
18+
19+
def main():
20+
pdf_bytes = render(html, mode="print")
21+
with open("output.pdf", "wb") as f:
22+
f.write(pdf_bytes)
23+
```
24+
25+
**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.
26+
27+
1. For POSIX systems, it relies on selectors.
28+
2. For Windows with Python 3.12+, it puts the file in non-blocking mode.
29+
3. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.
30+
31+
```python
32+
from paper_muncher.asynchronous import render
33+
34+
35+
html = """
36+
<h1>Hello, Paper Muncher!</h1>
37+
<p>This is a simple example of using Paper Muncher in an asynchronous context.</p>
38+
"""
39+
40+
41+
async def main():
42+
pdf_bytes = await render(html, mode="print")
43+
with open("output_async.pdf", "wb") as f:
44+
f.write(pdf_bytes)
45+
```
46+
47+
In addition to that it also includes a context based approach to automatically
48+
handle synchronous and asynchronous code execution.
49+
50+
```python
51+
from paper_muncher import render
52+
53+
54+
html = """
55+
<h1>Hello, Paper Muncher!</h1>
56+
<p>This is a simple example of using Paper Muncher in an auto context.</p>
57+
"""
58+
59+
async def main_async():
60+
pdf_bytes = await render(html, mode="print")
61+
with open("output_async.pdf", "wb") as f:
62+
f.write(pdf_bytes)
63+
64+
print("PDF generated and saved as output_async.pdf")
65+
66+
67+
def main_sync():
68+
pdf_bytes = render(html, mode="print")
69+
with open("output_sync.pdf", "wb") as f:
70+
f.write(pdf_bytes)
71+
72+
print("PDF generated and saved as output_sync.pdf")
73+
```
74+
75+
### Context Manager Usage
76+
77+
Paper Muncher includes both synchronous and asynchronous context manager APIs.
78+
79+
```python
80+
from paper_muncher.synchronous import rendered
81+
82+
83+
html = """
84+
<h1>Hello, Paper Muncher!</h1>
85+
<p>This is a simple example of using Paper Muncher in a synchronous context.</p>
86+
"""
87+
88+
89+
def main():
90+
with rendered(html, mode="print") as (pdf_io_stream, std_err):
91+
pdf = pdf_io_stream.read()
92+
93+
with open("output_sync.pdf", "wb") as f:
94+
```
95+
96+
**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.
97+
98+
1. For POSIX systems, it relies on selectors.
99+
2. For Windows with Python 3.12+, it puts the file in non-blocking mode.
100+
3. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.
101+
102+
```python
103+
from paper_muncher.asynchronous import rendered
104+
105+
106+
html = """
107+
<h1>Hello, Paper Muncher!</h1>
108+
<p>This is a simple example of using Paper Muncher in an asynchronous context.</p>
109+
"""
110+
111+
112+
async def main():
113+
async with rendered(html, mode="print") as (pdf_stream_reader, std_err):
114+
pdf = await pdf_stream_reader.read()
115+
116+
with open("output_async.pdf", "wb") as f:
117+
f.write(pdf)
118+
```
119+
120+
In addition to that it also includes a context based approach to automatically
121+
handle synchronous and asynchronous code execution.
122+
123+
```python
124+
from paper_muncher import rendered
125+
126+
127+
html = """
128+
<h1>Hello, Paper Muncher!</h1>
129+
<p>This is a simple example of using Paper Muncher in an auto context.</p>
130+
"""
131+
132+
def main_sync():
133+
with rendered(html, mode="print") as (pdf_io_stream, std_err):
134+
pdf = pdf_io_stream.read()
135+
136+
with open("output_sync.pdf", "wb") as f:
137+
f.write(pdf)
138+
139+
print("PDF generated and saved as output_sync.pdf")
140+
141+
142+
async def main_async():
143+
async with rendered(html, mode="print") as (pdf_stream_reader, std_err):
144+
pdf = await pdf_stream_reader.read()
145+
146+
with open("output_async.pdf", "wb") as f:
147+
f.write(pdf)
148+
149+
print("PDF generated and saved as output_async.pdf")
150+
```
151+
152+
Paper Muncher comes with pre-made integration with some
153+
of the most popular frameworks as well!
154+
155+
* Flask
156+
* Quart
157+
* Fast API
158+
* Django
159+
160+
Your favorite framework is not in the list?
161+
No worries! Some general implementation are also
162+
present!
163+
164+
* agnostic WSGI integration
165+
* agnostic ASGI integration
166+
167+
### Flask
168+
169+
```python
170+
from paper_muncher.frameworks.flask import register_paper_muncher
171+
from flask import Flask, Response
172+
173+
app = Flask(__name__)
174+
register_paper_muncher(app)
175+
176+
177+
@app.route("/")
178+
def index():
179+
html_content = "<h1>Hello, Paper Muncher with Flask!</h1>"
180+
pdf_bytes = app.run_paper_muncher(html_content, mode="print")
181+
return Response(pdf_bytes, mimetype="application/pdf")
182+
```
183+
184+
### Quart
185+
186+
```python
187+
from paper_muncher.frameworks.quart import register_paper_muncher
188+
from quart import Quart, Response
189+
190+
app = Quart(__name__)
191+
register_paper_muncher(app)
192+
193+
194+
@app.route("/")
195+
async def index():
196+
html_content = "<h1>Hello, Paper Muncher with Quart!</h1>"
197+
pdf_bytes = await app.run_paper_muncher(html_content, mode="print")
198+
return Response(pdf_bytes, mimetype="application/pdf")
199+
```
200+
201+
### FastAPI
202+
203+
```python
204+
from fastapi import FastAPI, Response
205+
from paper_muncher.frameworks.fastapi import register_paper_muncher
206+
207+
app = FastAPI()
208+
register_paper_muncher(app)
209+
210+
211+
@app.get("/")
212+
async def index():
213+
html_content = "<h1>Hello, Paper Muncher with FastAPI!</h1>"
214+
pdf_bytes = await app.run_paper_muncher(html_content)
215+
return Response(content=pdf_bytes, media_type="application/pdf")
216+
```
217+
218+
### Django
219+
220+
WSGI.
221+
222+
```python
223+
import os
224+
from wsgiref.simple_server import make_server
225+
226+
from django.conf import settings
227+
from django.core.wsgi import get_wsgi_application
228+
from django.http import HttpResponse
229+
from django.urls import path
230+
from django.core.management import execute_from_command_line
231+
232+
from paper_muncher.frameworks.django_wsgi import register_paper_muncher
233+
234+
235+
BASE_DIR = os.path.dirname(__file__)
236+
settings.configure(
237+
DEBUG=True,
238+
ROOT_URLCONF=__name__,
239+
SECRET_KEY="dummy",
240+
ALLOWED_HOSTS=["*"],
241+
MIDDLEWARE=[],
242+
)
243+
244+
245+
def index(request):
246+
html = "<h1>Hello from Django WSGI!</h1>"
247+
pdf = application.run_paper_muncher(html)
248+
return HttpResponse(pdf, content_type="application/pdf")
249+
250+
251+
urlpatterns = [
252+
path("", index),
253+
]
254+
255+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "__main__")
256+
257+
django_wsgi_app = get_wsgi_application()
258+
application = register_paper_muncher(django_wsgi_app)
259+
```
260+
261+
ASGI.
262+
263+
```python
264+
import os
265+
import asyncio
266+
267+
from django.conf import settings
268+
from django.core.asgi import get_asgi_application
269+
from django.http import HttpResponse
270+
from django.urls import path
271+
from django.core.management import execute_from_command_line
272+
273+
from asgiref.sync import async_to_sync
274+
from hypercorn.config import Config
275+
from hypercorn.asyncio import serve
276+
277+
from paper_muncher.frameworks.django_asgi import register_paper_muncher # Your patch
278+
279+
280+
BASE_DIR = os.path.dirname(__file__)
281+
settings.configure(
282+
DEBUG=True,
283+
ROOT_URLCONF=__name__,
284+
SECRET_KEY="dummy",
285+
ALLOWED_HOSTS=["*"],
286+
MIDDLEWARE=[],
287+
)
288+
289+
290+
def index(request):
291+
html = "<h1>Hello from Django!</h1>"
292+
pdf = async_to_sync(application.run_paper_muncher)(html)
293+
return HttpResponse(pdf, content_type="application/pdf")
294+
295+
296+
urlpatterns = [
297+
path("", index),
298+
]
299+
300+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "__main__")
301+
django_asgi_app = get_asgi_application()
302+
application = register_paper_muncher(django_asgi_app)
303+
```
27.7 KB
Binary file not shown.
15.3 KB
Binary file not shown.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
extensions = [
2+
"myst_parser",
3+
"sphinx.ext.autodoc",
4+
"sphinx.ext.napoleon",
5+
]
6+
extensions.append("sphinx_markdown_builder")
7+
source_suffix = {
8+
'.rst': 'restructuredtext',
9+
'.md': 'markdown',
10+
}
11+
master_doc = 'readme'
12+
exclude_patterns = [
13+
'examples.rst',
14+
'framework_examples.rst'
15+
]
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
================
2+
Functional Usage
3+
================
4+
Paper Muncher includes both synchronous and asynchronous functional APIs.
5+
6+
.. literalinclude:: ../examples/sync_example.py
7+
:language: python
8+
:linenos:
9+
:lines: 1-13
10+
:caption: Synchronous example
11+
:name: sync_example
12+
13+
**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.
14+
15+
#. For POSIX systems, it relies on `selectors`.
16+
#. For Windows with Python 3.12+, it puts the file in non-blocking mode.
17+
#. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.
18+
19+
.. literalinclude:: ../examples/async_example.py
20+
:language: python
21+
:linenos:
22+
:lines: 1-13
23+
:caption: Asynchronous example
24+
:name: async_example
25+
26+
In addition to that it also includes a context based approach to automatically
27+
handle synchronous and asynchronous code execution.
28+
29+
.. literalinclude:: ../examples/auto_mode_example.py
30+
:language: python
31+
:linenos:
32+
:lines: 1-22
33+
:caption: Auto Switching example
34+
:name: auto_example
35+
36+
37+
=====================
38+
Context Manager Usage
39+
=====================
40+
Paper Muncher includes both synchronous and asynchronous context manager APIs.
41+
42+
.. literalinclude:: ../examples/sync_cm_example.py
43+
:language: python
44+
:linenos:
45+
:lines: 1-14
46+
:caption: Synchronous Context Manager example
47+
:name: sync_cm_example
48+
49+
**N.B.** The synchronous API is based on a per-OS integration for IO timeouts.
50+
51+
#. For POSIX systems, it relies on `selectors`.
52+
#. For Windows with Python 3.12+, it puts the file in non-blocking mode.
53+
#. For Windows with Python < 3.12, it falls back to a potentially blocking read without timeout.
54+
55+
.. literalinclude:: ../examples/async_cm_example.py
56+
:language: python
57+
:linenos:
58+
:lines: 1-15
59+
:caption: Asynchronous Context Manager example
60+
:name: async_cm_example
61+
62+
In addition to that it also includes a context based approach to automatically
63+
handle synchronous and asynchronous code execution.
64+
65+
.. literalinclude:: ../examples/auto_mode_cm_example.py
66+
:language: python
67+
:linenos:
68+
:lines: 1-26
69+
:caption: Auto Switching example
70+
:name: auto_cm_example

0 commit comments

Comments
 (0)