Poster3
Poster3 (version 0.8.1) is a Python library providing support for streaming HTTP POST requests and multipart/form-data encoding. It's a fork of the original 'poster' package, designed to address the limitation in Python's standard library where large files had to be loaded entirely into memory before uploading. The library allows for efficient uploading of large files without excessive memory consumption. Its last release was in December 2018, indicating a maintenance-level release cadence.
Common errors
-
TypeError: a bytes-like object is required, not 'str'
cause This error typically occurs when a file is opened in text mode ('r') but `poster3` expects a bytes-like object for stream processing, or when non-bytes data is passed where bytes are expected for encoding.fixAlways open files in binary read mode: `open(filename, 'rb')`. Ensure any string data passed for encoding is explicitly encoded to bytes if necessary, though `multipart_encode` usually handles string fields correctly. -
AttributeError: module 'poster' has no attribute 'streaminghttp' (or 'encode')
cause Users often try to import submodules directly from the top-level `poster` module (e.g., `import poster.streaminghttp`), but the correct way is to import specific components from their respective submodules (e.g., `from poster.streaminghttp import register_openers`).fixUse explicit `from poster.<submodule> import <symbol>` statements. For example, `from poster.streaminghttp import register_openers` or `from poster.encode import multipart_encode`. -
ValueError: Invalid boundary in multipart form data (or similar encoding errors)
cause This can happen if there are issues with non-ASCII characters in filenames or form field values, or if the `datagen` is modified incorrectly after `multipart_encode`.fixEnsure all string inputs (especially filenames and field values) are correctly encoded if they contain non-ASCII characters. `poster3` generally handles this, but explicit `str.encode('utf-8')` might be needed for unusual cases or when combining with other libraries. Also, avoid manual manipulation of `datagen`.
Warnings
- breaking The GitHub repository mentions a 'Version 0.9 Notice' indicating a complete internal rewrite and a shift from scattered functions to object-managed APIs. While 0.8.1 is the latest PyPI release, be aware that future versions (>=0.9) will likely introduce significant breaking changes to the API structure.
- gotcha The library's last release was in December 2018. This means it may not be actively maintained and might have compatibility issues with very recent Python versions (e.g., Python 3.9+) or modern HTTP client libraries. Consider testing thoroughly in your target environment.
- gotcha When opening files for upload, always use binary read mode ('rb'). Using text mode ('r') can lead to `TypeError` or incorrect encoding, especially on Windows where text mode might perform newline translations.
Install
-
pip install poster3
Imports
- multipart_encode
from poster.encode import multipart_encode
- streaminghttp
import poster.streaminghttp
from poster.streaminghttp import register_openers
Quickstart
import os
import urllib.request
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
# Register the streaming http handlers with urllib2
register_openers()
# Prepare file and simple field for upload
filename = 'test_upload.txt'
with open(filename, 'w') as f:
f.write('This is a test file for poster3 upload.')
# 'datagen' is a generator object that yields ranges of the encoded multipart data
# 'headers' is a dictionary of headers that must be included with the request
datagen, headers = multipart_encode({"field1": "value1", "file1": open(filename, "rb")})
# In a real scenario, you'd replace this with your actual upload URL
upload_url = os.environ.get('POSTER3_TEST_URL', 'http://httpbin.org/post')
# Create the request object
request = urllib.request.Request(upload_url, datagen, headers)
# Actually upload the file
print(f"Uploading to {upload_url}...")
try:
response = urllib.request.urlopen(request)
print("Upload successful!")
print(response.read().decode('utf-8'))
except urllib.error.URLError as e:
print(f"Upload failed: {e.reason}")
finally:
# Clean up the test file
os.remove(filename)