{"id":691,"library":"python-multipart","title":"Python Multipart","description":"python-multipart is an Apache2-licensed streaming multipart parser for Python. It is designed for handling `multipart/form-data` POST requests, typically used in web servers for file uploads and complex form data. The library is actively maintained with frequent releases, currently at version 0.0.22, and supports modern Python versions (>=3.10).","status":"active","version":"0.0.22","language":"python","source_language":"en","source_url":"https://github.com/Kludex/python-multipart","tags":["multipart","parser","streaming","http","forms","file-uploads","wsgi","asgi"],"install":[{"cmd":"pip install python-multipart","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Requires Python 3.10 or newer.","package":"python","optional":false}],"imports":[{"note":"The package to install is `python-multipart`, but the module to import is `python_multipart`. The old import path `import multipart` was changed in version 0.0.13 and conflicts with a separate, different PyPI package named `multipart`.","wrong":"import multipart","symbol":"MultipartParser","correct":"from python_multipart import MultipartParser"}],"quickstart":{"code":"import io\nfrom python_multipart import MultipartParser\n\n# Simulate an HTTP request body with multipart/form-data\nboundary = b\"----WebKitFormBoundary7MA4YWxkTrZu0gW\"\nbody_data = (\n    b\"--\" + boundary + b\"\\r\\n\"\n    b'Content-Disposition: form-data; name=\"username\"\\r\\n'\n    b'\\r\\n'\n    b'testuser\\r\\n'\n    b\"--\" + boundary + b\"\\r\\n\"\n    b'Content-Disposition: form-data; name=\"upload_file\"; filename=\"hello.txt\"\\r\\n'\n    b'Content-Type: text/plain\\r\\n'\n    b'\\r\\n'\n    b'Hello, World!\\nThis is a test file.\\r\\n'\n    b\"--\" + boundary + b\"--\\r\\n\"\n)\n\n# Simulate HTTP headers\nheaders = {\n    \"Content-Type\": f\"multipart/form-data; boundary={boundary.decode()}\",\n    \"Content-Length\": str(len(body_data)),\n}\n\n# Use BytesIO to simulate a file-like object for the body stream\nbody_stream = io.BytesIO(body_data)\n\n# Create a parser instance\nparser = MultipartParser(headers)\n\n# Iterate through parts and process them\nprint(\"Parsing multipart data:\")\nfor part in parser.parse(body_stream):\n    if hasattr(part, 'field_name'): # It's a form field\n        print(f\"  Field: name={part.field_name.decode()}, value={part.value.decode()}\")\n    elif hasattr(part, 'file_name'): # It's an uploaded file\n        print(f\"  File: name={part.field_name.decode()}, filename={part.file_name.decode()}, content_type={part.content_type.decode()}\")\n        file_content = part.value # The file content is available as bytes\n        print(f\"  File content length: {len(file_content)} bytes\")\n        # In a real application, you would typically save or process file_content\n\nprint(\"\\nParsing complete.\")","lang":"python","description":"This quickstart demonstrates how to parse a `multipart/form-data` request body using `MultipartParser`. It simulates an incoming HTTP request with form fields and a file, processing them using event-like iteration."},"warnings":[{"fix":"Update all import statements from `import multipart` or `from multipart import ...` to `from python_multipart import ...`.","message":"The import name was changed from `multipart` to `python_multipart` in version 0.0.13. Direct imports using `import multipart` will no longer work and may lead to `ModuleNotFoundError` or unexpected behavior if another `multipart` package is installed. Versions 0.0.13 and 0.0.14 were temporarily yanked due to breakage related to this change.","severity":"breaking","affected_versions":">=0.0.13"},{"fix":"Upgrade your Python environment to 3.10 or a newer supported version (e.g., 3.11, 3.12, 3.13, 3.14).","message":"Support for Python 3.8 and 3.9 was dropped in version 0.0.21. The library now requires Python 3.10 or newer.","severity":"breaking","affected_versions":">=0.0.21"},{"fix":"Always use `pip install python-multipart` to ensure the correct library is installed.","message":"A separate, unrelated package on PyPI is also named `multipart`. Installing `pip install multipart` instead of `pip install python-multipart` will install the wrong library, leading to `ModuleNotFoundError` if `from python_multipart import ...` is used, or unexpected behavior if `import multipart` is still in your code.","severity":"gotcha","affected_versions":"All versions"},{"fix":"If your application relied on `File.filename` containing a path, adjust your logic to expect only the base name. If paths are critical, you may need to implement custom logic to extract them from the `Content-Disposition` header directly (if present and needed).","message":"In version 0.0.22, the `File` object produced by the parser will no longer include directory paths in its `filename` attribute. It will only contain the base filename.","severity":"gotcha","affected_versions":">=0.0.22"},{"fix":"Ensure that clients sending multipart data adhere strictly to the `multipart/form-data` specification, particularly regarding the final boundary and any subsequent data.","message":"Version 0.0.18 introduced a 'hard break' if data is found after the last boundary in `MultipartParser`. This means the parser will now strictly enforce the end of the multipart body, potentially raising errors for malformed requests that previously might have been partially processed.","severity":"gotcha","affected_versions":">=0.0.18"},{"fix":"Monitor the project's changelog and documentation for details on upcoming deprecations. Address any `PendingDeprecationWarning` messages in your code to prepare for future breaking changes.","message":"In version 0.0.15, `FutureWarning` messages were replaced with `PendingDeprecationWarning`. While not a breaking change, it indicates that certain behaviors or features are slated for deprecation or removal in future major releases.","severity":"deprecated","affected_versions":">=0.0.15"},{"fix":"Instead of passing a dictionary of headers, extract the `Content-Type` header value (e.g., `headers.get('Content-Type')`) and pass that string or bytes object to `MultipartParser`. For example, `parser = MultipartParser(headers.get('Content-Type').encode('latin-1'))` if your headers are strings, or `parser = MultipartParser(headers.get(b'Content-Type'))` if your headers are bytes (assuming keys are bytes).","message":"The `TypeError: can't concat dict to bytes` when initializing `MultipartParser` indicates that a dictionary of HTTP headers (or any dict) was passed as the `content_type` argument. The `MultipartParser` constructor expects the raw value of the `Content-Type` header (a string or bytes) from which it can extract the boundary, or directly the boundary string/bytes, not the entire headers dictionary.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-12T17:51:43.162Z","next_check":"2026-06-26T00:00:00.000Z","problems":[{"fix":"pip install python-multipart","cause":"This error occurs when a web framework (like FastAPI or Starlette) attempts to process `multipart/form-data` requests but the `python-multipart` library, which it depends on for this functionality, is not installed.","error":"ImportError: 'python-multipart' must be installed to handle file uploads"},{"fix":"import multipart","cause":"The user is attempting to import the library using its PyPI distribution name (`python-multipart` converted to `python_multipart`), but the actual Python package name for import is `multipart`.","error":"ModuleNotFoundError: No module named 'python_multipart'"},{"fix":"Ensure the `Content-Type` header is set correctly (e.g., `multipart/form-data; boundary=your_boundary_string`) and matches the boundary string present in the request body.","cause":"This error indicates that the `multipart/form-data` parser could not find the expected boundary string in the request body, often due to a missing or incorrect `Content-Type` header or malformed multipart data.","error":"ValueError: No boundary found"},{"fix":"When working with the asynchronous `multipart.reader.MultipartReader`, ensure that all calls to its async methods (e.g., `read_part`, `next_part`) are prefixed with `await` within an `async` function.","cause":"This warning appears when an asynchronous method, such as `MultipartReader.read_part()`, is called but its returned coroutine object is not awaited, meaning the asynchronous operation is never actually executed.","error":"RuntimeWarning: coroutine 'MultipartReader.read_part' was never awaited"}],"ecosystem":"pypi","meta_description":null,"install_score":100,"install_tag":"verified","quickstart_score":0,"quickstart_tag":"stale","pypi_latest":"0.0.28","install_checks":{"last_tested":"2026-05-12","tag":"verified","tag_description":"installs cleanly on critical runtimes, fast import, recently tested","results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":3.3,"disk_size":"18.0M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":3.3,"disk_size":"18.0M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.5,"import_time_s":0.04,"mem_mb":3.3,"disk_size":"18M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.04,"mem_mb":3.3,"disk_size":"18M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.11,"mem_mb":3.7,"disk_size":"19.8M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.12,"mem_mb":3.7,"disk_size":"19.8M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.6,"import_time_s":0.1,"mem_mb":3.7,"disk_size":"20M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":3.7,"disk_size":"20M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":3.6,"disk_size":"11.7M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":3.6,"disk_size":"11.7M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.4,"import_time_s":0.09,"mem_mb":3.6,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":3.6,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":3.2,"disk_size":"11.5M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":3.2,"disk_size":"11.3M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.4,"import_time_s":0.07,"mem_mb":3,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.07,"mem_mb":3,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":3.2,"disk_size":"17.5M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":3.2,"disk_size":"17.5M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":" $EXIT -eq 0 ","exit_code":0,"wheel_type":"wheel","failure_reason":null,"install_time_s":1.7,"import_time_s":0.05,"mem_mb":3.2,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"default","exit_code":0,"wheel_type":null,"failure_reason":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":3.2,"disk_size":"18M"}]},"quickstart_checks":{"last_tested":"2026-04-24","tag":"stale","tag_description":"widespread failures or data too old to trust","results":[{"runtime":"python:3.10-alpine","exit_code":1},{"runtime":"python:3.10-slim","exit_code":1},{"runtime":"python:3.11-alpine","exit_code":1},{"runtime":"python:3.11-slim","exit_code":1},{"runtime":"python:3.12-alpine","exit_code":1},{"runtime":"python:3.12-slim","exit_code":1},{"runtime":"python:3.13-alpine","exit_code":1},{"runtime":"python:3.13-slim","exit_code":1},{"runtime":"python:3.9-alpine","exit_code":1},{"runtime":"python:3.9-slim","exit_code":1}]}}