GroupDocs.Assembly for Python via .NET supports both file paths and streams for template loading and document saving. Understanding when to use each approach helps you build efficient, scalable applications. File paths are simpler for local file system operations, while streams are essential for memory-based processing, remote templates, and web applications.
Here are the considerations for choosing between streams and file paths:
Use file paths for simple local file system operations
Use streams for memory-based processing, remote templates, or web applications
Open a file as a binary stream when one side is a file and the other is in memory
Always close the streams you open, preferably with a with block
Note
assemble_document takes the template and the report as two paths or as two streams, optionally with LoadSaveOptions before the data sources. A stream is a binary file object: open(path, "rb") or io.BytesIO. Streams can also be passed by keyword: source_stream=, target_stream= and then data_source_infos=.
When to Use File Paths
File paths are ideal for:
Simple local file system operations
Templates stored on disk
Output documents saved to disk
Scripts and desktop applications with direct file access
fromdecimalimportDecimalfromgroupdocs.assemblyimportDataSourceInfo,DocumentAssembler# Simple file path approachtemplate_path="delivery-invoice.docx"output_path="delivery-invoice-report.docx"data={"CustomerName":"Quayside Bistro","Amount":Decimal("552.00")}assembler=DocumentAssembler()assembler.assemble_document(template_path,output_path,DataSourceInfo(data,"invoice"))print("Document assembled using file paths.")
importiofromdatetimeimportdatetimefromgroupdocs.assemblyimportDataSourceInfo,DocumentAssembler# Load template into memorywithopen("stock-report.docx","rb")asf:template_bytes=f.read()withio.BytesIO(template_bytes)astemplate_stream,io.BytesIO()asoutput_stream:data={"Title":"Quarterly stock report","Date":datetime(2015,3,31)}assembler=DocumentAssembler()assembler.assemble_document(template_stream,output_stream,DataSourceInfo(data,"report"))# Use output stream (e.g., send via HTTP, save to database)output_bytes=output_stream.getvalue()withopen("stock-report-report.docx","wb")asf:f.write(output_bytes)print("Document assembled using streams.")
The following sample file is used in this example: stock-report.docx
assemble_document has no form that takes a path for one side and a stream for the other. To load the template from a file and keep the report in memory, open the file as a stream:
importiofromgroupdocs.assemblyimportDataSourceInfo,DocumentAssembler# Template from a file, output to a memory streamwithopen("stock-item.docx","rb")astemplate_stream,io.BytesIO()asoutput_stream:data={"Name":"Smoked sea salt","Value":100}assembler=DocumentAssembler()assembler.assemble_document(template_stream,output_stream,DataSourceInfo(data,"item"))# Use output stream (e.g., send via HTTP response)output_bytes=output_stream.getvalue()print("Document assembled, output size: {0} bytes".format(len(output_bytes)))
The following sample file is used in this example: stock-item.docx
To load the template from memory and save the report to a file, pass the file, opened for writing in binary mode, as the output stream:
importiofromdatetimeimportdatetimefromgroupdocs.assemblyimportDataSourceInfo,DocumentAssembler# Template from a memory streamwithopen("stock-report.docx","rb")asf:template_bytes=f.read()data={"Title":"Monthly stock report","Date":datetime(2015,4,30)}# Report to a file opened for writingwithio.BytesIO(template_bytes)astemplate_stream,open("stock-report-from-stream.docx","wb")asoutput_stream:assembler=DocumentAssembler()assembler.assemble_document(template_stream,output_stream,DataSourceInfo(data,"report"))print("Document assembled from stream to file.")
The following sample file is used in this example: stock-report.docx
In web applications, streams are typically preferred: the template comes as bytes and the response body is bytes. This function fits a Flask, Django or FastAPI view:
importiofromgroupdocs.assemblyimportDataSourceInfo,DocumentAssemblerdefgenerate_document_for_web(template_bytes,data):withio.BytesIO(template_bytes)astemplate_stream,io.BytesIO()asoutput_stream:assembler=DocumentAssembler()assembler.assemble_document(template_stream,output_stream,DataSourceInfo(data,"data"))returnoutput_stream.getvalue()withopen("web-order.docx","rb")asf:template_bytes=f.read()order={"CustomerName":"Pier Nine Kitchen","ProductName":"Smoked sea salt","Quantity":50}document_bytes=generate_document_for_web(template_bytes,order)withopen("web-order-report.docx","wb")asf:f.write(document_bytes)
The following sample file is used in this example: web-order.docx
Streams enable loading templates from URLs or remote sources. To keep the example runnable, it opens the template’s own file: URL; an https:// address works the same way:
Always close the streams you open. A with block closes them even when the assembly raises:
importiofromgroupdocs.assemblyimportDataSourceInfo,DocumentAssembler# Good: the with block closes both streamswithopen("stock-item.docx","rb")astemplate_stream,io.BytesIO()asoutput_stream:data={"Name":"Chestnut honey","Value":190}assembler=DocumentAssembler()assembler.assemble_document(template_stream,output_stream,DataSourceInfo(data,"item"))withopen("stock-item-report.docx","wb")asf:f.write(output_stream.getvalue())# Streams are closed hereprint("Streams properly disposed.")
The following sample file is used in this example: stock-item.docx
DocumentAssembler closes neither the template stream nor the output stream: both are still open when assemble_document returns, and the output io.BytesIO is positioned at 0 with the whole document in getvalue(). Closing them is up to your code.
Performance Considerations
File Paths: Simpler; the engine reads and writes the files itself
Streams: More flexible; nothing touches the disk unless you write it
Memory Streams (io.BytesIO): Best for small to medium documents, since the whole document is held in memory
File Streams (open(path, "rb")): Read a template from disk without loading it into a bytes object first
Advanced Usage Topics
To learn more about advanced stream handling and performance optimization, please refer to the advanced usage section.
More resources
GitHub Examples
You may easily run the code above and see the feature in action in our GitHub examples: