{"id":7761,"library":"streaming-form-data","title":"Streaming Form Data Parser","description":"streaming-form-data is a Python library designed for parsing `multipart/form-data` HTTP requests in a streaming fashion, making it suitable for handling large file uploads and form submissions without loading the entire request body into memory. The current version is 2.0.0, and it follows an active maintenance release cadence, with major versions introducing significant changes.","status":"active","version":"2.0.0","language":"en","source_language":"en","source_url":"https://github.com/siddhantgoel/streaming-form-data","tags":["http","forms","multipart","streaming","file-upload","web"],"install":[{"cmd":"pip install streaming-form-data","lang":"bash","label":"Install base library"},{"cmd":"pip install streaming-form-data[charset_detection]","lang":"bash","label":"Install with optional charset detection (cchardet)"}],"dependencies":[{"reason":"Optional dependency for more robust charset detection; without it, UTF-8 is assumed for field values.","package":"cchardet","optional":true}],"imports":[{"note":"Class was renamed from `MultipartFormParser` to `StreamingFormDataParser` in v2.0.0.","wrong":"from streaming_form_data import MultipartFormParser","symbol":"StreamingFormDataParser","correct":"from streaming_form_data import StreamingFormDataParser"},{"note":"`ParseFailed` exception was moved to the `exceptions` submodule in v2.0.0.","wrong":"from streaming_form_data import ParseFailed","symbol":"ParseFailed","correct":"from streaming_form_data.exceptions import ParseFailed"},{"note":"`File` target was renamed to `FileTarget` in v2.0.0.","wrong":"from streaming_form_data.targets import File","symbol":"FileTarget","correct":"from streaming_form_data.targets import FileTarget"},{"symbol":"ValueTarget","correct":"from streaming_form_data.targets import ValueTarget"}],"quickstart":{"code":"import io\nfrom streaming_form_data import StreamingFormDataParser\nfrom streaming_form_data.targets import ValueTarget, FileTarget\n\n# Simulate an incoming HTTP request body and headers\nboundary = b'----WebKitFormBoundary7MA4YWxkTrZu0gW'\ncontent_type = b'multipart/form-data; boundary=' + boundary\npayload = (\n    b'--' + boundary + b'\\r\\n'\n    b'Content-Disposition: form-data; name=\"text_field\"\\r\\n'\n    b'\\r\\n'\n    b'Hello Streaming World!'\n    b'\\r\\n'\n    b'--' + boundary + b'\\r\\n'\n    b'Content-Disposition: form-data; name=\"file_upload\"; filename=\"message.txt\"\\r\\n'\n    b'Content-Type: text/plain\\r\\n'\n    b'\\r\\n'\n    b'This is a test file content.\\nLine two.\\n'\n    b'\\r\\n'\n    b'--' + boundary + b'--\\r\\n'\n)\n\nheaders = {b'Content-Type': content_type}\nparser = StreamingFormDataParser(headers=headers)\n\ntext_field = ValueTarget()\nfile_target = FileTarget(file_path='/tmp/uploaded_message.txt') # Path where the file will be saved\n\nparser.register('text_field', text_field)\nparser.register('file_upload', file_target)\n\n# In a real web application, `request.body` would be streamed here\n# For this example, we use a BytesIO object to simulate the stream\nstream = io.BytesIO(payload)\nwhile True:\n    chunk = stream.read(8192) # Read in chunks\n    if not chunk:\n        break\n    parser.data_received(chunk)\n\nprint(f\"Text field value: '{text_field.value.decode()}'\")\nprint(f\"File saved to: '{file_target.file_path}'\")\n\n# Verify content (optional, for demonstration)\nwith open(file_target.file_path, 'rb') as f:\n    print(f\"File content: '{f.read().decode()}'\")","lang":"python","description":"This quickstart demonstrates how to parse a `multipart/form-data` payload containing both a text field and a file upload. It simulates an incoming HTTP stream using `io.BytesIO`, registers `ValueTarget` for text fields and `FileTarget` for files, and processes the stream in chunks."},"warnings":[{"fix":"Update all class names, import paths, and constructor calls according to the v2.0.0 changelog. Ensure your environment uses Python 3.10+.","message":"Version 2.0.0 introduced significant breaking changes. Key classes were renamed (`MultipartFormParser` to `StreamingFormDataParser`, `File` to `FileStream`), constructor arguments for `Field` and `FileStream` were modified, and `ParseFailed` exception was moved. Python 3.10 or newer is now required.","severity":"breaking","affected_versions":">=2.0.0 (from 1.x.x)"},{"fix":"Always wrap parser operations in a `try...except ParseFailed:` block. Thoroughly validate incoming `Content-Type` headers and ensure client-side form data generation adheres to RFC 7578. Double-check the boundary string.","message":"The `streaming_form_data.exceptions.ParseFailed` exception is raised for any malformed `multipart/form-data` payload. This includes incorrect `Content-Type` headers (missing boundary, wrong media type), or an invalid structure within the payload itself.","severity":"gotcha","affected_versions":"All"},{"fix":"Install `cchardet` via `pip install streaming-form-data[charset_detection]`. The library will then automatically use `cchardet` for charset detection if available.","message":"By default, `streaming-form-data` assumes UTF-8 encoding for text fields. If you need robust detection for other charsets (e.g., ISO-8859-1), you must install the optional `cchardet` dependency.","severity":"gotcha","affected_versions":"All"},{"fix":"Ensure you are reading from the incoming stream (e.g., `request.body` in a web framework) in small chunks (e.g., 8192 bytes) within a loop and passing each chunk to `parser.data_received(chunk)`.","message":"This library is designed for streaming. Failing to feed data to the parser in chunks (e.g., trying to read an entire large request body into memory before passing it to `parser.data_received`) defeats its purpose and can lead to memory exhaustion.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Change `MultipartFormParser` to `StreamingFormDataParser`.","cause":"You are using a class name from version 1.x.x of the library, which was renamed in v2.0.0.","error":"NameError: name 'MultipartFormParser' is not defined"},{"fix":"Update the import statement: `from streaming_form_data.exceptions import ParseFailed`.","cause":"The `ParseFailed` exception was moved to a specific submodule in v2.0.0.","error":"AttributeError: type object 'ParseFailed' has no attribute '__module__'"},{"fix":"Verify that the `Content-Type` header passed to `StreamingFormDataParser` exactly matches the client's header, particularly the `boundary`. Also, check that the payload is well-formed with correct boundary markers (`--boundary\\r\\n` and `--boundary--\\r\\n` at the end).","cause":"The incoming `multipart/form-data` payload is structurally incorrect, or the `Content-Type` header (especially the `boundary` parameter) does not match the actual boundary strings in the request body.","error":"streaming_form_data.exceptions.ParseFailed: Malformed multipart body"},{"fix":"Replace `filename='your_file.txt'` with `file_path='/path/to/save/your_file.txt'` when instantiating `FileTarget`.","cause":"The `FileTarget` class (previously `File`) in v2.0.0 no longer accepts a `filename` argument directly in its constructor. It expects `file_path` for a path or `target` for a file-like object.","error":"TypeError: FileTarget() got an unexpected keyword argument 'filename'"}]}