How to Convert Plain Text to PDF with Python
This Python tutorial sends a plain text file and structured conversion settings to the pdfRest Convert to PDF API Tool. It creates tagged output, preserves intentional source lines, and controls document metadata and visual presentation.
Why Convert Plain Text to PDF with Python?
Data pipelines and automation scripts often record validation findings, processing manifests, and experiment summaries in plain text. That output is convenient for machines and developers, but a PDF is easier to deliver as evidence, circulate for approval, or combine with other project documentation.
Suppose a Python data-quality job checks thousands of incoming records and writes a summary containing rule names, counts, and representative failures. After the run, the same workflow can convert the summary into a PDF for the data steward’s review packet. Preserved line handling keeps each finding distinct, while consistent page settings make recurring reports easier to compare.
A script producing longer narrative observations can request reflow instead and let the service form readable paragraphs. This gives Python automation an intentional text-layout choice while retaining centralized control over fonts, margins, language metadata, and tagging.
Python Code Example for Converting Plain Text to PDF
import json
import os
import requests
# By default, we use the US-based API service. This is the primary endpoint for global use.
api_url = "https://api.pdfrest.com"
# For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below.
# For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
#api_url = "https://eu-api.pdfrest.com"
# This sample converts plain text input to a tagged PDF through multipart /pdf.
# It demonstrates structured_text_options and the format-specific conversion options.
input_path = "/path/to/sample.txt"
options = json.loads(r'''{
"title": "Structured Content Sample",
"language": "en-US",
"enable_tagging": true,
"page_setup": {
"size": "Letter",
"orientation": "portrait",
"margin": {
"top": 36,
"right": 42,
"bottom": 36,
"left": 42
}
},
"style": {
"font": "Arial",
"heading_font": "Arial",
"code_font": "Courier",
"text_size": 11,
"text_color_rgb": [
34,
34,
34
],
"heading_scale": 1.35,
"table": {
"column_width_weights": [
2,
3,
2
],
"keep_header_with_first_row": true,
"repeat_headers_on_overflow": true,
"show_borders": true,
"border_width": 0.75,
"border_color_rgb": [
180,
188,
200
],
"header_fill_color_rgb": [
33,
64,
98
],
"header_text_color_rgb": [
255,
255,
255
],
"row_fill_color_rgb": [
250,
250,
252
],
"alternate_row_fill_color_rgb": [
235,
240,
246
],
"cell_padding": {
"top": 6,
"right": 8,
"bottom": 6,
"left": 8
}
}
},
"plain_text": {
"line_handling": "preserve"
}
}''')
from requests_toolbelt import MultipartEncoder
with open(input_path, "rb") as input_file:
fields = {
"file": (os.path.basename(input_path), input_file, "text/plain"),
"structured_text_options": json.dumps(options),
}
form = MultipartEncoder(fields=fields)
response = requests.post(api_url + "/pdf", data=form, headers={
"Accept": "application/json",
"Content-Type": form.content_type,
"Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
})
print("Response status code: " + str(response.status_code))
if response.ok:
print(json.dumps(response.json(), indent=2))
else:
print(response.text)
raise SystemExit(1)
Source: View the sample on GitHub
Breaking Down the Code
The Python Plain Text sample uses requests and MultipartEncoder from requests-toolbelt. Install both with python -m pip install requests requests-toolbelt when they are not already present.
import json import os import requests
This Python endpoint excerpt identifies the regional service used for Plain Text conversion:
# By default, we use the US-based API service. This is the primary endpoint for global use. api_url = "https://api.pdfrest.com" # For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below. # For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work #api_url = "https://eu-api.pdfrest.com"
Python opens the .txt input in binary mode and sends its base filename with the stream. /pdf uses that filename extension to infer the Plain Text input type.
# It demonstrates structured_text_options and the format-specific conversion options.
input_path = "/path/to/sample.txt"
options = json.loads(r'''{
The options dictionary becomes pdfRest’s structured_text_options field. It supplies document metadata, explicitly requests tags, establishes Letter portrait pages and 36-point margins, and selects the fonts, text size, color, and Plain Text-specific presentation values.
{
"plain_text": {
"line_handling": "preserve"
}
}
preserve keeps every normalized source line and its spacing in a preformatted block. Windows and legacy carriage-return line endings are normalized consistently. The alternative reflow joins consecutive nonblank lines into paragraphs, using blank lines as paragraph boundaries; reflow is the default when the field is omitted. Only those two values are accepted. When horizontal alignment matters, select a monospaced body font because preserve mode retains characters and spacing but does not force a particular font.
The sample also carries style.table because the repository uses one broad structured-text profile. Plain Text does not create a table, so those table colors, borders, widths, and padding have no effect and may be omitted from a text-only integration.
For the Plain Text call, MultipartEncoder combines the file tuple with serialized structured_text_options. Its content_type, including the boundary, becomes the request’s Content-Type header.
with open(input_path, "rb") as input_file:
fields = {
"file": (os.path.basename(input_path), input_file, "text/plain"),
"structured_text_options": json.dumps(options),
}
form = MultipartEncoder(fields=fields)
response = requests.post(api_url + "/pdf", data=form, headers={
"Accept": "application/json",
"Content-Type": form.content_type,
"Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
})
requests.post sends the encoded Plain Text form with the API key. The script pretty-prints resource JSON after success and otherwise displays the API message before exiting with a nonzero status.
"file": (os.path.basename(input_path), input_file, "text/plain"),
"structured_text_options": json.dumps(options),
}
form = MultipartEncoder(fields=fields)
response = requests.post(api_url + "/pdf", data=form, headers={
"Accept": "application/json",
"Content-Type": form.content_type,
"Api-Key": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
})
print("Response status code: " + str(response.status_code))
if response.ok:
print(json.dumps(response.json(), indent=2))
Beyond the Tutorial
Python automation can convert test output, research notes, and scheduled text exports into consistently paginated PDFs while selecting preserve or reflow behavior for each source. Document tags help expose structure but are not an accessibility certification.
Keep only the structured options that serve the workflow’s layout requirements. Compare results through API Lab, then consult the Convert to PDF documentation for defaults, accepted values, and constraints.